Line data Source code
1 : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 : /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 : // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
4 : // Use of this source code is governed by a BSD-style license that can be
5 : // found in the LICENSE file.
6 :
7 : #include <dirent.h>
8 : #include <errno.h>
9 : #include <fcntl.h>
10 : #include <signal.h>
11 : #include <stdlib.h>
12 : #include <sys/resource.h>
13 : #include <sys/time.h>
14 : #include <sys/types.h>
15 : #include <sys/wait.h>
16 : #include <unistd.h>
17 :
18 : #include <limits>
19 : #include <set>
20 :
21 : #include "base/basictypes.h"
22 : #include "base/eintr_wrapper.h"
23 : #include "base/logging.h"
24 : #include "base/platform_thread.h"
25 : #include "base/process_util.h"
26 : #include "base/sys_info.h"
27 : #include "base/time.h"
28 : #include "base/waitable_event.h"
29 : #include "base/dir_reader_posix.h"
30 :
31 : #include "mozilla/UniquePtr.h"
32 :
33 : const int kMicrosecondsPerSecond = 1000000;
34 :
35 : namespace base {
36 :
37 198 : ProcessId GetCurrentProcId() {
38 198 : return getpid();
39 : }
40 :
41 2 : ProcessHandle GetCurrentProcessHandle() {
42 2 : return GetCurrentProcId();
43 : }
44 :
45 2 : bool OpenProcessHandle(ProcessId pid, ProcessHandle* handle) {
46 : // On Posix platforms, process handles are the same as PIDs, so we
47 : // don't need to do anything.
48 2 : *handle = pid;
49 2 : return true;
50 : }
51 :
52 2 : bool OpenPrivilegedProcessHandle(ProcessId pid, ProcessHandle* handle) {
53 : // On POSIX permissions are checked for each operation on process,
54 : // not when opening a "handle".
55 2 : return OpenProcessHandle(pid, handle);
56 : }
57 :
58 0 : void CloseProcessHandle(ProcessHandle process) {
59 : // See OpenProcessHandle, nothing to do.
60 0 : return;
61 : }
62 :
63 8 : ProcessId GetProcId(ProcessHandle process) {
64 8 : return process;
65 : }
66 :
67 : // Attempts to kill the process identified by the given process
68 : // entry structure. Ignores specified exit_code; posix can't force that.
69 : // Returns true if this is successful, false otherwise.
70 0 : bool KillProcess(ProcessHandle process_id, int exit_code, bool wait) {
71 0 : bool result = kill(process_id, SIGTERM) == 0;
72 :
73 0 : if (!result && (errno == ESRCH)) {
74 0 : result = true;
75 0 : wait = false;
76 : }
77 :
78 0 : if (result && wait) {
79 0 : int tries = 60;
80 0 : bool exited = false;
81 : // The process may not end immediately due to pending I/O
82 0 : while (tries-- > 0) {
83 0 : int pid = HANDLE_EINTR(waitpid(process_id, NULL, WNOHANG));
84 0 : if (pid == process_id) {
85 0 : exited = true;
86 0 : break;
87 0 : } else if (errno == ECHILD) {
88 0 : exited = true;
89 0 : break;
90 : }
91 :
92 0 : sleep(1);
93 : }
94 :
95 0 : if (!exited) {
96 0 : result = kill(process_id, SIGKILL) == 0;
97 : }
98 : }
99 :
100 0 : if (!result)
101 0 : DLOG(ERROR) << "Unable to terminate process.";
102 :
103 0 : return result;
104 : }
105 :
106 : #ifdef ANDROID
107 : typedef unsigned long int rlim_t;
108 : #endif
109 :
110 : // A class to handle auto-closing of DIR*'s.
111 : class ScopedDIRClose {
112 : public:
113 0 : inline void operator()(DIR* x) const {
114 0 : if (x) {
115 0 : closedir(x);
116 : }
117 0 : }
118 : };
119 : typedef mozilla::UniquePtr<DIR, ScopedDIRClose> ScopedDIR;
120 :
121 :
122 0 : void CloseSuperfluousFds(const base::InjectiveMultimap& saved_mapping) {
123 : // DANGER: no calls to malloc are allowed from now on:
124 : // http://crbug.com/36678
125 : #if defined(ANDROID)
126 : static const rlim_t kSystemDefaultMaxFds = 1024;
127 : static const char kFDDir[] = "/proc/self/fd";
128 : #elif defined(OS_LINUX) || defined(OS_SOLARIS)
129 : static const rlim_t kSystemDefaultMaxFds = 8192;
130 : static const char kFDDir[] = "/proc/self/fd";
131 : #elif defined(OS_MACOSX)
132 : static const rlim_t kSystemDefaultMaxFds = 256;
133 : static const char kFDDir[] = "/dev/fd";
134 : #elif defined(OS_BSD)
135 : // the getrlimit below should never fail, so whatever ..
136 : static const rlim_t kSystemDefaultMaxFds = 1024;
137 : // at least /dev/fd will exist
138 : static const char kFDDir[] = "/dev/fd";
139 : #endif
140 :
141 : // Get the maximum number of FDs possible.
142 : struct rlimit nofile;
143 : rlim_t max_fds;
144 0 : if (getrlimit(RLIMIT_NOFILE, &nofile)) {
145 : // getrlimit failed. Take a best guess.
146 0 : max_fds = kSystemDefaultMaxFds;
147 0 : DLOG(ERROR) << "getrlimit(RLIMIT_NOFILE) failed: " << errno;
148 : } else {
149 0 : max_fds = nofile.rlim_cur;
150 : }
151 :
152 0 : if (max_fds > INT_MAX)
153 0 : max_fds = INT_MAX;
154 :
155 0 : DirReaderPosix fd_dir(kFDDir);
156 :
157 0 : if (!fd_dir.IsValid()) {
158 : // Fallback case: Try every possible fd.
159 0 : for (rlim_t i = 0; i < max_fds; ++i) {
160 0 : const int fd = static_cast<int>(i);
161 0 : if (fd == STDIN_FILENO || fd == STDOUT_FILENO || fd == STDERR_FILENO)
162 0 : continue;
163 0 : InjectiveMultimap::const_iterator j;
164 0 : for (j = saved_mapping.begin(); j != saved_mapping.end(); j++) {
165 0 : if (fd == j->dest)
166 0 : break;
167 : }
168 0 : if (j != saved_mapping.end())
169 0 : continue;
170 :
171 : // Since we're just trying to close anything we can find,
172 : // ignore any error return values of close().
173 0 : HANDLE_EINTR(close(fd));
174 : }
175 0 : return;
176 : }
177 :
178 0 : const int dir_fd = fd_dir.fd();
179 :
180 0 : for ( ; fd_dir.Next(); ) {
181 : // Skip . and .. entries.
182 0 : if (fd_dir.name()[0] == '.')
183 0 : continue;
184 :
185 : char *endptr;
186 0 : errno = 0;
187 0 : const long int fd = strtol(fd_dir.name(), &endptr, 10);
188 0 : if (fd_dir.name()[0] == 0 || *endptr || fd < 0 || errno)
189 0 : continue;
190 0 : if (fd == STDIN_FILENO || fd == STDOUT_FILENO || fd == STDERR_FILENO)
191 0 : continue;
192 0 : InjectiveMultimap::const_iterator i;
193 0 : for (i = saved_mapping.begin(); i != saved_mapping.end(); i++) {
194 0 : if (fd == i->dest)
195 0 : break;
196 : }
197 0 : if (i != saved_mapping.end())
198 0 : continue;
199 0 : if (fd == dir_fd)
200 0 : continue;
201 :
202 : // When running under Valgrind, Valgrind opens several FDs for its
203 : // own use and will complain if we try to close them. All of
204 : // these FDs are >= |max_fds|, so we can check against that here
205 : // before closing. See https://bugs.kde.org/show_bug.cgi?id=191758
206 0 : if (fd < static_cast<int>(max_fds)) {
207 0 : int ret = HANDLE_EINTR(close(fd));
208 0 : if (ret != 0) {
209 0 : DLOG(ERROR) << "Problem closing fd";
210 : }
211 : }
212 : }
213 : }
214 :
215 : // Sets all file descriptors to close on exec except for stdin, stdout
216 : // and stderr.
217 : // TODO(agl): Remove this function. It's fundamentally broken for multithreaded
218 : // apps.
219 0 : void SetAllFDsToCloseOnExec() {
220 : #if defined(OS_LINUX) || defined(OS_SOLARIS)
221 0 : const char fd_dir[] = "/proc/self/fd";
222 : #elif defined(OS_MACOSX) || defined(OS_BSD)
223 : const char fd_dir[] = "/dev/fd";
224 : #endif
225 0 : ScopedDIR dir_closer(opendir(fd_dir));
226 0 : DIR *dir = dir_closer.get();
227 0 : if (NULL == dir) {
228 0 : DLOG(ERROR) << "Unable to open " << fd_dir;
229 0 : return;
230 : }
231 :
232 : struct dirent *ent;
233 0 : while ((ent = readdir(dir))) {
234 : // Skip . and .. entries.
235 0 : if (ent->d_name[0] == '.')
236 0 : continue;
237 0 : int i = atoi(ent->d_name);
238 : // We don't close stdin, stdout or stderr.
239 0 : if (i <= STDERR_FILENO)
240 0 : continue;
241 :
242 0 : int flags = fcntl(i, F_GETFD);
243 0 : if ((flags == -1) || (fcntl(i, F_SETFD, flags | FD_CLOEXEC) == -1)) {
244 0 : DLOG(ERROR) << "fcntl failure.";
245 : }
246 : }
247 : }
248 :
249 0 : ProcessMetrics::ProcessMetrics(ProcessHandle process) : process_(process),
250 : last_time_(0),
251 0 : last_system_time_(0) {
252 0 : processor_count_ = base::SysInfo::NumberOfProcessors();
253 0 : }
254 :
255 : // static
256 0 : ProcessMetrics* ProcessMetrics::CreateProcessMetrics(ProcessHandle process) {
257 0 : return new ProcessMetrics(process);
258 : }
259 :
260 0 : ProcessMetrics::~ProcessMetrics() { }
261 :
262 0 : bool DidProcessCrash(bool* child_exited, ProcessHandle handle) {
263 : int status;
264 0 : const int result = HANDLE_EINTR(waitpid(handle, &status, WNOHANG));
265 0 : if (result == -1) {
266 : // This shouldn't happen, but sometimes it does. The error is
267 : // probably ECHILD and the reason is probably that a pid was
268 : // waited on again after a previous wait reclaimed its zombie.
269 : // (It could also occur if the process isn't a direct child, but
270 : // don't do that.) This is bad, because it risks interfering with
271 : // an unrelated child process if the pid is reused.
272 : //
273 : // So, lacking reliable information, we indicate that the process
274 : // is dead, in the hope that the caller will give up and stop
275 : // calling us. See also bug 943174 and bug 933680.
276 0 : CHROMIUM_LOG(ERROR) << "waitpid failed pid:" << handle << " errno:" << errno;
277 0 : if (child_exited)
278 0 : *child_exited = true;
279 0 : return false;
280 0 : } else if (result == 0) {
281 : // the child hasn't exited yet.
282 0 : if (child_exited)
283 0 : *child_exited = false;
284 0 : return false;
285 : }
286 :
287 0 : if (child_exited)
288 0 : *child_exited = true;
289 :
290 0 : if (WIFSIGNALED(status)) {
291 0 : switch(WTERMSIG(status)) {
292 : case SIGSYS:
293 : case SIGSEGV:
294 : case SIGILL:
295 : case SIGABRT:
296 : case SIGFPE:
297 0 : return true;
298 : default:
299 0 : return false;
300 : }
301 : }
302 :
303 0 : if (WIFEXITED(status))
304 0 : return WEXITSTATUS(status) != 0;
305 :
306 0 : return false;
307 : }
308 :
309 : namespace {
310 :
311 0 : int64_t TimeValToMicroseconds(const struct timeval& tv) {
312 0 : return tv.tv_sec * kMicrosecondsPerSecond + tv.tv_usec;
313 : }
314 :
315 : }
316 :
317 0 : int ProcessMetrics::GetCPUUsage() {
318 : struct timeval now;
319 : struct rusage usage;
320 :
321 0 : int retval = gettimeofday(&now, NULL);
322 0 : if (retval)
323 0 : return 0;
324 0 : retval = getrusage(RUSAGE_SELF, &usage);
325 0 : if (retval)
326 0 : return 0;
327 :
328 0 : int64_t system_time = (TimeValToMicroseconds(usage.ru_stime) +
329 0 : TimeValToMicroseconds(usage.ru_utime)) /
330 0 : processor_count_;
331 0 : int64_t time = TimeValToMicroseconds(now);
332 :
333 0 : if ((last_system_time_ == 0) || (last_time_ == 0)) {
334 : // First call, just set the last values.
335 0 : last_system_time_ = system_time;
336 0 : last_time_ = time;
337 0 : return 0;
338 : }
339 :
340 0 : int64_t system_time_delta = system_time - last_system_time_;
341 0 : int64_t time_delta = time - last_time_;
342 0 : DCHECK(time_delta != 0);
343 0 : if (time_delta == 0)
344 0 : return 0;
345 :
346 : // We add time_delta / 2 so the result is rounded.
347 0 : int cpu = static_cast<int>((system_time_delta * 100 + time_delta / 2) /
348 0 : time_delta);
349 :
350 0 : last_system_time_ = system_time;
351 0 : last_time_ = time;
352 :
353 0 : return cpu;
354 : }
355 :
356 : } // namespace base
|