]> granicus.if.org Git - python/commitdiff
asyncio: Fix the second half of issue #21447: race in _write_to_self().
authorGuido van Rossum <guido@python.org>
Tue, 6 May 2014 21:42:40 +0000 (14:42 -0700)
committerGuido van Rossum <guido@python.org>
Tue, 6 May 2014 21:42:40 +0000 (14:42 -0700)
Lib/asyncio/selector_events.py
Lib/test/test_asyncio/test_selector_events.py

index 367c5fbe3f5fe7ffc7eab73e39be3c34ce82434d..c7df8d8dd0015a9d8cbbdd4d7b2c1dd4ab2decb6 100644 (file)
@@ -87,10 +87,17 @@ class BaseSelectorEventLoop(base_events.BaseEventLoop):
             pass
 
     def _write_to_self(self):
-        try:
-            self._csock.send(b'x')
-        except (BlockingIOError, InterruptedError):
-            pass
+        # 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
+        # a socket is closed, send() raises OSError (with errno set to
+        # EBADF, but let's not rely on the exact error code).
+        csock = self._csock
+        if csock is not None:
+            try:
+                csock.send(b'x')
+            except OSError:
+                pass
 
     def _start_serving(self, protocol_factory, sock,
                        sslcontext=None, server=None):
index 964b2e8ec80bf227de0d7ffdc822d4eada153e24..0735237ccade410249ab26bd0eda396ae7d4c968 100644 (file)
@@ -121,8 +121,9 @@ class BaseSelectorEventLoopTests(unittest.TestCase):
         self.assertIsNone(self.loop._write_to_self())
 
     def test_write_to_self_exception(self):
-        self.loop._csock.send.side_effect = OSError()
-        self.assertRaises(OSError, self.loop._write_to_self)
+        # _write_to_self() swallows OSError
+        self.loop._csock.send.side_effect = RuntimeError()
+        self.assertRaises(RuntimeError, self.loop._write_to_self)
 
     def test_sock_recv(self):
         sock = mock.Mock()