[Python-checkins] cpython: asyncio: Ensure call_soon(), call_later() and call_at() are invoked on current

victor.stinner python-checkins at python.org
Fri Mar 21 10:01:43 CET 2014


http://hg.python.org/cpython/rev/30977e66a882
changeset:   89893:30977e66a882
user:        Victor Stinner <victor.stinner at gmail.com>
date:        Fri Mar 21 10:00:52 2014 +0100
summary:
  asyncio: Ensure call_soon(), call_later() and call_at() are invoked on current
loop in debug mode. Raise a RuntimeError if the event loop of the current
thread is different.  The check should help to debug thread-safetly issue.
Patch written by David Foster.

files:
  Lib/asyncio/base_events.py                |  23 ++++++++++-
  Lib/test/test_asyncio/test_base_events.py |  23 +++++++++++
  2 files changed, 45 insertions(+), 1 deletions(-)


diff --git a/Lib/asyncio/base_events.py b/Lib/asyncio/base_events.py
--- a/Lib/asyncio/base_events.py
+++ b/Lib/asyncio/base_events.py
@@ -259,6 +259,8 @@
         """Like call_later(), but uses an absolute time."""
         if tasks.iscoroutinefunction(callback):
             raise TypeError("coroutines cannot be used with call_at()")
+        if self._debug:
+            self._assert_is_current_event_loop()
         timer = events.TimerHandle(when, callback, args, self)
         heapq.heappush(self._scheduled, timer)
         return timer
@@ -273,15 +275,34 @@
         Any positional arguments after the callback will be passed to
         the callback when it is called.
         """
+        return self._call_soon(callback, args, check_loop=True)
+
+    def _call_soon(self, callback, args, check_loop):
         if tasks.iscoroutinefunction(callback):
             raise TypeError("coroutines cannot be used with call_soon()")
+        if self._debug and check_loop:
+            self._assert_is_current_event_loop()
         handle = events.Handle(callback, args, self)
         self._ready.append(handle)
         return handle
 
+    def _assert_is_current_event_loop(self):
+        """Asserts that this event loop is the current event loop.
+
+        Non-threadsafe methods of this class make this assumption and will
+        likely behave incorrectly when the assumption is violated.
+
+        Should only be called when (self._debug == True). The caller is
+        responsible for checking this condition for performance reasons.
+        """
+        if events.get_event_loop() is not self:
+            raise RuntimeError(
+                "non-threadsafe operation invoked on an event loop other "
+                "than the current one")
+
     def call_soon_threadsafe(self, callback, *args):
         """XXX"""
-        handle = self.call_soon(callback, *args)
+        handle = self._call_soon(callback, args, check_loop=False)
         self._write_to_self()
         return handle
 
diff --git a/Lib/test/test_asyncio/test_base_events.py b/Lib/test/test_asyncio/test_base_events.py
--- a/Lib/test/test_asyncio/test_base_events.py
+++ b/Lib/test/test_asyncio/test_base_events.py
@@ -136,6 +136,29 @@
         # are really slow
         self.assertLessEqual(dt, 0.9, dt)
 
+    def test_assert_is_current_event_loop(self):
+        def cb():
+            pass
+
+        other_loop = base_events.BaseEventLoop()
+        other_loop._selector = unittest.mock.Mock()
+        asyncio.set_event_loop(other_loop)
+
+        # raise RuntimeError if the event loop is different in debug mode
+        self.loop.set_debug(True)
+        with self.assertRaises(RuntimeError):
+            self.loop.call_soon(cb)
+        with self.assertRaises(RuntimeError):
+            self.loop.call_later(60, cb)
+        with self.assertRaises(RuntimeError):
+            self.loop.call_at(self.loop.time() + 60, cb)
+
+        # check disabled if debug mode is disabled
+        self.loop.set_debug(False)
+        self.loop.call_soon(cb)
+        self.loop.call_later(60, cb)
+        self.loop.call_at(self.loop.time() + 60, cb)
+
     def test_run_once_in_executor_handle(self):
         def cb():
             pass

-- 
Repository URL: http://hg.python.org/cpython


More information about the Python-checkins mailing list