Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(102)

Side by Side Diff: base/process/kill_posix.cc

Issue 938453002: Remove base::WaitForSingleProcess (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: cl format :( Created 5 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « base/process/kill.h ('k') | base/process/kill_win.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. 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 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 "base/process/kill.h" 5 #include "base/process/kill.h"
6 6
7 #include <signal.h> 7 #include <signal.h>
8 #include <sys/types.h> 8 #include <sys/types.h>
9 #include <sys/wait.h> 9 #include <sys/wait.h>
10 #include <unistd.h> 10 #include <unistd.h>
(...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after
77 ret_pid = HANDLE_EINTR(waitpid(handle, status, WNOHANG)); 77 ret_pid = HANDLE_EINTR(waitpid(handle, status, WNOHANG));
78 78
79 if ((max_sleep_time_usecs < kMaxSleepInMicroseconds) && 79 if ((max_sleep_time_usecs < kMaxSleepInMicroseconds) &&
80 (double_sleep_time++ % 4 == 0)) { 80 (double_sleep_time++ % 4 == 0)) {
81 max_sleep_time_usecs *= 2; 81 max_sleep_time_usecs *= 2;
82 } 82 }
83 } 83 }
84 84
85 return ret_pid > 0; 85 return ret_pid > 0;
86 } 86 }
87
88 #if defined(OS_MACOSX)
89 // Using kqueue on Mac so that we can wait on non-child processes.
90 // We can't use kqueues on child processes because we need to reap
91 // our own children using wait.
92 static bool WaitForSingleNonChildProcess(ProcessHandle handle,
93 TimeDelta wait) {
94 DCHECK_GT(handle, 0);
95 DCHECK(wait.InMilliseconds() == kNoTimeout || wait > TimeDelta());
96
97 ScopedFD kq(kqueue());
98 if (!kq.is_valid()) {
99 DPLOG(ERROR) << "kqueue";
100 return false;
101 }
102
103 struct kevent change = {0};
104 EV_SET(&change, handle, EVFILT_PROC, EV_ADD, NOTE_EXIT, 0, NULL);
105 int result = HANDLE_EINTR(kevent(kq.get(), &change, 1, NULL, 0, NULL));
106 if (result == -1) {
107 if (errno == ESRCH) {
108 // If the process wasn't found, it must be dead.
109 return true;
110 }
111
112 DPLOG(ERROR) << "kevent (setup " << handle << ")";
113 return false;
114 }
115
116 // Keep track of the elapsed time to be able to restart kevent if it's
117 // interrupted.
118 bool wait_forever = wait.InMilliseconds() == kNoTimeout;
119 TimeDelta remaining_delta;
120 TimeTicks deadline;
121 if (!wait_forever) {
122 remaining_delta = wait;
123 deadline = TimeTicks::Now() + remaining_delta;
124 }
125
126 result = -1;
127 struct kevent event = {0};
128
129 while (wait_forever || remaining_delta > TimeDelta()) {
130 struct timespec remaining_timespec;
131 struct timespec* remaining_timespec_ptr;
132 if (wait_forever) {
133 remaining_timespec_ptr = NULL;
134 } else {
135 remaining_timespec = remaining_delta.ToTimeSpec();
136 remaining_timespec_ptr = &remaining_timespec;
137 }
138
139 result = kevent(kq.get(), NULL, 0, &event, 1, remaining_timespec_ptr);
140
141 if (result == -1 && errno == EINTR) {
142 if (!wait_forever) {
143 remaining_delta = deadline - TimeTicks::Now();
144 }
145 result = 0;
146 } else {
147 break;
148 }
149 }
150
151 if (result < 0) {
152 DPLOG(ERROR) << "kevent (wait " << handle << ")";
153 return false;
154 } else if (result > 1) {
155 DLOG(ERROR) << "kevent (wait " << handle << "): unexpected result "
156 << result;
157 return false;
158 } else if (result == 0) {
159 // Timed out.
160 return false;
161 }
162
163 DCHECK_EQ(result, 1);
164
165 if (event.filter != EVFILT_PROC ||
166 (event.fflags & NOTE_EXIT) == 0 ||
167 event.ident != static_cast<uintptr_t>(handle)) {
168 DLOG(ERROR) << "kevent (wait " << handle
169 << "): unexpected event: filter=" << event.filter
170 << ", fflags=" << event.fflags
171 << ", ident=" << event.ident;
172 return false;
173 }
174
175 return true;
176 }
177 #endif // OS_MACOSX
87 #endif // !defined(OS_NACL_NONSFI) 178 #endif // !defined(OS_NACL_NONSFI)
88 179
89 TerminationStatus GetTerminationStatusImpl(ProcessHandle handle, 180 TerminationStatus GetTerminationStatusImpl(ProcessHandle handle,
90 bool can_block, 181 bool can_block,
91 int* exit_code) { 182 int* exit_code) {
92 int status = 0; 183 int status = 0;
93 const pid_t result = HANDLE_EINTR(waitpid(handle, &status, 184 const pid_t result = HANDLE_EINTR(waitpid(handle, &status,
94 can_block ? 0 : WNOHANG)); 185 can_block ? 0 : WNOHANG));
95 if (result == -1) { 186 if (result == -1) {
96 DPLOG(ERROR) << "waitpid(" << handle << ")"; 187 DPLOG(ERROR) << "waitpid(" << handle << ")";
(...skipping 126 matching lines...) Expand 10 before | Expand all | Expand 10 after
223 return true; 314 return true;
224 } 315 }
225 316
226 // If it didn't exit cleanly, it must have been signaled. 317 // If it didn't exit cleanly, it must have been signaled.
227 DCHECK(WIFSIGNALED(status)); 318 DCHECK(WIFSIGNALED(status));
228 return false; 319 return false;
229 } 320 }
230 321
231 bool WaitForExitCodeWithTimeout(ProcessHandle handle, 322 bool WaitForExitCodeWithTimeout(ProcessHandle handle,
232 int* exit_code, 323 int* exit_code,
233 base::TimeDelta timeout) { 324 TimeDelta timeout) {
325 ProcessHandle parent_pid = GetParentProcessId(handle);
326 ProcessHandle our_pid = GetCurrentProcessHandle();
327 if (parent_pid != our_pid) {
328 #if defined(OS_MACOSX)
329 // On Mac we can wait on non child processes.
330 return WaitForSingleNonChildProcess(handle, timeout);
331 #else
332 // Currently on Linux we can't handle non child processes.
333 NOTIMPLEMENTED();
334 #endif // OS_MACOSX
335 }
336
234 int status; 337 int status;
235 if (!WaitpidWithTimeout(handle, &status, timeout)) 338 if (!WaitpidWithTimeout(handle, &status, timeout))
236 return false; 339 return false;
237 if (WIFSIGNALED(status)) { 340 if (WIFSIGNALED(status)) {
238 *exit_code = -1; 341 *exit_code = -1;
239 return true; 342 return true;
240 } 343 }
241 if (WIFEXITED(status)) { 344 if (WIFEXITED(status)) {
242 *exit_code = WEXITSTATUS(status); 345 *exit_code = WEXITSTATUS(status);
243 return true; 346 return true;
244 } 347 }
245 return false; 348 return false;
246 } 349 }
247 350
248 bool WaitForProcessesToExit(const FilePath::StringType& executable_name, 351 bool WaitForProcessesToExit(const FilePath::StringType& executable_name,
249 base::TimeDelta wait, 352 TimeDelta wait,
250 const ProcessFilter* filter) { 353 const ProcessFilter* filter) {
251 bool result = false; 354 bool result = false;
252 355
253 // TODO(port): This is inefficient, but works if there are multiple procs. 356 // TODO(port): This is inefficient, but works if there are multiple procs.
254 // TODO(port): use waitpid to avoid leaving zombies around 357 // TODO(port): use waitpid to avoid leaving zombies around
255 358
256 base::TimeTicks end_time = base::TimeTicks::Now() + wait; 359 TimeTicks end_time = TimeTicks::Now() + wait;
257 do { 360 do {
258 NamedProcessIterator iter(executable_name, filter); 361 NamedProcessIterator iter(executable_name, filter);
259 if (!iter.NextProcessEntry()) { 362 if (!iter.NextProcessEntry()) {
260 result = true; 363 result = true;
261 break; 364 break;
262 } 365 }
263 base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(100)); 366 PlatformThread::Sleep(TimeDelta::FromMilliseconds(100));
264 } while ((end_time - base::TimeTicks::Now()) > base::TimeDelta()); 367 } while ((end_time - TimeTicks::Now()) > TimeDelta());
265 368
266 return result; 369 return result;
267 } 370 }
268 371
269 #if defined(OS_MACOSX)
270 // Using kqueue on Mac so that we can wait on non-child processes.
271 // We can't use kqueues on child processes because we need to reap
272 // our own children using wait.
273 static bool WaitForSingleNonChildProcess(ProcessHandle handle,
274 base::TimeDelta wait) {
275 DCHECK_GT(handle, 0);
276 DCHECK(wait.InMilliseconds() == base::kNoTimeout || wait > base::TimeDelta());
277
278 ScopedFD kq(kqueue());
279 if (!kq.is_valid()) {
280 DPLOG(ERROR) << "kqueue";
281 return false;
282 }
283
284 struct kevent change = {0};
285 EV_SET(&change, handle, EVFILT_PROC, EV_ADD, NOTE_EXIT, 0, NULL);
286 int result = HANDLE_EINTR(kevent(kq.get(), &change, 1, NULL, 0, NULL));
287 if (result == -1) {
288 if (errno == ESRCH) {
289 // If the process wasn't found, it must be dead.
290 return true;
291 }
292
293 DPLOG(ERROR) << "kevent (setup " << handle << ")";
294 return false;
295 }
296
297 // Keep track of the elapsed time to be able to restart kevent if it's
298 // interrupted.
299 bool wait_forever = wait.InMilliseconds() == base::kNoTimeout;
300 base::TimeDelta remaining_delta;
301 base::TimeTicks deadline;
302 if (!wait_forever) {
303 remaining_delta = wait;
304 deadline = base::TimeTicks::Now() + remaining_delta;
305 }
306
307 result = -1;
308 struct kevent event = {0};
309
310 while (wait_forever || remaining_delta > base::TimeDelta()) {
311 struct timespec remaining_timespec;
312 struct timespec* remaining_timespec_ptr;
313 if (wait_forever) {
314 remaining_timespec_ptr = NULL;
315 } else {
316 remaining_timespec = remaining_delta.ToTimeSpec();
317 remaining_timespec_ptr = &remaining_timespec;
318 }
319
320 result = kevent(kq.get(), NULL, 0, &event, 1, remaining_timespec_ptr);
321
322 if (result == -1 && errno == EINTR) {
323 if (!wait_forever) {
324 remaining_delta = deadline - base::TimeTicks::Now();
325 }
326 result = 0;
327 } else {
328 break;
329 }
330 }
331
332 if (result < 0) {
333 DPLOG(ERROR) << "kevent (wait " << handle << ")";
334 return false;
335 } else if (result > 1) {
336 DLOG(ERROR) << "kevent (wait " << handle << "): unexpected result "
337 << result;
338 return false;
339 } else if (result == 0) {
340 // Timed out.
341 return false;
342 }
343
344 DCHECK_EQ(result, 1);
345
346 if (event.filter != EVFILT_PROC ||
347 (event.fflags & NOTE_EXIT) == 0 ||
348 event.ident != static_cast<uintptr_t>(handle)) {
349 DLOG(ERROR) << "kevent (wait " << handle
350 << "): unexpected event: filter=" << event.filter
351 << ", fflags=" << event.fflags
352 << ", ident=" << event.ident;
353 return false;
354 }
355
356 return true;
357 }
358 #endif // OS_MACOSX
359
360 bool WaitForSingleProcess(ProcessHandle handle, base::TimeDelta wait) {
361 ProcessHandle parent_pid = GetParentProcessId(handle);
362 ProcessHandle our_pid = GetCurrentProcessHandle();
363 if (parent_pid != our_pid) {
364 #if defined(OS_MACOSX)
365 // On Mac we can wait on non child processes.
366 return WaitForSingleNonChildProcess(handle, wait);
367 #else
368 // Currently on Linux we can't handle non child processes.
369 NOTIMPLEMENTED();
370 #endif // OS_MACOSX
371 }
372
373 int status;
374 if (!WaitpidWithTimeout(handle, &status, wait))
375 return false;
376 return WIFEXITED(status);
377 }
378
379 bool CleanupProcesses(const FilePath::StringType& executable_name, 372 bool CleanupProcesses(const FilePath::StringType& executable_name,
380 base::TimeDelta wait, 373 TimeDelta wait,
381 int exit_code, 374 int exit_code,
382 const ProcessFilter* filter) { 375 const ProcessFilter* filter) {
383 bool exited_cleanly = WaitForProcessesToExit(executable_name, wait, filter); 376 bool exited_cleanly = WaitForProcessesToExit(executable_name, wait, filter);
384 if (!exited_cleanly) 377 if (!exited_cleanly)
385 KillProcesses(executable_name, exit_code, filter); 378 KillProcesses(executable_name, exit_code, filter);
386 return exited_cleanly; 379 return exited_cleanly;
387 } 380 }
388 381
389 #if !defined(OS_MACOSX) 382 #if !defined(OS_MACOSX)
390 383
(...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after
479 return; 472 return;
480 473
481 BackgroundReaper* reaper = new BackgroundReaper(pid, 0); 474 BackgroundReaper* reaper = new BackgroundReaper(pid, 0);
482 PlatformThread::CreateNonJoinable(0, reaper); 475 PlatformThread::CreateNonJoinable(0, reaper);
483 } 476 }
484 477
485 #endif // !defined(OS_MACOSX) 478 #endif // !defined(OS_MACOSX)
486 #endif // !defined(OS_NACL_NONSFI) 479 #endif // !defined(OS_NACL_NONSFI)
487 480
488 } // namespace base 481 } // namespace base
OLDNEW
« no previous file with comments | « base/process/kill.h ('k') | base/process/kill_win.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698