summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPeter Hutterer <peter.hutterer@who-t.net>2012-08-15 09:30:15 +1000
committerPeter Hutterer <peter.hutterer@who-t.net>2012-08-17 10:19:41 +1000
commit8653076163c6c515f77cb3a7e4b0bc8dd416537f (patch)
tree9b16f6d41cf34ea24cc60c7f9b1f73aa7f9f057a
parent9263c0fc5be087c5876700dd53be710f39f2f317 (diff)
process: terminate the child if the parent dies
It's annoying to have the forked X server linger around when the test segfaults, so make sure we take it down with us. Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net> Reviewed-by: Chase Douglas <chase.douglas@canonical.com>
-rw-r--r--src/process.cpp5
-rw-r--r--test/process-test.cpp45
2 files changed, 50 insertions, 0 deletions
diff --git a/src/process.cpp b/src/process.cpp
index ec39c97..1a1739a 100644
--- a/src/process.cpp
+++ b/src/process.cpp
@@ -27,6 +27,7 @@
#include "xorg/gtest/xorg-gtest-process.h"
+#include <sys/prctl.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
@@ -81,6 +82,10 @@ void xorg::testing::Process::Start(const std::string &program, const std::vector
close(2);
}
+#ifdef __linux
+ prctl(PR_SET_PDEATHSIG, SIGTERM);
+#endif
+
std::vector<char*> args;
std::vector<std::string>::const_iterator it;
diff --git a/test/process-test.cpp b/test/process-test.cpp
index dc5402c..183b9f8 100644
--- a/test/process-test.cpp
+++ b/test/process-test.cpp
@@ -1,3 +1,5 @@
+#include <errno.h>
+#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
@@ -63,6 +65,49 @@ TEST(Process, TerminationFailure)
ASSERT_EQ(p.GetState(), Process::FINISHED_FAILURE);
}
+TEST(Process, ChildTearDown)
+{
+ SCOPED_TRACE("TESTCASE: ensure child process dies when parent does");
+
+ int pipefd[2];
+ ASSERT_NE(pipe(pipefd), -1);
+
+ /* Fork, the child will spawn a Process, write that Process's PID to a
+ pipe and then kill itself. The parent checks that the child was
+ terminated when the parent was killed.
+ */
+ pid_t pid = fork();
+ if (pid == 0) { /* child */
+ close(pipefd[0]);
+
+ Process p;
+ p.Start("sleep", "1000", NULL); /* forks another child */
+ ASSERT_GT(p.Pid(), 0);
+
+ char *buffer;
+ ASSERT_GT(asprintf(&buffer, "%d", p.Pid()), 0);
+ ASSERT_EQ(write(pipefd[1], buffer, strlen(buffer)), (int)strlen(buffer));
+ close(pipefd[1]);
+
+ raise(SIGKILL);
+ } else { /* parent */
+ close(pipefd[1]);
+
+ char buffer[20] = {0};
+ ASSERT_GT(read(pipefd[0], buffer, sizeof(buffer)), 0);
+ close(pipefd[0]);
+
+ pid_t child_pid = atoi(buffer);
+ for (int i = 0; i < 10; i++) {
+ if (kill(child_pid, 0) != -1)
+ usleep(100);
+
+ }
+ ASSERT_EQ(kill(child_pid, 0), -1);
+ ASSERT_EQ(errno, ESRCH);
+ }
+}
+
int main(int argc, char *argv[]) {
testing::InitGoogleTest(&argc, argv);