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