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 |