]> git.ipfire.org Git - thirdparty/tornado.git/commitdiff
Make AddThreadEventLoop.close() idempotent
authorMin RK <benjaminrk@gmail.com>
Wed, 19 May 2021 07:58:09 +0000 (09:58 +0200)
committerMin RK <benjaminrk@gmail.com>
Wed, 19 May 2021 08:02:08 +0000 (10:02 +0200)
according to spec: https://docs.python.org/3/library/asyncio-eventloop.html#asyncio.loop.close

The call to _wake_selector would fail with EBADF when close is called a second time

tornado/platform/asyncio.py
tornado/test/asyncio_test.py

index b07af3a953f01d9c8fb3c97c6b106e48055ccbfd..3863e78f2e43ad49ad2b78e105012b0f962cb04a 100644 (file)
@@ -412,6 +412,8 @@ class SelectorThread:
     but can be attached to a running asyncio loop.
     """
 
+    _closed = False
+
     def __init__(self, real_loop: asyncio.AbstractEventLoop) -> None:
         self._real_loop = real_loop
 
@@ -456,6 +458,8 @@ class SelectorThread:
         self._waker_w.close()
 
     def close(self) -> None:
+        if self._closed:
+            return
         with self._select_cond:
             self._closing_selector = True
             self._select_cond.notify()
@@ -464,6 +468,7 @@ class SelectorThread:
         _selector_loops.discard(self)
         self._waker_r.close()
         self._waker_w.close()
+        self._closed = True
 
     def _wake_selector(self) -> None:
         try:
index 3f9f3389a2e3b5a27ac701ace6eaf9be87f38505..59825e8f22d9895525a9bba81f112c00f393c757 100644 (file)
@@ -20,6 +20,7 @@ from tornado.platform.asyncio import (
     AsyncIOLoop,
     to_asyncio_future,
     AnyThreadEventLoopPolicy,
+    AddThreadSelectorEventLoop,
 )
 from tornado.testing import AsyncTestCase, gen_test
 
@@ -107,6 +108,11 @@ class AsyncIOLoopTest(AsyncTestCase):
             42,
         )
 
+    def test_add_thread_close_idempotent(self):
+        loop = AddThreadSelectorEventLoop(asyncio.get_event_loop())
+        loop.close()
+        loop.close()
+
 
 class LeakTest(unittest.TestCase):
     def setUp(self):