OLD | NEW |
1 // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. | 1 // 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include <dirent.h> | 5 #include <dirent.h> |
6 #include <errno.h> | 6 #include <errno.h> |
7 #include <fcntl.h> | 7 #include <fcntl.h> |
8 #include <signal.h> | 8 #include <signal.h> |
9 #include <stdlib.h> | 9 #include <stdlib.h> |
10 #include <sys/resource.h> | 10 #include <sys/resource.h> |
11 #include <sys/time.h> | 11 #include <sys/time.h> |
12 #include <sys/types.h> | 12 #include <sys/types.h> |
13 #include <sys/wait.h> | 13 #include <sys/wait.h> |
14 #include <unistd.h> | 14 #include <unistd.h> |
15 | 15 |
16 #include <limits> | 16 #include <limits> |
17 #include <set> | 17 #include <set> |
18 | 18 |
19 #include "base/basictypes.h" | 19 #include "base/basictypes.h" |
| 20 #include "base/eintr_wrappers.h" |
20 #include "base/logging.h" | 21 #include "base/logging.h" |
21 #include "base/platform_thread.h" | 22 #include "base/platform_thread.h" |
22 #include "base/process_util.h" | 23 #include "base/process_util.h" |
23 #include "base/scoped_ptr.h" | 24 #include "base/scoped_ptr.h" |
24 #include "base/sys_info.h" | 25 #include "base/sys_info.h" |
25 #include "base/time.h" | 26 #include "base/time.h" |
26 #include "base/waitable_event.h" | 27 #include "base/waitable_event.h" |
27 | 28 |
28 const int kMicrosecondsPerSecond = 1000000; | 29 const int kMicrosecondsPerSecond = 1000000; |
29 | 30 |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
62 // Attempts to kill the process identified by the given process | 63 // Attempts to kill the process identified by the given process |
63 // entry structure. Ignores specified exit_code; posix can't force that. | 64 // entry structure. Ignores specified exit_code; posix can't force that. |
64 // Returns true if this is successful, false otherwise. | 65 // Returns true if this is successful, false otherwise. |
65 bool KillProcess(ProcessHandle process_id, int exit_code, bool wait) { | 66 bool KillProcess(ProcessHandle process_id, int exit_code, bool wait) { |
66 bool result = kill(process_id, SIGTERM) == 0; | 67 bool result = kill(process_id, SIGTERM) == 0; |
67 | 68 |
68 if (result && wait) { | 69 if (result && wait) { |
69 int tries = 60; | 70 int tries = 60; |
70 // The process may not end immediately due to pending I/O | 71 // The process may not end immediately due to pending I/O |
71 while (tries-- > 0) { | 72 while (tries-- > 0) { |
72 int pid = waitpid(process_id, NULL, WNOHANG); | 73 int pid = HANDLE_EINTR(waitpid(process_id, NULL, WNOHANG)); |
73 if (pid == process_id) | 74 if (pid == process_id) |
74 break; | 75 break; |
75 | 76 |
76 sleep(1); | 77 sleep(1); |
77 } | 78 } |
78 | 79 |
79 result = kill(process_id, SIGKILL) == 0; | 80 result = kill(process_id, SIGKILL) == 0; |
80 } | 81 } |
81 | 82 |
82 if (!result) | 83 if (!result) |
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
132 } | 133 } |
133 | 134 |
134 if (num_fds > INT_MAX) | 135 if (num_fds > INT_MAX) |
135 num_fds = INT_MAX; | 136 num_fds = INT_MAX; |
136 | 137 |
137 for (rlim_t i = 0; i < num_fds; ++i) { | 138 for (rlim_t i = 0; i < num_fds; ++i) { |
138 const int fd = static_cast<int>(i); | 139 const int fd = static_cast<int>(i); |
139 if (saved_fds.find(fd) != saved_fds.end()) | 140 if (saved_fds.find(fd) != saved_fds.end()) |
140 continue; | 141 continue; |
141 | 142 |
142 int result; | 143 HANDLE_EINTR(close(fd)); |
143 do { | |
144 result = close(fd); | |
145 } while (result == -1 && errno == EINTR); | |
146 } | 144 } |
147 return; | 145 return; |
148 } | 146 } |
149 | 147 |
150 struct dirent *ent; | 148 struct dirent *ent; |
151 while ((ent = readdir(dir))) { | 149 while ((ent = readdir(dir))) { |
152 // Skip . and .. entries. | 150 // Skip . and .. entries. |
153 if (ent->d_name[0] == '.') | 151 if (ent->d_name[0] == '.') |
154 continue; | 152 continue; |
155 | 153 |
156 char *endptr; | 154 char *endptr; |
157 errno = 0; | 155 errno = 0; |
158 const long int fd = strtol(ent->d_name, &endptr, 10); | 156 const long int fd = strtol(ent->d_name, &endptr, 10); |
159 if (ent->d_name[0] == 0 || *endptr || fd < 0 || fd >= INT_MAX || errno) | 157 if (ent->d_name[0] == 0 || *endptr || fd < 0 || fd >= INT_MAX || errno) |
160 continue; | 158 continue; |
161 if (saved_fds.find(fd) != saved_fds.end()) | 159 if (saved_fds.find(fd) != saved_fds.end()) |
162 continue; | 160 continue; |
163 | 161 |
164 int result; | 162 HANDLE_EINTR(close(fd)); |
165 do { | |
166 result = close(fd); | |
167 } while (result == -1 && errno == EINTR); | |
168 } | 163 } |
169 } | 164 } |
170 | 165 |
171 // Sets all file descriptors to close on exec except for stdin, stdout | 166 // Sets all file descriptors to close on exec except for stdin, stdout |
172 // and stderr. | 167 // and stderr. |
173 // TODO(agl): Remove this function. It's fundamentally broken for multithreaded | 168 // TODO(agl): Remove this function. It's fundamentally broken for multithreaded |
174 // apps. | 169 // apps. |
175 void SetAllFDsToCloseOnExec() { | 170 void SetAllFDsToCloseOnExec() { |
176 #if defined(OS_LINUX) | 171 #if defined(OS_LINUX) |
177 const char fd_dir[] = "/proc/self/fd"; | 172 const char fd_dir[] = "/proc/self/fd"; |
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
219 // On POSIX, there nothing to do AFAIK. | 214 // On POSIX, there nothing to do AFAIK. |
220 } | 215 } |
221 | 216 |
222 void RaiseProcessToHighPriority() { | 217 void RaiseProcessToHighPriority() { |
223 // On POSIX, we don't actually do anything here. We could try to nice() or | 218 // On POSIX, we don't actually do anything here. We could try to nice() or |
224 // setpriority() or sched_getscheduler, but these all require extra rights. | 219 // setpriority() or sched_getscheduler, but these all require extra rights. |
225 } | 220 } |
226 | 221 |
227 bool DidProcessCrash(bool* child_exited, ProcessHandle handle) { | 222 bool DidProcessCrash(bool* child_exited, ProcessHandle handle) { |
228 int status; | 223 int status; |
229 const int result = waitpid(handle, &status, WNOHANG); | 224 const int result = HANDLE_EINTR(waitpid(handle, &status, WNOHANG)); |
230 if (result == -1) { | 225 if (result == -1) { |
231 LOG(ERROR) << "waitpid failed pid:" << handle << " errno:" << errno; | 226 LOG(ERROR) << "waitpid failed pid:" << handle << " errno:" << errno; |
232 if (child_exited) | 227 if (child_exited) |
233 *child_exited = false; | 228 *child_exited = false; |
234 return false; | 229 return false; |
235 } else if (result == 0) { | 230 } else if (result == 0) { |
236 // the child hasn't exited yet. | 231 // the child hasn't exited yet. |
237 if (child_exited) | 232 if (child_exited) |
238 *child_exited = false; | 233 *child_exited = false; |
239 return false; | 234 return false; |
(...skipping 15 matching lines...) Expand all Loading... |
255 } | 250 } |
256 | 251 |
257 if (WIFEXITED(status)) | 252 if (WIFEXITED(status)) |
258 return WEXITSTATUS(status) != 0; | 253 return WEXITSTATUS(status) != 0; |
259 | 254 |
260 return false; | 255 return false; |
261 } | 256 } |
262 | 257 |
263 bool WaitForExitCode(ProcessHandle handle, int* exit_code) { | 258 bool WaitForExitCode(ProcessHandle handle, int* exit_code) { |
264 int status; | 259 int status; |
265 while (waitpid(handle, &status, 0) == -1) { | 260 if (HANDLE_EINTR(waitpid(handle, &status, 0)) == -1) { |
266 if (errno != EINTR) { | 261 NOTREACHED(); |
267 NOTREACHED(); | 262 return false; |
268 return false; | |
269 } | |
270 } | 263 } |
271 | 264 |
272 if (WIFEXITED(status)) { | 265 if (WIFEXITED(status)) { |
273 *exit_code = WEXITSTATUS(status); | 266 *exit_code = WEXITSTATUS(status); |
274 return true; | 267 return true; |
275 } | 268 } |
276 | 269 |
277 // If it didn't exit cleanly, it must have been signaled. | 270 // If it didn't exit cleanly, it must have been signaled. |
278 DCHECK(WIFSIGNALED(status)); | 271 DCHECK(WIFSIGNALED(status)); |
279 return false; | 272 return false; |
(...skipping 18 matching lines...) Expand all Loading... |
298 // has already exited, otherwise to loop for wait_milliseconds, sleeping for | 291 // has already exited, otherwise to loop for wait_milliseconds, sleeping for |
299 // at most 0.25 secs each time using usleep() and then calling waitpid(). | 292 // at most 0.25 secs each time using usleep() and then calling waitpid(). |
300 // | 293 // |
301 // usleep() is speced to exit if a signal is received for which a handler | 294 // usleep() is speced to exit if a signal is received for which a handler |
302 // has been installed. This means that when a SIGCHLD is sent, it will exit | 295 // has been installed. This means that when a SIGCHLD is sent, it will exit |
303 // depending on behavior external to this function. | 296 // depending on behavior external to this function. |
304 // | 297 // |
305 // This function is used primarily for unit tests, if we want to use it in | 298 // This function is used primarily for unit tests, if we want to use it in |
306 // the application itself it would probably be best to examine other routes. | 299 // the application itself it would probably be best to examine other routes. |
307 int status = -1; | 300 int status = -1; |
308 pid_t ret_pid = waitpid(handle, &status, WNOHANG); | 301 pid_t ret_pid = HANDLE_EINTR(waitpid(handle, &status, WNOHANG)); |
309 static const int64 kQuarterSecondInMicroseconds = kMicrosecondsPerSecond/4; | 302 static const int64 kQuarterSecondInMicroseconds = kMicrosecondsPerSecond/4; |
310 | 303 |
311 // If the process hasn't exited yet, then sleep and try again. | 304 // If the process hasn't exited yet, then sleep and try again. |
312 Time wakeup_time = Time::Now() + TimeDelta::FromMilliseconds( | 305 Time wakeup_time = Time::Now() + TimeDelta::FromMilliseconds( |
313 wait_milliseconds); | 306 wait_milliseconds); |
314 while (ret_pid == 0) { | 307 while (ret_pid == 0) { |
315 Time now = Time::Now(); | 308 Time now = Time::Now(); |
316 if (now > wakeup_time) | 309 if (now > wakeup_time) |
317 break; | 310 break; |
318 // Guaranteed to be non-negative! | 311 // Guaranteed to be non-negative! |
319 int64 sleep_time_usecs = (wakeup_time - now).InMicroseconds(); | 312 int64 sleep_time_usecs = (wakeup_time - now).InMicroseconds(); |
320 // Don't sleep for more than 0.25 secs at a time. | 313 // Don't sleep for more than 0.25 secs at a time. |
321 if (sleep_time_usecs > kQuarterSecondInMicroseconds) { | 314 if (sleep_time_usecs > kQuarterSecondInMicroseconds) { |
322 sleep_time_usecs = kQuarterSecondInMicroseconds; | 315 sleep_time_usecs = kQuarterSecondInMicroseconds; |
323 } | 316 } |
324 | 317 |
325 // usleep() will return 0 and set errno to EINTR on receipt of a signal | 318 // usleep() will return 0 and set errno to EINTR on receipt of a signal |
326 // such as SIGCHLD. | 319 // such as SIGCHLD. |
327 usleep(sleep_time_usecs); | 320 usleep(sleep_time_usecs); |
328 ret_pid = waitpid(handle, &status, WNOHANG); | 321 ret_pid = HANDLE_EINTR(waitpid(handle, &status, WNOHANG)); |
329 } | 322 } |
330 | 323 |
331 if (success) | 324 if (success) |
332 *success = (ret_pid != -1); | 325 *success = (ret_pid != -1); |
333 | 326 |
334 return status; | 327 return status; |
335 } | 328 } |
336 | 329 |
337 } // namespace | 330 } // namespace |
338 | 331 |
339 bool WaitForSingleProcess(ProcessHandle handle, int wait_milliseconds) { | 332 bool WaitForSingleProcess(ProcessHandle handle, int wait_milliseconds) { |
340 bool waitpid_success; | 333 bool waitpid_success; |
341 int status; | 334 int status; |
342 if (wait_milliseconds == base::kNoTimeout) | 335 if (wait_milliseconds == base::kNoTimeout) |
343 waitpid_success = (waitpid(handle, &status, 0) != -1); | 336 waitpid_success = (HANDLE_EINTR(waitpid(handle, &status, 0)) != -1); |
344 else | 337 else |
345 status = WaitpidWithTimeout(handle, wait_milliseconds, &waitpid_success); | 338 status = WaitpidWithTimeout(handle, wait_milliseconds, &waitpid_success); |
346 if (status != -1) { | 339 if (status != -1) { |
347 DCHECK(waitpid_success); | 340 DCHECK(waitpid_success); |
348 return WIFEXITED(status); | 341 return WIFEXITED(status); |
349 } else { | 342 } else { |
350 return false; | 343 return false; |
351 } | 344 } |
352 } | 345 } |
353 | 346 |
(...skipping 102 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
456 | 449 |
457 int exit_code = EXIT_FAILURE; | 450 int exit_code = EXIT_FAILURE; |
458 bool success = WaitForExitCode(pid, &exit_code); | 451 bool success = WaitForExitCode(pid, &exit_code); |
459 if (!success || exit_code != EXIT_SUCCESS) { | 452 if (!success || exit_code != EXIT_SUCCESS) { |
460 close(pipe_fd[0]); | 453 close(pipe_fd[0]); |
461 return false; | 454 return false; |
462 } | 455 } |
463 | 456 |
464 char buffer[256]; | 457 char buffer[256]; |
465 std::string buf_output; | 458 std::string buf_output; |
466 ssize_t bytes_read = 0; | |
467 | 459 |
468 while (true) { | 460 while (true) { |
469 bytes_read = read(pipe_fd[0], buffer, sizeof(buffer)); | 461 ssize_t bytes_read = |
470 if (bytes_read == 0) | 462 HANDLE_EINTR(read(pipe_fd[0], buffer, sizeof(buffer))); |
| 463 if (bytes_read <= 0) |
471 break; | 464 break; |
472 if (bytes_read == -1 && errno != EINTR) | 465 buf_output.append(buffer, bytes_read); |
473 break; | |
474 if (bytes_read > 0) | |
475 buf_output.append(buffer, bytes_read); | |
476 } | 466 } |
477 output->swap(buf_output); | 467 output->swap(buf_output); |
478 close(pipe_fd[0]); | 468 close(pipe_fd[0]); |
479 return true; | 469 return true; |
480 } | 470 } |
481 } | 471 } |
482 } | 472 } |
483 | 473 |
484 int GetProcessCount(const std::wstring& executable_name, | 474 int GetProcessCount(const std::wstring& executable_name, |
485 const ProcessFilter* filter) { | 475 const ProcessFilter* filter) { |
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
531 const ProcessFilter* filter) { | 521 const ProcessFilter* filter) { |
532 bool exited_cleanly = | 522 bool exited_cleanly = |
533 WaitForProcessesToExit(executable_name, wait_milliseconds, | 523 WaitForProcessesToExit(executable_name, wait_milliseconds, |
534 filter); | 524 filter); |
535 if (!exited_cleanly) | 525 if (!exited_cleanly) |
536 KillProcesses(executable_name, exit_code, filter); | 526 KillProcesses(executable_name, exit_code, filter); |
537 return exited_cleanly; | 527 return exited_cleanly; |
538 } | 528 } |
539 | 529 |
540 } // namespace base | 530 } // namespace base |
OLD | NEW |