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