Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include <dirent.h> | 5 #include <dirent.h> |
| 6 #include <errno.h> | 6 #include <errno.h> |
| 7 #include <fcntl.h> | 7 #include <fcntl.h> |
| 8 #include <signal.h> | 8 #include <signal.h> |
| 9 #include <stdlib.h> | 9 #include <stdlib.h> |
| 10 #include <sys/resource.h> | 10 #include <sys/resource.h> |
| (...skipping 1192 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1203 int exit_code, | 1203 int exit_code, |
| 1204 const ProcessFilter* filter) { | 1204 const ProcessFilter* filter) { |
| 1205 bool exited_cleanly = | 1205 bool exited_cleanly = |
| 1206 WaitForProcessesToExit(executable_name, wait_milliseconds, | 1206 WaitForProcessesToExit(executable_name, wait_milliseconds, |
| 1207 filter); | 1207 filter); |
| 1208 if (!exited_cleanly) | 1208 if (!exited_cleanly) |
| 1209 KillProcesses(executable_name, exit_code, filter); | 1209 KillProcesses(executable_name, exit_code, filter); |
| 1210 return exited_cleanly; | 1210 return exited_cleanly; |
| 1211 } | 1211 } |
| 1212 | 1212 |
| 1213 #if !defined(OS_MACOSX) | |
| 1214 | |
| 1215 namespace { | |
| 1216 | |
| 1217 // Return true if the given child is dead. This will also reap the process. | |
| 1218 // Doesn't block. | |
| 1219 static bool IsChildDead(pid_t child) { | |
| 1220 const pid_t result = HANDLE_EINTR(waitpid(child, NULL, WNOHANG)); | |
| 1221 if (result == -1) { | |
| 1222 DPLOG(ERROR) << "waitpid(" << child << ")"; | |
| 1223 NOTREACHED(); | |
| 1224 } else if (result > 0) { | |
| 1225 // The child has died. | |
| 1226 return true; | |
| 1227 } | |
| 1228 | |
| 1229 return false; | |
| 1230 } | |
| 1231 | |
| 1232 // A thread class which waits for the given child to exit and reaps it. | |
| 1233 // If the child doesn't exit within a couple of seconds, kill it. | |
| 1234 class BackgroundReaper : public PlatformThread::Delegate { | |
| 1235 public: | |
| 1236 BackgroundReaper(pid_t child, unsigned timeout) | |
| 1237 : child_(child), | |
| 1238 timeout_(timeout) { | |
| 1239 } | |
| 1240 | |
| 1241 void ThreadMain() { | |
| 1242 WaitForChildToDie(); | |
| 1243 delete this; | |
| 1244 } | |
| 1245 | |
| 1246 void WaitForChildToDie() { | |
| 1247 // Wait forever case. | |
| 1248 if (timeout_ == 0) { | |
| 1249 pid_t r = HANDLE_EINTR(waitpid(child_, NULL, 0)); | |
| 1250 if (r != child_) { | |
| 1251 DPLOG(ERROR) << "While waiting for " << child_ | |
| 1252 << " to terminate, we got the following result: " << r; | |
| 1253 } | |
| 1254 return; | |
| 1255 } | |
| 1256 | |
| 1257 // There's no good way to wait for a specific child to exit in a timed | |
| 1258 // fashion. (No kqueue on Linux), so we just loop and sleep. | |
| 1259 | |
| 1260 // Wait for 2 * timeout_ 500 milliseconds intervals. | |
| 1261 for (unsigned i = 0; i < 2 * timeout_; ++i) { | |
| 1262 PlatformThread::Sleep(500); // 0.5 seconds | |
| 1263 if (IsChildDead(child_)) | |
| 1264 return; | |
| 1265 } | |
| 1266 | |
| 1267 if (kill(child_, SIGKILL) == 0) { | |
| 1268 // SIGKILL is uncatchable. Since the signal was delivered, we can | |
| 1269 // just wait for the process to die now in a blocking manner. | |
| 1270 if (HANDLE_EINTR(waitpid(child_, NULL, 0)) < 0) | |
| 1271 DPLOG(WARNING) << "waitpid"; | |
| 1272 } else { | |
| 1273 DLOG(ERROR) << "While waiting for " << child_ << " to terminate we" | |
| 1274 << " failed to deliver a SIGKILL signal (" << errno << ")."; | |
| 1275 } | |
| 1276 } | |
| 1277 | |
| 1278 private: | |
| 1279 const pid_t child_; | |
| 1280 // Number of seconds to wait, if 0 then wait forever and do not attempt to | |
| 1281 // kill |child_|. | |
| 1282 const unsigned timeout_; | |
| 1283 | |
| 1284 DISALLOW_COPY_AND_ASSIGN(BackgroundReaper); | |
| 1285 }; | |
| 1286 | |
| 1287 } // namespace | |
| 1288 | |
| 1289 void EnsureProcessTerminated(ProcessHandle process) { | |
| 1290 // If the child is already dead, then there's nothing to do. | |
| 1291 if (IsChildDead(process)) | |
| 1292 return; | |
| 1293 | |
| 1294 const unsigned timeout = 2; // seconds | |
| 1295 BackgroundReaper* reaper = new BackgroundReaper(process, timeout); | |
| 1296 PlatformThread::CreateNonJoinable(0, reaper); | |
| 1297 } | |
| 1298 | |
| 1299 void EnsureProcessGetsReaped(ProcessHandle process) { | |
| 1300 // If the child is already dead, then there's nothing to do. | |
| 1301 if (IsChildDead(process)) | |
| 1302 return; | |
| 1303 | |
| 1304 BackgroundReaper* reaper = new BackgroundReaper(process, 0); | |
| 1305 PlatformThread::CreateNonJoinable(0, reaper); | |
| 1306 } | |
| 1307 | |
| 1308 #endif | |
|
willchan no longer on Chromium
2011/11/23 17:46:37
Up to you, but it's my personal preference to term
jam
2011/11/23 17:48:33
Done.
| |
| 1309 | |
| 1213 } // namespace base | 1310 } // namespace base |
| OLD | NEW |