mirror of
https://github.com/python/cpython.git
synced 2025-08-11 12:29:34 +00:00
[3.12] gh-108520: Fix bad fork detection in nested multiprocessing use case (GH-108568) (#108691)
gh-108520: Fix bad fork detection in nested multiprocessing use case (GH-108568)
gh-107275 introduced a regression where a SemLock would fail being passed along nested child processes, as the `is_fork_ctx` attribute would be left missing after the first deserialization.
---------
(cherry picked from commit add8d45cbe
)
Co-authored-by: albanD <desmaison.alban@gmail.com>
Co-authored-by: blurb-it[bot] <43283697+blurb-it[bot]@users.noreply.github.com>
Co-authored-by: Antoine Pitrou <pitrou@free.fr>
This commit is contained in:
parent
420db1027b
commit
320d398262
3 changed files with 34 additions and 3 deletions
|
@ -50,8 +50,8 @@ class SemLock(object):
|
||||||
def __init__(self, kind, value, maxvalue, *, ctx):
|
def __init__(self, kind, value, maxvalue, *, ctx):
|
||||||
if ctx is None:
|
if ctx is None:
|
||||||
ctx = context._default_context.get_context()
|
ctx = context._default_context.get_context()
|
||||||
self.is_fork_ctx = ctx.get_start_method() == 'fork'
|
self._is_fork_ctx = ctx.get_start_method() == 'fork'
|
||||||
unlink_now = sys.platform == 'win32' or self.is_fork_ctx
|
unlink_now = sys.platform == 'win32' or self._is_fork_ctx
|
||||||
for i in range(100):
|
for i in range(100):
|
||||||
try:
|
try:
|
||||||
sl = self._semlock = _multiprocessing.SemLock(
|
sl = self._semlock = _multiprocessing.SemLock(
|
||||||
|
@ -103,7 +103,7 @@ class SemLock(object):
|
||||||
if sys.platform == 'win32':
|
if sys.platform == 'win32':
|
||||||
h = context.get_spawning_popen().duplicate_for_child(sl.handle)
|
h = context.get_spawning_popen().duplicate_for_child(sl.handle)
|
||||||
else:
|
else:
|
||||||
if self.is_fork_ctx:
|
if self._is_fork_ctx:
|
||||||
raise RuntimeError('A SemLock created in a fork context is being '
|
raise RuntimeError('A SemLock created in a fork context is being '
|
||||||
'shared with a process in a spawn context. This is '
|
'shared with a process in a spawn context. This is '
|
||||||
'not supported. Please use the same context to create '
|
'not supported. Please use the same context to create '
|
||||||
|
@ -115,6 +115,8 @@ class SemLock(object):
|
||||||
self._semlock = _multiprocessing.SemLock._rebuild(*state)
|
self._semlock = _multiprocessing.SemLock._rebuild(*state)
|
||||||
util.debug('recreated blocker with handle %r' % state[0])
|
util.debug('recreated blocker with handle %r' % state[0])
|
||||||
self._make_methods()
|
self._make_methods()
|
||||||
|
# Ensure that deserialized SemLock can be serialized again (gh-108520).
|
||||||
|
self._is_fork_ctx = False
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _make_name():
|
def _make_name():
|
||||||
|
|
|
@ -5405,6 +5405,32 @@ class TestStartMethod(unittest.TestCase):
|
||||||
p.start()
|
p.start()
|
||||||
p.join()
|
p.join()
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _put_one_in_queue(cls, queue):
|
||||||
|
queue.put(1)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _put_two_and_nest_once(cls, queue):
|
||||||
|
queue.put(2)
|
||||||
|
process = multiprocessing.Process(target=cls._put_one_in_queue, args=(queue,))
|
||||||
|
process.start()
|
||||||
|
process.join()
|
||||||
|
|
||||||
|
def test_nested_startmethod(self):
|
||||||
|
# gh-108520: Regression test to ensure that child process can send its
|
||||||
|
# arguments to another process
|
||||||
|
queue = multiprocessing.Queue()
|
||||||
|
|
||||||
|
process = multiprocessing.Process(target=self._put_two_and_nest_once, args=(queue,))
|
||||||
|
process.start()
|
||||||
|
process.join()
|
||||||
|
|
||||||
|
results = []
|
||||||
|
while not queue.empty():
|
||||||
|
results.append(queue.get())
|
||||||
|
|
||||||
|
self.assertEqual(results, [2, 1])
|
||||||
|
|
||||||
|
|
||||||
@unittest.skipIf(sys.platform == "win32",
|
@unittest.skipIf(sys.platform == "win32",
|
||||||
"test semantics don't make sense on Windows")
|
"test semantics don't make sense on Windows")
|
||||||
|
|
|
@ -0,0 +1,3 @@
|
||||||
|
Fix :meth:`multiprocessing.synchronize.SemLock.__setstate__` to properly initialize :attr:`multiprocessing.synchronize.SemLock._is_fork_ctx`. This fixes a regression when passing a SemLock accross nested processes.
|
||||||
|
|
||||||
|
Rename :attr:`multiprocessing.synchronize.SemLock.is_fork_ctx` to :attr:`multiprocessing.synchronize.SemLock._is_fork_ctx` to avoid exposing it as public API.
|
Loading…
Add table
Add a link
Reference in a new issue