diff options
Diffstat (limited to 'base/process_util_win.cc')
-rw-r--r-- | base/process_util_win.cc | 71 |
1 files changed, 71 insertions, 0 deletions
diff --git a/base/process_util_win.cc b/base/process_util_win.cc index 85aeace..891dc3b 100644 --- a/base/process_util_win.cc +++ b/base/process_util_win.cc @@ -16,8 +16,10 @@ #include "base/debug/stack_trace.h" #include "base/logging.h" #include "base/memory/scoped_ptr.h" +#include "base/message_loop.h" #include "base/metrics/histogram.h" #include "base/sys_info.h" +#include "base/win/object_watcher.h" #include "base/win/scoped_handle.h" #include "base/win/windows_version.h" @@ -37,6 +39,9 @@ const DWORD kDebuggerInactiveExitCode = 0xC0000354; const DWORD kKeyboardInterruptExitCode = 0xC000013A; const DWORD kDebuggerTerminatedExitCode = 0x40010004; +// Maximum amount of time (in milliseconds) to wait for the process to exit. +static const int kWaitInterval = 2000; + // This exit code is used by the Windows task manager when it kills a // process. It's value is obviously not that unique, and it's // surprising to me that the task manager uses this value, but it @@ -103,6 +108,58 @@ void OnNoMemory() { _exit(1); } +class TimerExpiredTask : public Task, + public win::ObjectWatcher::Delegate { + public: + explicit TimerExpiredTask(ProcessHandle process) : process_(process) { + watcher_.StartWatching(process_, this); + } + + virtual ~TimerExpiredTask() { + if (process_) { + KillProcess(); + DCHECK(!process_) << "Make sure to close the handle."; + } + } + + // Task --------------------------------------------------------------------- + + virtual void Run() { + if (process_) + KillProcess(); + } + + // MessageLoop::Watcher ----------------------------------------------------- + + virtual void OnObjectSignaled(HANDLE object) { + // When we're called from KillProcess, the ObjectWatcher may still be + // watching. the process handle, so make sure it has stopped. + watcher_.StopWatching(); + + CloseHandle(process_); + process_ = NULL; + } + + private: + void KillProcess() { + // OK, time to get frisky. We don't actually care when the process + // terminates. We just care that it eventually terminates, and that's what + // TerminateProcess should do for us. Don't check for the result code since + // it fails quite often. This should be investigated eventually. + base::KillProcess(process_, kProcessKilledExitCode, false); + + // Now, just cleanup as if the process exited normally. + OnObjectSignaled(process_); + } + + // The process that we are watching. + ProcessHandle process_; + + win::ObjectWatcher watcher_; + + DISALLOW_COPY_AND_ASSIGN(TimerExpiredTask); +}; + } // namespace ProcessId GetCurrentProcId() { @@ -551,6 +608,20 @@ bool CleanupProcesses(const std::wstring& executable_name, return exited_cleanly; } +void EnsureProcessTerminated(ProcessHandle process) { + DCHECK(process != GetCurrentProcess()); + + // If already signaled, then we are done! + if (WaitForSingleObject(process, 0) == WAIT_OBJECT_0) { + CloseHandle(process); + return; + } + + MessageLoop::current()->PostDelayedTask(FROM_HERE, + new TimerExpiredTask(process), + kWaitInterval); +} + /////////////////////////////////////////////////////////////////////////////// // ProcesMetrics |