Index: base/process/kill_posix.cc |
diff --git a/base/process/kill_posix.cc b/base/process/kill_posix.cc |
index 5e8b61f6b86be7eb6ddc11ce503f733c37a74b8c..77705eeb6789b0a53a81ae11c468b2270e3a736e 100644 |
--- a/base/process/kill_posix.cc |
+++ b/base/process/kill_posix.cc |
@@ -84,6 +84,97 @@ bool WaitpidWithTimeout(ProcessHandle handle, |
return ret_pid > 0; |
} |
+ |
+#if defined(OS_MACOSX) |
+// Using kqueue on Mac so that we can wait on non-child processes. |
+// We can't use kqueues on child processes because we need to reap |
+// our own children using wait. |
+static bool WaitForSingleNonChildProcess(ProcessHandle handle, |
+ TimeDelta wait) { |
+ DCHECK_GT(handle, 0); |
+ DCHECK(wait.InMilliseconds() == kNoTimeout || wait > TimeDelta()); |
+ |
+ ScopedFD kq(kqueue()); |
+ if (!kq.is_valid()) { |
+ DPLOG(ERROR) << "kqueue"; |
+ return false; |
+ } |
+ |
+ struct kevent change = {0}; |
+ EV_SET(&change, handle, EVFILT_PROC, EV_ADD, NOTE_EXIT, 0, NULL); |
+ int result = HANDLE_EINTR(kevent(kq.get(), &change, 1, NULL, 0, NULL)); |
+ if (result == -1) { |
+ if (errno == ESRCH) { |
+ // If the process wasn't found, it must be dead. |
+ return true; |
+ } |
+ |
+ DPLOG(ERROR) << "kevent (setup " << handle << ")"; |
+ return false; |
+ } |
+ |
+ // Keep track of the elapsed time to be able to restart kevent if it's |
+ // interrupted. |
+ bool wait_forever = wait.InMilliseconds() == kNoTimeout; |
+ TimeDelta remaining_delta; |
+ TimeTicks deadline; |
+ if (!wait_forever) { |
+ remaining_delta = wait; |
+ deadline = TimeTicks::Now() + remaining_delta; |
+ } |
+ |
+ result = -1; |
+ struct kevent event = {0}; |
+ |
+ while (wait_forever || remaining_delta > TimeDelta()) { |
+ struct timespec remaining_timespec; |
+ struct timespec* remaining_timespec_ptr; |
+ if (wait_forever) { |
+ remaining_timespec_ptr = NULL; |
+ } else { |
+ remaining_timespec = remaining_delta.ToTimeSpec(); |
+ remaining_timespec_ptr = &remaining_timespec; |
+ } |
+ |
+ result = kevent(kq.get(), NULL, 0, &event, 1, remaining_timespec_ptr); |
+ |
+ if (result == -1 && errno == EINTR) { |
+ if (!wait_forever) { |
+ remaining_delta = deadline - TimeTicks::Now(); |
+ } |
+ result = 0; |
+ } else { |
+ break; |
+ } |
+ } |
+ |
+ if (result < 0) { |
+ DPLOG(ERROR) << "kevent (wait " << handle << ")"; |
+ return false; |
+ } else if (result > 1) { |
+ DLOG(ERROR) << "kevent (wait " << handle << "): unexpected result " |
+ << result; |
+ return false; |
+ } else if (result == 0) { |
+ // Timed out. |
+ return false; |
+ } |
+ |
+ DCHECK_EQ(result, 1); |
+ |
+ if (event.filter != EVFILT_PROC || |
+ (event.fflags & NOTE_EXIT) == 0 || |
+ event.ident != static_cast<uintptr_t>(handle)) { |
+ DLOG(ERROR) << "kevent (wait " << handle |
+ << "): unexpected event: filter=" << event.filter |
+ << ", fflags=" << event.fflags |
+ << ", ident=" << event.ident; |
+ return false; |
+ } |
+ |
+ return true; |
+} |
+#endif // OS_MACOSX |
#endif // !defined(OS_NACL_NONSFI) |
TerminationStatus GetTerminationStatusImpl(ProcessHandle handle, |
@@ -230,7 +321,19 @@ bool WaitForExitCode(ProcessHandle handle, int* exit_code) { |
bool WaitForExitCodeWithTimeout(ProcessHandle handle, |
int* exit_code, |
- base::TimeDelta timeout) { |
+ TimeDelta timeout) { |
+ ProcessHandle parent_pid = GetParentProcessId(handle); |
+ ProcessHandle our_pid = GetCurrentProcessHandle(); |
+ if (parent_pid != our_pid) { |
+#if defined(OS_MACOSX) |
+ // On Mac we can wait on non child processes. |
+ return WaitForSingleNonChildProcess(handle, timeout); |
+#else |
+ // Currently on Linux we can't handle non child processes. |
+ NOTIMPLEMENTED(); |
+#endif // OS_MACOSX |
+ } |
+ |
int status; |
if (!WaitpidWithTimeout(handle, &status, timeout)) |
return false; |
@@ -246,138 +349,28 @@ bool WaitForExitCodeWithTimeout(ProcessHandle handle, |
} |
bool WaitForProcessesToExit(const FilePath::StringType& executable_name, |
- base::TimeDelta wait, |
+ TimeDelta wait, |
const ProcessFilter* filter) { |
bool result = false; |
// TODO(port): This is inefficient, but works if there are multiple procs. |
// TODO(port): use waitpid to avoid leaving zombies around |
- base::TimeTicks end_time = base::TimeTicks::Now() + wait; |
+ TimeTicks end_time = TimeTicks::Now() + wait; |
do { |
NamedProcessIterator iter(executable_name, filter); |
if (!iter.NextProcessEntry()) { |
result = true; |
break; |
} |
- base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(100)); |
- } while ((end_time - base::TimeTicks::Now()) > base::TimeDelta()); |
+ PlatformThread::Sleep(TimeDelta::FromMilliseconds(100)); |
+ } while ((end_time - TimeTicks::Now()) > TimeDelta()); |
return result; |
} |
-#if defined(OS_MACOSX) |
-// Using kqueue on Mac so that we can wait on non-child processes. |
-// We can't use kqueues on child processes because we need to reap |
-// our own children using wait. |
-static bool WaitForSingleNonChildProcess(ProcessHandle handle, |
- base::TimeDelta wait) { |
- DCHECK_GT(handle, 0); |
- DCHECK(wait.InMilliseconds() == base::kNoTimeout || wait > base::TimeDelta()); |
- |
- ScopedFD kq(kqueue()); |
- if (!kq.is_valid()) { |
- DPLOG(ERROR) << "kqueue"; |
- return false; |
- } |
- |
- struct kevent change = {0}; |
- EV_SET(&change, handle, EVFILT_PROC, EV_ADD, NOTE_EXIT, 0, NULL); |
- int result = HANDLE_EINTR(kevent(kq.get(), &change, 1, NULL, 0, NULL)); |
- if (result == -1) { |
- if (errno == ESRCH) { |
- // If the process wasn't found, it must be dead. |
- return true; |
- } |
- |
- DPLOG(ERROR) << "kevent (setup " << handle << ")"; |
- return false; |
- } |
- |
- // Keep track of the elapsed time to be able to restart kevent if it's |
- // interrupted. |
- bool wait_forever = wait.InMilliseconds() == base::kNoTimeout; |
- base::TimeDelta remaining_delta; |
- base::TimeTicks deadline; |
- if (!wait_forever) { |
- remaining_delta = wait; |
- deadline = base::TimeTicks::Now() + remaining_delta; |
- } |
- |
- result = -1; |
- struct kevent event = {0}; |
- |
- while (wait_forever || remaining_delta > base::TimeDelta()) { |
- struct timespec remaining_timespec; |
- struct timespec* remaining_timespec_ptr; |
- if (wait_forever) { |
- remaining_timespec_ptr = NULL; |
- } else { |
- remaining_timespec = remaining_delta.ToTimeSpec(); |
- remaining_timespec_ptr = &remaining_timespec; |
- } |
- |
- result = kevent(kq.get(), NULL, 0, &event, 1, remaining_timespec_ptr); |
- |
- if (result == -1 && errno == EINTR) { |
- if (!wait_forever) { |
- remaining_delta = deadline - base::TimeTicks::Now(); |
- } |
- result = 0; |
- } else { |
- break; |
- } |
- } |
- |
- if (result < 0) { |
- DPLOG(ERROR) << "kevent (wait " << handle << ")"; |
- return false; |
- } else if (result > 1) { |
- DLOG(ERROR) << "kevent (wait " << handle << "): unexpected result " |
- << result; |
- return false; |
- } else if (result == 0) { |
- // Timed out. |
- return false; |
- } |
- |
- DCHECK_EQ(result, 1); |
- |
- if (event.filter != EVFILT_PROC || |
- (event.fflags & NOTE_EXIT) == 0 || |
- event.ident != static_cast<uintptr_t>(handle)) { |
- DLOG(ERROR) << "kevent (wait " << handle |
- << "): unexpected event: filter=" << event.filter |
- << ", fflags=" << event.fflags |
- << ", ident=" << event.ident; |
- return false; |
- } |
- |
- return true; |
-} |
-#endif // OS_MACOSX |
- |
-bool WaitForSingleProcess(ProcessHandle handle, base::TimeDelta wait) { |
- ProcessHandle parent_pid = GetParentProcessId(handle); |
- ProcessHandle our_pid = GetCurrentProcessHandle(); |
- if (parent_pid != our_pid) { |
-#if defined(OS_MACOSX) |
- // On Mac we can wait on non child processes. |
- return WaitForSingleNonChildProcess(handle, wait); |
-#else |
- // Currently on Linux we can't handle non child processes. |
- NOTIMPLEMENTED(); |
-#endif // OS_MACOSX |
- } |
- |
- int status; |
- if (!WaitpidWithTimeout(handle, &status, wait)) |
- return false; |
- return WIFEXITED(status); |
-} |
- |
bool CleanupProcesses(const FilePath::StringType& executable_name, |
- base::TimeDelta wait, |
+ TimeDelta wait, |
int exit_code, |
const ProcessFilter* filter) { |
bool exited_cleanly = WaitForProcessesToExit(executable_name, wait, filter); |