| 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 |