summaryrefslogtreecommitdiffstats
path: root/base/process_util_win.cc
diff options
context:
space:
mode:
authorjam@chromium.org <jam@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-11-23 18:32:00 +0000
committerjam@chromium.org <jam@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-11-23 18:32:00 +0000
commiteaac715956492f57bae3f30957662aca56462abe (patch)
tree4a98772d114fcd710936a12ae1f03f38278cfba3 /base/process_util_win.cc
parent407a38f923c6d76fe91de1bab7d8e190b6aa6f1d (diff)
downloadchromium_src-eaac715956492f57bae3f30957662aca56462abe.zip
chromium_src-eaac715956492f57bae3f30957662aca56462abe.tar.gz
chromium_src-eaac715956492f57bae3f30957662aca56462abe.tar.bz2
Move the ProcessWatcher methods out of content/common/process_watcher into base/process_util, alongside the other process methods.
The only non-trivial move change is to the Windows implementation, where I changed KillProcess to use an exit code of kProcessKilledExitCode instead of content::RESULT_CODE_HUNG. cpu said that the existing code was incorrect, since GetTerminationStatus() should be mapping that result to TERMINATION_STATUS_PROCESS_WAS_KILLED. So I changed the exit code to kProcessKilledExitCode. This might make the UMA stats for killed processes to go up (and crashed to go down), but that will be an accounting change and should be zero-sum. BUG=98716 Review URL: http://codereview.chromium.org/8674003 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@111371 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'base/process_util_win.cc')
-rw-r--r--base/process_util_win.cc71
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