diff -r 7e1bed443d77 asyncio/base_events.py --- a/asyncio/base_events.py Tue Feb 10 14:37:37 2015 +0100 +++ b/asyncio/base_events.py Tue Feb 17 22:12:48 2015 +0100 @@ -189,6 +189,7 @@ # Identifier of the thread running the event loop, or None if the # event loop is not running self._thread_id = None + self._pid = os.getpid() self._clock_resolution = time.get_clock_info('monotonic').resolution self._exception_handler = None self._debug = (not sys.flags.ignore_environment @@ -203,6 +204,15 @@ % (self.__class__.__name__, self.is_running(), self.is_closed(), self.get_debug())) + def _detect_fork(self): + pid = os.getpid() + if pid != self._pid: + self._pid = pid + self._at_fork() + + def _at_fork(self): + pass + def create_task(self, coro): """Schedule a coroutine object. @@ -1112,6 +1122,9 @@ when = self._scheduled[0]._when timeout = max(0, when - self.time()) + # detect fork before using the selector + self._detect_fork() + if self._debug and timeout != 0: t0 = self.time() event_list = self._selector.select(timeout) diff -r 7e1bed443d77 asyncio/proactor_events.py --- a/asyncio/proactor_events.py Tue Feb 10 14:37:37 2015 +0100 +++ b/asyncio/proactor_events.py Tue Feb 17 22:12:48 2015 +0100 @@ -489,6 +489,10 @@ f.add_done_callback(self._loop_self_reading) def _write_to_self(self): + # The self-pipe must not be shared between two processes: at fork, + # create a new pipe to unshare it + self._detect_fork() + self._csock.send(b'\0') def _start_serving(self, protocol_factory, sock, diff -r 7e1bed443d77 asyncio/selector_events.py --- a/asyncio/selector_events.py Tue Feb 10 14:37:37 2015 +0100 +++ b/asyncio/selector_events.py Tue Feb 17 22:12:48 2015 +0100 @@ -94,6 +94,8 @@ raise RuntimeError("Cannot close a running event loop") if self.is_closed(): return + # detect fork before using the self-pipe or the selector + self._detect_fork() self._close_self_pipe() super().close() if self._selector is not None: @@ -135,6 +137,9 @@ break def _write_to_self(self): + # detect fork before using the self-pipe + self._detect_fork() + # This may be called from a different thread, possibly after # _close_self_pipe() has been called or even while it is # running. Guard for self._csock being None or closed. When @@ -230,6 +235,8 @@ """Add a reader callback.""" self._check_closed() handle = events.Handle(callback, args, self) + # detect fork before using the selector + self._detect_fork() try: key = self._selector.get_key(fd) except KeyError: @@ -246,6 +253,8 @@ """Remove a reader callback.""" if self.is_closed(): return False + # detect fork before using the selector + self._detect_fork() try: key = self._selector.get_key(fd) except KeyError: @@ -268,6 +277,8 @@ """Add a writer callback..""" self._check_closed() handle = events.Handle(callback, args, self) + # detect fork before using the selector + self._detect_fork() try: key = self._selector.get_key(fd) except KeyError: @@ -284,6 +295,8 @@ """Remove a writer callback.""" if self.is_closed(): return False + # detect fork before using the selector + self._detect_fork() try: key = self._selector.get_key(fd) except KeyError: diff -r 7e1bed443d77 asyncio/unix_events.py --- a/asyncio/unix_events.py Tue Feb 10 14:37:37 2015 +0100 +++ b/asyncio/unix_events.py Tue Feb 17 22:12:48 2015 +0100 @@ -48,6 +48,16 @@ super().__init__(selector) self._signal_handlers = {} + def _at_fork(self): + super()._at_fork() + parent_selector = self._selector + self._selector = type(parent_selector)() + for key in parent_selector.get_map().values(): + self._selector.register(key.fileobj, key.events, key.data) + parent_selector.close() + self._close_self_pipe() + self._make_self_pipe() + def _socketpair(self): return socket.socketpair()