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