| 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/debug_util.h" | 
|   20 #include "base/eintr_wrapper.h" |   20 #include "base/eintr_wrapper.h" | 
|   21 #include "base/logging.h" |   21 #include "base/logging.h" | 
|   22 #include "base/platform_thread.h" |   22 #include "base/platform_thread.h" | 
|   23 #include "base/process_util.h" |   23 #include "base/process_util.h" | 
|   24 #include "base/scoped_ptr.h" |   24 #include "base/scoped_ptr.h" | 
|   25 #include "base/sys_info.h" |   25 #include "base/sys_info.h" | 
|   26 #include "base/time.h" |   26 #include "base/time.h" | 
|   27 #include "base/waitable_event.h" |   27 #include "base/waitable_event.h" | 
|   28  |   28  | 
|   29 const int kMicrosecondsPerSecond = 1000000; |   29 const int kMicrosecondsPerSecond = 1000000; | 
|   30  |   30  | 
|   31 namespace base { |   31 namespace base { | 
|   32  |   32  | 
 |   33 namespace { | 
 |   34  | 
 |   35 int WaitpidWithTimeout(ProcessHandle handle, int64 wait_milliseconds, | 
 |   36                        bool* success) { | 
 |   37   // This POSIX version of this function only guarantees that we wait no less | 
 |   38   // than |wait_milliseconds| for the proces to exit.  The child process may | 
 |   39   // exit sometime before the timeout has ended but we may still block for | 
 |   40   // up to 0.25 seconds after the fact. | 
 |   41   // | 
 |   42   // waitpid() has no direct support on POSIX for specifying a timeout, you can | 
 |   43   // either ask it to block indefinitely or return immediately (WNOHANG). | 
 |   44   // When a child process terminates a SIGCHLD signal is sent to the parent. | 
 |   45   // Catching this signal would involve installing a signal handler which may | 
 |   46   // affect other parts of the application and would be difficult to debug. | 
 |   47   // | 
 |   48   // Our strategy is to call waitpid() once up front to check if the process | 
 |   49   // has already exited, otherwise to loop for wait_milliseconds, sleeping for | 
 |   50   // at most 0.25 secs each time using usleep() and then calling waitpid(). | 
 |   51   // | 
 |   52   // usleep() is speced to exit if a signal is received for which a handler | 
 |   53   // has been installed.  This means that when a SIGCHLD is sent, it will exit | 
 |   54   // depending on behavior external to this function. | 
 |   55   // | 
 |   56   // This function is used primarily for unit tests, if we want to use it in | 
 |   57   // the application itself it would probably be best to examine other routes. | 
 |   58   int status = -1; | 
 |   59   pid_t ret_pid = HANDLE_EINTR(waitpid(handle, &status, WNOHANG)); | 
 |   60   static const int64 kQuarterSecondInMicroseconds = kMicrosecondsPerSecond / 4; | 
 |   61  | 
 |   62   // If the process hasn't exited yet, then sleep and try again. | 
 |   63   Time wakeup_time = Time::Now() + TimeDelta::FromMilliseconds( | 
 |   64       wait_milliseconds); | 
 |   65   while (ret_pid == 0) { | 
 |   66     Time now = Time::Now(); | 
 |   67     if (now > wakeup_time) | 
 |   68       break; | 
 |   69     // Guaranteed to be non-negative! | 
 |   70     int64 sleep_time_usecs = (wakeup_time - now).InMicroseconds(); | 
 |   71     // Don't sleep for more than 0.25 secs at a time. | 
 |   72     if (sleep_time_usecs > kQuarterSecondInMicroseconds) { | 
 |   73       sleep_time_usecs = kQuarterSecondInMicroseconds; | 
 |   74     } | 
 |   75  | 
 |   76     // usleep() will return 0 and set errno to EINTR on receipt of a signal | 
 |   77     // such as SIGCHLD. | 
 |   78     usleep(sleep_time_usecs); | 
 |   79     ret_pid = HANDLE_EINTR(waitpid(handle, &status, WNOHANG)); | 
 |   80   } | 
 |   81  | 
 |   82   if (success) | 
 |   83     *success = (ret_pid != -1); | 
 |   84  | 
 |   85   return status; | 
 |   86 } | 
 |   87  | 
 |   88 void StackDumpSignalHandler(int signal) { | 
 |   89   StackTrace().PrintBacktrace(); | 
 |   90   _exit(1); | 
 |   91 } | 
 |   92  | 
 |   93 }  // namespace | 
 |   94  | 
|   33 ProcessId GetCurrentProcId() { |   95 ProcessId GetCurrentProcId() { | 
|   34   return getpid(); |   96   return getpid(); | 
|   35 } |   97 } | 
|   36  |   98  | 
|   37 ProcessHandle GetCurrentProcessHandle() { |   99 ProcessHandle GetCurrentProcessHandle() { | 
|   38   return GetCurrentProcId(); |  100   return GetCurrentProcId(); | 
|   39 } |  101 } | 
|   40  |  102  | 
|   41 bool OpenProcessHandle(ProcessId pid, ProcessHandle* handle) { |  103 bool OpenProcessHandle(ProcessId pid, ProcessHandle* handle) { | 
|   42   // On Posix platforms, process handles are the same as PIDs, so we |  104   // On Posix platforms, process handles are the same as PIDs, so we | 
| (...skipping 273 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
|  316 ProcessMetrics* ProcessMetrics::CreateProcessMetrics(ProcessHandle process) { |  378 ProcessMetrics* ProcessMetrics::CreateProcessMetrics(ProcessHandle process) { | 
|  317   return new ProcessMetrics(process); |  379   return new ProcessMetrics(process); | 
|  318 } |  380 } | 
|  319  |  381  | 
|  320 ProcessMetrics::~ProcessMetrics() { } |  382 ProcessMetrics::~ProcessMetrics() { } | 
|  321  |  383  | 
|  322 void EnableTerminationOnHeapCorruption() { |  384 void EnableTerminationOnHeapCorruption() { | 
|  323   // On POSIX, there nothing to do AFAIK. |  385   // On POSIX, there nothing to do AFAIK. | 
|  324 } |  386 } | 
|  325  |  387  | 
 |  388 bool EnableInProcessStackDumping() { | 
 |  389   // When running in an application, our code typically expects SIGPIPE | 
 |  390   // to be ignored.  Therefore, when testing that same code, it should run | 
 |  391   // with SIGPIPE ignored as well. | 
 |  392   struct sigaction action; | 
 |  393   action.sa_handler = SIG_IGN; | 
 |  394   action.sa_flags = 0; | 
 |  395   sigemptyset(&action.sa_mask); | 
 |  396   bool success = (sigaction(SIGPIPE, &action, NULL) == 0); | 
 |  397  | 
 |  398   // TODO(phajdan.jr): Catch other crashy signals, like SIGABRT. | 
 |  399   success &= (signal(SIGSEGV, &StackDumpSignalHandler) != SIG_ERR); | 
 |  400   success &= (signal(SIGILL, &StackDumpSignalHandler) != SIG_ERR); | 
 |  401   success &= (signal(SIGBUS, &StackDumpSignalHandler) != SIG_ERR); | 
 |  402   success &= (signal(SIGFPE, &StackDumpSignalHandler) != SIG_ERR); | 
 |  403   return success; | 
 |  404 } | 
 |  405  | 
 |  406 void AttachToConsole() { | 
 |  407   // On POSIX, there nothing to do AFAIK. Maybe create a new console if none | 
 |  408   // exist? | 
 |  409 } | 
 |  410  | 
|  326 void RaiseProcessToHighPriority() { |  411 void RaiseProcessToHighPriority() { | 
|  327   // On POSIX, we don't actually do anything here.  We could try to nice() or |  412   // On POSIX, we don't actually do anything here.  We could try to nice() or | 
|  328   // setpriority() or sched_getscheduler, but these all require extra rights. |  413   // setpriority() or sched_getscheduler, but these all require extra rights. | 
|  329 } |  414 } | 
|  330  |  415  | 
|  331 bool DidProcessCrash(bool* child_exited, ProcessHandle handle) { |  416 bool DidProcessCrash(bool* child_exited, ProcessHandle handle) { | 
|  332   int status; |  417   int status; | 
|  333   const pid_t result = HANDLE_EINTR(waitpid(handle, &status, WNOHANG)); |  418   const pid_t result = HANDLE_EINTR(waitpid(handle, &status, WNOHANG)); | 
|  334   if (result == -1) { |  419   if (result == -1) { | 
|  335     PLOG(ERROR) << "waitpid(" << handle << ")"; |  420     PLOG(ERROR) << "waitpid(" << handle << ")"; | 
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
|  374   if (WIFEXITED(status)) { |  459   if (WIFEXITED(status)) { | 
|  375     *exit_code = WEXITSTATUS(status); |  460     *exit_code = WEXITSTATUS(status); | 
|  376     return true; |  461     return true; | 
|  377   } |  462   } | 
|  378  |  463  | 
|  379   // If it didn't exit cleanly, it must have been signaled. |  464   // If it didn't exit cleanly, it must have been signaled. | 
|  380   DCHECK(WIFSIGNALED(status)); |  465   DCHECK(WIFSIGNALED(status)); | 
|  381   return false; |  466   return false; | 
|  382 } |  467 } | 
|  383  |  468  | 
|  384 namespace { |  | 
|  385  |  | 
|  386 int WaitpidWithTimeout(ProcessHandle handle, int64 wait_milliseconds, |  | 
|  387                        bool* success) { |  | 
|  388   // This POSIX version of this function only guarantees that we wait no less |  | 
|  389   // than |wait_milliseconds| for the proces to exit.  The child process may |  | 
|  390   // exit sometime before the timeout has ended but we may still block for |  | 
|  391   // up to 0.25 seconds after the fact. |  | 
|  392   // |  | 
|  393   // waitpid() has no direct support on POSIX for specifying a timeout, you can |  | 
|  394   // either ask it to block indefinitely or return immediately (WNOHANG). |  | 
|  395   // When a child process terminates a SIGCHLD signal is sent to the parent. |  | 
|  396   // Catching this signal would involve installing a signal handler which may |  | 
|  397   // affect other parts of the application and would be difficult to debug. |  | 
|  398   // |  | 
|  399   // Our strategy is to call waitpid() once up front to check if the process |  | 
|  400   // has already exited, otherwise to loop for wait_milliseconds, sleeping for |  | 
|  401   // at most 0.25 secs each time using usleep() and then calling waitpid(). |  | 
|  402   // |  | 
|  403   // usleep() is speced to exit if a signal is received for which a handler |  | 
|  404   // has been installed.  This means that when a SIGCHLD is sent, it will exit |  | 
|  405   // depending on behavior external to this function. |  | 
|  406   // |  | 
|  407   // This function is used primarily for unit tests, if we want to use it in |  | 
|  408   // the application itself it would probably be best to examine other routes. |  | 
|  409   int status = -1; |  | 
|  410   pid_t ret_pid = HANDLE_EINTR(waitpid(handle, &status, WNOHANG)); |  | 
|  411   static const int64 kQuarterSecondInMicroseconds = kMicrosecondsPerSecond/4; |  | 
|  412  |  | 
|  413   // If the process hasn't exited yet, then sleep and try again. |  | 
|  414   Time wakeup_time = Time::Now() + TimeDelta::FromMilliseconds( |  | 
|  415       wait_milliseconds); |  | 
|  416   while (ret_pid == 0) { |  | 
|  417     Time now = Time::Now(); |  | 
|  418     if (now > wakeup_time) |  | 
|  419       break; |  | 
|  420     // Guaranteed to be non-negative! |  | 
|  421     int64 sleep_time_usecs = (wakeup_time - now).InMicroseconds(); |  | 
|  422     // Don't sleep for more than 0.25 secs at a time. |  | 
|  423     if (sleep_time_usecs > kQuarterSecondInMicroseconds) { |  | 
|  424       sleep_time_usecs = kQuarterSecondInMicroseconds; |  | 
|  425     } |  | 
|  426  |  | 
|  427     // usleep() will return 0 and set errno to EINTR on receipt of a signal |  | 
|  428     // such as SIGCHLD. |  | 
|  429     usleep(sleep_time_usecs); |  | 
|  430     ret_pid = HANDLE_EINTR(waitpid(handle, &status, WNOHANG)); |  | 
|  431   } |  | 
|  432  |  | 
|  433   if (success) |  | 
|  434     *success = (ret_pid != -1); |  | 
|  435  |  | 
|  436   return status; |  | 
|  437 } |  | 
|  438  |  | 
|  439 }  // namespace |  | 
|  440  |  | 
|  441 bool WaitForSingleProcess(ProcessHandle handle, int64 wait_milliseconds) { |  469 bool WaitForSingleProcess(ProcessHandle handle, int64 wait_milliseconds) { | 
|  442   bool waitpid_success; |  470   bool waitpid_success; | 
|  443   int status; |  471   int status; | 
|  444   if (wait_milliseconds == base::kNoTimeout) |  472   if (wait_milliseconds == base::kNoTimeout) | 
|  445     waitpid_success = (HANDLE_EINTR(waitpid(handle, &status, 0)) != -1); |  473     waitpid_success = (HANDLE_EINTR(waitpid(handle, &status, 0)) != -1); | 
|  446   else |  474   else | 
|  447     status = WaitpidWithTimeout(handle, wait_milliseconds, &waitpid_success); |  475     status = WaitpidWithTimeout(handle, wait_milliseconds, &waitpid_success); | 
|  448   if (status != -1) { |  476   if (status != -1) { | 
|  449     DCHECK(waitpid_success); |  477     DCHECK(waitpid_success); | 
|  450     return WIFEXITED(status); |  478     return WIFEXITED(status); | 
| (...skipping 187 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
|  638                       const ProcessFilter* filter) { |  666                       const ProcessFilter* filter) { | 
|  639   bool exited_cleanly = |  667   bool exited_cleanly = | 
|  640       WaitForProcessesToExit(executable_name, wait_milliseconds, |  668       WaitForProcessesToExit(executable_name, wait_milliseconds, | 
|  641                              filter); |  669                              filter); | 
|  642   if (!exited_cleanly) |  670   if (!exited_cleanly) | 
|  643     KillProcesses(executable_name, exit_code, filter); |  671     KillProcesses(executable_name, exit_code, filter); | 
|  644   return exited_cleanly; |  672   return exited_cleanly; | 
|  645 } |  673 } | 
|  646  |  674  | 
|  647 }  // namespace base |  675 }  // namespace base | 
| OLD | NEW |