| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 67 // Set the process's "environment" (i.e. the thing that setenv/getenv | 67 // Set the process's "environment" (i.e. the thing that setenv/getenv |
| 68 // work with). | 68 // work with). |
| 69 void SetEnvironment(char** env) { | 69 void SetEnvironment(char** env) { |
| 70 #if defined(OS_MACOSX) | 70 #if defined(OS_MACOSX) |
| 71 *_NSGetEnviron() = env; | 71 *_NSGetEnviron() = env; |
| 72 #else | 72 #else |
| 73 environ = env; | 73 environ = env; |
| 74 #endif | 74 #endif |
| 75 } | 75 } |
| 76 | 76 |
| 77 int WaitpidWithTimeout(ProcessHandle handle, int64 wait_milliseconds, | |
| 78 bool* success) { | |
| 79 // This POSIX version of this function only guarantees that we wait no less | |
| 80 // than |wait_milliseconds| for the process to exit. The child process may | |
| 81 // exit sometime before the timeout has ended but we may still block for up | |
| 82 // to 256 milliseconds after the fact. | |
| 83 // | |
| 84 // waitpid() has no direct support on POSIX for specifying a timeout, you can | |
| 85 // either ask it to block indefinitely or return immediately (WNOHANG). | |
| 86 // When a child process terminates a SIGCHLD signal is sent to the parent. | |
| 87 // Catching this signal would involve installing a signal handler which may | |
| 88 // affect other parts of the application and would be difficult to debug. | |
| 89 // | |
| 90 // Our strategy is to call waitpid() once up front to check if the process | |
| 91 // has already exited, otherwise to loop for wait_milliseconds, sleeping for | |
| 92 // at most 256 milliseconds each time using usleep() and then calling | |
| 93 // waitpid(). The amount of time we sleep starts out at 1 milliseconds, and | |
| 94 // we double it every 4 sleep cycles. | |
| 95 // | |
| 96 // usleep() is speced to exit if a signal is received for which a handler | |
| 97 // has been installed. This means that when a SIGCHLD is sent, it will exit | |
| 98 // depending on behavior external to this function. | |
| 99 // | |
| 100 // This function is used primarily for unit tests, if we want to use it in | |
| 101 // the application itself it would probably be best to examine other routes. | |
| 102 int status = -1; | |
| 103 pid_t ret_pid = HANDLE_EINTR(waitpid(handle, &status, WNOHANG)); | |
| 104 static const int64 kMaxSleepInMicroseconds = 1 << 18; // ~256 milliseconds. | |
| 105 int64 max_sleep_time_usecs = 1 << 10; // ~1 milliseconds. | |
| 106 int64 double_sleep_time = 0; | |
| 107 | |
| 108 // If the process hasn't exited yet, then sleep and try again. | |
| 109 TimeTicks wakeup_time = TimeTicks::Now() + | |
| 110 TimeDelta::FromMilliseconds(wait_milliseconds); | |
| 111 while (ret_pid == 0) { | |
| 112 TimeTicks now = TimeTicks::Now(); | |
| 113 if (now > wakeup_time) | |
| 114 break; | |
| 115 // Guaranteed to be non-negative! | |
| 116 int64 sleep_time_usecs = (wakeup_time - now).InMicroseconds(); | |
| 117 // Sleep for a bit while we wait for the process to finish. | |
| 118 if (sleep_time_usecs > max_sleep_time_usecs) | |
| 119 sleep_time_usecs = max_sleep_time_usecs; | |
| 120 | |
| 121 // usleep() will return 0 and set errno to EINTR on receipt of a signal | |
| 122 // such as SIGCHLD. | |
| 123 usleep(sleep_time_usecs); | |
| 124 ret_pid = HANDLE_EINTR(waitpid(handle, &status, WNOHANG)); | |
| 125 | |
| 126 if ((max_sleep_time_usecs < kMaxSleepInMicroseconds) && | |
| 127 (double_sleep_time++ % 4 == 0)) { | |
| 128 max_sleep_time_usecs *= 2; | |
| 129 } | |
| 130 } | |
| 131 | |
| 132 if (success) | |
| 133 *success = (ret_pid != -1); | |
| 134 | |
| 135 return status; | |
| 136 } | |
| 137 | |
| 138 #if !defined(OS_LINUX) || \ | 77 #if !defined(OS_LINUX) || \ |
| 139 (!defined(__i386__) && !defined(__x86_64__) && !defined(__arm__)) | 78 (!defined(__i386__) && !defined(__x86_64__) && !defined(__arm__)) |
| 140 void ResetChildSignalHandlersToDefaults() { | 79 void ResetChildSignalHandlersToDefaults() { |
| 141 // The previous signal handlers are likely to be meaningless in the child's | 80 // The previous signal handlers are likely to be meaningless in the child's |
| 142 // context so we reset them to the defaults for now. http://crbug.com/44953 | 81 // context so we reset them to the defaults for now. http://crbug.com/44953 |
| 143 // These signal handlers are set up at least in browser_main_posix.cc: | 82 // These signal handlers are set up at least in browser_main_posix.cc: |
| 144 // BrowserMainPartsPosix::PreEarlyInitialization and stack_trace_posix.cc: | 83 // BrowserMainPartsPosix::PreEarlyInitialization and stack_trace_posix.cc: |
| 145 // EnableInProcessStackDumping. | 84 // EnableInProcessStackDumping. |
| 146 signal(SIGHUP, SIG_DFL); | 85 signal(SIGHUP, SIG_DFL); |
| 147 signal(SIGINT, SIG_DFL); | 86 signal(SIGINT, SIG_DFL); |
| (...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 214 // Now ask the kernel again and check that no restorer will leak. | 153 // Now ask the kernel again and check that no restorer will leak. |
| 215 if (sys_rt_sigaction(signum, NULL, &act) || act.k_sa_restorer) { | 154 if (sys_rt_sigaction(signum, NULL, &act) || act.k_sa_restorer) { |
| 216 RAW_LOG(FATAL, "Cound not fix sa_restorer."); | 155 RAW_LOG(FATAL, "Cound not fix sa_restorer."); |
| 217 } | 156 } |
| 218 #endif // !defined(NDEBUG) | 157 #endif // !defined(NDEBUG) |
| 219 } | 158 } |
| 220 } | 159 } |
| 221 #endif // !defined(OS_LINUX) || | 160 #endif // !defined(OS_LINUX) || |
| 222 // (!defined(__i386__) && !defined(__x86_64__) && !defined(__arm__)) | 161 // (!defined(__i386__) && !defined(__x86_64__) && !defined(__arm__)) |
| 223 | 162 |
| 224 TerminationStatus GetTerminationStatusImpl(ProcessHandle handle, | |
| 225 bool can_block, | |
| 226 int* exit_code) { | |
| 227 int status = 0; | |
| 228 const pid_t result = HANDLE_EINTR(waitpid(handle, &status, | |
| 229 can_block ? 0 : WNOHANG)); | |
| 230 if (result == -1) { | |
| 231 DPLOG(ERROR) << "waitpid(" << handle << ")"; | |
| 232 if (exit_code) | |
| 233 *exit_code = 0; | |
| 234 return TERMINATION_STATUS_NORMAL_TERMINATION; | |
| 235 } else if (result == 0) { | |
| 236 // the child hasn't exited yet. | |
| 237 if (exit_code) | |
| 238 *exit_code = 0; | |
| 239 return TERMINATION_STATUS_STILL_RUNNING; | |
| 240 } | |
| 241 | |
| 242 if (exit_code) | |
| 243 *exit_code = status; | |
| 244 | |
| 245 if (WIFSIGNALED(status)) { | |
| 246 switch (WTERMSIG(status)) { | |
| 247 case SIGABRT: | |
| 248 case SIGBUS: | |
| 249 case SIGFPE: | |
| 250 case SIGILL: | |
| 251 case SIGSEGV: | |
| 252 return TERMINATION_STATUS_PROCESS_CRASHED; | |
| 253 case SIGINT: | |
| 254 case SIGKILL: | |
| 255 case SIGTERM: | |
| 256 return TERMINATION_STATUS_PROCESS_WAS_KILLED; | |
| 257 default: | |
| 258 break; | |
| 259 } | |
| 260 } | |
| 261 | |
| 262 if (WIFEXITED(status) && WEXITSTATUS(status) != 0) | |
| 263 return TERMINATION_STATUS_ABNORMAL_TERMINATION; | |
| 264 | |
| 265 return TERMINATION_STATUS_NORMAL_TERMINATION; | |
| 266 } | |
| 267 | |
| 268 } // anonymous namespace | 163 } // anonymous namespace |
| 269 | 164 |
| 270 ProcessId GetCurrentProcId() { | 165 ProcessId GetCurrentProcId() { |
| 271 return getpid(); | 166 return getpid(); |
| 272 } | 167 } |
| 273 | 168 |
| 274 ProcessHandle GetCurrentProcessHandle() { | 169 ProcessHandle GetCurrentProcessHandle() { |
| 275 return GetCurrentProcId(); | 170 return GetCurrentProcId(); |
| 276 } | 171 } |
| 277 | 172 |
| (...skipping 20 matching lines...) Expand all Loading... |
| 298 | 193 |
| 299 void CloseProcessHandle(ProcessHandle process) { | 194 void CloseProcessHandle(ProcessHandle process) { |
| 300 // See OpenProcessHandle, nothing to do. | 195 // See OpenProcessHandle, nothing to do. |
| 301 return; | 196 return; |
| 302 } | 197 } |
| 303 | 198 |
| 304 ProcessId GetProcId(ProcessHandle process) { | 199 ProcessId GetProcId(ProcessHandle process) { |
| 305 return process; | 200 return process; |
| 306 } | 201 } |
| 307 | 202 |
| 308 // Attempts to kill the process identified by the given process | |
| 309 // entry structure. Ignores specified exit_code; posix can't force that. | |
| 310 // Returns true if this is successful, false otherwise. | |
| 311 bool KillProcess(ProcessHandle process_id, int exit_code, bool wait) { | |
| 312 DCHECK_GT(process_id, 1) << " tried to kill invalid process_id"; | |
| 313 if (process_id <= 1) | |
| 314 return false; | |
| 315 bool result = kill(process_id, SIGTERM) == 0; | |
| 316 if (result && wait) { | |
| 317 int tries = 60; | |
| 318 | |
| 319 if (RunningOnValgrind()) { | |
| 320 // Wait for some extra time when running under Valgrind since the child | |
| 321 // processes may take some time doing leak checking. | |
| 322 tries *= 2; | |
| 323 } | |
| 324 | |
| 325 unsigned sleep_ms = 4; | |
| 326 | |
| 327 // The process may not end immediately due to pending I/O | |
| 328 bool exited = false; | |
| 329 while (tries-- > 0) { | |
| 330 pid_t pid = HANDLE_EINTR(waitpid(process_id, NULL, WNOHANG)); | |
| 331 if (pid == process_id) { | |
| 332 exited = true; | |
| 333 break; | |
| 334 } | |
| 335 if (pid == -1) { | |
| 336 if (errno == ECHILD) { | |
| 337 // The wait may fail with ECHILD if another process also waited for | |
| 338 // the same pid, causing the process state to get cleaned up. | |
| 339 exited = true; | |
| 340 break; | |
| 341 } | |
| 342 DPLOG(ERROR) << "Error waiting for process " << process_id; | |
| 343 } | |
| 344 | |
| 345 usleep(sleep_ms * 1000); | |
| 346 const unsigned kMaxSleepMs = 1000; | |
| 347 if (sleep_ms < kMaxSleepMs) | |
| 348 sleep_ms *= 2; | |
| 349 } | |
| 350 | |
| 351 // If we're waiting and the child hasn't died by now, force it | |
| 352 // with a SIGKILL. | |
| 353 if (!exited) | |
| 354 result = kill(process_id, SIGKILL) == 0; | |
| 355 } | |
| 356 | |
| 357 if (!result) | |
| 358 DPLOG(ERROR) << "Unable to terminate process " << process_id; | |
| 359 | |
| 360 return result; | |
| 361 } | |
| 362 | |
| 363 bool KillProcessGroup(ProcessHandle process_group_id) { | |
| 364 bool result = kill(-1 * process_group_id, SIGKILL) == 0; | |
| 365 if (!result) | |
| 366 DPLOG(ERROR) << "Unable to terminate process group " << process_group_id; | |
| 367 return result; | |
| 368 } | |
| 369 | |
| 370 // A class to handle auto-closing of DIR*'s. | 203 // A class to handle auto-closing of DIR*'s. |
| 371 class ScopedDIRClose { | 204 class ScopedDIRClose { |
| 372 public: | 205 public: |
| 373 inline void operator()(DIR* x) const { | 206 inline void operator()(DIR* x) const { |
| 374 if (x) { | 207 if (x) { |
| 375 closedir(x); | 208 closedir(x); |
| 376 } | 209 } |
| 377 } | 210 } |
| 378 }; | 211 }; |
| 379 typedef scoped_ptr_malloc<DIR, ScopedDIRClose> ScopedDIR; | 212 typedef scoped_ptr_malloc<DIR, ScopedDIRClose> ScopedDIR; |
| (...skipping 389 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 769 const LaunchOptions& options, | 602 const LaunchOptions& options, |
| 770 ProcessHandle* process_handle) { | 603 ProcessHandle* process_handle) { |
| 771 return LaunchProcess(cmdline.argv(), options, process_handle); | 604 return LaunchProcess(cmdline.argv(), options, process_handle); |
| 772 } | 605 } |
| 773 | 606 |
| 774 void RaiseProcessToHighPriority() { | 607 void RaiseProcessToHighPriority() { |
| 775 // On POSIX, we don't actually do anything here. We could try to nice() or | 608 // On POSIX, we don't actually do anything here. We could try to nice() or |
| 776 // setpriority() or sched_getscheduler, but these all require extra rights. | 609 // setpriority() or sched_getscheduler, but these all require extra rights. |
| 777 } | 610 } |
| 778 | 611 |
| 779 TerminationStatus GetTerminationStatus(ProcessHandle handle, int* exit_code) { | |
| 780 return GetTerminationStatusImpl(handle, false /* can_block */, exit_code); | |
| 781 } | |
| 782 | |
| 783 TerminationStatus WaitForTerminationStatus(ProcessHandle handle, | |
| 784 int* exit_code) { | |
| 785 return GetTerminationStatusImpl(handle, true /* can_block */, exit_code); | |
| 786 } | |
| 787 | |
| 788 bool WaitForExitCode(ProcessHandle handle, int* exit_code) { | |
| 789 int status; | |
| 790 if (HANDLE_EINTR(waitpid(handle, &status, 0)) == -1) { | |
| 791 NOTREACHED(); | |
| 792 return false; | |
| 793 } | |
| 794 | |
| 795 if (WIFEXITED(status)) { | |
| 796 *exit_code = WEXITSTATUS(status); | |
| 797 return true; | |
| 798 } | |
| 799 | |
| 800 // If it didn't exit cleanly, it must have been signaled. | |
| 801 DCHECK(WIFSIGNALED(status)); | |
| 802 return false; | |
| 803 } | |
| 804 | |
| 805 bool WaitForExitCodeWithTimeout(ProcessHandle handle, int* exit_code, | |
| 806 base::TimeDelta timeout) { | |
| 807 bool waitpid_success = false; | |
| 808 int status = WaitpidWithTimeout(handle, timeout.InMilliseconds(), | |
| 809 &waitpid_success); | |
| 810 if (status == -1) | |
| 811 return false; | |
| 812 if (!waitpid_success) | |
| 813 return false; | |
| 814 if (WIFSIGNALED(status)) { | |
| 815 *exit_code = -1; | |
| 816 return true; | |
| 817 } | |
| 818 if (WIFEXITED(status)) { | |
| 819 *exit_code = WEXITSTATUS(status); | |
| 820 return true; | |
| 821 } | |
| 822 return false; | |
| 823 } | |
| 824 | |
| 825 #if defined(OS_MACOSX) | |
| 826 // Using kqueue on Mac so that we can wait on non-child processes. | |
| 827 // We can't use kqueues on child processes because we need to reap | |
| 828 // our own children using wait. | |
| 829 static bool WaitForSingleNonChildProcess(ProcessHandle handle, | |
| 830 base::TimeDelta wait) { | |
| 831 DCHECK_GT(handle, 0); | |
| 832 DCHECK(wait.InMilliseconds() == base::kNoTimeout || wait > base::TimeDelta()); | |
| 833 | |
| 834 int kq = kqueue(); | |
| 835 if (kq == -1) { | |
| 836 DPLOG(ERROR) << "kqueue"; | |
| 837 return false; | |
| 838 } | |
| 839 file_util::ScopedFD kq_closer(&kq); | |
| 840 | |
| 841 struct kevent change = {0}; | |
| 842 EV_SET(&change, handle, EVFILT_PROC, EV_ADD, NOTE_EXIT, 0, NULL); | |
| 843 int result = HANDLE_EINTR(kevent(kq, &change, 1, NULL, 0, NULL)); | |
| 844 if (result == -1) { | |
| 845 if (errno == ESRCH) { | |
| 846 // If the process wasn't found, it must be dead. | |
| 847 return true; | |
| 848 } | |
| 849 | |
| 850 DPLOG(ERROR) << "kevent (setup " << handle << ")"; | |
| 851 return false; | |
| 852 } | |
| 853 | |
| 854 // Keep track of the elapsed time to be able to restart kevent if it's | |
| 855 // interrupted. | |
| 856 bool wait_forever = wait.InMilliseconds() == base::kNoTimeout; | |
| 857 base::TimeDelta remaining_delta; | |
| 858 base::TimeTicks deadline; | |
| 859 if (!wait_forever) { | |
| 860 remaining_delta = wait; | |
| 861 deadline = base::TimeTicks::Now() + remaining_delta; | |
| 862 } | |
| 863 | |
| 864 result = -1; | |
| 865 struct kevent event = {0}; | |
| 866 | |
| 867 while (wait_forever || remaining_delta > base::TimeDelta()) { | |
| 868 struct timespec remaining_timespec; | |
| 869 struct timespec* remaining_timespec_ptr; | |
| 870 if (wait_forever) { | |
| 871 remaining_timespec_ptr = NULL; | |
| 872 } else { | |
| 873 remaining_timespec = remaining_delta.ToTimeSpec(); | |
| 874 remaining_timespec_ptr = &remaining_timespec; | |
| 875 } | |
| 876 | |
| 877 result = kevent(kq, NULL, 0, &event, 1, remaining_timespec_ptr); | |
| 878 | |
| 879 if (result == -1 && errno == EINTR) { | |
| 880 if (!wait_forever) { | |
| 881 remaining_delta = deadline - base::TimeTicks::Now(); | |
| 882 } | |
| 883 result = 0; | |
| 884 } else { | |
| 885 break; | |
| 886 } | |
| 887 } | |
| 888 | |
| 889 if (result < 0) { | |
| 890 DPLOG(ERROR) << "kevent (wait " << handle << ")"; | |
| 891 return false; | |
| 892 } else if (result > 1) { | |
| 893 DLOG(ERROR) << "kevent (wait " << handle << "): unexpected result " | |
| 894 << result; | |
| 895 return false; | |
| 896 } else if (result == 0) { | |
| 897 // Timed out. | |
| 898 return false; | |
| 899 } | |
| 900 | |
| 901 DCHECK_EQ(result, 1); | |
| 902 | |
| 903 if (event.filter != EVFILT_PROC || | |
| 904 (event.fflags & NOTE_EXIT) == 0 || | |
| 905 event.ident != static_cast<uintptr_t>(handle)) { | |
| 906 DLOG(ERROR) << "kevent (wait " << handle | |
| 907 << "): unexpected event: filter=" << event.filter | |
| 908 << ", fflags=" << event.fflags | |
| 909 << ", ident=" << event.ident; | |
| 910 return false; | |
| 911 } | |
| 912 | |
| 913 return true; | |
| 914 } | |
| 915 #endif // OS_MACOSX | |
| 916 | |
| 917 bool WaitForSingleProcess(ProcessHandle handle, base::TimeDelta wait) { | |
| 918 ProcessHandle parent_pid = GetParentProcessId(handle); | |
| 919 ProcessHandle our_pid = Process::Current().handle(); | |
| 920 if (parent_pid != our_pid) { | |
| 921 #if defined(OS_MACOSX) | |
| 922 // On Mac we can wait on non child processes. | |
| 923 return WaitForSingleNonChildProcess(handle, wait); | |
| 924 #else | |
| 925 // Currently on Linux we can't handle non child processes. | |
| 926 NOTIMPLEMENTED(); | |
| 927 #endif // OS_MACOSX | |
| 928 } | |
| 929 | |
| 930 bool waitpid_success; | |
| 931 int status = -1; | |
| 932 if (wait.InMilliseconds() == base::kNoTimeout) { | |
| 933 waitpid_success = (HANDLE_EINTR(waitpid(handle, &status, 0)) != -1); | |
| 934 } else { | |
| 935 status = WaitpidWithTimeout( | |
| 936 handle, wait.InMilliseconds(), &waitpid_success); | |
| 937 } | |
| 938 | |
| 939 if (status != -1) { | |
| 940 DCHECK(waitpid_success); | |
| 941 return WIFEXITED(status); | |
| 942 } else { | |
| 943 return false; | |
| 944 } | |
| 945 } | |
| 946 | |
| 947 // Return value used by GetAppOutputInternal to encapsulate the various exit | 612 // Return value used by GetAppOutputInternal to encapsulate the various exit |
| 948 // scenarios from the function. | 613 // scenarios from the function. |
| 949 enum GetAppOutputInternalResult { | 614 enum GetAppOutputInternalResult { |
| 950 EXECUTE_FAILURE, | 615 EXECUTE_FAILURE, |
| 951 EXECUTE_SUCCESS, | 616 EXECUTE_SUCCESS, |
| 952 GOT_MAX_OUTPUT, | 617 GOT_MAX_OUTPUT, |
| 953 }; | 618 }; |
| 954 | 619 |
| 955 // Executes the application specified by |argv| and wait for it to exit. Stores | 620 // Executes the application specified by |argv| and wait for it to exit. Stores |
| 956 // the output (stdout) in |output|. If |do_search_path| is set, it searches the | 621 // the output (stdout) in |output|. If |do_search_path| is set, it searches the |
| (...skipping 155 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1112 bool GetAppOutputWithExitCode(const CommandLine& cl, | 777 bool GetAppOutputWithExitCode(const CommandLine& cl, |
| 1113 std::string* output, | 778 std::string* output, |
| 1114 int* exit_code) { | 779 int* exit_code) { |
| 1115 // Run |execve()| with the current environment and store "unlimited" data. | 780 // Run |execve()| with the current environment and store "unlimited" data. |
| 1116 GetAppOutputInternalResult result = GetAppOutputInternal( | 781 GetAppOutputInternalResult result = GetAppOutputInternal( |
| 1117 cl.argv(), NULL, output, std::numeric_limits<std::size_t>::max(), true, | 782 cl.argv(), NULL, output, std::numeric_limits<std::size_t>::max(), true, |
| 1118 exit_code); | 783 exit_code); |
| 1119 return result == EXECUTE_SUCCESS; | 784 return result == EXECUTE_SUCCESS; |
| 1120 } | 785 } |
| 1121 | 786 |
| 1122 bool WaitForProcessesToExit(const FilePath::StringType& executable_name, | |
| 1123 base::TimeDelta wait, | |
| 1124 const ProcessFilter* filter) { | |
| 1125 bool result = false; | |
| 1126 | |
| 1127 // TODO(port): This is inefficient, but works if there are multiple procs. | |
| 1128 // TODO(port): use waitpid to avoid leaving zombies around | |
| 1129 | |
| 1130 base::TimeTicks end_time = base::TimeTicks::Now() + wait; | |
| 1131 do { | |
| 1132 NamedProcessIterator iter(executable_name, filter); | |
| 1133 if (!iter.NextProcessEntry()) { | |
| 1134 result = true; | |
| 1135 break; | |
| 1136 } | |
| 1137 base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(100)); | |
| 1138 } while ((end_time - base::TimeTicks::Now()) > base::TimeDelta()); | |
| 1139 | |
| 1140 return result; | |
| 1141 } | |
| 1142 | |
| 1143 bool CleanupProcesses(const FilePath::StringType& executable_name, | |
| 1144 base::TimeDelta wait, | |
| 1145 int exit_code, | |
| 1146 const ProcessFilter* filter) { | |
| 1147 bool exited_cleanly = WaitForProcessesToExit(executable_name, wait, filter); | |
| 1148 if (!exited_cleanly) | |
| 1149 KillProcesses(executable_name, exit_code, filter); | |
| 1150 return exited_cleanly; | |
| 1151 } | |
| 1152 | |
| 1153 #if !defined(OS_MACOSX) | |
| 1154 | |
| 1155 namespace { | |
| 1156 | |
| 1157 // Return true if the given child is dead. This will also reap the process. | |
| 1158 // Doesn't block. | |
| 1159 static bool IsChildDead(pid_t child) { | |
| 1160 const pid_t result = HANDLE_EINTR(waitpid(child, NULL, WNOHANG)); | |
| 1161 if (result == -1) { | |
| 1162 DPLOG(ERROR) << "waitpid(" << child << ")"; | |
| 1163 NOTREACHED(); | |
| 1164 } else if (result > 0) { | |
| 1165 // The child has died. | |
| 1166 return true; | |
| 1167 } | |
| 1168 | |
| 1169 return false; | |
| 1170 } | |
| 1171 | |
| 1172 // A thread class which waits for the given child to exit and reaps it. | |
| 1173 // If the child doesn't exit within a couple of seconds, kill it. | |
| 1174 class BackgroundReaper : public PlatformThread::Delegate { | |
| 1175 public: | |
| 1176 BackgroundReaper(pid_t child, unsigned timeout) | |
| 1177 : child_(child), | |
| 1178 timeout_(timeout) { | |
| 1179 } | |
| 1180 | |
| 1181 // Overridden from PlatformThread::Delegate: | |
| 1182 virtual void ThreadMain() OVERRIDE { | |
| 1183 WaitForChildToDie(); | |
| 1184 delete this; | |
| 1185 } | |
| 1186 | |
| 1187 void WaitForChildToDie() { | |
| 1188 // Wait forever case. | |
| 1189 if (timeout_ == 0) { | |
| 1190 pid_t r = HANDLE_EINTR(waitpid(child_, NULL, 0)); | |
| 1191 if (r != child_) { | |
| 1192 DPLOG(ERROR) << "While waiting for " << child_ | |
| 1193 << " to terminate, we got the following result: " << r; | |
| 1194 } | |
| 1195 return; | |
| 1196 } | |
| 1197 | |
| 1198 // There's no good way to wait for a specific child to exit in a timed | |
| 1199 // fashion. (No kqueue on Linux), so we just loop and sleep. | |
| 1200 | |
| 1201 // Wait for 2 * timeout_ 500 milliseconds intervals. | |
| 1202 for (unsigned i = 0; i < 2 * timeout_; ++i) { | |
| 1203 PlatformThread::Sleep(TimeDelta::FromMilliseconds(500)); | |
| 1204 if (IsChildDead(child_)) | |
| 1205 return; | |
| 1206 } | |
| 1207 | |
| 1208 if (kill(child_, SIGKILL) == 0) { | |
| 1209 // SIGKILL is uncatchable. Since the signal was delivered, we can | |
| 1210 // just wait for the process to die now in a blocking manner. | |
| 1211 if (HANDLE_EINTR(waitpid(child_, NULL, 0)) < 0) | |
| 1212 DPLOG(WARNING) << "waitpid"; | |
| 1213 } else { | |
| 1214 DLOG(ERROR) << "While waiting for " << child_ << " to terminate we" | |
| 1215 << " failed to deliver a SIGKILL signal (" << errno << ")."; | |
| 1216 } | |
| 1217 } | |
| 1218 | |
| 1219 private: | |
| 1220 const pid_t child_; | |
| 1221 // Number of seconds to wait, if 0 then wait forever and do not attempt to | |
| 1222 // kill |child_|. | |
| 1223 const unsigned timeout_; | |
| 1224 | |
| 1225 DISALLOW_COPY_AND_ASSIGN(BackgroundReaper); | |
| 1226 }; | |
| 1227 | |
| 1228 } // namespace | |
| 1229 | |
| 1230 void EnsureProcessTerminated(ProcessHandle process) { | |
| 1231 // If the child is already dead, then there's nothing to do. | |
| 1232 if (IsChildDead(process)) | |
| 1233 return; | |
| 1234 | |
| 1235 const unsigned timeout = 2; // seconds | |
| 1236 BackgroundReaper* reaper = new BackgroundReaper(process, timeout); | |
| 1237 PlatformThread::CreateNonJoinable(0, reaper); | |
| 1238 } | |
| 1239 | |
| 1240 void EnsureProcessGetsReaped(ProcessHandle process) { | |
| 1241 // If the child is already dead, then there's nothing to do. | |
| 1242 if (IsChildDead(process)) | |
| 1243 return; | |
| 1244 | |
| 1245 BackgroundReaper* reaper = new BackgroundReaper(process, 0); | |
| 1246 PlatformThread::CreateNonJoinable(0, reaper); | |
| 1247 } | |
| 1248 | |
| 1249 #endif // !defined(OS_MACOSX) | |
| 1250 | |
| 1251 } // namespace base | 787 } // namespace base |
| OLD | NEW |