|
2 | 2 | * I/O core tools. |
3 | 3 | */ |
4 | 4 | pub(crate) use _io::module_def; |
| 5 | +#[cfg(all(unix, feature = "threading"))] |
| 6 | +pub(crate) use _io::reinit_std_streams_after_fork; |
5 | 7 |
|
6 | 8 | cfg_if::cfg_if! { |
7 | 9 | if #[cfg(any(not(target_arch = "wasm32"), target_os = "wasi"))] { |
@@ -4985,6 +4987,61 @@ mod _io { |
4985 | 4987 | } |
4986 | 4988 | } |
4987 | 4989 |
|
| 4990 | + /// 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. |
| 4996 | + #[cfg(all(unix, feature = "threading"))] |
| 4997 | + pub unsafe fn reinit_std_streams_after_fork(vm: &VirtualMachine) { |
| 4998 | + for name in ["stdin", "stdout", "stderr"] { |
| 4999 | + let Ok(stream) = vm.sys_module.get_attr(name, vm) else { |
| 5000 | + continue; |
| 5001 | + }; |
| 5002 | + reinit_io_locks(&stream); |
| 5003 | + } |
| 5004 | + } |
| 5005 | + |
| 5006 | + #[cfg(all(unix, feature = "threading"))] |
| 5007 | + fn reinit_io_locks(obj: &PyObject) { |
| 5008 | + use crate::common::lock::reinit_thread_mutex_after_fork; |
| 5009 | + |
| 5010 | + if let Some(tio) = obj.downcast_ref::<TextIOWrapper>() { |
| 5011 | + unsafe { reinit_thread_mutex_after_fork(&tio.data) }; |
| 5012 | + if let Some(guard) = tio.data.lock() { |
| 5013 | + if let Some(ref data) = *guard { |
| 5014 | + if let Some(ref decoder) = data.decoder { |
| 5015 | + reinit_io_locks(decoder); |
| 5016 | + } |
| 5017 | + reinit_io_locks(&data.buffer); |
| 5018 | + } |
| 5019 | + } |
| 5020 | + return; |
| 5021 | + } |
| 5022 | + if let Some(nl) = obj.downcast_ref::<IncrementalNewlineDecoder>() { |
| 5023 | + unsafe { reinit_thread_mutex_after_fork(&nl.data) }; |
| 5024 | + return; |
| 5025 | + } |
| 5026 | + if let Some(br) = obj.downcast_ref::<BufferedReader>() { |
| 5027 | + unsafe { reinit_thread_mutex_after_fork(&br.data) }; |
| 5028 | + return; |
| 5029 | + } |
| 5030 | + if let Some(bw) = obj.downcast_ref::<BufferedWriter>() { |
| 5031 | + unsafe { reinit_thread_mutex_after_fork(&bw.data) }; |
| 5032 | + return; |
| 5033 | + } |
| 5034 | + if let Some(brw) = obj.downcast_ref::<BufferedRandom>() { |
| 5035 | + unsafe { reinit_thread_mutex_after_fork(&brw.data) }; |
| 5036 | + return; |
| 5037 | + } |
| 5038 | + if let Some(brw) = obj.downcast_ref::<BufferedRWPair>() { |
| 5039 | + unsafe { reinit_thread_mutex_after_fork(&brw.read.data) }; |
| 5040 | + unsafe { reinit_thread_mutex_after_fork(&brw.write.data) }; |
| 5041 | + return; |
| 5042 | + } |
| 5043 | + } |
| 5044 | + |
4988 | 5045 | pub fn io_open( |
4989 | 5046 | file: PyObjectRef, |
4990 | 5047 | mode: Option<&str>, |
|
0 commit comments