blob: 453316d910c27ff30c96ac2f09a859259b689aa6 [file] [log] [blame]
[email protected]3d5617e2008-08-27 14:36:191// Copyright (c) 2006-2008 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.
4
[email protected]05d4b0a2009-01-29 17:51:515#include <dirent.h>
[email protected]c7856632009-01-13 17:38:496#include <errno.h>
[email protected]05d4b0a2009-01-29 17:51:517#include <fcntl.h>
[email protected]8cf7cebd2009-01-05 19:53:308#include <signal.h>
[email protected]05d4b0a2009-01-29 17:51:519#include <stdlib.h>
[email protected]0d83c732008-12-02 16:50:4710#include <sys/resource.h>
11#include <sys/time.h>
[email protected]3d5617e2008-08-27 14:36:1912#include <sys/types.h>
[email protected]43bc28322008-12-05 01:57:2113#include <sys/wait.h>
[email protected]3d5617e2008-08-27 14:36:1914#include <unistd.h>
[email protected]05d4b0a2009-01-29 17:51:5115
[email protected]fa3097a6a52008-12-17 22:41:5016#include <limits>
[email protected]3d5617e2008-08-27 14:36:1917
18#include "base/basictypes.h"
[email protected]0d83c732008-12-02 16:50:4719#include "base/logging.h"
[email protected]962dd312009-02-05 21:44:1320#include "base/platform_thread.h"
[email protected]05d4b0a2009-01-29 17:51:5121#include "base/process_util.h"
[email protected]0b100bc8b2008-10-14 20:49:1622#include "base/sys_info.h"
[email protected]43bc28322008-12-05 01:57:2123#include "base/time.h"
[email protected]3d5617e2008-08-27 14:36:1924
[email protected]0d83c732008-12-02 16:50:4725const int kMicrosecondsPerSecond = 1000000;
26
[email protected]aa660752008-11-14 03:39:4627namespace base {
[email protected]3d5617e2008-08-27 14:36:1928
29int GetCurrentProcId() {
30 return getpid();
31}
32
[email protected]113ab132008-09-18 20:42:5533ProcessHandle GetCurrentProcessHandle() {
34 return GetCurrentProcId();
35}
36
[email protected]5986ed22009-02-06 00:19:1737ProcessHandle OpenProcessHandle(int pid) {
38 // On Posix platforms, process handles are the same as PIDs, so we
39 // don't need to do anything.
40 return pid;
41}
42
43void CloseProcessHandle(ProcessHandle process) {
44 // See OpenProcessHandle, nothing to do.
45 return;
46}
47
[email protected]3d5617e2008-08-27 14:36:1948int GetProcId(ProcessHandle process) {
[email protected]fadb8ea2008-08-27 15:36:3749 return process;
[email protected]3d5617e2008-08-27 14:36:1950}
[email protected]fadb8ea2008-08-27 15:36:3751
[email protected]8cf7cebd2009-01-05 19:53:3052// Attempts to kill the process identified by the given process
53// entry structure. Ignores specified exit_code; posix can't force that.
54// Returns true if this is successful, false otherwise.
[email protected]cd4fd152009-02-09 19:28:4155bool KillProcess(ProcessHandle process_id, int exit_code, bool wait) {
[email protected]8cf7cebd2009-01-05 19:53:3056 bool result = false;
57
58 int status = kill(process_id, SIGTERM);
59 if (!status && wait) {
60 int tries = 60;
61 // The process may not end immediately due to pending I/O
62 while (tries-- > 0) {
63 int pid = waitpid(process_id, &status, WNOHANG);
64 if (pid == process_id) {
65 result = true;
66 break;
67 }
68 sleep(1);
69 }
70 }
71 if (!result)
72 DLOG(ERROR) << "Unable to terminate process.";
73 return result;
74}
75
[email protected]05d4b0a2009-01-29 17:51:5176// A class to handle auto-closing of DIR*'s.
77class ScopedDIRClose {
78 public:
79 inline void operator()(DIR* x) const {
80 if (x) {
81 closedir(x);
82 }
83 }
84};
85typedef scoped_ptr_malloc<DIR, ScopedDIRClose> ScopedDIR;
86
87// Sets all file descriptors to close on exec except for stdin, stdout
88// and stderr.
89void SetAllFDsToCloseOnExec() {
90#if defined(OS_LINUX)
91 const char fd_dir[] = "/proc/self/fd";
92#elif defined(OS_MACOSX)
93 const char fd_dir[] = "/dev/fd";
94#endif
95 ScopedDIR dir_closer(opendir(fd_dir));
96 DIR *dir = dir_closer.get();
97 if (NULL == dir) {
98 DLOG(ERROR) << "Unable to open " << fd_dir;
99 return;
[email protected]fa3097a6a52008-12-17 22:41:50100 }
101
[email protected]05d4b0a2009-01-29 17:51:51102 struct dirent *ent;
103 while ((ent = readdir(dir))) {
104 // Skip . and .. entries.
105 if (ent->d_name[0] == '.')
106 continue;
107 int i = atoi(ent->d_name);
108 // We don't close stdin, stdout or stderr.
109 if (i <= STDERR_FILENO)
110 continue;
[email protected]fa3097a6a52008-12-17 22:41:50111
[email protected]05d4b0a2009-01-29 17:51:51112 int flags = fcntl(i, F_GETFD);
113 if ((flags == -1) || (fcntl(i, F_SETFD, flags | FD_CLOEXEC) == -1)) {
114 DLOG(ERROR) << "fcntl failure.";
115 }
116 }
[email protected]fa3097a6a52008-12-17 22:41:50117}
118
[email protected]0b100bc8b2008-10-14 20:49:16119ProcessMetrics::ProcessMetrics(ProcessHandle process) : process_(process),
120 last_time_(0),
121 last_system_time_(0) {
122 processor_count_ = base::SysInfo::NumberOfProcessors();
123}
124
125// static
126ProcessMetrics* ProcessMetrics::CreateProcessMetrics(ProcessHandle process) {
127 return new ProcessMetrics(process);
128}
129
130ProcessMetrics::~ProcessMetrics() { }
131
[email protected]c9d40872008-09-24 12:58:37132void EnableTerminationOnHeapCorruption() {
133 // On POSIX, there nothing to do AFAIK.
134}
135
[email protected]3d5617e2008-08-27 14:36:19136void RaiseProcessToHighPriority() {
137 // On POSIX, we don't actually do anything here. We could try to nice() or
138 // setpriority() or sched_getscheduler, but these all require extra rights.
139}
140
[email protected]9c19aa12009-01-21 13:50:11141bool DidProcessCrash(ProcessHandle handle) {
142 int status;
143 if (waitpid(handle, &status, WNOHANG)) {
144 // I feel like dancing!
145 return false;
146 }
147
148 if (WIFSIGNALED(status)) {
149 switch(WTERMSIG(status)) {
150 case SIGSEGV:
151 case SIGILL:
152 case SIGABRT:
153 case SIGFPE:
154 return true;
155 default:
156 return false;
157 }
158 }
159
160 if (WIFEXITED(status))
161 return WEXITSTATUS(status) != 0;
162
163 return false;
164}
165
[email protected]c7856632009-01-13 17:38:49166bool WaitForExitCode(ProcessHandle handle, int* exit_code) {
167 int status;
168 while (waitpid(handle, &status, 0) == -1) {
169 if (errno != EINTR) {
170 NOTREACHED();
171 return false;
172 }
173 }
174
175 if (WIFEXITED(status)) {
176 *exit_code = WEXITSTATUS(status);
177 return true;
178 }
179
180 // If it didn't exit cleanly, it must have been signaled.
181 DCHECK(WIFSIGNALED(status));
182 return false;
183}
184
[email protected]076bf0b62009-03-04 20:57:58185namespace {
186
187int WaitpidWithTimeout(ProcessHandle handle, int wait_milliseconds) {
[email protected]c1443912008-12-08 19:00:53188 // This POSIX version of this function only guarantees that we wait no less
189 // than |wait_milliseconds| for the proces to exit. The child process may
190 // exit sometime before the timeout has ended but we may still block for
191 // up to 0.25 seconds after the fact.
192 //
193 // waitpid() has no direct support on POSIX for specifying a timeout, you can
194 // either ask it to block indefinitely or return immediately (WNOHANG).
195 // When a child process terminates a SIGCHLD signal is sent to the parent.
196 // Catching this signal would involve installing a signal handler which may
197 // affect other parts of the application and would be difficult to debug.
198 //
199 // Our strategy is to call waitpid() once up front to check if the process
200 // has already exited, otherwise to loop for wait_milliseconds, sleeping for
201 // at most 0.25 secs each time using usleep() and then calling waitpid().
202 //
203 // usleep() is speced to exit if a signal is received for which a handler
204 // has been installed. This means that when a SIGCHLD is sent, it will exit
205 // depending on behavior external to this function.
206 //
207 // This function is used primarilly for unit tests, if we want to use it in
208 // the application itself it would probably be best to examine other routes.
209 int status = -1;
[email protected]43bc28322008-12-05 01:57:21210 pid_t ret_pid = waitpid(handle, &status, WNOHANG);
[email protected]c1443912008-12-08 19:00:53211 static const int64 kQuarterSecondInMicroseconds = kMicrosecondsPerSecond/4;
[email protected]43bc28322008-12-05 01:57:21212
213 // If the process hasn't exited yet, then sleep and try again.
214 Time wakeup_time = Time::Now() + TimeDelta::FromMilliseconds(
215 wait_milliseconds);
[email protected]c1443912008-12-08 19:00:53216 while (ret_pid == 0) {
217 Time now = Time::Now();
218 if (now > wakeup_time)
219 break;
220 // Guaranteed to be non-negative!
221 int64 sleep_time_usecs = (wakeup_time - now).InMicroseconds();
222 // Don't sleep for more than 0.25 secs at a time.
223 if (sleep_time_usecs > kQuarterSecondInMicroseconds) {
224 sleep_time_usecs = kQuarterSecondInMicroseconds;
225 }
226
227 // usleep() will return 0 and set errno to EINTR on receipt of a signal
228 // such as SIGCHLD.
229 usleep(sleep_time_usecs);
[email protected]43bc28322008-12-05 01:57:21230 ret_pid = waitpid(handle, &status, WNOHANG);
231 }
232
[email protected]076bf0b62009-03-04 20:57:58233 return status;
234}
235
236} // namespace
237
238bool WaitForSingleProcess(ProcessHandle handle, int wait_milliseconds) {
239 int status = WaitpidWithTimeout(handle, wait_milliseconds);
240 if (status != -1)
[email protected]c1443912008-12-08 19:00:53241 return WIFEXITED(status);
[email protected]076bf0b62009-03-04 20:57:58242 else
[email protected]c1443912008-12-08 19:00:53243 return false;
[email protected]076bf0b62009-03-04 20:57:58244}
245
246bool CrashAwareSleep(ProcessHandle handle, int wait_milliseconds) {
247 int status = WaitpidWithTimeout(handle, wait_milliseconds);
248 if (status != -1)
249 return !(WIFEXITED(status) || WIFSIGNALED(status));
250 else
251 return false;
[email protected]43bc28322008-12-05 01:57:21252}
253
[email protected]0d83c732008-12-02 16:50:47254namespace {
255
256int64 TimeValToMicroseconds(const struct timeval& tv) {
257 return tv.tv_sec * kMicrosecondsPerSecond + tv.tv_usec;
258}
259
260}
261
262int ProcessMetrics::GetCPUUsage() {
[email protected]0d83c732008-12-02 16:50:47263 struct timeval now;
264 struct rusage usage;
265
[email protected]cfc36562008-12-02 20:46:34266 int retval = gettimeofday(&now, NULL);
[email protected]0d83c732008-12-02 16:50:47267 if (retval)
268 return 0;
269 retval = getrusage(RUSAGE_SELF, &usage);
270 if (retval)
271 return 0;
[email protected]43bc28322008-12-05 01:57:21272
[email protected]0d83c732008-12-02 16:50:47273 int64 system_time = (TimeValToMicroseconds(usage.ru_stime) +
274 TimeValToMicroseconds(usage.ru_utime)) /
275 processor_count_;
276 int64 time = TimeValToMicroseconds(now);
277
278 if ((last_system_time_ == 0) || (last_time_ == 0)) {
279 // First call, just set the last values.
280 last_system_time_ = system_time;
281 last_time_ = time;
282 return 0;
283 }
284
285 int64 system_time_delta = system_time - last_system_time_;
286 int64 time_delta = time - last_time_;
287 DCHECK(time_delta != 0);
288 if (time_delta == 0)
289 return 0;
290
291 // We add time_delta / 2 so the result is rounded.
292 int cpu = static_cast<int>((system_time_delta * 100 + time_delta / 2) /
293 time_delta);
294
295 last_system_time_ = system_time;
296 last_time_ = time;
297
298 return cpu;
299}
300
[email protected]962dd312009-02-05 21:44:13301int GetProcessCount(const std::wstring& executable_name,
302 const ProcessFilter* filter) {
303 int count = 0;
304
305 NamedProcessIterator iter(executable_name, filter);
306 while (iter.NextProcessEntry())
307 ++count;
308 return count;
309}
310
311bool KillProcesses(const std::wstring& executable_name, int exit_code,
312 const ProcessFilter* filter) {
313 bool result = true;
314 const ProcessEntry* entry;
315
316 NamedProcessIterator iter(executable_name, filter);
317 while ((entry = iter.NextProcessEntry()) != NULL)
318 result = KillProcess((*entry).pid, exit_code, true) && result;
319
320 return result;
321}
322
323bool WaitForProcessesToExit(const std::wstring& executable_name,
324 int wait_milliseconds,
325 const ProcessFilter* filter) {
326 bool result = false;
327
328 // TODO(port): This is inefficient, but works if there are multiple procs.
329 // TODO(port): use waitpid to avoid leaving zombies around
330
331 base::Time end_time = base::Time::Now() +
332 base::TimeDelta::FromMilliseconds(wait_milliseconds);
333 do {
334 NamedProcessIterator iter(executable_name, filter);
335 if (!iter.NextProcessEntry()) {
336 result = true;
337 break;
338 }
339 PlatformThread::Sleep(100);
340 } while ((base::Time::Now() - end_time) > base::TimeDelta());
341
342 return result;
343}
344
345bool CleanupProcesses(const std::wstring& executable_name,
346 int wait_milliseconds,
347 int exit_code,
348 const ProcessFilter* filter) {
349 bool exited_cleanly =
350 WaitForProcessesToExit(executable_name, wait_milliseconds,
351 filter);
352 if (!exited_cleanly)
353 KillProcesses(executable_name, exit_code, filter);
354 return exited_cleanly;
355}
356
[email protected]aa660752008-11-14 03:39:46357} // namespace base