334
335
# TODO: I think we can change this to a simple 'while True: (c_pid,
335
336
# status) = os.wait() if c_pid == 0: break. But that needs some
337
for child_pid, child_path in self._child_processes.iteritems():
340
(c_pid, status) = os.waitpid(child_pid, os.WNOHANG)
342
trace.warning('Exception while checking child %s status: %s'
345
if c_pid == 0: # Child did not exit
348
self.log(None, 'child %s exited with status: %s'
351
# On error or child exiting, stop tracking the child
352
to_remove.append(child_pid)
353
for c_id in to_remove:
354
# Should we do something about the temporary paths?
338
while self._child_processes:
339
c_id, exit_code, rusage = os.wait3(os.WNOHANG)
341
# No children stopped right now
355
343
c_path = self._child_processes.pop(c_id)
344
trace.mutter('%s exited %s and usage: %s'
345
% (c_id, exit_code, rusage))
356
346
if os.path.exists(c_path):
357
347
# The child failed to cleanup after itself, do the work here
358
348
trace.warning('Had to clean up after child %d: %s\n'
359
349
% (c_id, c_path))
360
350
shutil.rmtree(c_path)
362
def _wait_for_children(self):
352
def _wait_secs_for_children(self, secs):
363
353
start = time.time()
364
end = start + self.WAIT_FOR_CHILDREN_TIMEOUT
365
355
while self._child_processes:
366
356
self._poll_children()
367
if self.WAIT_FOR_CHILDREN_TIMEOUT > 0 and time.time() > end:
357
if secs > 0 and time.time() > end:
369
359
time.sleep(self.SLEEP_FOR_CHILDREN_TIMEOUT)
361
def _wait_for_children(self):
362
self._wait_secs_for_children(self.WAIT_FOR_CHILDREN_TIMEOUT)
370
363
if self._child_processes:
371
364
trace.warning('Failed to stop children: %s'
372
365
% ', '.join(map(str, self._child_processes)))
373
366
for c_id, c_path in self._child_processes.iteritems():
367
trace.warning('sending SIGINT to %d' % (c_id,))
368
os.kill(c_id, signal.SIGINT)
369
# We sent the SIGINT signal, see if they exited
370
self._wait_secs_for_children(1.0)
371
if self._child_processes:
372
# No? Then maybe something more powerful
373
for c_id, c_path in self._child_processes.iteritems():
374
trace.warning('sending SIGKILL to %d' % (c_id,))
375
os.kill(c_id, signal.SIGKILL)
376
# We sent the SIGKILL signal, see if they exited
377
self._wait_secs_for_children(1.0)
378
if self._child_processes:
379
for c_id, c_path in self._child_processes.iteritems():
374
380
if os.path.exists(c_path):
375
trace.warning('Had to clean up after child %d: %s\n'
381
trace.warning('Cleaning up after immortal child %d: %s\n'
376
382
% (c_id, c_path))
377
383
shutil.rmtree(c_path)