|
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- |
|
2 * vim: set ts=8 et sw=2 tw=80: |
|
3 */ |
|
4 /* This Source Code Form is subject to the terms of the Mozilla Public |
|
5 * License, v. 2.0. If a copy of the MPL was not distributed with this |
|
6 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
|
7 |
|
8 #include <errno.h> |
|
9 #include <signal.h> |
|
10 #include <sys/types.h> |
|
11 #include <sys/wait.h> |
|
12 |
|
13 #include "base/eintr_wrapper.h" |
|
14 #include "base/message_loop.h" |
|
15 #include "base/process_util.h" |
|
16 |
|
17 #include "chrome/common/process_watcher.h" |
|
18 |
|
19 // Maximum amount of time (in milliseconds) to wait for the process to exit. |
|
20 // XXX/cjones: fairly arbitrary, chosen to match process_watcher_win.cc |
|
21 static const int kMaxWaitMs = 2000; |
|
22 |
|
23 namespace { |
|
24 |
|
25 bool |
|
26 IsProcessDead(pid_t process) |
|
27 { |
|
28 bool exited = false; |
|
29 // don't care if the process crashed, just if it exited |
|
30 base::DidProcessCrash(&exited, process); |
|
31 return exited; |
|
32 } |
|
33 |
|
34 |
|
35 class ChildReaper : public base::MessagePumpLibevent::SignalEvent, |
|
36 public base::MessagePumpLibevent::SignalWatcher |
|
37 { |
|
38 public: |
|
39 explicit ChildReaper(pid_t process) : process_(process) |
|
40 { |
|
41 } |
|
42 |
|
43 virtual ~ChildReaper() |
|
44 { |
|
45 // subclasses should have cleaned up |process_| already |
|
46 DCHECK(!process_); |
|
47 |
|
48 // StopCatching() is implicit |
|
49 } |
|
50 |
|
51 // @override |
|
52 virtual void OnSignal(int sig) |
|
53 { |
|
54 DCHECK(SIGCHLD == sig); |
|
55 DCHECK(process_); |
|
56 |
|
57 // this may be the SIGCHLD for a process other than |process_| |
|
58 if (IsProcessDead(process_)) { |
|
59 process_ = 0; |
|
60 StopCatching(); |
|
61 } |
|
62 } |
|
63 |
|
64 protected: |
|
65 void WaitForChildExit() |
|
66 { |
|
67 DCHECK(process_); |
|
68 HANDLE_EINTR(waitpid(process_, NULL, 0)); |
|
69 } |
|
70 |
|
71 pid_t process_; |
|
72 |
|
73 private: |
|
74 DISALLOW_EVIL_CONSTRUCTORS(ChildReaper); |
|
75 }; |
|
76 |
|
77 |
|
78 // Fear the reaper |
|
79 class ChildGrimReaper : public ChildReaper, |
|
80 public Task |
|
81 { |
|
82 public: |
|
83 explicit ChildGrimReaper(pid_t process) : ChildReaper(process) |
|
84 { |
|
85 } |
|
86 |
|
87 virtual ~ChildGrimReaper() |
|
88 { |
|
89 if (process_) |
|
90 KillProcess(); |
|
91 } |
|
92 |
|
93 // @override |
|
94 virtual void Run() |
|
95 { |
|
96 // we may have already been signaled by the time this runs |
|
97 if (process_) |
|
98 KillProcess(); |
|
99 } |
|
100 |
|
101 private: |
|
102 void KillProcess() |
|
103 { |
|
104 DCHECK(process_); |
|
105 |
|
106 if (IsProcessDead(process_)) { |
|
107 process_ = 0; |
|
108 return; |
|
109 } |
|
110 |
|
111 if (0 == kill(process_, SIGKILL)) { |
|
112 // XXX this will block for whatever amount of time it takes the |
|
113 // XXX OS to tear down the process's resources. might need to |
|
114 // XXX rethink this if it proves expensive |
|
115 WaitForChildExit(); |
|
116 } |
|
117 else { |
|
118 CHROMIUM_LOG(ERROR) << "Failed to deliver SIGKILL to " << process_ << "!" |
|
119 << "("<< errno << ")."; |
|
120 } |
|
121 process_ = 0; |
|
122 } |
|
123 |
|
124 DISALLOW_EVIL_CONSTRUCTORS(ChildGrimReaper); |
|
125 }; |
|
126 |
|
127 |
|
128 class ChildLaxReaper : public ChildReaper, |
|
129 public MessageLoop::DestructionObserver |
|
130 { |
|
131 public: |
|
132 explicit ChildLaxReaper(pid_t process) : ChildReaper(process) |
|
133 { |
|
134 } |
|
135 |
|
136 virtual ~ChildLaxReaper() |
|
137 { |
|
138 // WillDestroyCurrentMessageLoop() should have reaped process_ already |
|
139 DCHECK(!process_); |
|
140 } |
|
141 |
|
142 // @override |
|
143 virtual void OnSignal(int sig) |
|
144 { |
|
145 ChildReaper::OnSignal(sig); |
|
146 |
|
147 if (!process_) { |
|
148 MessageLoop::current()->RemoveDestructionObserver(this); |
|
149 delete this; |
|
150 } |
|
151 } |
|
152 |
|
153 // @override |
|
154 virtual void WillDestroyCurrentMessageLoop() |
|
155 { |
|
156 DCHECK(process_); |
|
157 |
|
158 WaitForChildExit(); |
|
159 process_ = 0; |
|
160 |
|
161 // XXX don't think this is necessary, since destruction can only |
|
162 // be observed once, but can't hurt |
|
163 MessageLoop::current()->RemoveDestructionObserver(this); |
|
164 delete this; |
|
165 } |
|
166 |
|
167 private: |
|
168 DISALLOW_EVIL_CONSTRUCTORS(ChildLaxReaper); |
|
169 }; |
|
170 |
|
171 } // namespace <anon> |
|
172 |
|
173 |
|
174 /** |
|
175 * Do everything possible to ensure that |process| has been reaped |
|
176 * before this process exits. |
|
177 * |
|
178 * |grim| decides how strict to be with the child's shutdown. |
|
179 * |
|
180 * | child exit timeout | upon parent shutdown: |
|
181 * +--------------------+---------------------------------- |
|
182 * force=true | 2 seconds | kill(child, SIGKILL) |
|
183 * force=false | infinite | waitpid(child) |
|
184 * |
|
185 * If a child process doesn't shut down properly, and |grim=false| |
|
186 * used, then the parent will wait on the child forever. So, |
|
187 * |force=false| is expected to be used when an external entity can be |
|
188 * responsible for terminating hung processes, e.g. automated test |
|
189 * harnesses. |
|
190 */ |
|
191 void |
|
192 ProcessWatcher::EnsureProcessTerminated(base::ProcessHandle process, |
|
193 bool force) |
|
194 { |
|
195 DCHECK(process != base::GetCurrentProcId()); |
|
196 DCHECK(process > 0); |
|
197 |
|
198 if (IsProcessDead(process)) |
|
199 return; |
|
200 |
|
201 MessageLoopForIO* loop = MessageLoopForIO::current(); |
|
202 if (force) { |
|
203 ChildGrimReaper* reaper = new ChildGrimReaper(process); |
|
204 |
|
205 loop->CatchSignal(SIGCHLD, reaper, reaper); |
|
206 // |loop| takes ownership of |reaper| |
|
207 loop->PostDelayedTask(FROM_HERE, reaper, kMaxWaitMs); |
|
208 } else { |
|
209 ChildLaxReaper* reaper = new ChildLaxReaper(process); |
|
210 |
|
211 loop->CatchSignal(SIGCHLD, reaper, reaper); |
|
212 // |reaper| destroys itself after destruction notification |
|
213 loop->AddDestructionObserver(reaper); |
|
214 } |
|
215 } |