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/files/scoped_file.h" 14#include "base/logging.h" 15#include "base/posix/eintr_wrapper.h" 16#include "base/process/process_iterator.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 25bool WaitpidWithTimeout(ProcessHandle handle, 26 int* status, 27 base::TimeDelta wait) { 28 // This POSIX version of this function only guarantees that we wait no less 29 // than |wait| 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|, 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 52 if (wait.InMilliseconds() == base::kNoTimeout) { 53 return HANDLE_EINTR(waitpid(handle, status, 0)) > 0; 54 } 55 56 pid_t ret_pid = HANDLE_EINTR(waitpid(handle, status, WNOHANG)); 57 static const int64 kMaxSleepInMicroseconds = 1 << 18; // ~256 milliseconds. 58 int64 max_sleep_time_usecs = 1 << 10; // ~1 milliseconds. 59 int64 double_sleep_time = 0; 60 61 // If the process hasn't exited yet, then sleep and try again. 62 TimeTicks wakeup_time = TimeTicks::Now() + wait; 63 while (ret_pid == 0) { 64 TimeTicks now = TimeTicks::Now(); 65 if (now > wakeup_time) 66 break; 67 // Guaranteed to be non-negative! 68 int64 sleep_time_usecs = (wakeup_time - now).InMicroseconds(); 69 // Sleep for a bit while we wait for the process to finish. 70 if (sleep_time_usecs > max_sleep_time_usecs) 71 sleep_time_usecs = max_sleep_time_usecs; 72 73 // usleep() will return 0 and set errno to EINTR on receipt of a signal 74 // such as SIGCHLD. 75 usleep(sleep_time_usecs); 76 ret_pid = HANDLE_EINTR(waitpid(handle, status, WNOHANG)); 77 78 if ((max_sleep_time_usecs < kMaxSleepInMicroseconds) && 79 (double_sleep_time++ % 4 == 0)) { 80 max_sleep_time_usecs *= 2; 81 } 82 } 83 84 return ret_pid > 0; 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 GetKnownDeadTerminationStatus(ProcessHandle handle, 200 int* exit_code) { 201 bool result = kill(handle, SIGKILL) == 0; 202 203 if (!result) 204 DPLOG(ERROR) << "Unable to terminate process " << handle; 205 206 return GetTerminationStatusImpl(handle, true /* can_block */, exit_code); 207} 208 209bool WaitForExitCode(ProcessHandle handle, int* exit_code) { 210 int status; 211 if (HANDLE_EINTR(waitpid(handle, &status, 0)) == -1) { 212 NOTREACHED(); 213 return false; 214 } 215 216 if (WIFEXITED(status)) { 217 *exit_code = WEXITSTATUS(status); 218 return true; 219 } 220 221 // If it didn't exit cleanly, it must have been signaled. 222 DCHECK(WIFSIGNALED(status)); 223 return false; 224} 225 226bool WaitForExitCodeWithTimeout(ProcessHandle handle, 227 int* exit_code, 228 base::TimeDelta timeout) { 229 int status; 230 if (!WaitpidWithTimeout(handle, &status, timeout)) 231 return false; 232 if (WIFSIGNALED(status)) { 233 *exit_code = -1; 234 return true; 235 } 236 if (WIFEXITED(status)) { 237 *exit_code = WEXITSTATUS(status); 238 return true; 239 } 240 return false; 241} 242 243bool WaitForProcessesToExit(const FilePath::StringType& executable_name, 244 base::TimeDelta wait, 245 const ProcessFilter* filter) { 246 bool result = false; 247 248 // TODO(port): This is inefficient, but works if there are multiple procs. 249 // TODO(port): use waitpid to avoid leaving zombies around 250 251 base::TimeTicks end_time = base::TimeTicks::Now() + wait; 252 do { 253 NamedProcessIterator iter(executable_name, filter); 254 if (!iter.NextProcessEntry()) { 255 result = true; 256 break; 257 } 258 base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(100)); 259 } while ((end_time - base::TimeTicks::Now()) > base::TimeDelta()); 260 261 return result; 262} 263 264#if defined(OS_MACOSX) 265// Using kqueue on Mac so that we can wait on non-child processes. 266// We can't use kqueues on child processes because we need to reap 267// our own children using wait. 268static bool WaitForSingleNonChildProcess(ProcessHandle handle, 269 base::TimeDelta wait) { 270 DCHECK_GT(handle, 0); 271 DCHECK(wait.InMilliseconds() == base::kNoTimeout || wait > base::TimeDelta()); 272 273 ScopedFD kq(kqueue()); 274 if (!kq.is_valid()) { 275 DPLOG(ERROR) << "kqueue"; 276 return false; 277 } 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.get(), &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.get(), 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 int status; 369 if (!WaitpidWithTimeout(handle, &status, wait)) 370 return false; 371 return WIFEXITED(status); 372} 373 374bool CleanupProcesses(const FilePath::StringType& executable_name, 375 base::TimeDelta wait, 376 int exit_code, 377 const ProcessFilter* filter) { 378 bool exited_cleanly = WaitForProcessesToExit(executable_name, wait, filter); 379 if (!exited_cleanly) 380 KillProcesses(executable_name, exit_code, filter); 381 return exited_cleanly; 382} 383 384#if !defined(OS_MACOSX) 385 386namespace { 387 388// Return true if the given child is dead. This will also reap the process. 389// Doesn't block. 390static bool IsChildDead(pid_t child) { 391 const pid_t result = HANDLE_EINTR(waitpid(child, NULL, WNOHANG)); 392 if (result == -1) { 393 DPLOG(ERROR) << "waitpid(" << child << ")"; 394 NOTREACHED(); 395 } else if (result > 0) { 396 // The child has died. 397 return true; 398 } 399 400 return false; 401} 402 403// A thread class which waits for the given child to exit and reaps it. 404// If the child doesn't exit within a couple of seconds, kill it. 405class BackgroundReaper : public PlatformThread::Delegate { 406 public: 407 BackgroundReaper(pid_t child, unsigned timeout) 408 : child_(child), 409 timeout_(timeout) { 410 } 411 412 // Overridden from PlatformThread::Delegate: 413 virtual void ThreadMain() OVERRIDE { 414 WaitForChildToDie(); 415 delete this; 416 } 417 418 void WaitForChildToDie() { 419 // Wait forever case. 420 if (timeout_ == 0) { 421 pid_t r = HANDLE_EINTR(waitpid(child_, NULL, 0)); 422 if (r != child_) { 423 DPLOG(ERROR) << "While waiting for " << child_ 424 << " to terminate, we got the following result: " << r; 425 } 426 return; 427 } 428 429 // There's no good way to wait for a specific child to exit in a timed 430 // fashion. (No kqueue on Linux), so we just loop and sleep. 431 432 // Wait for 2 * timeout_ 500 milliseconds intervals. 433 for (unsigned i = 0; i < 2 * timeout_; ++i) { 434 PlatformThread::Sleep(TimeDelta::FromMilliseconds(500)); 435 if (IsChildDead(child_)) 436 return; 437 } 438 439 if (kill(child_, SIGKILL) == 0) { 440 // SIGKILL is uncatchable. Since the signal was delivered, we can 441 // just wait for the process to die now in a blocking manner. 442 if (HANDLE_EINTR(waitpid(child_, NULL, 0)) < 0) 443 DPLOG(WARNING) << "waitpid"; 444 } else { 445 DLOG(ERROR) << "While waiting for " << child_ << " to terminate we" 446 << " failed to deliver a SIGKILL signal (" << errno << ")."; 447 } 448 } 449 450 private: 451 const pid_t child_; 452 // Number of seconds to wait, if 0 then wait forever and do not attempt to 453 // kill |child_|. 454 const unsigned timeout_; 455 456 DISALLOW_COPY_AND_ASSIGN(BackgroundReaper); 457}; 458 459} // namespace 460 461void EnsureProcessTerminated(ProcessHandle process) { 462 // If the child is already dead, then there's nothing to do. 463 if (IsChildDead(process)) 464 return; 465 466 const unsigned timeout = 2; // seconds 467 BackgroundReaper* reaper = new BackgroundReaper(process, timeout); 468 PlatformThread::CreateNonJoinable(0, reaper); 469} 470 471void EnsureProcessGetsReaped(ProcessHandle process) { 472 // If the child is already dead, then there's nothing to do. 473 if (IsChildDead(process)) 474 return; 475 476 BackgroundReaper* reaper = new BackgroundReaper(process, 0); 477 PlatformThread::CreateNonJoinable(0, reaper); 478} 479 480#endif // !defined(OS_MACOSX) 481 482} // namespace base 483