summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJulien Tinnes <jln@chromium.org>2015-01-29 19:33:35 (GMT)
committerJulien Tinnes <jln@chromium.org>2015-01-29 19:36:30 (GMT)
commit7b34ee99cdd350511942c2d84fc36ce1696e1686 (patch)
tree6ced67e1bc4dbb3e7f48b381a426b50b4f3379f4
parent62458b6f19dd134d2a4a38ff81e368c8b7e5605d (diff)
downloadNinja-7b34ee99cdd350511942c2d84fc36ce1696e1686.zip
Ninja-7b34ee99cdd350511942c2d84fc36ce1696e1686.tar.gz
Ninja-7b34ee99cdd350511942c2d84fc36ce1696e1686.tar.bz2
POSIX: detach background subprocesses from terminal.
Put background subprocesses (i.e. subprocesses with no access to the console) in their own session and detach them from the terminal. This fixes martine/ninja#909.
-rw-r--r--src/subprocess-posix.cc7
-rw-r--r--src/subprocess_test.cc31
2 files changed, 33 insertions, 5 deletions
diff --git a/src/subprocess-posix.cc b/src/subprocess-posix.cc
index 40c9ae1..cc8bff6 100644
--- a/src/subprocess-posix.cc
+++ b/src/subprocess-posix.cc
@@ -80,8 +80,11 @@ bool Subprocess::Start(SubprocessSet* set, const string& command) {
break;
if (!use_console_) {
- // Put the child in its own process group, so ctrl-c won't reach it.
- if (setpgid(0, 0) < 0)
+ // Put the child in its own session and process group. It will be
+ // detached from the current terminal and ctrl-c won't reach it.
+ // Since this process was just forked, it is not a process group leader
+ // and setsid() will succeed.
+ if (setsid() < 0)
break;
// Open /dev/null over stdin.
diff --git a/src/subprocess_test.cc b/src/subprocess_test.cc
index 8a0787c..76f5c6c 100644
--- a/src/subprocess_test.cc
+++ b/src/subprocess_test.cc
@@ -16,6 +16,8 @@
#include "test.h"
+#include <string>
+
#ifndef _WIN32
// SetWithLots need setrlimit.
#include <stdio.h>
@@ -96,12 +98,23 @@ TEST_F(SubprocessTest, InterruptParent) {
ASSERT_FALSE("We should have been interrupted");
}
+// A shell command to check if the current process is connected to a terminal.
+// This is different from having stdin/stdout/stderr be a terminal. (For
+// instance consider the command "yes < /dev/null > /dev/null 2>&1".
+// As "ps" will confirm, "yes" could still be connected to a terminal, despite
+// not having any of the standard file descriptors be a terminal.
+static const char kIsConnectedToTerminal[] = "tty < /dev/tty > /dev/null";
+
TEST_F(SubprocessTest, Console) {
// Skip test if we don't have the console ourselves.
if (isatty(0) && isatty(1) && isatty(2)) {
- Subprocess* subproc = subprocs_.Add("test -t 0 -a -t 1 -a -t 2",
- /*use_console=*/true);
- ASSERT_NE((Subprocess *) 0, subproc);
+ // Test that stdin, stdout and stderr are a terminal.
+ // Also check that the current process is connected to a terminal.
+ Subprocess* subproc =
+ subprocs_.Add(std::string("test -t 0 -a -t 1 -a -t 2 && ") +
+ std::string(kIsConnectedToTerminal),
+ /*use_console=*/true);
+ ASSERT_NE((Subprocess*)0, subproc);
while (!subproc->Done()) {
subprocs_.DoWork();
@@ -111,6 +124,18 @@ TEST_F(SubprocessTest, Console) {
}
}
+TEST_F(SubprocessTest, NoConsole) {
+ Subprocess* subproc =
+ subprocs_.Add(kIsConnectedToTerminal, /*use_console=*/false);
+ ASSERT_NE((Subprocess*)0, subproc);
+
+ while (!subproc->Done()) {
+ subprocs_.DoWork();
+ }
+
+ EXPECT_NE(ExitSuccess, subproc->Finish());
+}
+
#endif
TEST_F(SubprocessTest, SetWithSingle) {