Skip to content

Commit fe0076c

Browse files
authored
Merge branch 'main' into small_int_immortal
2 parents 312c790 + 5ba67af commit fe0076c

File tree

6 files changed

+33
-8
lines changed

6 files changed

+33
-8
lines changed

Doc/library/argparse.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -195,7 +195,7 @@ your usage messages.
195195
When a custom usage message is specified for the main parser, you may also want to
196196
consider passing the ``prog`` argument to :meth:`~ArgumentParser.add_subparsers`
197197
or the ``prog`` and the ``usage`` arguments to
198-
:meth:`~_SubParsersAction.add_parser`, to ensure consistent command prefixes and
198+
:meth:`~_SubParsersAction.add_parser`, to ensure consistent command prefixes and
199199
usage information across subparsers.
200200

201201

Include/internal/pycore_interp.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -283,6 +283,8 @@ struct _is {
283283

284284
/* the initial PyInterpreterState.threads.head */
285285
_PyThreadStateImpl _initial_thread;
286+
// _initial_thread should be the last field of PyInterpreterState.
287+
// See https://github.com/python/cpython/issues/127117.
286288
};
287289

288290

Include/internal/pycore_runtime.h

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,12 @@ typedef struct pyruntimestate {
169169
struct _Py_unicode_runtime_state unicode_state;
170170
struct _types_runtime_state types;
171171

172+
#if defined(__EMSCRIPTEN__) && defined(PY_CALL_TRAMPOLINE)
173+
// Used in "Python/emscripten_trampoline.c" to choose between type
174+
// reflection trampoline and EM_JS trampoline.
175+
bool wasm_type_reflection_available;
176+
#endif
177+
172178
/* All the objects that are shared by the runtime's interpreters. */
173179
struct _Py_cached_objects cached_objects;
174180
struct _Py_static_objects static_objects;
@@ -189,13 +195,8 @@ typedef struct pyruntimestate {
189195

190196
/* _PyRuntimeState.interpreters.main */
191197
PyInterpreterState _main_interpreter;
192-
193-
#if defined(__EMSCRIPTEN__) && defined(PY_CALL_TRAMPOLINE)
194-
// Used in "Python/emscripten_trampoline.c" to choose between type
195-
// reflection trampoline and EM_JS trampoline.
196-
bool wasm_type_reflection_available;
197-
#endif
198-
198+
// _main_interpreter should be the last field of _PyRuntimeState.
199+
// See https://github.com/python/cpython/issues/127117.
199200
} _PyRuntimeState;
200201

201202

Lib/concurrent/futures/thread.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ def _python_exit():
4141
os.register_at_fork(before=_global_shutdown_lock.acquire,
4242
after_in_child=_global_shutdown_lock._at_fork_reinit,
4343
after_in_parent=_global_shutdown_lock.release)
44+
os.register_at_fork(after_in_child=_threads_queues.clear)
4445

4546

4647
class WorkerContext:

Lib/test/test_concurrent_futures/test_thread_pool.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,25 @@ def submit(pool):
6666
with futures.ProcessPoolExecutor(1, mp_context=mp.get_context('fork')) as workers:
6767
workers.submit(tuple)
6868

69+
@support.requires_fork()
70+
@unittest.skipUnless(hasattr(os, 'register_at_fork'), 'need os.register_at_fork')
71+
def test_process_fork_from_a_threadpool(self):
72+
# bpo-43944: clear concurrent.futures.thread._threads_queues after fork,
73+
# otherwise child process will try to join parent thread
74+
def fork_process_and_return_exitcode():
75+
# Ignore the warning about fork with threads.
76+
with self.assertWarnsRegex(DeprecationWarning,
77+
r"use of fork\(\) may lead to deadlocks in the child"):
78+
p = mp.get_context('fork').Process(target=lambda: 1)
79+
p.start()
80+
p.join()
81+
return p.exitcode
82+
83+
with futures.ThreadPoolExecutor(1) as pool:
84+
process_exitcode = pool.submit(fork_process_and_return_exitcode).result()
85+
86+
self.assertEqual(process_exitcode, 0)
87+
6988
def test_executor_map_current_future_cancel(self):
7089
stop_event = threading.Event()
7190
log = []
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Fixed :class:`multiprocessing.Process` reporting a ``.exitcode`` of 1 even on success when
2+
using the ``"fork"`` start method while using a :class:`concurrent.futures.ThreadPoolExecutor`.

0 commit comments

Comments
 (0)