Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(498)

Side by Side Diff: base/process_util_unittest.cc

Issue 5172009: This adds some plumbing for propagating the reason for a renderer's death (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Final review changes Created 10 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « base/process_util_posix.cc ('k') | base/process_util_win.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #define _CRT_SECURE_NO_WARNINGS 5 #define _CRT_SECURE_NO_WARNINGS
6 6
7 #include <limits> 7 #include <limits>
8 8
9 #include "base/command_line.h" 9 #include "base/command_line.h"
10 #include "base/debug_util.h"
10 #include "base/eintr_wrapper.h" 11 #include "base/eintr_wrapper.h"
11 #include "base/file_path.h" 12 #include "base/file_path.h"
12 #include "base/logging.h" 13 #include "base/logging.h"
13 #include "base/path_service.h" 14 #include "base/path_service.h"
14 #include "base/platform_thread.h" 15 #include "base/platform_thread.h"
15 #include "base/process_util.h" 16 #include "base/process_util.h"
16 #include "base/scoped_ptr.h" 17 #include "base/scoped_ptr.h"
17 #include "base/test/multiprocess_test.h" 18 #include "base/test/multiprocess_test.h"
19 #include "base/test/test_timeouts.h"
18 #include "base/utf_string_conversions.h" 20 #include "base/utf_string_conversions.h"
19 #include "testing/gtest/include/gtest/gtest.h" 21 #include "testing/gtest/include/gtest/gtest.h"
20 #include "testing/multiprocess_func_list.h" 22 #include "testing/multiprocess_func_list.h"
21 23
22 #if defined(OS_LINUX) 24 #if defined(OS_LINUX)
23 #include <errno.h> 25 #include <errno.h>
24 #include <malloc.h> 26 #include <malloc.h>
25 #include <glib.h> 27 #include <glib.h>
26 #endif 28 #endif
27 #if defined(OS_POSIX) 29 #if defined(OS_POSIX)
28 #include <dlfcn.h> 30 #include <dlfcn.h>
29 #include <fcntl.h> 31 #include <fcntl.h>
32 #include <signal.h>
30 #include <sys/resource.h> 33 #include <sys/resource.h>
31 #include <sys/socket.h> 34 #include <sys/socket.h>
32 #endif 35 #endif
33 #if defined(OS_WIN) 36 #if defined(OS_WIN)
34 #include <windows.h> 37 #include <windows.h>
35 #endif 38 #endif
36 #if defined(OS_MACOSX) 39 #if defined(OS_MACOSX)
37 #include <malloc/malloc.h> 40 #include <malloc/malloc.h>
38 #include "base/process_util_unittest_mac.h" 41 #include "base/process_util_unittest_mac.h"
39 #endif 42 #endif
40 43
41 namespace { 44 namespace {
42 45
43 #if defined(OS_WIN) 46 #if defined(OS_WIN)
44 const wchar_t* const kProcessName = L"base_unittests.exe"; 47 const wchar_t kProcessName[] = L"base_unittests.exe";
45 #else 48 #else
46 const wchar_t* const kProcessName = L"base_unittests"; 49 const wchar_t kProcessName[] = L"base_unittests";
47 #endif // defined(OS_WIN) 50 #endif // defined(OS_WIN)
48 51
52 const char kSignalFileSlow[] = "SlowChildProcess.die";
53 const char kSignalFileCrash[] = "CrashingChildProcess.die";
54 const char kSignalFileKill[] = "KilledChildProcess.die";
55
56 #if defined(OS_WIN)
57 const int kExpectedStillRunningExitCode = 0x102;
58 const int kExpectedKilledExitCode = 1;
59 #else
60 const int kExpectedStillRunningExitCode = 0;
61 #endif
62
63 // The longest we'll wait for a process, in milliseconds.
64 const int kMaxWaitTimeMs = TestTimeouts::action_max_timeout_ms();
65
49 // Sleeps until file filename is created. 66 // Sleeps until file filename is created.
50 void WaitToDie(const char* filename) { 67 void WaitToDie(const char* filename) {
51 FILE *fp; 68 FILE *fp;
52 do { 69 do {
53 PlatformThread::Sleep(10); 70 PlatformThread::Sleep(10);
54 fp = fopen(filename, "r"); 71 fp = fopen(filename, "r");
55 } while (!fp); 72 } while (!fp);
56 fclose(fp); 73 fclose(fp);
57 } 74 }
58 75
59 // Signals children they should die now. 76 // Signals children they should die now.
60 void SignalChildren(const char* filename) { 77 void SignalChildren(const char* filename) {
61 FILE *fp = fopen(filename, "w"); 78 FILE *fp = fopen(filename, "w");
62 fclose(fp); 79 fclose(fp);
63 } 80 }
64 81
82 // Using a pipe to the child to wait for an event was considered, but
83 // there were cases in the past where pipes caused problems (other
84 // libraries closing the fds, child deadlocking). This is a simple
85 // case, so it's not worth the risk. Using wait loops is discouraged
86 // in most instances.
87 base::TerminationStatus WaitForChildTermination(base::ProcessHandle handle,
88 int* exit_code) {
89 // Now we wait until the result is something other than STILL_RUNNING.
90 base::TerminationStatus status = base::TERMINATION_STATUS_STILL_RUNNING;
91 const int kIntervalMs = 20;
92 int waited = 0;
93 do {
94 status = base::GetTerminationStatus(handle, exit_code);
95 PlatformThread::Sleep(kIntervalMs);
96 waited += kIntervalMs;
97 } while (status == base::TERMINATION_STATUS_STILL_RUNNING &&
98 waited < kMaxWaitTimeMs);
99
100 return status;
101 }
102
65 } // namespace 103 } // namespace
66 104
67 class ProcessUtilTest : public base::MultiProcessTest { 105 class ProcessUtilTest : public base::MultiProcessTest {
68 #if defined(OS_POSIX) 106 #if defined(OS_POSIX)
69 public: 107 public:
70 // Spawn a child process that counts how many file descriptors are open. 108 // Spawn a child process that counts how many file descriptors are open.
71 int CountOpenFDsInChild(); 109 int CountOpenFDsInChild();
72 #endif 110 #endif
73 }; 111 };
74 112
75 MULTIPROCESS_TEST_MAIN(SimpleChildProcess) { 113 MULTIPROCESS_TEST_MAIN(SimpleChildProcess) {
76 return 0; 114 return 0;
77 } 115 }
78 116
79 TEST_F(ProcessUtilTest, SpawnChild) { 117 TEST_F(ProcessUtilTest, SpawnChild) {
80 base::ProcessHandle handle = this->SpawnChild("SimpleChildProcess", false); 118 base::ProcessHandle handle = this->SpawnChild("SimpleChildProcess", false);
81 ASSERT_NE(base::kNullProcessHandle, handle); 119 ASSERT_NE(base::kNullProcessHandle, handle);
82 EXPECT_TRUE(base::WaitForSingleProcess(handle, 5000)); 120 EXPECT_TRUE(base::WaitForSingleProcess(handle, kMaxWaitTimeMs));
83 base::CloseProcessHandle(handle); 121 base::CloseProcessHandle(handle);
84 } 122 }
85 123
86 MULTIPROCESS_TEST_MAIN(SlowChildProcess) { 124 MULTIPROCESS_TEST_MAIN(SlowChildProcess) {
87 WaitToDie("SlowChildProcess.die"); 125 WaitToDie(kSignalFileSlow);
88 return 0; 126 return 0;
89 } 127 }
90 128
91 TEST_F(ProcessUtilTest, KillSlowChild) { 129 TEST_F(ProcessUtilTest, KillSlowChild) {
92 remove("SlowChildProcess.die"); 130 remove(kSignalFileSlow);
93 base::ProcessHandle handle = this->SpawnChild("SlowChildProcess", false); 131 base::ProcessHandle handle = this->SpawnChild("SlowChildProcess", false);
94 ASSERT_NE(base::kNullProcessHandle, handle); 132 ASSERT_NE(base::kNullProcessHandle, handle);
95 SignalChildren("SlowChildProcess.die"); 133 SignalChildren(kSignalFileSlow);
96 EXPECT_TRUE(base::WaitForSingleProcess(handle, 5000)); 134 EXPECT_TRUE(base::WaitForSingleProcess(handle, kMaxWaitTimeMs));
97 base::CloseProcessHandle(handle); 135 base::CloseProcessHandle(handle);
98 remove("SlowChildProcess.die"); 136 remove(kSignalFileSlow);
99 } 137 }
100 138
101 TEST_F(ProcessUtilTest, DidProcessCrash) { 139 TEST_F(ProcessUtilTest, GetTerminationStatusExit) {
102 remove("SlowChildProcess.die"); 140 remove(kSignalFileSlow);
103 base::ProcessHandle handle = this->SpawnChild("SlowChildProcess", false); 141 base::ProcessHandle handle = this->SpawnChild("SlowChildProcess", false);
104 ASSERT_NE(base::kNullProcessHandle, handle); 142 ASSERT_NE(base::kNullProcessHandle, handle);
105 143
106 bool child_exited = true; 144 int exit_code = 42;
107 EXPECT_FALSE(base::DidProcessCrash(&child_exited, handle)); 145 EXPECT_EQ(base::TERMINATION_STATUS_STILL_RUNNING,
108 EXPECT_FALSE(child_exited); 146 base::GetTerminationStatus(handle, &exit_code));
147 EXPECT_EQ(kExpectedStillRunningExitCode, exit_code);
109 148
110 SignalChildren("SlowChildProcess.die"); 149 SignalChildren(kSignalFileSlow);
111 EXPECT_TRUE(base::WaitForSingleProcess(handle, 5000)); 150 exit_code = 42;
151 base::TerminationStatus status =
152 WaitForChildTermination(handle, &exit_code);
153 EXPECT_EQ(base::TERMINATION_STATUS_NORMAL_TERMINATION, status);
154 EXPECT_EQ(0, exit_code);
155 base::CloseProcessHandle(handle);
156 remove(kSignalFileSlow);
157 }
112 158
113 EXPECT_FALSE(base::DidProcessCrash(&child_exited, handle)); 159 #if !defined(OS_MACOSX)
160 // This test is disabled on Mac, since it's flaky due to ReportCrash
161 // taking a variable amount of time to parse and load the debug and
162 // symbol data for this unit test's executable before firing the
163 // signal handler.
164 //
165 // TODO(gspencer): turn this test process into a very small program
166 // with no symbols (instead of using the multiprocess testing
167 // framework) to reduce the ReportCrash overhead.
168
169 MULTIPROCESS_TEST_MAIN(CrashingChildProcess) {
170 WaitToDie(kSignalFileCrash);
171 #if defined(OS_POSIX)
172 // Have to disable to signal handler for segv so we can get a crash
173 // instead of an abnormal termination through the crash dump handler.
174 ::signal(SIGSEGV, SIG_DFL);
175 #endif
176 // Make this process have a segmentation fault.
177 int* oops = NULL;
178 *oops = 0xDEAD;
179 return 1;
180 }
181
182 TEST_F(ProcessUtilTest, GetTerminationStatusCrash) {
183 remove(kSignalFileCrash);
184 base::ProcessHandle handle = this->SpawnChild("CrashingChildProcess",
185 false);
186 ASSERT_NE(base::kNullProcessHandle, handle);
187
188 int exit_code = 42;
189 EXPECT_EQ(base::TERMINATION_STATUS_STILL_RUNNING,
190 base::GetTerminationStatus(handle, &exit_code));
191 EXPECT_EQ(kExpectedStillRunningExitCode, exit_code);
192
193 SignalChildren(kSignalFileCrash);
194 exit_code = 42;
195 base::TerminationStatus status =
196 WaitForChildTermination(handle, &exit_code);
197 EXPECT_EQ(base::TERMINATION_STATUS_PROCESS_CRASHED, status);
198
199 #if defined(OS_WIN)
200 EXPECT_EQ(0xc0000005, exit_code);
201 #elif defined(OS_POSIX)
202 int signaled = WIFSIGNALED(exit_code);
203 EXPECT_NE(0, signaled);
204 int signal = WTERMSIG(exit_code);
205 EXPECT_EQ(SIGSEGV, signal);
206 #endif
114 base::CloseProcessHandle(handle); 207 base::CloseProcessHandle(handle);
115 remove("SlowChildProcess.die"); 208
209 // Reset signal handlers back to "normal".
210 base::EnableInProcessStackDumping();
211 remove(kSignalFileCrash);
212 }
213 #endif // !defined(OS_MACOSX)
214
215 MULTIPROCESS_TEST_MAIN(KilledChildProcess) {
216 WaitToDie(kSignalFileKill);
217 #if defined(OS_WIN)
218 // Kill ourselves.
219 HANDLE handle = ::OpenProcess(PROCESS_ALL_ACCESS, 0, ::GetCurrentProcessId());
220 ::TerminateProcess(handle, kExpectedKilledExitCode);
221 #elif defined(OS_POSIX)
222 // Send a SIGKILL to this process, just like the OOM killer would.
223 ::kill(getpid(), SIGKILL);
224 #endif
225 return 1;
226 }
227
228 TEST_F(ProcessUtilTest, GetTerminationStatusKill) {
229 remove(kSignalFileKill);
230 base::ProcessHandle handle = this->SpawnChild("KilledChildProcess",
231 false);
232 ASSERT_NE(base::kNullProcessHandle, handle);
233
234 int exit_code = 42;
235 EXPECT_EQ(base::TERMINATION_STATUS_STILL_RUNNING,
236 base::GetTerminationStatus(handle, &exit_code));
237 EXPECT_EQ(kExpectedStillRunningExitCode, exit_code);
238
239 SignalChildren(kSignalFileKill);
240 exit_code = 42;
241 base::TerminationStatus status =
242 WaitForChildTermination(handle, &exit_code);
243 EXPECT_EQ(base::TERMINATION_STATUS_PROCESS_WAS_KILLED, status);
244 #if defined(OS_WIN)
245 EXPECT_EQ(kExpectedKilledExitCode, exit_code);
246 #elif defined(OS_POSIX)
247 int signaled = WIFSIGNALED(exit_code);
248 EXPECT_NE(0, signaled);
249 int signal = WTERMSIG(exit_code);
250 EXPECT_EQ(SIGKILL, signal);
251 #endif
252 base::CloseProcessHandle(handle);
253 remove(kSignalFileKill);
116 } 254 }
117 255
118 // Ensure that the priority of a process is restored correctly after 256 // Ensure that the priority of a process is restored correctly after
119 // backgrounding and restoring. 257 // backgrounding and restoring.
120 // Note: a platform may not be willing or able to lower the priority of 258 // Note: a platform may not be willing or able to lower the priority of
121 // a process. The calls to SetProcessBackground should be noops then. 259 // a process. The calls to SetProcessBackground should be noops then.
122 TEST_F(ProcessUtilTest, SetProcessBackgrounded) { 260 TEST_F(ProcessUtilTest, SetProcessBackgrounded) {
123 base::ProcessHandle handle = this->SpawnChild("SimpleChildProcess", false); 261 base::ProcessHandle handle = this->SpawnChild("SimpleChildProcess", false);
124 base::Process process(handle); 262 base::Process process(handle);
125 int old_priority = process.GetPriority(); 263 int old_priority = process.GetPriority();
(...skipping 655 matching lines...) Expand 10 before | Expand all | Expand 10 after
781 ASSERT_DEATH({ 919 ASSERT_DEATH({
782 SetUpInDeathAssert(); 920 SetUpInDeathAssert();
783 while ((value_ = base::AllocatePsychoticallyBigObjCObject())) {} 921 while ((value_ = base::AllocatePsychoticallyBigObjCObject())) {}
784 }, ""); 922 }, "");
785 } 923 }
786 924
787 #endif // !ARCH_CPU_64_BITS 925 #endif // !ARCH_CPU_64_BITS
788 #endif // OS_MACOSX 926 #endif // OS_MACOSX
789 927
790 #endif // !defined(OS_WIN) 928 #endif // !defined(OS_WIN)
OLDNEW
« no previous file with comments | « base/process_util_posix.cc ('k') | base/process_util_win.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698