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

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: Created 10 years, 1 month 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"
18 #include "base/utf_string_conversions.h" 19 #include "base/utf_string_conversions.h"
19 #include "testing/gtest/include/gtest/gtest.h" 20 #include "testing/gtest/include/gtest/gtest.h"
20 #include "testing/multiprocess_func_list.h" 21 #include "testing/multiprocess_func_list.h"
21 22
22 #if defined(OS_LINUX) 23 #if defined(OS_LINUX)
23 #include <errno.h> 24 #include <errno.h>
24 #include <malloc.h> 25 #include <malloc.h>
25 #include <glib.h> 26 #include <glib.h>
26 #endif 27 #endif
27 #if defined(OS_POSIX) 28 #if defined(OS_POSIX)
28 #include <dlfcn.h> 29 #include <dlfcn.h>
29 #include <fcntl.h> 30 #include <fcntl.h>
31 #include <signal.h>
30 #include <sys/resource.h> 32 #include <sys/resource.h>
31 #include <sys/socket.h> 33 #include <sys/socket.h>
32 #endif 34 #endif
33 #if defined(OS_WIN) 35 #if defined(OS_WIN)
34 #include <windows.h> 36 #include <windows.h>
35 #endif 37 #endif
36 #if defined(OS_MACOSX) 38 #if defined(OS_MACOSX)
37 #include <malloc/malloc.h> 39 #include <malloc/malloc.h>
38 #include "base/process_util_unittest_mac.h" 40 #include "base/process_util_unittest_mac.h"
39 #endif 41 #endif
40 42
41 namespace { 43 namespace {
42 44
43 #if defined(OS_WIN) 45 #if defined(OS_WIN)
44 const wchar_t* const kProcessName = L"base_unittests.exe"; 46 const wchar_t kProcessName[] = L"base_unittests.exe";
45 #else 47 #else
46 const wchar_t* const kProcessName = L"base_unittests"; 48 const wchar_t kProcessName[] = L"base_unittests";
47 #endif // defined(OS_WIN) 49 #endif // defined(OS_WIN)
48 50
51 const char kSignalFileSlow[] = "SlowChildProcess.die";
52 const char kSignalFileCrash[] = "CrashingChildProcess.die";
53 const char kSignalFileKill[] = "KilledChildProcess.die";
54
55 #if defined(OS_WIN)
56 const int kExpectedStillRunningExitCode = 0x102;
57 #else
58 const int kExpectedStillRunningExitCode = 0;
59 #endif
60
61 // The longest we'll wait for a process, in milliseconds.
62 const int kMaxWaitTimeMs = 5000;
Paweł Hajdan Jr. 2010/11/30 09:39:38 Please use base/test/test_timeouts.
Greg Spencer (Chromium) 2010/11/30 19:42:29 Done.
63
49 // Sleeps until file filename is created. 64 // Sleeps until file filename is created.
50 void WaitToDie(const char* filename) { 65 void WaitToDie(const char* filename) {
51 FILE *fp; 66 FILE *fp;
52 do { 67 do {
53 PlatformThread::Sleep(10); 68 PlatformThread::Sleep(10);
54 fp = fopen(filename, "r"); 69 fp = fopen(filename, "r");
55 } while (!fp); 70 } while (!fp);
56 fclose(fp); 71 fclose(fp);
57 } 72 }
58 73
59 // Signals children they should die now. 74 // Signals children they should die now.
60 void SignalChildren(const char* filename) { 75 void SignalChildren(const char* filename) {
61 FILE *fp = fopen(filename, "w"); 76 FILE *fp = fopen(filename, "w");
62 fclose(fp); 77 fclose(fp);
63 } 78 }
64 79
80 // Using a pipe to the child to wait for an event was considered, but
81 // there were cases in the past where pipes caused problems (other
82 // libraries closing the fds, child deadlocking). This is a simple
83 // case, so it's not worth the risk. Using wait loops is discouraged
84 // in most instances.
85 base::TerminationStatus WaitForChildTermination(base::ProcessHandle handle,
86 int* exit_code) {
87 // Now we wait until the result is something other than STILL_RUNNING.
88 base::TerminationStatus status = base::TERMINATION_STATUS_STILL_RUNNING;
89 const int kIntervalMs = 20;
90 int waited = 0;
91 do {
92 status = base::GetTerminationStatus(handle, exit_code);
93 PlatformThread::Sleep(kIntervalMs);
94 waited += kIntervalMs;
95 } while (status == base::TERMINATION_STATUS_STILL_RUNNING &&
96 waited < kMaxWaitTimeMs);
97
98 return status;
99 }
100
65 } // namespace 101 } // namespace
66 102
67 class ProcessUtilTest : public base::MultiProcessTest { 103 class ProcessUtilTest : public base::MultiProcessTest {
68 #if defined(OS_POSIX) 104 #if defined(OS_POSIX)
69 public: 105 public:
70 // Spawn a child process that counts how many file descriptors are open. 106 // Spawn a child process that counts how many file descriptors are open.
71 int CountOpenFDsInChild(); 107 int CountOpenFDsInChild();
72 #endif 108 #endif
73 }; 109 };
74 110
75 MULTIPROCESS_TEST_MAIN(SimpleChildProcess) { 111 MULTIPROCESS_TEST_MAIN(SimpleChildProcess) {
76 return 0; 112 return 0;
77 } 113 }
78 114
79 TEST_F(ProcessUtilTest, SpawnChild) { 115 TEST_F(ProcessUtilTest, SpawnChild) {
80 base::ProcessHandle handle = this->SpawnChild("SimpleChildProcess", false); 116 base::ProcessHandle handle = this->SpawnChild("SimpleChildProcess", false);
81 ASSERT_NE(base::kNullProcessHandle, handle); 117 ASSERT_NE(base::kNullProcessHandle, handle);
82 EXPECT_TRUE(base::WaitForSingleProcess(handle, 5000)); 118 EXPECT_TRUE(base::WaitForSingleProcess(handle, kMaxWaitTimeMs));
83 base::CloseProcessHandle(handle); 119 base::CloseProcessHandle(handle);
84 } 120 }
85 121
86 MULTIPROCESS_TEST_MAIN(SlowChildProcess) { 122 MULTIPROCESS_TEST_MAIN(SlowChildProcess) {
87 WaitToDie("SlowChildProcess.die"); 123 WaitToDie(kSignalFileSlow);
88 return 0; 124 return 0;
89 } 125 }
90 126
91 TEST_F(ProcessUtilTest, KillSlowChild) { 127 TEST_F(ProcessUtilTest, KillSlowChild) {
92 remove("SlowChildProcess.die"); 128 remove(kSignalFileSlow);
93 base::ProcessHandle handle = this->SpawnChild("SlowChildProcess", false); 129 base::ProcessHandle handle = this->SpawnChild("SlowChildProcess", false);
94 ASSERT_NE(base::kNullProcessHandle, handle); 130 ASSERT_NE(base::kNullProcessHandle, handle);
95 SignalChildren("SlowChildProcess.die"); 131 SignalChildren(kSignalFileSlow);
96 EXPECT_TRUE(base::WaitForSingleProcess(handle, 5000)); 132 EXPECT_TRUE(base::WaitForSingleProcess(handle, kMaxWaitTimeMs));
97 base::CloseProcessHandle(handle); 133 base::CloseProcessHandle(handle);
98 remove("SlowChildProcess.die"); 134 remove(kSignalFileSlow);
99 } 135 }
100 136
101 TEST_F(ProcessUtilTest, DidProcessCrash) { 137 TEST_F(ProcessUtilTest, GetTerminationStatusExit) {
102 remove("SlowChildProcess.die"); 138 remove(kSignalFileSlow);
103 base::ProcessHandle handle = this->SpawnChild("SlowChildProcess", false); 139 base::ProcessHandle handle = this->SpawnChild("SlowChildProcess", false);
104 ASSERT_NE(base::kNullProcessHandle, handle); 140 ASSERT_NE(base::kNullProcessHandle, handle);
105 141
106 bool child_exited = true; 142 int exit_code = 42;
107 EXPECT_FALSE(base::DidProcessCrash(&child_exited, handle)); 143 EXPECT_EQ(base::TERMINATION_STATUS_STILL_RUNNING,
108 EXPECT_FALSE(child_exited); 144 base::GetTerminationStatus(handle, &exit_code));
145 EXPECT_EQ(kExpectedStillRunningExitCode, exit_code);
109 146
110 SignalChildren("SlowChildProcess.die"); 147 SignalChildren(kSignalFileSlow);
111 EXPECT_TRUE(base::WaitForSingleProcess(handle, 5000)); 148 exit_code = 42;
149 base::TerminationStatus status =
150 WaitForChildTermination(handle, &exit_code);
Paweł Hajdan Jr. 2010/11/30 09:39:38 Why not WaitForSingleProcess?
Greg Spencer (Chromium) 2010/11/30 19:42:29 Because on Linux, WaitForSingleProcess uses waitpi
Paweł Hajdan Jr. 2010/12/01 08:40:46 I suspected something like that. However, the prev
151 EXPECT_EQ(base::TERMINATION_STATUS_NORMAL_TERMINATION, status);
152 EXPECT_EQ(0, exit_code);
153 base::CloseProcessHandle(handle);
154 remove(kSignalFileSlow);
155 }
112 156
113 EXPECT_FALSE(base::DidProcessCrash(&child_exited, handle)); 157 MULTIPROCESS_TEST_MAIN(CrashingChildProcess) {
158 WaitToDie(kSignalFileCrash);
159 #if defined(OS_MACOSX)
160 // Have to reset the exception ports on mac so we get a crash.
161 base::RestoreDefaultExceptionHandler();
162 // We disable crash dumps because we don't really need one if we are
163 // *trying* to cause a crash.
164 DebugUtil::DisableOSCrashDumps();
165 // Mac gets a SIGBUS instead of SIGSEGV on x86 (but not x86_64), so
166 // we have to disable handling for both.
167 ::signal(SIGBUS, SIG_DFL);
168 #endif
169 #if defined(OS_POSIX)
170 // Have to disable to signal handler for segv so we can get a crash
171 // instead of an abnormal termination through the crash dump handler.
172 ::signal(SIGSEGV, SIG_DFL);
173 #endif
174 // Make this process have a segmentation fault.
175 int* oops = NULL;
176 *oops = 0xDEAD;
177 return 1;
178 }
179
180 TEST_F(ProcessUtilTest, GetTerminationStatusCrash) {
181 remove(kSignalFileCrash);
182 base::ProcessHandle handle = this->SpawnChild("CrashingChildProcess",
183 false);
184 ASSERT_NE(base::kNullProcessHandle, handle);
185
186 int exit_code = 42;
187 EXPECT_EQ(base::TERMINATION_STATUS_STILL_RUNNING,
188 base::GetTerminationStatus(handle, &exit_code));
189 EXPECT_EQ(kExpectedStillRunningExitCode, exit_code);
190
191 SignalChildren(kSignalFileCrash);
192 exit_code = 42;
193 base::TerminationStatus status =
194 WaitForChildTermination(handle, &exit_code);
Paweł Hajdan Jr. 2010/11/30 09:39:38 Why not WaitForSingleProcess?
Greg Spencer (Chromium) 2010/11/30 19:42:29 See above.
195 EXPECT_EQ(base::TERMINATION_STATUS_PROCESS_CRASHED, status);
196
197 #if defined(OS_WIN)
198 EXPECT_EQ(0xc0000005, exit_code);
199 #elif defined(OS_POSIX)
200 int signaled = WIFSIGNALED(exit_code);
201 EXPECT_NE(0, signaled);
202 int signal = WTERMSIG(exit_code);
203 #if defined(OS_MACOSX)
204 // Mac gets a SIGBUS instead of SIGSEGV on x86 (but not x86_64), so
205 // we have to expect either one.
206 EXPECT_TRUE(signal == SIGBUS || signal == SIGSEGV);
207 #else
208 EXPECT_EQ(SIGSEGV, signal);
209 #endif
210 #endif
114 base::CloseProcessHandle(handle); 211 base::CloseProcessHandle(handle);
115 remove("SlowChildProcess.die"); 212
213 // Reset signal handlers back to "normal".
214 base::EnableInProcessStackDumping();
215 remove(kSignalFileCrash);
216 }
217
218 MULTIPROCESS_TEST_MAIN(KilledChildProcess) {
219 WaitToDie(kSignalFileKill);
220 #if defined(OS_WIN)
221 // Kill ourselves.
222 HANDLE handle = ::OpenProcess(PROCESS_ALL_ACCESS, 0, ::GetCurrentProcessId());
223 ::TerminateProcess(handle, base::PROCESS_END_PROCESS_WAS_KILLED);
224 #elif defined(OS_POSIX)
225 // Send a SIGKILL to this process, just like the OOM killer would.
226 ::kill(getpid(), SIGKILL);
227 #endif
228 return 1;
229 }
230
231 TEST_F(ProcessUtilTest, GetTerminationStatusKill) {
232 remove(kSignalFileKill);
233 base::ProcessHandle handle = this->SpawnChild("KilledChildProcess",
234 false);
235 ASSERT_NE(base::kNullProcessHandle, handle);
236
237 int exit_code = 42;
238 EXPECT_EQ(base::TERMINATION_STATUS_STILL_RUNNING,
239 base::GetTerminationStatus(handle, &exit_code));
240 EXPECT_EQ(kExpectedStillRunningExitCode, exit_code);
241
242 SignalChildren(kSignalFileKill);
243 exit_code = 42;
244 base::TerminationStatus status =
245 WaitForChildTermination(handle, &exit_code);
Paweł Hajdan Jr. 2010/11/30 09:39:38 Why not WaitForSingleProcess?
Greg Spencer (Chromium) 2010/11/30 19:42:29 See above.
246 EXPECT_EQ(base::TERMINATION_STATUS_PROCESS_WAS_KILLED, status);
247 #if defined(OS_WIN)
248 EXPECT_EQ(base::PROCESS_END_PROCESS_WAS_KILLED, exit_code);
249 #elif defined(OS_POSIX)
250 int signaled = WIFSIGNALED(exit_code);
251 EXPECT_NE(0, signaled);
252 int signal = WTERMSIG(exit_code);
253 EXPECT_EQ(SIGKILL, signal);
254 #endif
255 base::CloseProcessHandle(handle);
256 remove(kSignalFileKill);
116 } 257 }
117 258
118 // Ensure that the priority of a process is restored correctly after 259 // Ensure that the priority of a process is restored correctly after
119 // backgrounding and restoring. 260 // backgrounding and restoring.
120 // Note: a platform may not be willing or able to lower the priority of 261 // 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. 262 // a process. The calls to SetProcessBackground should be noops then.
122 TEST_F(ProcessUtilTest, SetProcessBackgrounded) { 263 TEST_F(ProcessUtilTest, SetProcessBackgrounded) {
123 base::ProcessHandle handle = this->SpawnChild("SimpleChildProcess", false); 264 base::ProcessHandle handle = this->SpawnChild("SimpleChildProcess", false);
124 base::Process process(handle); 265 base::Process process(handle);
125 int old_priority = process.GetPriority(); 266 int old_priority = process.GetPriority();
(...skipping 655 matching lines...) Expand 10 before | Expand all | Expand 10 after
781 ASSERT_DEATH({ 922 ASSERT_DEATH({
782 SetUpInDeathAssert(); 923 SetUpInDeathAssert();
783 while ((value_ = base::AllocatePsychoticallyBigObjCObject())) {} 924 while ((value_ = base::AllocatePsychoticallyBigObjCObject())) {}
784 }, ""); 925 }, "");
785 } 926 }
786 927
787 #endif // !ARCH_CPU_64_BITS 928 #endif // !ARCH_CPU_64_BITS
788 #endif // OS_MACOSX 929 #endif // OS_MACOSX
789 930
790 #endif // !defined(OS_WIN) 931 #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