Skip to content

Commit 874971c

Browse files
committed
Address review: unsafe fn + decoder lock reinit
- Mark reinit_std_streams_after_fork as unsafe fn to encode fork-only precondition, update call site in posix.rs - Reinit IncrementalNewlineDecoder's PyThreadMutex via TextIOWrapper's decoder field to prevent child deadlocks
1 parent ad20942 commit 874971c

File tree

2 files changed

+14
-2
lines changed

2 files changed

+14
-2
lines changed

crates/vm/src/stdlib/io.rs

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4988,8 +4988,13 @@ mod _io {
49884988
}
49894989

49904990
/// Reinit per-object IO buffer locks on std streams after `fork()`.
4991+
///
4992+
/// # Safety
4993+
///
4994+
/// Must only be called from the single-threaded child process immediately
4995+
/// after `fork()`, before any other thread is created.
49914996
#[cfg(all(unix, feature = "threading"))]
4992-
pub fn reinit_std_streams_after_fork(vm: &VirtualMachine) {
4997+
pub unsafe fn reinit_std_streams_after_fork(vm: &VirtualMachine) {
49934998
for name in ["stdin", "stdout", "stderr"] {
49944999
let Ok(stream) = vm.sys_module.get_attr(name, vm) else {
49955000
continue;
@@ -5006,11 +5011,18 @@ mod _io {
50065011
unsafe { reinit_thread_mutex_after_fork(&tio.data) };
50075012
if let Some(guard) = tio.data.lock() {
50085013
if let Some(ref data) = *guard {
5014+
if let Some(ref decoder) = data.decoder {
5015+
reinit_io_locks(decoder);
5016+
}
50095017
reinit_io_locks(&data.buffer);
50105018
}
50115019
}
50125020
return;
50135021
}
5022+
if let Some(nl) = obj.downcast_ref::<IncrementalNewlineDecoder>() {
5023+
unsafe { reinit_thread_mutex_after_fork(&nl.data) };
5024+
return;
5025+
}
50145026
if let Some(br) = obj.downcast_ref::<BufferedReader>() {
50155027
unsafe { reinit_thread_mutex_after_fork(&br.data) };
50165028
return;

crates/vm/src/stdlib/posix.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -723,7 +723,7 @@ pub mod module {
723723
// BufferedReader/Writer/TextIOWrapper use PyThreadMutex which can be
724724
// held by dead parent threads, causing deadlocks on any IO in the child.
725725
#[cfg(feature = "threading")]
726-
crate::stdlib::io::reinit_std_streams_after_fork(vm);
726+
unsafe { crate::stdlib::io::reinit_std_streams_after_fork(vm) };
727727

728728
// Phase 2: Reset low-level atomic state (no locks needed).
729729
crate::signal::clear_after_fork();

0 commit comments

Comments
 (0)