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 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 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: 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 63 TEST_F(ProcessReaperTest, UnregisterWhenNotRegistered) { 64 ProcessReaper another_process_reaper_; 65 another_process_reaper_.Unregister(); 66 } 67 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 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. 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 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 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