diff options
author | Yury Selivanov <yury@magic.io> | 2016-11-04 18:30:11 (GMT) |
---|---|---|
committer | Yury Selivanov <yury@magic.io> | 2016-11-04 18:30:11 (GMT) |
commit | 69312fa4a2712b3ff37e473c833a42162aa9b5cd (patch) | |
tree | 008bb64b7ee485a5031e94744ecf5fa22f51cf3d /Lib/asyncio | |
parent | 4b8eb7b8b4d2d4c2c900f0931d475ffa951d3215 (diff) | |
parent | 600a349781bfa0a8239e1cb95fac29c7c4a3302e (diff) | |
download | cpython-69312fa4a2712b3ff37e473c833a42162aa9b5cd.zip cpython-69312fa4a2712b3ff37e473c833a42162aa9b5cd.tar.gz cpython-69312fa4a2712b3ff37e473c833a42162aa9b5cd.tar.bz2 |
Merge 3.5 (issue #28613)
Diffstat (limited to 'Lib/asyncio')
-rw-r--r-- | Lib/asyncio/base_events.py | 7 | ||||
-rw-r--r-- | Lib/asyncio/events.py | 36 | ||||
-rw-r--r-- | Lib/asyncio/test_utils.py | 6 |
3 files changed, 47 insertions, 2 deletions
diff --git a/Lib/asyncio/base_events.py b/Lib/asyncio/base_events.py index 68e676b..85cc1e4 100644 --- a/Lib/asyncio/base_events.py +++ b/Lib/asyncio/base_events.py @@ -393,7 +393,10 @@ class BaseEventLoop(events.AbstractEventLoop): """Run until stop() is called.""" self._check_closed() if self.is_running(): - raise RuntimeError('Event loop is running.') + raise RuntimeError('This event loop is already running') + if events._get_running_loop() is not None: + raise RuntimeError( + 'Cannot run the event loop while another loop is running') self._set_coroutine_wrapper(self._debug) self._thread_id = threading.get_ident() if self._asyncgens is not None: @@ -401,6 +404,7 @@ class BaseEventLoop(events.AbstractEventLoop): sys.set_asyncgen_hooks(firstiter=self._asyncgen_firstiter_hook, finalizer=self._asyncgen_finalizer_hook) try: + events._set_running_loop(self) while True: self._run_once() if self._stopping: @@ -408,6 +412,7 @@ class BaseEventLoop(events.AbstractEventLoop): finally: self._stopping = False self._thread_id = None + events._set_running_loop(None) self._set_coroutine_wrapper(False) if self._asyncgens is not None: sys.set_asyncgen_hooks(*old_agen_hooks) diff --git a/Lib/asyncio/events.py b/Lib/asyncio/events.py index b89b4b2..8575e2c 100644 --- a/Lib/asyncio/events.py +++ b/Lib/asyncio/events.py @@ -607,6 +607,30 @@ _event_loop_policy = None _lock = threading.Lock() +# A TLS for the running event loop, used by _get_running_loop. +class _RunningLoop(threading.local): + _loop = None +_running_loop = _RunningLoop() + + +def _get_running_loop(): + """Return the running event loop or None. + + This is a low-level function intended to be used by event loops. + This function is thread-specific. + """ + return _running_loop._loop + + +def _set_running_loop(loop): + """Set the running event loop. + + This is a low-level function intended to be used by event loops. + This function is thread-specific. + """ + _running_loop._loop = loop + + def _init_event_loop_policy(): global _event_loop_policy with _lock: @@ -632,7 +656,17 @@ def set_event_loop_policy(policy): def get_event_loop(): - """Equivalent to calling get_event_loop_policy().get_event_loop().""" + """Return an asyncio event loop. + + When called from a coroutine or a callback (e.g. scheduled with call_soon + or similar API), this function will always return the running event loop. + + If there is no running event loop set, the function will return + the result of `get_event_loop_policy().get_event_loop()` call. + """ + current_loop = _get_running_loop() + if current_loop is not None: + return current_loop return get_event_loop_policy().get_event_loop() diff --git a/Lib/asyncio/test_utils.py b/Lib/asyncio/test_utils.py index fdd3ba0..99e3839 100644 --- a/Lib/asyncio/test_utils.py +++ b/Lib/asyncio/test_utils.py @@ -449,7 +449,13 @@ class TestCase(unittest.TestCase): self.set_event_loop(loop) return loop + def setUp(self): + self._get_running_loop = events._get_running_loop + events._get_running_loop = lambda: None + def tearDown(self): + events._get_running_loop = self._get_running_loop + events.set_event_loop(None) # Detect CPython bug #23353: ensure that yield/yield-from is not used |