From: Guido van Rossum Date: Sun, 26 Jan 2014 00:32:17 +0000 (-0800) Subject: asyncio: Fix race in FastChildWatcher (by its original author, Anthony Baire). X-Git-Tag: v3.4.0b3~11 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=ab27a9fc4b4edff7c17e699b7e9e2173e9f8bc53;p=python asyncio: Fix race in FastChildWatcher (by its original author, Anthony Baire). --- diff --git a/Lib/asyncio/unix_events.py b/Lib/asyncio/unix_events.py index 7a6546d136..2418642087 100644 --- a/Lib/asyncio/unix_events.py +++ b/Lib/asyncio/unix_events.py @@ -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)