Skip to content

Commit d95e4ab

Browse files
committed
fork safety
1 parent f7b2660 commit d95e4ab

File tree

4 files changed

+11
-16
lines changed

4 files changed

+11
-16
lines changed

Cargo.lock

Lines changed: 1 addition & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,8 @@ lto = "thin"
9191
[patch.crates-io]
9292
# REDOX START, Uncomment when you want to compile/check with redoxer
9393
# REDOX END
94+
# Fork-safety: expose reinit_after_fork() to reset global hash table after fork
95+
parking_lot_core = { git = "https://github.com/youknowone/parking_lot", rev = "e7c6c4e53a65d0143ffe417e2cc55c9467c3f3e1" }
9496

9597
[package.metadata.packager]
9698
product-name = "RustPython"
@@ -184,6 +186,7 @@ num_enum = { version = "0.7", default-features = false }
184186
optional = "0.5"
185187
once_cell = "1.20.3"
186188
parking_lot = "0.12.3"
189+
parking_lot_core = { version = "0.9.12", features = ["fork"] }
187190
paste = "1.0.15"
188191
proc-macro2 = "1.0.105"
189192
pymath = { version = "0.1.5", features = ["mul_add", "malachite-bigint", "complex"] }

crates/vm/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ num-traits = { workspace = true }
6464
num_enum = { workspace = true }
6565
once_cell = { workspace = true }
6666
parking_lot = { workspace = true }
67+
parking_lot_core = { workspace = true }
6768
paste = { workspace = true }
6869
scoped-tls = { workspace = true }
6970
scopeguard = { workspace = true }

crates/vm/src/stdlib/thread.rs

Lines changed: 6 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -147,15 +147,9 @@ pub(crate) mod _thread {
147147

148148
#[pymethod]
149149
fn _at_fork_reinit(&self, _vm: &VirtualMachine) -> PyResult<()> {
150-
if self.mu.is_locked() {
151-
unsafe {
152-
self.mu.unlock();
153-
};
154-
}
155-
// Casting to AtomicCell is as unsafe as CPython code.
156-
// Using AtomicCell will prevent compiler optimizer move it to somewhere later unsafe place.
157-
// It will be not under the cell anymore after init call.
158-
150+
// Don't call unlock() — it may invoke unlock_slow() which accesses
151+
// parking_lot_core's global hash table that is stale after fork().
152+
// Just overwrite the mutex with a fresh INIT value.
159153
let new_mut = RawMutex::INIT;
160154
unsafe {
161155
let old_mutex: &AtomicCell<RawMutex> = core::mem::transmute(&self.mu);
@@ -247,11 +241,9 @@ pub(crate) mod _thread {
247241

248242
#[pymethod]
249243
fn _at_fork_reinit(&self, _vm: &VirtualMachine) -> PyResult<()> {
250-
if self.mu.is_locked() {
251-
unsafe {
252-
self.mu.unlock();
253-
};
254-
}
244+
// Don't call unlock() — it may invoke unlock_slow() which accesses
245+
// parking_lot_core's global hash table that is stale after fork().
246+
// Just overwrite the mutex with a fresh INIT value.
255247
self.count.store(0, core::sync::atomic::Ordering::Relaxed);
256248
let new_mut = RawRMutex::INIT;
257249
unsafe {

0 commit comments

Comments
 (0)