def add_child_handler(self, pid, callback, *args):
assert self._forks, "Must use the context manager"
+ with self._lock:
+ try:
+ returncode = self._zombies.pop(pid)
+ except KeyError:
+ # The child is running.
+ self._callbacks[pid] = callback, args
+ return
- self._callbacks[pid] = callback, args
-
- try:
- # Ensure that the child is not already terminated.
- # (raise KeyError if still alive)
- returncode = self._zombies.pop(pid)
-
- # Child is dead, therefore we can fire the callback immediately.
- # First we remove it from the dict.
- # (raise KeyError if .remove_child_handler() was called in-between)
- del self._callbacks[pid]
- except KeyError:
- pass
- else:
- callback(pid, returncode, *args)
+ # The child is dead already. We can fire the callback.
+ callback(pid, returncode, *args)
def remove_child_handler(self, pid):
try:
returncode = self._compute_returncode(status)
- try:
- callback, args = self._callbacks.pop(pid)
- except KeyError:
- # unknown child
- with self._lock:
+ with self._lock:
+ try:
+ callback, args = self._callbacks.pop(pid)
+ except KeyError:
+ # unknown child
if self._forks:
# It may not be registered yet.
self._zombies[pid] = returncode
continue
+ callback = None
+ if callback is None:
logger.warning(
"Caught subprocess termination from unknown pid: "
"%d -> %d", pid, returncode)