File tree Expand file tree Collapse file tree 4 files changed +42
-1
lines changed
Expand file tree Collapse file tree 4 files changed +42
-1
lines changed Original file line number Diff line number Diff line change @@ -197,6 +197,15 @@ mod weakref_lock {
197197 core:: hint:: spin_loop ( ) ;
198198 }
199199 }
200+
201+ /// Reset all weakref stripe locks after fork in child process.
202+ /// Locks held by parent threads would cause infinite spin in the child.
203+ #[ cfg( unix) ]
204+ pub ( crate ) fn reset_all_after_fork ( ) {
205+ for lock in & LOCKS {
206+ lock. store ( 0 , Ordering :: Release ) ;
207+ }
208+ }
200209}
201210
202211#[ cfg( not( feature = "threading" ) ) ]
@@ -212,6 +221,13 @@ mod weakref_lock {
212221 }
213222}
214223
224+ /// Reset weakref stripe locks after fork. Must be called before any
225+ /// Python code runs in the child process.
226+ #[ cfg( all( unix, feature = "threading" ) ) ]
227+ pub ( crate ) fn reset_weakref_locks_after_fork ( ) {
228+ weakref_lock:: reset_all_after_fork ( ) ;
229+ }
230+
215231// === WeakRefList: inline on every object (tp_weaklist) ===
216232
217233pub ( super ) struct WeakRefList {
Original file line number Diff line number Diff line change @@ -50,6 +50,16 @@ pub(crate) fn set_triggered() {
5050 ANY_TRIGGERED . store ( true , Ordering :: Release ) ;
5151}
5252
53+ /// Reset all signal trigger state after fork in child process.
54+ /// Stale triggers from the parent must not fire in the child.
55+ #[ cfg( unix) ]
56+ pub ( crate ) fn clear_after_fork ( ) {
57+ ANY_TRIGGERED . store ( false , Ordering :: Release ) ;
58+ for trigger in & TRIGGERS {
59+ trigger. store ( false , Ordering :: Relaxed ) ;
60+ }
61+ }
62+
5363pub fn assert_in_range ( signum : i32 , vm : & VirtualMachine ) -> PyResult < ( ) > {
5464 if ( 1 ..NSIG as i32 ) . contains ( & signum) {
5565 Ok ( ( ) )
Original file line number Diff line number Diff line change @@ -660,8 +660,16 @@ pub mod module {
660660 }
661661
662662 fn py_os_after_fork_child ( vm : & VirtualMachine ) {
663+ // Reset low-level state before any Python code runs in the child.
664+ // Signal triggers from the parent must not fire in the child.
665+ crate :: signal:: clear_after_fork ( ) ;
666+ crate :: stdlib:: signal:: _signal:: clear_wakeup_fd_after_fork ( ) ;
667+
668+ // Reset weakref stripe locks that may have been held during fork.
669+ #[ cfg( feature = "threading" ) ]
670+ crate :: object:: reset_weakref_locks_after_fork ( ) ;
671+
663672 // Mark all other threads as done before running Python callbacks
664- // See _PyThread_AfterFork behavior
665673 #[ cfg( feature = "threading" ) ]
666674 crate :: stdlib:: thread:: after_fork_child ( vm) ;
667675
Original file line number Diff line number Diff line change @@ -679,6 +679,13 @@ pub(crate) mod _signal {
679679 }
680680 }
681681
682+ /// Reset wakeup fd after fork in child process.
683+ /// The child must not write to the parent's wakeup fd.
684+ #[ cfg( unix) ]
685+ pub ( crate ) fn clear_wakeup_fd_after_fork ( ) {
686+ WAKEUP . store ( INVALID_WAKEUP , Ordering :: Relaxed ) ;
687+ }
688+
682689 pub ( crate ) fn module_exec (
683690 vm : & VirtualMachine ,
684691 module : & Py < crate :: builtins:: PyModule > ,
You can’t perform that action at this time.
0 commit comments