OLD | NEW |
1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2013 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 #include "base/process/kill.h" | 5 #include "base/process/kill.h" |
6 | 6 |
7 #include <signal.h> | 7 #include <signal.h> |
8 #include <sys/types.h> | 8 #include <sys/types.h> |
9 #include <sys/wait.h> | 9 #include <sys/wait.h> |
10 #include <unistd.h> | 10 #include <unistd.h> |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
43 // waitpid(). The amount of time we sleep starts out at 1 milliseconds, and | 43 // waitpid(). The amount of time we sleep starts out at 1 milliseconds, and |
44 // we double it every 4 sleep cycles. | 44 // we double it every 4 sleep cycles. |
45 // | 45 // |
46 // usleep() is speced to exit if a signal is received for which a handler | 46 // usleep() is speced to exit if a signal is received for which a handler |
47 // has been installed. This means that when a SIGCHLD is sent, it will exit | 47 // has been installed. This means that when a SIGCHLD is sent, it will exit |
48 // depending on behavior external to this function. | 48 // depending on behavior external to this function. |
49 // | 49 // |
50 // This function is used primarily for unit tests, if we want to use it in | 50 // This function is used primarily for unit tests, if we want to use it in |
51 // the application itself it would probably be best to examine other routes. | 51 // the application itself it would probably be best to examine other routes. |
52 | 52 |
53 if (wait.InMilliseconds() == base::kNoTimeout) { | 53 if (wait.InMilliseconds() == base::internal::kNoTimeout) { |
54 return HANDLE_EINTR(waitpid(handle, status, 0)) > 0; | 54 return HANDLE_EINTR(waitpid(handle, status, 0)) > 0; |
55 } | 55 } |
56 | 56 |
57 pid_t ret_pid = HANDLE_EINTR(waitpid(handle, status, WNOHANG)); | 57 pid_t ret_pid = HANDLE_EINTR(waitpid(handle, status, WNOHANG)); |
58 static const int64 kMaxSleepInMicroseconds = 1 << 18; // ~256 milliseconds. | 58 static const int64 kMaxSleepInMicroseconds = 1 << 18; // ~256 milliseconds. |
59 int64 max_sleep_time_usecs = 1 << 10; // ~1 milliseconds. | 59 int64 max_sleep_time_usecs = 1 << 10; // ~1 milliseconds. |
60 int64 double_sleep_time = 0; | 60 int64 double_sleep_time = 0; |
61 | 61 |
62 // If the process hasn't exited yet, then sleep and try again. | 62 // If the process hasn't exited yet, then sleep and try again. |
63 TimeTicks wakeup_time = TimeTicks::Now() + wait; | 63 TimeTicks wakeup_time = TimeTicks::Now() + wait; |
(...skipping 21 matching lines...) Expand all Loading... |
85 return ret_pid > 0; | 85 return ret_pid > 0; |
86 } | 86 } |
87 | 87 |
88 #if defined(OS_MACOSX) | 88 #if defined(OS_MACOSX) |
89 // Using kqueue on Mac so that we can wait on non-child processes. | 89 // Using kqueue on Mac so that we can wait on non-child processes. |
90 // We can't use kqueues on child processes because we need to reap | 90 // We can't use kqueues on child processes because we need to reap |
91 // our own children using wait. | 91 // our own children using wait. |
92 static bool WaitForSingleNonChildProcess(ProcessHandle handle, | 92 static bool WaitForSingleNonChildProcess(ProcessHandle handle, |
93 TimeDelta wait) { | 93 TimeDelta wait) { |
94 DCHECK_GT(handle, 0); | 94 DCHECK_GT(handle, 0); |
95 DCHECK(wait.InMilliseconds() == kNoTimeout || wait > TimeDelta()); | 95 DCHECK(wait.InMilliseconds() == internal::kNoTimeout || wait > TimeDelta()); |
96 | 96 |
97 ScopedFD kq(kqueue()); | 97 ScopedFD kq(kqueue()); |
98 if (!kq.is_valid()) { | 98 if (!kq.is_valid()) { |
99 DPLOG(ERROR) << "kqueue"; | 99 DPLOG(ERROR) << "kqueue"; |
100 return false; | 100 return false; |
101 } | 101 } |
102 | 102 |
103 struct kevent change = {0}; | 103 struct kevent change = {0}; |
104 EV_SET(&change, handle, EVFILT_PROC, EV_ADD, NOTE_EXIT, 0, NULL); | 104 EV_SET(&change, handle, EVFILT_PROC, EV_ADD, NOTE_EXIT, 0, NULL); |
105 int result = HANDLE_EINTR(kevent(kq.get(), &change, 1, NULL, 0, NULL)); | 105 int result = HANDLE_EINTR(kevent(kq.get(), &change, 1, NULL, 0, NULL)); |
106 if (result == -1) { | 106 if (result == -1) { |
107 if (errno == ESRCH) { | 107 if (errno == ESRCH) { |
108 // If the process wasn't found, it must be dead. | 108 // If the process wasn't found, it must be dead. |
109 return true; | 109 return true; |
110 } | 110 } |
111 | 111 |
112 DPLOG(ERROR) << "kevent (setup " << handle << ")"; | 112 DPLOG(ERROR) << "kevent (setup " << handle << ")"; |
113 return false; | 113 return false; |
114 } | 114 } |
115 | 115 |
116 // Keep track of the elapsed time to be able to restart kevent if it's | 116 // Keep track of the elapsed time to be able to restart kevent if it's |
117 // interrupted. | 117 // interrupted. |
118 bool wait_forever = wait.InMilliseconds() == kNoTimeout; | 118 bool wait_forever = (wait.InMilliseconds() == internal::kNoTimeout); |
119 TimeDelta remaining_delta; | 119 TimeDelta remaining_delta; |
120 TimeTicks deadline; | 120 TimeTicks deadline; |
121 if (!wait_forever) { | 121 if (!wait_forever) { |
122 remaining_delta = wait; | 122 remaining_delta = wait; |
123 deadline = TimeTicks::Now() + remaining_delta; | 123 deadline = TimeTicks::Now() + remaining_delta; |
124 } | 124 } |
125 | 125 |
126 result = -1; | 126 result = -1; |
127 struct kevent event = {0}; | 127 struct kevent event = {0}; |
128 | 128 |
(...skipping 166 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
295 int* exit_code) { | 295 int* exit_code) { |
296 bool result = kill(handle, SIGKILL) == 0; | 296 bool result = kill(handle, SIGKILL) == 0; |
297 | 297 |
298 if (!result) | 298 if (!result) |
299 DPLOG(ERROR) << "Unable to terminate process " << handle; | 299 DPLOG(ERROR) << "Unable to terminate process " << handle; |
300 | 300 |
301 return GetTerminationStatusImpl(handle, true /* can_block */, exit_code); | 301 return GetTerminationStatusImpl(handle, true /* can_block */, exit_code); |
302 } | 302 } |
303 | 303 |
304 #if !defined(OS_NACL_NONSFI) | 304 #if !defined(OS_NACL_NONSFI) |
305 bool WaitForExitCode(ProcessHandle handle, int* exit_code) { | 305 bool internal::WaitForExitCodeWithTimeout(ProcessHandle handle, |
306 int status; | 306 int* exit_code, |
307 if (HANDLE_EINTR(waitpid(handle, &status, 0)) == -1) { | 307 TimeDelta timeout) { |
308 NOTREACHED(); | |
309 return false; | |
310 } | |
311 | |
312 if (WIFEXITED(status)) { | |
313 *exit_code = WEXITSTATUS(status); | |
314 return true; | |
315 } | |
316 | |
317 // If it didn't exit cleanly, it must have been signaled. | |
318 DCHECK(WIFSIGNALED(status)); | |
319 return false; | |
320 } | |
321 | |
322 bool WaitForExitCodeWithTimeout(ProcessHandle handle, | |
323 int* exit_code, | |
324 TimeDelta timeout) { | |
325 ProcessHandle parent_pid = GetParentProcessId(handle); | 308 ProcessHandle parent_pid = GetParentProcessId(handle); |
326 ProcessHandle our_pid = GetCurrentProcessHandle(); | 309 ProcessHandle our_pid = GetCurrentProcessHandle(); |
327 if (parent_pid != our_pid) { | 310 if (parent_pid != our_pid) { |
328 #if defined(OS_MACOSX) | 311 #if defined(OS_MACOSX) |
329 // On Mac we can wait on non child processes. | 312 // On Mac we can wait on non child processes. |
330 return WaitForSingleNonChildProcess(handle, timeout); | 313 return WaitForSingleNonChildProcess(handle, timeout); |
331 #else | 314 #else |
332 // Currently on Linux we can't handle non child processes. | 315 // Currently on Linux we can't handle non child processes. |
333 NOTIMPLEMENTED(); | 316 NOTIMPLEMENTED(); |
334 #endif // OS_MACOSX | 317 #endif // OS_MACOSX |
(...skipping 137 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
472 return; | 455 return; |
473 | 456 |
474 BackgroundReaper* reaper = new BackgroundReaper(pid, 0); | 457 BackgroundReaper* reaper = new BackgroundReaper(pid, 0); |
475 PlatformThread::CreateNonJoinable(0, reaper); | 458 PlatformThread::CreateNonJoinable(0, reaper); |
476 } | 459 } |
477 | 460 |
478 #endif // !defined(OS_MACOSX) | 461 #endif // !defined(OS_MACOSX) |
479 #endif // !defined(OS_NACL_NONSFI) | 462 #endif // !defined(OS_NACL_NONSFI) |
480 | 463 |
481 } // namespace base | 464 } // namespace base |
OLD | NEW |