summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNicolas Despres <nicolas.despres@gmail.com>2014-04-16 08:05:25 (GMT)
committerNicolas Despres <nicolas.despres@gmail.com>2015-04-24 14:40:03 (GMT)
commitb4bc5cf7c924be251a5c8abdfca58f47c3f5c185 (patch)
treead8fd16c3285fb8582734148663b8ce18d7cc77c
parentb2b8f3a12d3323c4273aa63460f482d6f7f03211 (diff)
downloadNinja-b4bc5cf7c924be251a5c8abdfca58f47c3f5c185.zip
Ninja-b4bc5cf7c924be251a5c8abdfca58f47c3f5c185.tar.gz
Ninja-b4bc5cf7c924be251a5c8abdfca58f47c3f5c185.tar.bz2
Allow SIGTERM for interruption.
Default signal sent by many other programs (mainly kill(1)) to gently terminates another one is SIGTERM.
-rw-r--r--src/subprocess-posix.cc15
-rw-r--r--src/subprocess.h3
-rw-r--r--src/subprocess_test.cc26
3 files changed, 38 insertions, 6 deletions
diff --git a/src/subprocess-posix.cc b/src/subprocess-posix.cc
index cc8bff6..c784a39 100644
--- a/src/subprocess-posix.cc
+++ b/src/subprocess-posix.cc
@@ -74,7 +74,9 @@ bool Subprocess::Start(SubprocessSet* set, const string& command) {
// Track which fd we use to report errors on.
int error_pipe = output_pipe[1];
do {
- if (sigaction(SIGINT, &set->old_act_, 0) < 0)
+ if (sigaction(SIGINT, &set->old_int_act_, 0) < 0)
+ break;
+ if (sigaction(SIGTERM, &set->old_term_act_, 0) < 0)
break;
if (sigprocmask(SIG_SETMASK, &set->old_mask_, 0) < 0)
break;
@@ -148,7 +150,7 @@ ExitStatus Subprocess::Finish() {
if (exit == 0)
return ExitSuccess;
} else if (WIFSIGNALED(status)) {
- if (WTERMSIG(status) == SIGINT)
+ if (WTERMSIG(status) == SIGINT || WTERMSIG(status) == SIGTERM)
return ExitInterrupted;
}
return ExitFailure;
@@ -173,20 +175,25 @@ SubprocessSet::SubprocessSet() {
sigset_t set;
sigemptyset(&set);
sigaddset(&set, SIGINT);
+ sigaddset(&set, SIGTERM);
if (sigprocmask(SIG_BLOCK, &set, &old_mask_) < 0)
Fatal("sigprocmask: %s", strerror(errno));
struct sigaction act;
memset(&act, 0, sizeof(act));
act.sa_handler = SetInterruptedFlag;
- if (sigaction(SIGINT, &act, &old_act_) < 0)
+ if (sigaction(SIGINT, &act, &old_int_act_) < 0)
+ Fatal("sigaction: %s", strerror(errno));
+ if (sigaction(SIGTERM, &act, &old_term_act_) < 0)
Fatal("sigaction: %s", strerror(errno));
}
SubprocessSet::~SubprocessSet() {
Clear();
- if (sigaction(SIGINT, &old_act_, 0) < 0)
+ if (sigaction(SIGINT, &old_int_act_, 0) < 0)
+ Fatal("sigaction: %s", strerror(errno));
+ if (sigaction(SIGTERM, &old_term_act_, 0) < 0)
Fatal("sigaction: %s", strerror(errno));
if (sigprocmask(SIG_SETMASK, &old_mask_, 0) < 0)
Fatal("sigprocmask: %s", strerror(errno));
diff --git a/src/subprocess.h b/src/subprocess.h
index b7a1a4c..daeeef6 100644
--- a/src/subprocess.h
+++ b/src/subprocess.h
@@ -91,7 +91,8 @@ struct SubprocessSet {
static void SetInterruptedFlag(int signum);
static bool interrupted_;
- struct sigaction old_act_;
+ struct sigaction old_int_act_;
+ struct sigaction old_term_act_;
sigset_t old_mask_;
#endif
};
diff --git a/src/subprocess_test.cc b/src/subprocess_test.cc
index 1838c43..07cc52f 100644
--- a/src/subprocess_test.cc
+++ b/src/subprocess_test.cc
@@ -98,6 +98,30 @@ TEST_F(SubprocessTest, InterruptParent) {
ASSERT_FALSE("We should have been interrupted");
}
+TEST_F(SubprocessTest, InterruptChildWithSigTerm) {
+ Subprocess* subproc = subprocs_.Add("kill -TERM $$");
+ ASSERT_NE((Subprocess *) 0, subproc);
+
+ while (!subproc->Done()) {
+ subprocs_.DoWork();
+ }
+
+ EXPECT_EQ(ExitInterrupted, subproc->Finish());
+}
+
+TEST_F(SubprocessTest, InterruptParentWithSigTerm) {
+ Subprocess* subproc = subprocs_.Add("kill -TERM $PPID ; sleep 1");
+ ASSERT_NE((Subprocess *) 0, subproc);
+
+ while (!subproc->Done()) {
+ bool interrupted = subprocs_.DoWork();
+ if (interrupted)
+ return;
+ }
+
+ 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".
@@ -221,7 +245,7 @@ TEST_F(SubprocessTest, SetWithLots) {
}
ASSERT_EQ(kNumProcs, subprocs_.finished_.size());
}
-#endif // !__APPLE__ && !_WIN32
+#endif // !__APPLE__ && !_WIN32
// TODO: this test could work on Windows, just not sure how to simply
// read stdin.