File tree Expand file tree Collapse file tree
Expand file tree Collapse file tree Original file line number Diff line number Diff line change @@ -173,6 +173,9 @@ PyAPI_FUNC(void) _PyRecursiveMutex_Lock(_PyRecursiveMutex *m);
173173extern PyLockStatus _PyRecursiveMutex_LockTimed (_PyRecursiveMutex *m, PyTime_t timeout, _PyLockFlags flags);
174174PyAPI_FUNC (void ) _PyRecursiveMutex_Unlock(_PyRecursiveMutex *m);
175175extern int _PyRecursiveMutex_TryUnlock (_PyRecursiveMutex *m);
176+ #ifdef HAVE_FORK
177+ extern void _PyRecursiveMutex_at_fork_reinit (_PyRecursiveMutex *m, int owned);
178+ #endif
176179
177180// A readers-writer (RW) lock. The lock supports multiple concurrent readers or
178181// a single writer. The lock is write-preferring: if a writer is waiting while
Original file line number Diff line number Diff line change @@ -282,24 +282,14 @@ void
282282_PyWarnings_BeforeFork (PyInterpreterState * interp )
283283{
284284 WarningsState * st = warnings_get_state (interp );
285- // Record ownership before fork(): the thread ID can change in the child.
286285 st -> lock_held_at_fork = _PyRecursiveMutex_IsLockedByCurrentThread (& st -> lock );
287286}
288287
289288void
290289_PyWarnings_AfterFork (PyInterpreterState * interp )
291290{
292291 WarningsState * st = warnings_get_state (interp );
293- if (st -> lock_held_at_fork ) {
294- // The surviving thread will still release the lock as its stack
295- // unwinds. Preserve the recursion depth, but discard dead waiters.
296- st -> lock .mutex = (PyMutex ){._bits = _Py_LOCKED };
297- st -> lock .thread = PyThread_get_thread_ident_ex ();
298- }
299- else {
300- // The owner (if any) no longer exists in the child.
301- st -> lock = (_PyRecursiveMutex ){0 };
302- }
292+ _PyRecursiveMutex_at_fork_reinit (& st -> lock , st -> lock_held_at_fork );
303293 st -> lock_held_at_fork = false;
304294}
305295#endif
Original file line number Diff line number Diff line change @@ -453,6 +453,25 @@ _PyRecursiveMutex_TryUnlock(_PyRecursiveMutex *m)
453453 return 0 ;
454454}
455455
456+ #ifdef HAVE_FORK
457+ // Reinitialize the mutex in the child process after fork(). The caller must
458+ // record before fork() whether the forking thread owns the mutex, since the
459+ // thread ident can change in the child (gh-126688). If it does, the child
460+ // keeps the mutex with the same recursion level; otherwise the owner and any
461+ // waiters no longer exist in the child and the mutex is reset.
462+ void
463+ _PyRecursiveMutex_at_fork_reinit (_PyRecursiveMutex * m , int owned )
464+ {
465+ if (owned ) {
466+ m -> mutex = (PyMutex ){._bits = _Py_LOCKED };
467+ _Py_atomic_store_ullong_relaxed (& m -> thread , PyThread_get_thread_ident_ex ());
468+ }
469+ else {
470+ memset (m , 0 , sizeof (* m ));
471+ }
472+ }
473+ #endif
474+
456475#define _Py_WRITE_LOCKED 1
457476#define _PyRWMutex_READER_SHIFT 2
458477#define _Py_RWMUTEX_MAX_READERS (UINTPTR_MAX >> _PyRWMutex_READER_SHIFT)
You can’t perform that action at this time.
0 commit comments