• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2015 The Chromium OS Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include <brillo/process_reaper.h>
6 
7 #include <signal.h>
8 #include <sys/wait.h>
9 #include <unistd.h>
10 
11 #include <base/bind.h>
12 #include <base/location.h>
13 #include <base/message_loop/message_loop.h>
14 #include <brillo/asynchronous_signal_handler.h>
15 #include <brillo/bind_lambda.h>
16 #include <brillo/message_loops/base_message_loop.h>
17 #include <gtest/gtest.h>
18 
19 namespace {
20 
ForkChildAndExit(int exit_code)21 pid_t ForkChildAndExit(int exit_code) {
22   pid_t pid = fork();
23   PCHECK(pid != -1);
24   if (pid == 0) {
25     _exit(exit_code);
26   }
27   return pid;
28 }
29 
ForkChildAndKill(int sig)30 pid_t ForkChildAndKill(int sig) {
31   pid_t pid = fork();
32   PCHECK(pid != -1);
33   if (pid == 0) {
34     if (raise(sig) != 0) {
35       PLOG(ERROR) << "raise(" << sig << ")";
36     }
37     _exit(0);  // Not reached. This value will cause the test to fail.
38   }
39   return pid;
40 }
41 
42 }  // namespace
43 
44 namespace brillo {
45 
46 class ProcessReaperTest : public ::testing::Test {
47  public:
SetUp()48   void SetUp() override {
49     brillo_loop_.SetAsCurrent();
50     async_signal_handler_.Init();
51     process_reaper_.Register(&async_signal_handler_);
52   }
53 
54  protected:
55   base::MessageLoopForIO base_loop_;
56   brillo::BaseMessageLoop brillo_loop_{&base_loop_};
57   brillo::AsynchronousSignalHandler async_signal_handler_;
58 
59   // ProcessReaper under test.
60   ProcessReaper process_reaper_;
61 };
62 
TEST_F(ProcessReaperTest,UnregisterWhenNotRegistered)63 TEST_F(ProcessReaperTest, UnregisterWhenNotRegistered) {
64   ProcessReaper another_process_reaper_;
65   another_process_reaper_.Unregister();
66 }
67 
TEST_F(ProcessReaperTest,UnregisterAndReregister)68 TEST_F(ProcessReaperTest, UnregisterAndReregister) {
69   process_reaper_.Unregister();
70   process_reaper_.Register(&async_signal_handler_);
71   // This checks that we can unregister the ProcessReaper and then destroy it.
72   process_reaper_.Unregister();
73 }
74 
TEST_F(ProcessReaperTest,ReapExitedChild)75 TEST_F(ProcessReaperTest, ReapExitedChild) {
76   pid_t pid = ForkChildAndExit(123);
77   EXPECT_TRUE(process_reaper_.WatchForChild(FROM_HERE, pid, base::Bind(
78       [this](const siginfo_t& info) {
79         EXPECT_EQ(CLD_EXITED, info.si_code);
80         EXPECT_EQ(123, info.si_status);
81         this->brillo_loop_.BreakLoop();
82       })));
83   brillo_loop_.Run();
84 }
85 
86 // Test that simultaneous child processes fire their respective callbacks when
87 // exiting.
TEST_F(ProcessReaperTest,ReapedChildsMatchCallbacks)88 TEST_F(ProcessReaperTest, ReapedChildsMatchCallbacks) {
89   int running_childs = 10;
90   for (int i = 0; i < running_childs; ++i) {
91     // Different processes will have different exit values.
92     int exit_value = 1 + i;
93     pid_t pid = ForkChildAndExit(exit_value);
94     EXPECT_TRUE(process_reaper_.WatchForChild(FROM_HERE, pid, base::Bind(
95         [this, exit_value, &running_childs](const siginfo_t& info) {
96           EXPECT_EQ(CLD_EXITED, info.si_code);
97           EXPECT_EQ(exit_value, info.si_status);
98           running_childs--;
99           if (running_childs == 0)
100             this->brillo_loop_.BreakLoop();
101         })));
102   }
103   // This sleep is optional. It helps to have more processes exit before we
104   // start watching for them in the message loop.
105   usleep(10 * 1000);
106   brillo_loop_.Run();
107   EXPECT_EQ(0, running_childs);
108 }
109 
TEST_F(ProcessReaperTest,ReapKilledChild)110 TEST_F(ProcessReaperTest, ReapKilledChild) {
111   pid_t pid = ForkChildAndKill(SIGKILL);
112   EXPECT_TRUE(process_reaper_.WatchForChild(FROM_HERE, pid, base::Bind(
113       [this](const siginfo_t& info) {
114         EXPECT_EQ(CLD_KILLED, info.si_code);
115         EXPECT_EQ(SIGKILL, info.si_status);
116         this->brillo_loop_.BreakLoop();
117       })));
118   brillo_loop_.Run();
119 }
120 
TEST_F(ProcessReaperTest,ReapKilledAndForgottenChild)121 TEST_F(ProcessReaperTest, ReapKilledAndForgottenChild) {
122   pid_t pid = ForkChildAndExit(0);
123   EXPECT_TRUE(process_reaper_.WatchForChild(FROM_HERE, pid, base::Bind(
124       [this](const siginfo_t& /* info */) {
125         ADD_FAILURE() << "Child process was still tracked.";
126         this->brillo_loop_.BreakLoop();
127       })));
128   EXPECT_TRUE(process_reaper_.ForgetChild(pid));
129 
130   // A second call should return failure.
131   EXPECT_FALSE(process_reaper_.ForgetChild(pid));
132 
133   // Run the loop with a timeout, as the BreakLoop() above is not expected.
134   brillo_loop_.PostDelayedTask(FROM_HERE,
135                                base::Bind(&MessageLoop::BreakLoop,
136                                           base::Unretained(&brillo_loop_)),
137                                base::TimeDelta::FromMilliseconds(100));
138   brillo_loop_.Run();
139 }
140 
141 }  // namespace brillo
142