]> git.ipfire.org Git - thirdparty/tornado.git/commitdiff
Ensure that add_callback fails cleanly if called while IOLoop is closing.
authorBen Darnell <ben@bendarnell.com>
Sat, 17 Nov 2012 20:44:21 +0000 (15:44 -0500)
committerBen Darnell <ben@bendarnell.com>
Sat, 17 Nov 2012 20:44:21 +0000 (15:44 -0500)
Previously there would (sometimes) be an exception when writing to the
waker pipe.

Closes #635.

tornado/ioloop.py
tornado/test/ioloop_test.py

index 5f01223be7ef41ca5444aa249caf07ac75094e06..3c9b05b9a998371cfa906b5545f0b48e72c0ccba 100644 (file)
@@ -406,6 +406,7 @@ class PollIOLoop(IOLoop):
         self._timeouts = []
         self._running = False
         self._stopped = False
+        self._closing = False
         self._thread_ident = None
         self._blocking_signal_threshold = None
 
@@ -417,6 +418,8 @@ class PollIOLoop(IOLoop):
                          self.READ)
 
     def close(self, all_fds=False):
+        with self._callback_lock:
+            self._closing = True
         self.remove_handler(self._waker.fileno())
         if all_fds:
             for fd in self._handlers.keys()[:]:
@@ -608,6 +611,8 @@ class PollIOLoop(IOLoop):
 
     def add_callback(self, callback):
         with self._callback_lock:
+            if self._closing:
+                raise RuntimeError("IOLoop is closing")
             list_empty = not self._callbacks
             self._callbacks.append(stack_context.wrap(callback))
         if list_empty and thread.get_ident() != self._thread_ident:
index 27c58bd3507fb3db9608e3150b1b60f6c3a8831e..569b03ca531172121d2646d99195f188c907e601 100644 (file)
@@ -82,6 +82,25 @@ class TestIOLoop(AsyncTestCase):
         thread.join()
         other_ioloop.close()
 
+    def test_add_callback_while_closing(self):
+        # Issue #635: add_callback() should raise a clean exception
+        # if called while another thread is closing the IOLoop.
+        closing = threading.Event()
+        def target():
+            other_ioloop.add_callback(other_ioloop.stop)
+            other_ioloop.start()
+            closing.set()
+            other_ioloop.close(all_fds=True)
+        other_ioloop = IOLoop()
+        thread = threading.Thread(target=target)
+        thread.start()
+        closing.wait()
+        for i in range(1000):
+            try:
+                other_ioloop.add_callback(lambda: None)
+            except RuntimeError, e:
+                self.assertEqual("IOLoop is closing", str(e))
+                break
 
 class TestIOLoopFutures(AsyncTestCase):
     def test_add_future_threads(self):