Commit 5d97b7bc authored by Yury Selivanov's avatar Yury Selivanov Committed by GitHub

bpo-22087: Fix Policy.get_event_loop() to detect fork (GH-7208)

Original patch by Dan O'Reilly.
parent e55de2d7
...@@ -625,16 +625,23 @@ class BaseDefaultEventLoopPolicy(AbstractEventLoopPolicy): ...@@ -625,16 +625,23 @@ class BaseDefaultEventLoopPolicy(AbstractEventLoopPolicy):
class _Local(threading.local): class _Local(threading.local):
_loop = None _loop = None
_pid = None
_set_called = False _set_called = False
def __init__(self): def __init__(self):
self._local = self._Local() self._local = self._Local()
self._local._pid = os.getpid()
def get_event_loop(self): def get_event_loop(self):
"""Get the event loop. """Get the event loop.
This may be None or an instance of EventLoop. This may be None or an instance of EventLoop.
""" """
if self._local._pid != os.getpid():
# If we detect we're in a child process forked by multiprocessing,
# we reset self._local so that we'll get a new event loop.
self._local = self._Local()
if (self._local._loop is None and if (self._local._loop is None and
not self._local._set_called and not self._local._set_called and
isinstance(threading.current_thread(), threading._MainThread)): isinstance(threading.current_thread(), threading._MainThread)):
......
...@@ -13,6 +13,7 @@ import sys ...@@ -13,6 +13,7 @@ import sys
import tempfile import tempfile
import threading import threading
import unittest import unittest
import multiprocessing
from unittest import mock from unittest import mock
from test import support from test import support
...@@ -1804,6 +1805,37 @@ class FastChildWatcherTests (ChildWatcherTestsMixin, test_utils.TestCase): ...@@ -1804,6 +1805,37 @@ class FastChildWatcherTests (ChildWatcherTestsMixin, test_utils.TestCase):
return asyncio.FastChildWatcher() return asyncio.FastChildWatcher()
class ForkedProcessTests(unittest.TestCase):
def setUp(self):
self.parent_loop = asyncio.SelectorEventLoop()
asyncio.set_event_loop(self.parent_loop)
self.ctx = multiprocessing.get_context("fork")
def tearDown(self):
self.parent_loop.close()
def _check_loops_not_equal(self, old_loop):
loop = asyncio.get_event_loop()
if loop is old_loop:
raise RuntimeError("Child process inherited parent's event loop")
try:
val = loop.run_until_complete(asyncio.sleep(0.05, result=42))
if val != 42:
raise RuntimeError("new event loop does not work")
finally:
loop.close()
sys.exit(loop is old_loop)
def test_new_loop_in_child(self):
p = self.ctx.Process(target=self._check_loops_not_equal,
args=(self.parent_loop,))
p.start()
p.join()
self.assertEqual(p.exitcode, 0)
class PolicyTests(unittest.TestCase): class PolicyTests(unittest.TestCase):
def create_policy(self): def create_policy(self):
......
Fix Policy.get_event_loop() to detect fork and return a new loop.
Original patch by Dan O'Reilly.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment