diff options
Diffstat (limited to 'src/libutil/util.cc')
-rw-r--r-- | src/libutil/util.cc | 50 |
1 files changed, 35 insertions, 15 deletions
diff --git a/src/libutil/util.cc b/src/libutil/util.cc index 0a5f796e4eaa..0bd51afd1a9f 100644 --- a/src/libutil/util.cc +++ b/src/libutil/util.cc @@ -1,6 +1,7 @@ #include "util.hh" #include "affinity.hh" #include "sync.hh" +#include "finally.hh" #include <cctype> #include <cerrno> @@ -10,6 +11,7 @@ #include <iostream> #include <sstream> #include <thread> +#include <future> #include <sys/wait.h> #include <unistd.h> @@ -94,6 +96,8 @@ Path absPath(Path path, Path dir) Path canonPath(const Path & path, bool resolveSymlinks) { + assert(path != ""); + string s; if (path[0] != '/') @@ -485,6 +489,7 @@ void readFull(int fd, unsigned char * buf, size_t count) void writeFull(int fd, const unsigned char * buf, size_t count, bool allowInterrupts) { while (count) { + if (allowInterrupts) checkInterrupt(); ssize_t res = write(fd, (char *) buf, count); if (res == -1 && errno != EINTR) throw SysError("writing to file"); @@ -492,7 +497,6 @@ void writeFull(int fd, const unsigned char * buf, size_t count, bool allowInterr count -= res; buf += res; } - if (allowInterrupts) checkInterrupt(); } } @@ -676,12 +680,11 @@ Pid::operator pid_t() } -int Pid::kill(bool quiet) +int Pid::kill() { assert(pid != -1); - if (!quiet) - printError(format("killing process %1%") % pid); + debug(format("killing process %1%") % pid); /* Send the requested signal to the child. If it has its own process group, send the signal to every process in the child @@ -837,23 +840,21 @@ std::vector<char *> stringsToCharPtrs(const Strings & ss) string runProgram(Path program, bool searchPath, const Strings & args, - const string & input) + const std::experimental::optional<std::string> & input) { checkInterrupt(); /* Create a pipe. */ Pipe out, in; out.create(); - if (!input.empty()) in.create(); + if (input) in.create(); /* Fork. */ Pid pid = startProcess([&]() { if (dup2(out.writeSide.get(), STDOUT_FILENO) == -1) throw SysError("dupping stdout"); - if (!input.empty()) { - if (dup2(in.readSide.get(), STDIN_FILENO) == -1) - throw SysError("dupping stdin"); - } + if (input && dup2(in.readSide.get(), STDIN_FILENO) == -1) + throw SysError("dupping stdin"); Strings args_(args); args_.push_front(program); @@ -870,11 +871,27 @@ string runProgram(Path program, bool searchPath, const Strings & args, out.writeSide = -1; - /* FIXME: This can deadlock if the input is too long. */ - if (!input.empty()) { + std::thread writerThread; + + std::promise<void> promise; + + Finally doJoin([&]() { + if (writerThread.joinable()) + writerThread.join(); + }); + + + if (input) { in.readSide = -1; - writeFull(in.writeSide.get(), input); - in.writeSide = -1; + writerThread = std::thread([&]() { + try { + writeFull(in.writeSide.get(), *input); + promise.set_value(); + } catch (...) { + promise.set_exception(std::current_exception()); + } + in.writeSide = -1; + }); } string result = drainFD(out.readSide.get()); @@ -885,6 +902,9 @@ string runProgram(Path program, bool searchPath, const Strings & args, throw ExecError(status, format("program ‘%1%’ %2%") % program % statusToString(status)); + /* Wait for the writer thread to finish. */ + if (input) promise.get_future().get(); + return result; } @@ -1194,7 +1214,7 @@ static void signalHandlerThread(sigset_t set) void triggerInterrupt() { - _isInterrupted = 1; + _isInterrupted = true; { auto interruptCallbacks(_interruptCallbacks.lock()); |