Skip to content

Commit b55cd6a

Browse files
authored
Merge branch 'main' into 3willows-patch-1
2 parents 1ca8a41 + 9a2346d commit b55cd6a

File tree

5 files changed

+36
-0
lines changed

5 files changed

+36
-0
lines changed

Lib/test/_test_multiprocessing.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6844,6 +6844,28 @@ def f(x): return x*x
68446844
self.assertEqual("332833500", out.decode('utf-8').strip())
68456845
self.assertFalse(err, msg=err.decode('utf-8'))
68466846

6847+
def test_forked_thread_not_started(self):
6848+
# gh-134381: Ensure that a thread that has not been started yet in
6849+
# the parent process can be started within a forked child process.
6850+
6851+
if multiprocessing.get_start_method() != "fork":
6852+
self.skipTest("fork specific test")
6853+
6854+
q = multiprocessing.Queue()
6855+
t = threading.Thread(target=lambda: q.put("done"), daemon=True)
6856+
6857+
def child():
6858+
t.start()
6859+
t.join()
6860+
6861+
p = multiprocessing.Process(target=child)
6862+
p.start()
6863+
p.join(support.SHORT_TIMEOUT)
6864+
6865+
self.assertEqual(p.exitcode, 0)
6866+
self.assertEqual(q.get_nowait(), "done")
6867+
close_queue(q)
6868+
68476869

68486870
#
68496871
# Mixins
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Fix :exc:`RuntimeError` when using a not-started :class:`threading.Thread` after calling :func:`os.fork`
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
Fix an issue in the :mod:`!_pickle` extension module in which importing
2+
:mod:`multiprocessing` could change how pickle identifies which module an
3+
object belongs to, potentially breaking the unpickling of those objects.

Modules/_pickle.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1879,6 +1879,10 @@ _checkmodule(PyObject *module_name, PyObject *module,
18791879
_PyUnicode_EqualToASCIIString(module_name, "__main__")) {
18801880
return -1;
18811881
}
1882+
if (PyUnicode_Check(module_name) &&
1883+
_PyUnicode_EqualToASCIIString(module_name, "__mp_main__")) {
1884+
return -1;
1885+
}
18821886

18831887
PyObject *candidate = getattribute(module, dotted_path, 0);
18841888
if (candidate == NULL) {

Modules/_threadmodule.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -296,6 +296,12 @@ _PyThread_AfterFork(struct _pythread_runtime_state *state)
296296
continue;
297297
}
298298

299+
// Keep handles for threads that have not been started yet. They are
300+
// safe to start in the child process.
301+
if (handle->state == THREAD_HANDLE_NOT_STARTED) {
302+
continue;
303+
}
304+
299305
// Mark all threads as done. Any attempts to join or detach the
300306
// underlying OS thread (if any) could crash. We are the only thread;
301307
// it's safe to set this non-atomically.

0 commit comments

Comments
 (0)