Plugin Power Saver: Record PPS UMAs only for users with PPS enabled.
[chromium-blink-merge.git] / base / process / process_posix.cc
bloba083123b75fe2cbda0c34f18bf6e39fa3ad3b58c
1 // Copyright (c) 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>
8 #include <sys/wait.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"
15 #if defined(OS_MACOSX)
16 #include <sys/event.h>
17 #endif
19 namespace {
21 #if !defined(OS_NACL_NONSFI)
23 bool WaitpidWithTimeout(base::ProcessHandle handle,
24 int* status,
25 base::TimeDelta wait) {
26 // This POSIX version of this function only guarantees that we wait no less
27 // than |wait| for the process to exit. The child process may
28 // exit sometime before the timeout has ended but we may still block for up
29 // to 256 milliseconds after the fact.
31 // waitpid() has no direct support on POSIX for specifying a timeout, you can
32 // either ask it to block indefinitely or return immediately (WNOHANG).
33 // When a child process terminates a SIGCHLD signal is sent to the parent.
34 // Catching this signal would involve installing a signal handler which may
35 // affect other parts of the application and would be difficult to debug.
37 // Our strategy is to call waitpid() once up front to check if the process
38 // has already exited, otherwise to loop for |wait|, sleeping for
39 // at most 256 milliseconds each time using usleep() and then calling
40 // waitpid(). The amount of time we sleep starts out at 1 milliseconds, and
41 // we double it every 4 sleep cycles.
43 // usleep() is speced to exit if a signal is received for which a handler
44 // has been installed. This means that when a SIGCHLD is sent, it will exit
45 // depending on behavior external to this function.
47 // This function is used primarily for unit tests, if we want to use it in
48 // the application itself it would probably be best to examine other routes.
50 if (wait == base::TimeDelta::Max()) {
51 return HANDLE_EINTR(waitpid(handle, status, 0)) > 0;
54 pid_t ret_pid = HANDLE_EINTR(waitpid(handle, status, WNOHANG));
55 static const int64 kMaxSleepInMicroseconds = 1 << 18; // ~256 milliseconds.
56 int64 max_sleep_time_usecs = 1 << 10; // ~1 milliseconds.
57 int64 double_sleep_time = 0;
59 // If the process hasn't exited yet, then sleep and try again.
60 base::TimeTicks wakeup_time = base::TimeTicks::Now() + wait;
61 while (ret_pid == 0) {
62 base::TimeTicks now = base::TimeTicks::Now();
63 if (now > wakeup_time)
64 break;
65 // Guaranteed to be non-negative!
66 int64 sleep_time_usecs = (wakeup_time - now).InMicroseconds();
67 // Sleep for a bit while we wait for the process to finish.
68 if (sleep_time_usecs > max_sleep_time_usecs)
69 sleep_time_usecs = max_sleep_time_usecs;
71 // usleep() will return 0 and set errno to EINTR on receipt of a signal
72 // such as SIGCHLD.
73 usleep(sleep_time_usecs);
74 ret_pid = HANDLE_EINTR(waitpid(handle, status, WNOHANG));
76 if ((max_sleep_time_usecs < kMaxSleepInMicroseconds) &&
77 (double_sleep_time++ % 4 == 0)) {
78 max_sleep_time_usecs *= 2;
82 return ret_pid > 0;
85 #if defined(OS_MACOSX)
86 // Using kqueue on Mac so that we can wait on non-child processes.
87 // We can't use kqueues on child processes because we need to reap
88 // our own children using wait.
89 static bool WaitForSingleNonChildProcess(base::ProcessHandle handle,
90 base::TimeDelta wait) {
91 DCHECK_GT(handle, 0);
92 DCHECK_GT(wait, base::TimeDelta());
94 base::ScopedFD kq(kqueue());
95 if (!kq.is_valid()) {
96 DPLOG(ERROR) << "kqueue";
97 return false;
100 struct kevent change = {0};
101 EV_SET(&change, handle, EVFILT_PROC, EV_ADD, NOTE_EXIT, 0, NULL);
102 int result = HANDLE_EINTR(kevent(kq.get(), &change, 1, NULL, 0, NULL));
103 if (result == -1) {
104 if (errno == ESRCH) {
105 // If the process wasn't found, it must be dead.
106 return true;
109 DPLOG(ERROR) << "kevent (setup " << handle << ")";
110 return false;
113 // Keep track of the elapsed time to be able to restart kevent if it's
114 // interrupted.
115 bool wait_forever = (wait == base::TimeDelta::Max());
116 base::TimeDelta remaining_delta;
117 base::TimeTicks deadline;
118 if (!wait_forever) {
119 remaining_delta = wait;
120 deadline = base::TimeTicks::Now() + remaining_delta;
123 result = -1;
124 struct kevent event = {0};
126 while (wait_forever || remaining_delta > base::TimeDelta()) {
127 struct timespec remaining_timespec;
128 struct timespec* remaining_timespec_ptr;
129 if (wait_forever) {
130 remaining_timespec_ptr = NULL;
131 } else {
132 remaining_timespec = remaining_delta.ToTimeSpec();
133 remaining_timespec_ptr = &remaining_timespec;
136 result = kevent(kq.get(), NULL, 0, &event, 1, remaining_timespec_ptr);
138 if (result == -1 && errno == EINTR) {
139 if (!wait_forever) {
140 remaining_delta = deadline - base::TimeTicks::Now();
142 result = 0;
143 } else {
144 break;
148 if (result < 0) {
149 DPLOG(ERROR) << "kevent (wait " << handle << ")";
150 return false;
151 } else if (result > 1) {
152 DLOG(ERROR) << "kevent (wait " << handle << "): unexpected result "
153 << result;
154 return false;
155 } else if (result == 0) {
156 // Timed out.
157 return false;
160 DCHECK_EQ(result, 1);
162 if (event.filter != EVFILT_PROC ||
163 (event.fflags & NOTE_EXIT) == 0 ||
164 event.ident != static_cast<uintptr_t>(handle)) {
165 DLOG(ERROR) << "kevent (wait " << handle
166 << "): unexpected event: filter=" << event.filter
167 << ", fflags=" << event.fflags
168 << ", ident=" << event.ident;
169 return false;
172 return true;
174 #endif // OS_MACOSX
176 bool WaitForExitWithTimeoutImpl(base::ProcessHandle handle,
177 int* exit_code,
178 base::TimeDelta timeout) {
179 base::ProcessHandle parent_pid = base::GetParentProcessId(handle);
180 base::ProcessHandle our_pid = base::GetCurrentProcessHandle();
181 if (parent_pid != our_pid) {
182 #if defined(OS_MACOSX)
183 // On Mac we can wait on non child processes.
184 return WaitForSingleNonChildProcess(handle, timeout);
185 #else
186 // Currently on Linux we can't handle non child processes.
187 NOTIMPLEMENTED();
188 #endif // OS_MACOSX
191 int status;
192 if (!WaitpidWithTimeout(handle, &status, timeout))
193 return false;
194 if (WIFSIGNALED(status)) {
195 *exit_code = -1;
196 return true;
198 if (WIFEXITED(status)) {
199 *exit_code = WEXITSTATUS(status);
200 return true;
202 return false;
204 #endif // !defined(OS_NACL_NONSFI)
206 } // namespace
208 namespace base {
210 Process::Process(ProcessHandle handle) : process_(handle) {
213 Process::Process(RValue other)
214 : process_(other.object->process_) {
215 other.object->Close();
218 Process& Process::operator=(RValue other) {
219 if (this != other.object) {
220 process_ = other.object->process_;
221 other.object->Close();
223 return *this;
226 // static
227 Process Process::Current() {
228 return Process(GetCurrentProcessHandle());
231 // static
232 Process Process::Open(ProcessId pid) {
233 if (pid == GetCurrentProcId())
234 return Current();
236 // On POSIX process handles are the same as PIDs.
237 return Process(pid);
240 // static
241 Process Process::OpenWithExtraPrivileges(ProcessId pid) {
242 // On POSIX there are no privileges to set.
243 return Open(pid);
246 // static
247 Process Process::DeprecatedGetProcessFromHandle(ProcessHandle handle) {
248 DCHECK_NE(handle, GetCurrentProcessHandle());
249 return Process(handle);
252 #if !defined(OS_LINUX)
253 // static
254 bool Process::CanBackgroundProcesses() {
255 return false;
257 #endif // !defined(OS_LINUX)
259 bool Process::IsValid() const {
260 return process_ != kNullProcessHandle;
263 ProcessHandle Process::Handle() const {
264 return process_;
267 Process Process::Duplicate() const {
268 if (is_current())
269 return Current();
271 return Process(process_);
274 ProcessId Process::Pid() const {
275 DCHECK(IsValid());
276 return GetProcId(process_);
279 bool Process::is_current() const {
280 return process_ == GetCurrentProcessHandle();
283 void Process::Close() {
284 process_ = kNullProcessHandle;
285 // if the process wasn't terminated (so we waited) or the state
286 // wasn't already collected w/ a wait from process_utils, we're gonna
287 // end up w/ a zombie when it does finally exit.
290 bool Process::Terminate(int result_code, bool wait) const {
291 // result_code isn't supportable.
292 DCHECK(IsValid());
293 // We don't wait here. It's the responsibility of other code to reap the
294 // child.
295 // TODO(rvargas) crbug/417532: Move the implementation here.
296 return KillProcess(process_, result_code, wait);
299 bool Process::WaitForExit(int* exit_code) {
300 return WaitForExitWithTimeout(TimeDelta::Max(), exit_code);
303 bool Process::WaitForExitWithTimeout(TimeDelta timeout, int* exit_code) {
304 return WaitForExitWithTimeoutImpl(Handle(), exit_code, timeout);
307 #if !defined(OS_LINUX)
308 bool Process::IsProcessBackgrounded() const {
309 // See SetProcessBackgrounded().
310 DCHECK(IsValid());
311 return false;
314 bool Process::SetProcessBackgrounded(bool value) {
315 // POSIX only allows lowering the priority of a process, so if we
316 // were to lower it we wouldn't be able to raise it back to its initial
317 // priority.
318 DCHECK(IsValid());
319 return false;
321 #endif // !defined(OS_LINUX)
323 int Process::GetPriority() const {
324 DCHECK(IsValid());
325 return getpriority(PRIO_PROCESS, process_);
328 } // namespace base