1 // Copyright 2011 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "base/process/process.h"
7 #include <sys/resource.h>
10 #include "base/files/scoped_file.h"
11 #include "base/logging.h"
12 #include "base/posix/eintr_wrapper.h"
13 #include "base/process/kill.h"
14 #include "base/third_party/dynamic_annotations/dynamic_annotations.h"
16 #if defined(OS_MACOSX)
17 #include <sys/event.h>
22 #if !defined(OS_NACL_NONSFI)
24 bool WaitpidWithTimeout(base::ProcessHandle handle
,
26 base::TimeDelta wait
) {
27 // This POSIX version of this function only guarantees that we wait no less
28 // than |wait| for the process to exit. The child process may
29 // exit sometime before the timeout has ended but we may still block for up
30 // to 256 milliseconds after the fact.
32 // waitpid() has no direct support on POSIX for specifying a timeout, you can
33 // either ask it to block indefinitely or return immediately (WNOHANG).
34 // When a child process terminates a SIGCHLD signal is sent to the parent.
35 // Catching this signal would involve installing a signal handler which may
36 // affect other parts of the application and would be difficult to debug.
38 // Our strategy is to call waitpid() once up front to check if the process
39 // has already exited, otherwise to loop for |wait|, sleeping for
40 // at most 256 milliseconds each time using usleep() and then calling
41 // waitpid(). The amount of time we sleep starts out at 1 milliseconds, and
42 // we double it every 4 sleep cycles.
44 // usleep() is speced to exit if a signal is received for which a handler
45 // has been installed. This means that when a SIGCHLD is sent, it will exit
46 // depending on behavior external to this function.
48 // This function is used primarily for unit tests, if we want to use it in
49 // the application itself it would probably be best to examine other routes.
51 if (wait
== base::TimeDelta::Max()) {
52 return HANDLE_EINTR(waitpid(handle
, status
, 0)) > 0;
55 pid_t ret_pid
= HANDLE_EINTR(waitpid(handle
, status
, WNOHANG
));
56 static const int64 kMaxSleepInMicroseconds
= 1 << 18; // ~256 milliseconds.
57 int64 max_sleep_time_usecs
= 1 << 10; // ~1 milliseconds.
58 int64 double_sleep_time
= 0;
60 // If the process hasn't exited yet, then sleep and try again.
61 base::TimeTicks wakeup_time
= base::TimeTicks::Now() + wait
;
62 while (ret_pid
== 0) {
63 base::TimeTicks now
= base::TimeTicks::Now();
64 if (now
> wakeup_time
)
66 // Guaranteed to be non-negative!
67 int64 sleep_time_usecs
= (wakeup_time
- now
).InMicroseconds();
68 // Sleep for a bit while we wait for the process to finish.
69 if (sleep_time_usecs
> max_sleep_time_usecs
)
70 sleep_time_usecs
= max_sleep_time_usecs
;
72 // usleep() will return 0 and set errno to EINTR on receipt of a signal
74 usleep(sleep_time_usecs
);
75 ret_pid
= HANDLE_EINTR(waitpid(handle
, status
, WNOHANG
));
77 if ((max_sleep_time_usecs
< kMaxSleepInMicroseconds
) &&
78 (double_sleep_time
++ % 4 == 0)) {
79 max_sleep_time_usecs
*= 2;
86 #if defined(OS_MACOSX)
87 // Using kqueue on Mac so that we can wait on non-child processes.
88 // We can't use kqueues on child processes because we need to reap
89 // our own children using wait.
90 static bool WaitForSingleNonChildProcess(base::ProcessHandle handle
,
91 base::TimeDelta wait
) {
93 DCHECK_GT(wait
, base::TimeDelta());
95 base::ScopedFD
kq(kqueue());
97 DPLOG(ERROR
) << "kqueue";
101 struct kevent change
= {0};
102 EV_SET(&change
, handle
, EVFILT_PROC
, EV_ADD
, NOTE_EXIT
, 0, NULL
);
103 int result
= HANDLE_EINTR(kevent(kq
.get(), &change
, 1, NULL
, 0, NULL
));
105 if (errno
== ESRCH
) {
106 // If the process wasn't found, it must be dead.
110 DPLOG(ERROR
) << "kevent (setup " << handle
<< ")";
114 // Keep track of the elapsed time to be able to restart kevent if it's
116 bool wait_forever
= (wait
== base::TimeDelta::Max());
117 base::TimeDelta remaining_delta
;
118 base::TimeTicks deadline
;
120 remaining_delta
= wait
;
121 deadline
= base::TimeTicks::Now() + remaining_delta
;
125 struct kevent event
= {0};
127 while (wait_forever
|| remaining_delta
> base::TimeDelta()) {
128 struct timespec remaining_timespec
;
129 struct timespec
* remaining_timespec_ptr
;
131 remaining_timespec_ptr
= NULL
;
133 remaining_timespec
= remaining_delta
.ToTimeSpec();
134 remaining_timespec_ptr
= &remaining_timespec
;
137 result
= kevent(kq
.get(), NULL
, 0, &event
, 1, remaining_timespec_ptr
);
139 if (result
== -1 && errno
== EINTR
) {
141 remaining_delta
= deadline
- base::TimeTicks::Now();
150 DPLOG(ERROR
) << "kevent (wait " << handle
<< ")";
152 } else if (result
> 1) {
153 DLOG(ERROR
) << "kevent (wait " << handle
<< "): unexpected result "
156 } else if (result
== 0) {
161 DCHECK_EQ(result
, 1);
163 if (event
.filter
!= EVFILT_PROC
||
164 (event
.fflags
& NOTE_EXIT
) == 0 ||
165 event
.ident
!= static_cast<uintptr_t>(handle
)) {
166 DLOG(ERROR
) << "kevent (wait " << handle
167 << "): unexpected event: filter=" << event
.filter
168 << ", fflags=" << event
.fflags
169 << ", ident=" << event
.ident
;
177 bool WaitForExitWithTimeoutImpl(base::ProcessHandle handle
,
179 base::TimeDelta timeout
) {
180 base::ProcessHandle parent_pid
= base::GetParentProcessId(handle
);
181 base::ProcessHandle our_pid
= base::GetCurrentProcessHandle();
182 if (parent_pid
!= our_pid
) {
183 #if defined(OS_MACOSX)
184 // On Mac we can wait on non child processes.
185 return WaitForSingleNonChildProcess(handle
, timeout
);
187 // Currently on Linux we can't handle non child processes.
193 if (!WaitpidWithTimeout(handle
, &status
, timeout
))
195 if (WIFSIGNALED(status
)) {
200 if (WIFEXITED(status
)) {
202 *exit_code
= WEXITSTATUS(status
);
207 #endif // !defined(OS_NACL_NONSFI)
213 Process::Process(ProcessHandle handle
) : process_(handle
) {
216 Process::~Process() {
219 Process::Process(RValue other
)
220 : process_(other
.object
->process_
) {
221 other
.object
->Close();
224 Process
& Process::operator=(RValue other
) {
225 if (this != other
.object
) {
226 process_
= other
.object
->process_
;
227 other
.object
->Close();
233 Process
Process::Current() {
234 return Process(GetCurrentProcessHandle());
238 Process
Process::Open(ProcessId pid
) {
239 if (pid
== GetCurrentProcId())
242 // On POSIX process handles are the same as PIDs.
247 Process
Process::OpenWithExtraPrivileges(ProcessId pid
) {
248 // On POSIX there are no privileges to set.
253 Process
Process::DeprecatedGetProcessFromHandle(ProcessHandle handle
) {
254 DCHECK_NE(handle
, GetCurrentProcessHandle());
255 return Process(handle
);
258 #if !defined(OS_LINUX) && !defined(OS_MACOSX)
260 bool Process::CanBackgroundProcesses() {
263 #endif // !defined(OS_LINUX) && !defined(OS_MACOSX)
265 bool Process::IsValid() const {
266 return process_
!= kNullProcessHandle
;
269 ProcessHandle
Process::Handle() const {
273 Process
Process::Duplicate() const {
277 return Process(process_
);
280 ProcessId
Process::Pid() const {
282 return GetProcId(process_
);
285 bool Process::is_current() const {
286 return process_
== GetCurrentProcessHandle();
289 void Process::Close() {
290 process_
= kNullProcessHandle
;
291 // if the process wasn't terminated (so we waited) or the state
292 // wasn't already collected w/ a wait from process_utils, we're gonna
293 // end up w/ a zombie when it does finally exit.
296 #if !defined(OS_NACL_NONSFI)
297 bool Process::Terminate(int exit_code
, bool wait
) const {
298 // exit_code isn't supportable.
300 CHECK_GT(process_
, 0);
302 bool result
= kill(process_
, SIGTERM
) == 0;
303 if (result
&& wait
) {
306 if (RunningOnValgrind()) {
307 // Wait for some extra time when running under Valgrind since the child
308 // processes may take some time doing leak checking.
312 unsigned sleep_ms
= 4;
314 // The process may not end immediately due to pending I/O
316 while (tries
-- > 0) {
317 pid_t pid
= HANDLE_EINTR(waitpid(process_
, NULL
, WNOHANG
));
318 if (pid
== process_
) {
323 if (errno
== ECHILD
) {
324 // The wait may fail with ECHILD if another process also waited for
325 // the same pid, causing the process state to get cleaned up.
329 DPLOG(ERROR
) << "Error waiting for process " << process_
;
332 usleep(sleep_ms
* 1000);
333 const unsigned kMaxSleepMs
= 1000;
334 if (sleep_ms
< kMaxSleepMs
)
338 // If we're waiting and the child hasn't died by now, force it
341 result
= kill(process_
, SIGKILL
) == 0;
345 DPLOG(ERROR
) << "Unable to terminate process " << process_
;
349 #endif // !defined(OS_NACL_NONSFI)
351 bool Process::WaitForExit(int* exit_code
) {
352 return WaitForExitWithTimeout(TimeDelta::Max(), exit_code
);
355 bool Process::WaitForExitWithTimeout(TimeDelta timeout
, int* exit_code
) {
356 return WaitForExitWithTimeoutImpl(Handle(), exit_code
, timeout
);
359 #if !defined(OS_LINUX) && !defined(OS_MACOSX)
360 bool Process::IsProcessBackgrounded() const {
361 // See SetProcessBackgrounded().
366 bool Process::SetProcessBackgrounded(bool value
) {
367 // Not implemented for POSIX systems other than Mac and Linux. With POSIX, if
368 // we were to lower the process priority we wouldn't be able to raise it back
369 // to its initial priority.
373 #endif // !defined(OS_LINUX) && !defined(OS_MACOSX)
375 int Process::GetPriority() const {
377 return getpriority(PRIO_PROCESS
, process_
);