Skip to content

Commit e58b7b3

Browse files
committed
clear_after_fork
1 parent 25bf682 commit e58b7b3

File tree

4 files changed

+42
-1
lines changed

4 files changed

+42
-1
lines changed

crates/vm/src/object/core.rs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff 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

217233
pub(super) struct WeakRefList {

crates/vm/src/signal.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff 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+
5363
pub fn assert_in_range(signum: i32, vm: &VirtualMachine) -> PyResult<()> {
5464
if (1..NSIG as i32).contains(&signum) {
5565
Ok(())

crates/vm/src/stdlib/posix.rs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff 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

crates/vm/src/stdlib/signal.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff 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>,

0 commit comments

Comments
 (0)