diff options
author | maruel@chromium.org <maruel@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-10-27 18:03:47 +0000 |
---|---|---|
committer | maruel@chromium.org <maruel@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-10-27 18:03:47 +0000 |
commit | d6fc9fd286eb7a3a6cad937da3b99cf8f4acd5c2 (patch) | |
tree | ff8de9ff438626c6d26a9df0acb94fadfd640431 /base/process_util_posix.cc | |
parent | 30be1ce62471386dbdebf8d8f4f87e31a772661c (diff) | |
download | chromium_src-d6fc9fd286eb7a3a6cad937da3b99cf8f4acd5c2.zip chromium_src-d6fc9fd286eb7a3a6cad937da3b99cf8f4acd5c2.tar.gz chromium_src-d6fc9fd286eb7a3a6cad937da3b99cf8f4acd5c2.tar.bz2 |
Move console stack dumping code to a function so it can be reused in test_shell_tests.
TEST=none
BUG=13770
Review URL: http://codereview.chromium.org/339024
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@30220 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'base/process_util_posix.cc')
-rw-r--r-- | base/process_util_posix.cc | 144 |
1 files changed, 86 insertions, 58 deletions
diff --git a/base/process_util_posix.cc b/base/process_util_posix.cc index d365d01..d5eb4ee 100644 --- a/base/process_util_posix.cc +++ b/base/process_util_posix.cc @@ -16,7 +16,7 @@ #include <limits> #include <set> -#include "base/basictypes.h" +#include "base/debug_util.h" #include "base/eintr_wrapper.h" #include "base/logging.h" #include "base/platform_thread.h" @@ -30,6 +30,68 @@ const int kMicrosecondsPerSecond = 1000000; namespace base { +namespace { + +int WaitpidWithTimeout(ProcessHandle handle, int64 wait_milliseconds, + bool* success) { + // This POSIX version of this function only guarantees that we wait no less + // than |wait_milliseconds| for the proces to exit. The child process may + // exit sometime before the timeout has ended but we may still block for + // up to 0.25 seconds after the fact. + // + // waitpid() has no direct support on POSIX for specifying a timeout, you can + // either ask it to block indefinitely or return immediately (WNOHANG). + // When a child process terminates a SIGCHLD signal is sent to the parent. + // Catching this signal would involve installing a signal handler which may + // affect other parts of the application and would be difficult to debug. + // + // Our strategy is to call waitpid() once up front to check if the process + // has already exited, otherwise to loop for wait_milliseconds, sleeping for + // at most 0.25 secs each time using usleep() and then calling waitpid(). + // + // usleep() is speced to exit if a signal is received for which a handler + // has been installed. This means that when a SIGCHLD is sent, it will exit + // depending on behavior external to this function. + // + // This function is used primarily for unit tests, if we want to use it in + // the application itself it would probably be best to examine other routes. + int status = -1; + pid_t ret_pid = HANDLE_EINTR(waitpid(handle, &status, WNOHANG)); + static const int64 kQuarterSecondInMicroseconds = kMicrosecondsPerSecond / 4; + + // If the process hasn't exited yet, then sleep and try again. + Time wakeup_time = Time::Now() + TimeDelta::FromMilliseconds( + wait_milliseconds); + while (ret_pid == 0) { + Time now = Time::Now(); + if (now > wakeup_time) + break; + // Guaranteed to be non-negative! + int64 sleep_time_usecs = (wakeup_time - now).InMicroseconds(); + // Don't sleep for more than 0.25 secs at a time. + if (sleep_time_usecs > kQuarterSecondInMicroseconds) { + sleep_time_usecs = kQuarterSecondInMicroseconds; + } + + // usleep() will return 0 and set errno to EINTR on receipt of a signal + // such as SIGCHLD. + usleep(sleep_time_usecs); + ret_pid = HANDLE_EINTR(waitpid(handle, &status, WNOHANG)); + } + + if (success) + *success = (ret_pid != -1); + + return status; +} + +void StackDumpSignalHandler(int signal) { + StackTrace().PrintBacktrace(); + _exit(1); +} + +} // namespace + ProcessId GetCurrentProcId() { return getpid(); } @@ -323,6 +385,29 @@ void EnableTerminationOnHeapCorruption() { // On POSIX, there nothing to do AFAIK. } +bool EnableInProcessStackDumping() { + // When running in an application, our code typically expects SIGPIPE + // to be ignored. Therefore, when testing that same code, it should run + // with SIGPIPE ignored as well. + struct sigaction action; + action.sa_handler = SIG_IGN; + action.sa_flags = 0; + sigemptyset(&action.sa_mask); + bool success = (sigaction(SIGPIPE, &action, NULL) == 0); + + // TODO(phajdan.jr): Catch other crashy signals, like SIGABRT. + success &= (signal(SIGSEGV, &StackDumpSignalHandler) != SIG_ERR); + success &= (signal(SIGILL, &StackDumpSignalHandler) != SIG_ERR); + success &= (signal(SIGBUS, &StackDumpSignalHandler) != SIG_ERR); + success &= (signal(SIGFPE, &StackDumpSignalHandler) != SIG_ERR); + return success; +} + +void AttachToConsole() { + // On POSIX, there nothing to do AFAIK. Maybe create a new console if none + // exist? +} + void RaiseProcessToHighPriority() { // On POSIX, we don't actually do anything here. We could try to nice() or // setpriority() or sched_getscheduler, but these all require extra rights. @@ -381,63 +466,6 @@ bool WaitForExitCode(ProcessHandle handle, int* exit_code) { return false; } -namespace { - -int WaitpidWithTimeout(ProcessHandle handle, int64 wait_milliseconds, - bool* success) { - // This POSIX version of this function only guarantees that we wait no less - // than |wait_milliseconds| for the proces to exit. The child process may - // exit sometime before the timeout has ended but we may still block for - // up to 0.25 seconds after the fact. - // - // waitpid() has no direct support on POSIX for specifying a timeout, you can - // either ask it to block indefinitely or return immediately (WNOHANG). - // When a child process terminates a SIGCHLD signal is sent to the parent. - // Catching this signal would involve installing a signal handler which may - // affect other parts of the application and would be difficult to debug. - // - // Our strategy is to call waitpid() once up front to check if the process - // has already exited, otherwise to loop for wait_milliseconds, sleeping for - // at most 0.25 secs each time using usleep() and then calling waitpid(). - // - // usleep() is speced to exit if a signal is received for which a handler - // has been installed. This means that when a SIGCHLD is sent, it will exit - // depending on behavior external to this function. - // - // This function is used primarily for unit tests, if we want to use it in - // the application itself it would probably be best to examine other routes. - int status = -1; - pid_t ret_pid = HANDLE_EINTR(waitpid(handle, &status, WNOHANG)); - static const int64 kQuarterSecondInMicroseconds = kMicrosecondsPerSecond/4; - - // If the process hasn't exited yet, then sleep and try again. - Time wakeup_time = Time::Now() + TimeDelta::FromMilliseconds( - wait_milliseconds); - while (ret_pid == 0) { - Time now = Time::Now(); - if (now > wakeup_time) - break; - // Guaranteed to be non-negative! - int64 sleep_time_usecs = (wakeup_time - now).InMicroseconds(); - // Don't sleep for more than 0.25 secs at a time. - if (sleep_time_usecs > kQuarterSecondInMicroseconds) { - sleep_time_usecs = kQuarterSecondInMicroseconds; - } - - // usleep() will return 0 and set errno to EINTR on receipt of a signal - // such as SIGCHLD. - usleep(sleep_time_usecs); - ret_pid = HANDLE_EINTR(waitpid(handle, &status, WNOHANG)); - } - - if (success) - *success = (ret_pid != -1); - - return status; -} - -} // namespace - bool WaitForSingleProcess(ProcessHandle handle, int64 wait_milliseconds) { bool waitpid_success; int status; |