aboutsummaryrefslogtreecommitdiff
path: root/src/libutil/util.cc
diff options
context:
space:
mode:
authorEelco Dolstra <edolstra@gmail.com>2017-03-15 14:40:47 +0100
committerEelco Dolstra <edolstra@gmail.com>2017-03-15 16:50:19 +0100
commit25dff2b7dbab54bd97b5ec22a05e594504555a12 (patch)
tree5847593a4cd246899ef09a47fd44b0c872c5fe6e /src/libutil/util.cc
parent042975ea8e2e081c0d44190c8b41104131f8c6d4 (diff)
runProgram(): Distinguish between empty input and no input
For example, if we call brotli with an empty input, it shouldn't read from the caller's stdin.
Diffstat (limited to 'src/libutil/util.cc')
-rw-r--r--src/libutil/util.cc33
1 files changed, 23 insertions, 10 deletions
diff --git a/src/libutil/util.cc b/src/libutil/util.cc
index bc66b0c53..d2d32782d 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>
@@ -837,23 +839,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);
@@ -872,10 +872,23 @@ string runProgram(Path program, bool searchPath, const Strings & args,
std::thread writerThread;
- if (!input.empty()) {
+ std::promise<void> promise;
+
+ Finally doJoin([&]() {
+ if (writerThread.joinable())
+ writerThread.join();
+ });
+
+
+ if (input) {
in.readSide = -1;
writerThread = std::thread([&]() {
- writeFull(in.writeSide.get(), input);
+ try {
+ writeFull(in.writeSide.get(), *input);
+ promise.set_value();
+ } catch (...) {
+ promise.set_exception(std::current_exception());
+ }
in.writeSide = -1;
});
}
@@ -888,8 +901,8 @@ string runProgram(Path program, bool searchPath, const Strings & args,
throw ExecError(status, format("program ‘%1%’ %2%")
% program % statusToString(status));
- if (!input.empty())
- writerThread.join();
+ /* Wait for the writer thread to finish. */
+ if (input) promise.get_future().get();
return result;
}