OLD | NEW |
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 Loading... |
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) |
OLD | NEW |