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

Original patch by Dan O'Reilly.
(cherry picked from commit 5d97b7bcc1)

Co-authored-by: Yury Selivanov <yury@magic.io>
This commit is contained in:
Miss Islington (bot) 2018-05-29 14:09:17 -07:00 committed by GitHub
parent ca64f3ee5a
commit 2a7eb0b531
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 42 additions and 0 deletions

View File

@ -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)):

View File

@ -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
@ -1792,6 +1793,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):

View File

@ -0,0 +1,3 @@
Fix Policy.get_event_loop() to detect fork and return a new loop.
Original patch by Dan O'Reilly.