| 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 |