asyncio: Fix race in FastChildWatcher (by its original author, Anthony Baire).

This commit is contained in:
Guido van Rossum 2014-01-25 16:32:17 -08:00
parent 669eeaf933
commit ab27a9fc4b

View file

@ -641,22 +641,16 @@ class FastChildWatcher(BaseChildWatcher):
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:
@ -681,16 +675,18 @@ class FastChildWatcher(BaseChildWatcher):
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)