kill_posix.cc revision 7dbb3d5cf0c15f500944d211057644d6a2f37371
1// Copyright (c) 2013 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 "base/process/kill.h" 6 7#include <signal.h> 8#include <sys/types.h> 9#include <sys/wait.h> 10#include <unistd.h> 11 12#include "base/file_util.h" 13#include "base/logging.h" 14#include "base/posix/eintr_wrapper.h" 15#include "base/process/process_iterator.h" 16#include "base/process_util.h" 17#include "base/synchronization/waitable_event.h" 18#include "base/third_party/dynamic_annotations/dynamic_annotations.h" 19#include "base/threading/platform_thread.h" 20 21namespace base { 22 23namespace { 24 25int WaitpidWithTimeout(ProcessHandle handle, 26 int64 wait_milliseconds, 27 bool* success) { 28 // This POSIX version of this function only guarantees that we wait no less 29 // than |wait_milliseconds| for the process to exit. The child process may 30 // exit sometime before the timeout has ended but we may still block for up 31 // to 256 milliseconds after the fact. 32 // 33 // waitpid() has no direct support on POSIX for specifying a timeout, you can 34 // either ask it to block indefinitely or return immediately (WNOHANG). 35 // When a child process terminates a SIGCHLD signal is sent to the parent. 36 // Catching this signal would involve installing a signal handler which may 37 // affect other parts of the application and would be difficult to debug. 38 // 39 // Our strategy is to call waitpid() once up front to check if the process 40 // has already exited, otherwise to loop for wait_milliseconds, sleeping for 41 // at most 256 milliseconds each time using usleep() and then calling 42 // waitpid(). The amount of time we sleep starts out at 1 milliseconds, and 43 // we double it every 4 sleep cycles. 44 // 45 // usleep() is speced to exit if a signal is received for which a handler 46 // has been installed. This means that when a SIGCHLD is sent, it will exit 47 // depending on behavior external to this function. 48 // 49 // This function is used primarily for unit tests, if we want to use it in 50 // the application itself it would probably be best to examine other routes. 51 int status = -1; 52 pid_t ret_pid = HANDLE_EINTR(waitpid(handle, &status, WNOHANG)); 53 static const int64 kMaxSleepInMicroseconds = 1 << 18; // ~256 milliseconds. 54 int64 max_sleep_time_usecs = 1 << 10; // ~1 milliseconds. 55 int64 double_sleep_time = 0; 56 57 // If the process hasn't exited yet, then sleep and try again. 58 TimeTicks wakeup_time = TimeTicks::Now() + 59 TimeDelta::FromMilliseconds(wait_milliseconds); 60 while (ret_pid == 0) { 61 TimeTicks now = TimeTicks::Now(); 62 if (now > wakeup_time) 63 break; 64 // Guaranteed to be non-negative! 65 int64 sleep_time_usecs = (wakeup_time - now).InMicroseconds(); 66 // Sleep for a bit while we wait for the process to finish. 67 if (sleep_time_usecs > max_sleep_time_usecs) 68 sleep_time_usecs = max_sleep_time_usecs; 69 70 // usleep() will return 0 and set errno to EINTR on receipt of a signal 71 // such as SIGCHLD. 72 usleep(sleep_time_usecs); 73 ret_pid = HANDLE_EINTR(waitpid(handle, &status, WNOHANG)); 74 75 if ((max_sleep_time_usecs < kMaxSleepInMicroseconds) && 76 (double_sleep_time++ % 4 == 0)) { 77 max_sleep_time_usecs *= 2; 78 } 79 } 80 81 if (success) 82 *success = (ret_pid != -1); 83 84 return status; 85} 86 87TerminationStatus GetTerminationStatusImpl(ProcessHandle handle, 88 bool can_block, 89 int* exit_code) { 90 int status = 0; 91 const pid_t result = HANDLE_EINTR(waitpid(handle, &status, 92 can_block ? 0 : WNOHANG)); 93 if (result == -1) { 94 DPLOG(ERROR) << "waitpid(" << handle << ")"; 95 if (exit_code) 96 *exit_code = 0; 97 return TERMINATION_STATUS_NORMAL_TERMINATION; 98 } else if (result == 0) { 99 // the child hasn't exited yet. 100 if (exit_code) 101 *exit_code = 0; 102 return TERMINATION_STATUS_STILL_RUNNING; 103 } 104 105 if (exit_code) 106 *exit_code = status; 107 108 if (WIFSIGNALED(status)) { 109 switch (WTERMSIG(status)) { 110 case SIGABRT: 111 case SIGBUS: 112 case SIGFPE: 113 case SIGILL: 114 case SIGSEGV: 115 return TERMINATION_STATUS_PROCESS_CRASHED; 116 case SIGINT: 117 case SIGKILL: 118 case SIGTERM: 119 return TERMINATION_STATUS_PROCESS_WAS_KILLED; 120 default: 121 break; 122 } 123 } 124 125 if (WIFEXITED(status) && WEXITSTATUS(status) != 0) 126 return TERMINATION_STATUS_ABNORMAL_TERMINATION; 127 128 return TERMINATION_STATUS_NORMAL_TERMINATION; 129} 130 131} // namespace 132 133// Attempts to kill the process identified by the given process 134// entry structure. Ignores specified exit_code; posix can't force that. 135// Returns true if this is successful, false otherwise. 136bool KillProcess(ProcessHandle process_id, int exit_code, bool wait) { 137 DCHECK_GT(process_id, 1) << " tried to kill invalid process_id"; 138 if (process_id <= 1) 139 return false; 140 bool result = kill(process_id, SIGTERM) == 0; 141 if (result && wait) { 142 int tries = 60; 143 144 if (RunningOnValgrind()) { 145 // Wait for some extra time when running under Valgrind since the child 146 // processes may take some time doing leak checking. 147 tries *= 2; 148 } 149 150 unsigned sleep_ms = 4; 151 152 // The process may not end immediately due to pending I/O 153 bool exited = false; 154 while (tries-- > 0) { 155 pid_t pid = HANDLE_EINTR(waitpid(process_id, NULL, WNOHANG)); 156 if (pid == process_id) { 157 exited = true; 158 break; 159 } 160 if (pid == -1) { 161 if (errno == ECHILD) { 162 // The wait may fail with ECHILD if another process also waited for 163 // the same pid, causing the process state to get cleaned up. 164 exited = true; 165 break; 166 } 167 DPLOG(ERROR) << "Error waiting for process " << process_id; 168 } 169 170 usleep(sleep_ms * 1000); 171 const unsigned kMaxSleepMs = 1000; 172 if (sleep_ms < kMaxSleepMs) 173 sleep_ms *= 2; 174 } 175 176 // If we're waiting and the child hasn't died by now, force it 177 // with a SIGKILL. 178 if (!exited) 179 result = kill(process_id, SIGKILL) == 0; 180 } 181 182 if (!result) 183 DPLOG(ERROR) << "Unable to terminate process " << process_id; 184 185 return result; 186} 187 188bool KillProcessGroup(ProcessHandle process_group_id) { 189 bool result = kill(-1 * process_group_id, SIGKILL) == 0; 190 if (!result) 191 DPLOG(ERROR) << "Unable to terminate process group " << process_group_id; 192 return result; 193} 194 195TerminationStatus GetTerminationStatus(ProcessHandle handle, int* exit_code) { 196 return GetTerminationStatusImpl(handle, false /* can_block */, exit_code); 197} 198 199TerminationStatus WaitForTerminationStatus(ProcessHandle handle, 200 int* exit_code) { 201 return GetTerminationStatusImpl(handle, true /* can_block */, exit_code); 202} 203 204bool WaitForExitCode(ProcessHandle handle, int* exit_code) { 205 int status; 206 if (HANDLE_EINTR(waitpid(handle, &status, 0)) == -1) { 207 NOTREACHED(); 208 return false; 209 } 210 211 if (WIFEXITED(status)) { 212 *exit_code = WEXITSTATUS(status); 213 return true; 214 } 215 216 // If it didn't exit cleanly, it must have been signaled. 217 DCHECK(WIFSIGNALED(status)); 218 return false; 219} 220 221bool WaitForExitCodeWithTimeout(ProcessHandle handle, 222 int* exit_code, 223 base::TimeDelta timeout) { 224 bool waitpid_success = false; 225 int status = WaitpidWithTimeout(handle, timeout.InMilliseconds(), 226 &waitpid_success); 227 if (status == -1) 228 return false; 229 if (!waitpid_success) 230 return false; 231 if (WIFSIGNALED(status)) { 232 *exit_code = -1; 233 return true; 234 } 235 if (WIFEXITED(status)) { 236 *exit_code = WEXITSTATUS(status); 237 return true; 238 } 239 return false; 240} 241 242bool WaitForProcessesToExit(const FilePath::StringType& executable_name, 243 base::TimeDelta wait, 244 const ProcessFilter* filter) { 245 bool result = false; 246 247 // TODO(port): This is inefficient, but works if there are multiple procs. 248 // TODO(port): use waitpid to avoid leaving zombies around 249 250 base::TimeTicks end_time = base::TimeTicks::Now() + wait; 251 do { 252 NamedProcessIterator iter(executable_name, filter); 253 if (!iter.NextProcessEntry()) { 254 result = true; 255 break; 256 } 257 base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(100)); 258 } while ((end_time - base::TimeTicks::Now()) > base::TimeDelta()); 259 260 return result; 261} 262 263#if defined(OS_MACOSX) 264// Using kqueue on Mac so that we can wait on non-child processes. 265// We can't use kqueues on child processes because we need to reap 266// our own children using wait. 267static bool WaitForSingleNonChildProcess(ProcessHandle handle, 268 base::TimeDelta wait) { 269 DCHECK_GT(handle, 0); 270 DCHECK(wait.InMilliseconds() == base::kNoTimeout || wait > base::TimeDelta()); 271 272 int kq = kqueue(); 273 if (kq == -1) { 274 DPLOG(ERROR) << "kqueue"; 275 return false; 276 } 277 file_util::ScopedFD kq_closer(&kq); 278 279 struct kevent change = {0}; 280 EV_SET(&change, handle, EVFILT_PROC, EV_ADD, NOTE_EXIT, 0, NULL); 281 int result = HANDLE_EINTR(kevent(kq, &change, 1, NULL, 0, NULL)); 282 if (result == -1) { 283 if (errno == ESRCH) { 284 // If the process wasn't found, it must be dead. 285 return true; 286 } 287 288 DPLOG(ERROR) << "kevent (setup " << handle << ")"; 289 return false; 290 } 291 292 // Keep track of the elapsed time to be able to restart kevent if it's 293 // interrupted. 294 bool wait_forever = wait.InMilliseconds() == base::kNoTimeout; 295 base::TimeDelta remaining_delta; 296 base::TimeTicks deadline; 297 if (!wait_forever) { 298 remaining_delta = wait; 299 deadline = base::TimeTicks::Now() + remaining_delta; 300 } 301 302 result = -1; 303 struct kevent event = {0}; 304 305 while (wait_forever || remaining_delta > base::TimeDelta()) { 306 struct timespec remaining_timespec; 307 struct timespec* remaining_timespec_ptr; 308 if (wait_forever) { 309 remaining_timespec_ptr = NULL; 310 } else { 311 remaining_timespec = remaining_delta.ToTimeSpec(); 312 remaining_timespec_ptr = &remaining_timespec; 313 } 314 315 result = kevent(kq, NULL, 0, &event, 1, remaining_timespec_ptr); 316 317 if (result == -1 && errno == EINTR) { 318 if (!wait_forever) { 319 remaining_delta = deadline - base::TimeTicks::Now(); 320 } 321 result = 0; 322 } else { 323 break; 324 } 325 } 326 327 if (result < 0) { 328 DPLOG(ERROR) << "kevent (wait " << handle << ")"; 329 return false; 330 } else if (result > 1) { 331 DLOG(ERROR) << "kevent (wait " << handle << "): unexpected result " 332 << result; 333 return false; 334 } else if (result == 0) { 335 // Timed out. 336 return false; 337 } 338 339 DCHECK_EQ(result, 1); 340 341 if (event.filter != EVFILT_PROC || 342 (event.fflags & NOTE_EXIT) == 0 || 343 event.ident != static_cast<uintptr_t>(handle)) { 344 DLOG(ERROR) << "kevent (wait " << handle 345 << "): unexpected event: filter=" << event.filter 346 << ", fflags=" << event.fflags 347 << ", ident=" << event.ident; 348 return false; 349 } 350 351 return true; 352} 353#endif // OS_MACOSX 354 355bool WaitForSingleProcess(ProcessHandle handle, base::TimeDelta wait) { 356 ProcessHandle parent_pid = GetParentProcessId(handle); 357 ProcessHandle our_pid = Process::Current().handle(); 358 if (parent_pid != our_pid) { 359#if defined(OS_MACOSX) 360 // On Mac we can wait on non child processes. 361 return WaitForSingleNonChildProcess(handle, wait); 362#else 363 // Currently on Linux we can't handle non child processes. 364 NOTIMPLEMENTED(); 365#endif // OS_MACOSX 366 } 367 368 bool waitpid_success; 369 int status = -1; 370 if (wait.InMilliseconds() == base::kNoTimeout) { 371 waitpid_success = (HANDLE_EINTR(waitpid(handle, &status, 0)) != -1); 372 } else { 373 status = WaitpidWithTimeout( 374 handle, wait.InMilliseconds(), &waitpid_success); 375 } 376 377 if (status != -1) { 378 DCHECK(waitpid_success); 379 return WIFEXITED(status); 380 } else { 381 return false; 382 } 383} 384 385bool CleanupProcesses(const FilePath::StringType& executable_name, 386 base::TimeDelta wait, 387 int exit_code, 388 const ProcessFilter* filter) { 389 bool exited_cleanly = WaitForProcessesToExit(executable_name, wait, filter); 390 if (!exited_cleanly) 391 KillProcesses(executable_name, exit_code, filter); 392 return exited_cleanly; 393} 394 395#if !defined(OS_MACOSX) 396 397namespace { 398 399// Return true if the given child is dead. This will also reap the process. 400// Doesn't block. 401static bool IsChildDead(pid_t child) { 402 const pid_t result = HANDLE_EINTR(waitpid(child, NULL, WNOHANG)); 403 if (result == -1) { 404 DPLOG(ERROR) << "waitpid(" << child << ")"; 405 NOTREACHED(); 406 } else if (result > 0) { 407 // The child has died. 408 return true; 409 } 410 411 return false; 412} 413 414// A thread class which waits for the given child to exit and reaps it. 415// If the child doesn't exit within a couple of seconds, kill it. 416class BackgroundReaper : public PlatformThread::Delegate { 417 public: 418 BackgroundReaper(pid_t child, unsigned timeout) 419 : child_(child), 420 timeout_(timeout) { 421 } 422 423 // Overridden from PlatformThread::Delegate: 424 virtual void ThreadMain() OVERRIDE { 425 WaitForChildToDie(); 426 delete this; 427 } 428 429 void WaitForChildToDie() { 430 // Wait forever case. 431 if (timeout_ == 0) { 432 pid_t r = HANDLE_EINTR(waitpid(child_, NULL, 0)); 433 if (r != child_) { 434 DPLOG(ERROR) << "While waiting for " << child_ 435 << " to terminate, we got the following result: " << r; 436 } 437 return; 438 } 439 440 // There's no good way to wait for a specific child to exit in a timed 441 // fashion. (No kqueue on Linux), so we just loop and sleep. 442 443 // Wait for 2 * timeout_ 500 milliseconds intervals. 444 for (unsigned i = 0; i < 2 * timeout_; ++i) { 445 PlatformThread::Sleep(TimeDelta::FromMilliseconds(500)); 446 if (IsChildDead(child_)) 447 return; 448 } 449 450 if (kill(child_, SIGKILL) == 0) { 451 // SIGKILL is uncatchable. Since the signal was delivered, we can 452 // just wait for the process to die now in a blocking manner. 453 if (HANDLE_EINTR(waitpid(child_, NULL, 0)) < 0) 454 DPLOG(WARNING) << "waitpid"; 455 } else { 456 DLOG(ERROR) << "While waiting for " << child_ << " to terminate we" 457 << " failed to deliver a SIGKILL signal (" << errno << ")."; 458 } 459 } 460 461 private: 462 const pid_t child_; 463 // Number of seconds to wait, if 0 then wait forever and do not attempt to 464 // kill |child_|. 465 const unsigned timeout_; 466 467 DISALLOW_COPY_AND_ASSIGN(BackgroundReaper); 468}; 469 470} // namespace 471 472void EnsureProcessTerminated(ProcessHandle process) { 473 // If the child is already dead, then there's nothing to do. 474 if (IsChildDead(process)) 475 return; 476 477 const unsigned timeout = 2; // seconds 478 BackgroundReaper* reaper = new BackgroundReaper(process, timeout); 479 PlatformThread::CreateNonJoinable(0, reaper); 480} 481 482void EnsureProcessGetsReaped(ProcessHandle process) { 483 // If the child is already dead, then there's nothing to do. 484 if (IsChildDead(process)) 485 return; 486 487 BackgroundReaper* reaper = new BackgroundReaper(process, 0); 488 PlatformThread::CreateNonJoinable(0, reaper); 489} 490 491#endif // !defined(OS_MACOSX) 492 493} // namespace base 494