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

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: Upload after sync for proper diffs 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
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 #else
59 const int kExpectedStillRunningExitCode = 0;
60 #endif
61
62 // The longest we'll wait for a process, in milliseconds.
63 const int kMaxWaitTimeMs = TestTimeouts::action_max_timeout_ms();
64
49 // Sleeps until file filename is created. 65 // Sleeps until file filename is created.
50 void WaitToDie(const char* filename) { 66 void WaitToDie(const char* filename) {
51 FILE *fp; 67 FILE *fp;
52 do { 68 do {
53 PlatformThread::Sleep(10); 69 PlatformThread::Sleep(10);
54 fp = fopen(filename, "r"); 70 fp = fopen(filename, "r");
55 } while (!fp); 71 } while (!fp);
56 fclose(fp); 72 fclose(fp);
57 } 73 }
58 74
59 // Signals children they should die now. 75 // Signals children they should die now.
60 void SignalChildren(const char* filename) { 76 void SignalChildren(const char* filename) {
61 FILE *fp = fopen(filename, "w"); 77 FILE *fp = fopen(filename, "w");
62 fclose(fp); 78 fclose(fp);
63 } 79 }
64 80
81 // Using a pipe to the child to wait for an event was considered, but
82 // there were cases in the past where pipes caused problems (other
83 // libraries closing the fds, child deadlocking). This is a simple
84 // case, so it's not worth the risk. Using wait loops is discouraged
85 // in most instances.
86 base::TerminationStatus WaitForChildTermination(base::ProcessHandle handle,
87 int* exit_code) {
88 // Now we wait until the result is something other than STILL_RUNNING.
89 base::TerminationStatus status = base::TERMINATION_STATUS_STILL_RUNNING;
90 const int kIntervalMs = 20;
91 int waited = 0;
92 do {
93 status = base::GetTerminationStatus(handle, exit_code);
94 PlatformThread::Sleep(kIntervalMs);
95 waited += kIntervalMs;
96 } while (status == base::TERMINATION_STATUS_STILL_RUNNING &&
97 waited < kMaxWaitTimeMs);
98
99 return status;
100 }
101
65 } // namespace 102 } // namespace
66 103
67 class ProcessUtilTest : public base::MultiProcessTest { 104 class ProcessUtilTest : public base::MultiProcessTest {
68 #if defined(OS_POSIX) 105 #if defined(OS_POSIX)
69 public: 106 public:
70 // Spawn a child process that counts how many file descriptors are open. 107 // Spawn a child process that counts how many file descriptors are open.
71 int CountOpenFDsInChild(); 108 int CountOpenFDsInChild();
72 #endif 109 #endif
73 }; 110 };
74 111
75 MULTIPROCESS_TEST_MAIN(SimpleChildProcess) { 112 MULTIPROCESS_TEST_MAIN(SimpleChildProcess) {
76 return 0; 113 return 0;
77 } 114 }
78 115
79 TEST_F(ProcessUtilTest, SpawnChild) { 116 TEST_F(ProcessUtilTest, SpawnChild) {
80 base::ProcessHandle handle = this->SpawnChild("SimpleChildProcess", false); 117 base::ProcessHandle handle = this->SpawnChild("SimpleChildProcess", false);
81 ASSERT_NE(base::kNullProcessHandle, handle); 118 ASSERT_NE(base::kNullProcessHandle, handle);
82 EXPECT_TRUE(base::WaitForSingleProcess(handle, 5000)); 119 EXPECT_TRUE(base::WaitForSingleProcess(handle, kMaxWaitTimeMs));
83 base::CloseProcessHandle(handle); 120 base::CloseProcessHandle(handle);
84 } 121 }
85 122
86 MULTIPROCESS_TEST_MAIN(SlowChildProcess) { 123 MULTIPROCESS_TEST_MAIN(SlowChildProcess) {
87 WaitToDie("SlowChildProcess.die"); 124 WaitToDie(kSignalFileSlow);
88 return 0; 125 return 0;
89 } 126 }
90 127
91 TEST_F(ProcessUtilTest, KillSlowChild) { 128 TEST_F(ProcessUtilTest, KillSlowChild) {
92 remove("SlowChildProcess.die"); 129 remove(kSignalFileSlow);
93 base::ProcessHandle handle = this->SpawnChild("SlowChildProcess", false); 130 base::ProcessHandle handle = this->SpawnChild("SlowChildProcess", false);
94 ASSERT_NE(base::kNullProcessHandle, handle); 131 ASSERT_NE(base::kNullProcessHandle, handle);
95 SignalChildren("SlowChildProcess.die"); 132 SignalChildren(kSignalFileSlow);
96 EXPECT_TRUE(base::WaitForSingleProcess(handle, 5000)); 133 EXPECT_TRUE(base::WaitForSingleProcess(handle, kMaxWaitTimeMs));
97 base::CloseProcessHandle(handle); 134 base::CloseProcessHandle(handle);
98 remove("SlowChildProcess.die"); 135 remove(kSignalFileSlow);
99 } 136 }
100 137
101 TEST_F(ProcessUtilTest, DidProcessCrash) { 138 TEST_F(ProcessUtilTest, GetTerminationStatusExit) {
102 remove("SlowChildProcess.die"); 139 remove(kSignalFileSlow);
103 base::ProcessHandle handle = this->SpawnChild("SlowChildProcess", false); 140 base::ProcessHandle handle = this->SpawnChild("SlowChildProcess", false);
104 ASSERT_NE(base::kNullProcessHandle, handle); 141 ASSERT_NE(base::kNullProcessHandle, handle);
105 142
106 bool child_exited = true; 143 int exit_code = 42;
107 EXPECT_FALSE(base::DidProcessCrash(&child_exited, handle)); 144 EXPECT_EQ(base::TERMINATION_STATUS_STILL_RUNNING,
108 EXPECT_FALSE(child_exited); 145 base::GetTerminationStatus(handle, &exit_code));
146 EXPECT_EQ(kExpectedStillRunningExitCode, exit_code);
109 147
110 SignalChildren("SlowChildProcess.die"); 148 SignalChildren(kSignalFileSlow);
111 EXPECT_TRUE(base::WaitForSingleProcess(handle, 5000)); 149 exit_code = 42;
150 base::TerminationStatus status =
151 WaitForChildTermination(handle, &exit_code);
152 EXPECT_EQ(base::TERMINATION_STATUS_NORMAL_TERMINATION, status);
153 EXPECT_EQ(0, exit_code);
154 base::CloseProcessHandle(handle);
155 remove(kSignalFileSlow);
156 }
112 157
113 EXPECT_FALSE(base::DidProcessCrash(&child_exited, handle)); 158 #if !defined(OS_MACOSX)
159 // This test is disabled on Mac, since it's flaky due to ReportCrash
160 // taking a variable amount of time to parse and load the debug and
161 // symbol data for this unit test's executable before firing the
162 // signal handler.
163 //
164 // TODO(gspencer): turn this test process into a very small program
165 // with no symbols (instead of using the multiprocess testing
166 // framework) to reduce the ReportCrash overhead.
167
168 MULTIPROCESS_TEST_MAIN(CrashingChildProcess) {
169 WaitToDie(kSignalFileCrash);
170 #if defined(OS_POSIX)
171 // Have to disable to signal handler for segv so we can get a crash
172 // instead of an abnormal termination through the crash dump handler.
173 ::signal(SIGSEGV, SIG_DFL);
174 #endif
175 // Make this process have a segmentation fault.
176 int* oops = NULL;
177 *oops = 0xDEAD;
178 return 1;
179 }
180
181 TEST_F(ProcessUtilTest, GetTerminationStatusCrash) {
182 remove(kSignalFileCrash);
183 base::ProcessHandle handle = this->SpawnChild("CrashingChildProcess",
184 false);
185 ASSERT_NE(base::kNullProcessHandle, handle);
186
187 int exit_code = 42;
188 EXPECT_EQ(base::TERMINATION_STATUS_STILL_RUNNING,
189 base::GetTerminationStatus(handle, &exit_code));
190 EXPECT_EQ(kExpectedStillRunningExitCode, exit_code);
191
192 SignalChildren(kSignalFileCrash);
193 exit_code = 42;
194 base::TerminationStatus status =
195 WaitForChildTermination(handle, &exit_code);
196 EXPECT_EQ(base::TERMINATION_STATUS_PROCESS_CRASHED, status);
197
198 #if defined(OS_WIN)
199 EXPECT_EQ(0xc0000005, exit_code);
200 #elif defined(OS_POSIX)
201 int signaled = WIFSIGNALED(exit_code);
202 EXPECT_NE(0, signaled);
203 int signal = WTERMSIG(exit_code);
204 EXPECT_EQ(SIGSEGV, signal);
205 #endif
114 base::CloseProcessHandle(handle); 206 base::CloseProcessHandle(handle);
115 remove("SlowChildProcess.die"); 207
208 // Reset signal handlers back to "normal".
209 base::EnableInProcessStackDumping();
210 remove(kSignalFileCrash);
211 }
212 #endif // !defined(OS_MACOSX)
213
214 MULTIPROCESS_TEST_MAIN(KilledChildProcess) {
215 WaitToDie(kSignalFileKill);
216 #if defined(OS_WIN)
217 // Kill ourselves.
218 HANDLE handle = ::OpenProcess(PROCESS_ALL_ACCESS, 0, ::GetCurrentProcessId());
219 ::TerminateProcess(handle, base::EXIT_CODE_PROCESS_WAS_KILLED);
220 #elif defined(OS_POSIX)
221 // Send a SIGKILL to this process, just like the OOM killer would.
222 ::kill(getpid(), SIGKILL);
223 #endif
224 return 1;
225 }
226
227 TEST_F(ProcessUtilTest, GetTerminationStatusKill) {
228 remove(kSignalFileKill);
229 base::ProcessHandle handle = this->SpawnChild("KilledChildProcess",
230 false);
231 ASSERT_NE(base::kNullProcessHandle, handle);
232
233 int exit_code = 42;
234 EXPECT_EQ(base::TERMINATION_STATUS_STILL_RUNNING,
235 base::GetTerminationStatus(handle, &exit_code));
236 EXPECT_EQ(kExpectedStillRunningExitCode, exit_code);
237
238 SignalChildren(kSignalFileKill);
239 exit_code = 42;
240 base::TerminationStatus status =
241 WaitForChildTermination(handle, &exit_code);
242 EXPECT_EQ(base::TERMINATION_STATUS_PROCESS_WAS_KILLED, status);
243 #if defined(OS_WIN)
244 EXPECT_EQ(base::EXIT_CODE_PROCESS_WAS_KILLED, exit_code);
245 #elif defined(OS_POSIX)
246 int signaled = WIFSIGNALED(exit_code);
247 EXPECT_NE(0, signaled);
248 int signal = WTERMSIG(exit_code);
249 EXPECT_EQ(SIGKILL, signal);
250 #endif
251 base::CloseProcessHandle(handle);
252 remove(kSignalFileKill);
116 } 253 }
117 254
118 // Ensure that the priority of a process is restored correctly after 255 // Ensure that the priority of a process is restored correctly after
119 // backgrounding and restoring. 256 // backgrounding and restoring.
120 // Note: a platform may not be willing or able to lower the priority of 257 // 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. 258 // a process. The calls to SetProcessBackground should be noops then.
122 TEST_F(ProcessUtilTest, SetProcessBackgrounded) { 259 TEST_F(ProcessUtilTest, SetProcessBackgrounded) {
123 base::ProcessHandle handle = this->SpawnChild("SimpleChildProcess", false); 260 base::ProcessHandle handle = this->SpawnChild("SimpleChildProcess", false);
124 base::Process process(handle); 261 base::Process process(handle);
125 int old_priority = process.GetPriority(); 262 int old_priority = process.GetPriority();
(...skipping 655 matching lines...) Expand 10 before | Expand all | Expand 10 after
781 ASSERT_DEATH({ 918 ASSERT_DEATH({
782 SetUpInDeathAssert(); 919 SetUpInDeathAssert();
783 while ((value_ = base::AllocatePsychoticallyBigObjCObject())) {} 920 while ((value_ = base::AllocatePsychoticallyBigObjCObject())) {}
784 }, ""); 921 }, "");
785 } 922 }
786 923
787 #endif // !ARCH_CPU_64_BITS 924 #endif // !ARCH_CPU_64_BITS
788 #endif // OS_MACOSX 925 #endif // OS_MACOSX
789 926
790 #endif // !defined(OS_WIN) 927 #endif // !defined(OS_WIN)
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698