Skip to content

Commit 44dc01a

Browse files
naschemengoldbaum
andcommitted
Remove lock_held_at_fork struct member.
Use a process global instead. This avoids changing the interpreter structure. Co-authored-by: Nathan Goldbaum <nathan.goldbaum@gmail.com>
1 parent 445f3d8 commit 44dc01a

4 files changed

Lines changed: 14 additions & 7 deletions

File tree

‎Include/internal/pycore_interp_structs.h‎

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -661,10 +661,6 @@ struct _warnings_runtime_state {
661661
PyObject *once_registry; /* Dict */
662662
PyObject *default_action; /* String */
663663
_PyRecursiveMutex lock;
664-
#ifdef HAVE_FORK
665-
// Whether the thread calling fork() owns the warnings lock.
666-
bool lock_held_at_fork;
667-
#endif
668664
long filters_version;
669665
PyObject *context;
670666
};

‎Lib/test/test_warnings/__init__.py‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1693,6 +1693,11 @@ def test_fork_current_thread_holds_lock(self):
16931693
for _ in range(3):
16941694
_warnings._acquire_lock()
16951695
pid = os.fork()
1696+
if pid == 0:
1697+
# Ownership must also survive a second fork in the child.
1698+
child_pid = os.fork()
1699+
if child_pid != 0:
1700+
support.wait_process(child_pid, exitcode=0)
16961701
try:
16971702
# A warning must not change the inherited recursion depth.
16981703
warnings.warn('after fork')

‎Python/_warnings.c‎

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -278,19 +278,24 @@ warnings_lock_held(WarningsState *st)
278278
}
279279

280280
#ifdef HAVE_FORK
281+
// PyOS_BeforeFork() holds HEAD_LOCK while saving this value and until fork(),
282+
// so concurrent forks cannot overwrite it before the child inherits it.
283+
// The child consumes its private copy before running Python callbacks.
284+
static bool warnings_lock_held_at_fork;
285+
281286
void
282287
_PyWarnings_BeforeFork(PyInterpreterState *interp)
283288
{
284289
WarningsState *st = warnings_get_state(interp);
285-
st->lock_held_at_fork = _PyRecursiveMutex_IsLockedByCurrentThread(&st->lock);
290+
warnings_lock_held_at_fork = _PyRecursiveMutex_IsLockedByCurrentThread(&st->lock);
286291
}
287292

288293
void
289294
_PyWarnings_AfterFork(PyInterpreterState *interp)
290295
{
291296
WarningsState *st = warnings_get_state(interp);
292-
_PyRecursiveMutex_at_fork_reinit(&st->lock, st->lock_held_at_fork);
293-
st->lock_held_at_fork = false;
297+
_PyRecursiveMutex_at_fork_reinit(&st->lock, warnings_lock_held_at_fork);
298+
warnings_lock_held_at_fork = false;
294299
}
295300
#endif
296301

‎Tools/c-analyzer/cpython/ignored.tsv‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -362,6 +362,7 @@ Objects/unicodeobject.c unicode_translate_call_errorhandler argparse -
362362
Parser/parser.c - reserved_keywords -
363363
Parser/parser.c - soft_keywords -
364364
Parser/lexer/lexer.c - type_comment_prefix -
365+
Python/_warnings.c - warnings_lock_held_at_fork -
365366
Python/ceval.c - _PyEval_BinaryOps -
366367
Python/ceval.c - _Py_INTERPRETER_TRAMPOLINE_INSTRUCTIONS -
367368
Python/ceval.c - _Py_INTERPRETER_TRAMPOLINE_INSTRUCTIONS_PTR -

0 commit comments

Comments
 (0)