|
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 |
|
3 // found in the LICENSE file. |
|
4 |
|
5 #include "chrome/common/process_watcher.h" |
|
6 |
|
7 #include "base/message_loop.h" |
|
8 #include "base/object_watcher.h" |
|
9 #include "base/sys_info.h" |
|
10 #include "chrome/common/env_vars.h" |
|
11 #include "chrome/common/result_codes.h" |
|
12 |
|
13 // Maximum amount of time (in milliseconds) to wait for the process to exit. |
|
14 static const int kWaitInterval = 2000; |
|
15 |
|
16 namespace { |
|
17 |
|
18 class TimerExpiredTask : public Task, public base::ObjectWatcher::Delegate { |
|
19 public: |
|
20 explicit TimerExpiredTask(base::ProcessHandle process) : process_(process) { |
|
21 watcher_.StartWatching(process_, this); |
|
22 } |
|
23 |
|
24 virtual ~TimerExpiredTask() { |
|
25 if (process_) { |
|
26 KillProcess(); |
|
27 DCHECK(!process_) << "Make sure to close the handle."; |
|
28 } |
|
29 } |
|
30 |
|
31 // Task --------------------------------------------------------------------- |
|
32 |
|
33 virtual void Run() { |
|
34 if (process_) |
|
35 KillProcess(); |
|
36 } |
|
37 |
|
38 // MessageLoop::Watcher ----------------------------------------------------- |
|
39 |
|
40 virtual void OnObjectSignaled(HANDLE object) { |
|
41 // When we're called from KillProcess, the ObjectWatcher may still be |
|
42 // watching. the process handle, so make sure it has stopped. |
|
43 watcher_.StopWatching(); |
|
44 |
|
45 base::CloseProcessHandle(process_); |
|
46 process_ = NULL; |
|
47 } |
|
48 |
|
49 private: |
|
50 void KillProcess() { |
|
51 if (base::SysInfo::HasEnvVar(env_vars::kHeadless)) { |
|
52 // If running the distributed tests, give the renderer a little time |
|
53 // to figure out that the channel is shutdown and unwind. |
|
54 if (WaitForSingleObject(process_, kWaitInterval) == WAIT_OBJECT_0) { |
|
55 OnObjectSignaled(process_); |
|
56 return; |
|
57 } |
|
58 } |
|
59 |
|
60 // OK, time to get frisky. We don't actually care when the process |
|
61 // terminates. We just care that it eventually terminates, and that's what |
|
62 // TerminateProcess should do for us. Don't check for the result code since |
|
63 // it fails quite often. This should be investigated eventually. |
|
64 TerminateProcess(process_, ResultCodes::HUNG); |
|
65 |
|
66 // Now, just cleanup as if the process exited normally. |
|
67 OnObjectSignaled(process_); |
|
68 } |
|
69 |
|
70 // The process that we are watching. |
|
71 base::ProcessHandle process_; |
|
72 |
|
73 base::ObjectWatcher watcher_; |
|
74 |
|
75 DISALLOW_EVIL_CONSTRUCTORS(TimerExpiredTask); |
|
76 }; |
|
77 |
|
78 } // namespace |
|
79 |
|
80 // static |
|
81 void ProcessWatcher::EnsureProcessTerminated(base::ProcessHandle process |
|
82 , bool force |
|
83 ) { |
|
84 DCHECK(process != GetCurrentProcess()); |
|
85 |
|
86 if (!force) { |
|
87 WaitForSingleObject(process, INFINITE); |
|
88 base::CloseProcessHandle(process); |
|
89 return; |
|
90 } |
|
91 |
|
92 // If already signaled, then we are done! |
|
93 if (WaitForSingleObject(process, 0) == WAIT_OBJECT_0) { |
|
94 base::CloseProcessHandle(process); |
|
95 return; |
|
96 } |
|
97 |
|
98 MessageLoop::current()->PostDelayedTask(FROM_HERE, |
|
99 new TimerExpiredTask(process), |
|
100 kWaitInterval); |
|
101 } |