(vm: &VirtualMachine)
| 1000 | |
| 1001 | #[pyfunction] |
| 1002 | fn fork(vm: &VirtualMachine) -> PyResult<i32> { |
| 1003 | if vm |
| 1004 | .state |
| 1005 | .finalizing |
| 1006 | .load(core::sync::atomic::Ordering::Acquire) |
| 1007 | { |
| 1008 | return Err(vm.new_exception_msg( |
| 1009 | vm.ctx.exceptions.python_finalization_error.to_owned(), |
| 1010 | "can't fork at interpreter shutdown".into(), |
| 1011 | )); |
| 1012 | } |
| 1013 | |
| 1014 | // RustPython does not yet have C-level audit hooks; call sys.audit() |
| 1015 | // to preserve Python-visible behavior and failure semantics. |
| 1016 | vm.sys_module |
| 1017 | .get_attr("audit", vm)? |
| 1018 | .call(("os.fork",), vm)?; |
| 1019 | |
| 1020 | py_os_before_fork(vm); |
| 1021 | |
| 1022 | let pid = unsafe { libc::fork() }; |
| 1023 | // Save errno immediately — AfterFork callbacks may clobber it. |
| 1024 | let saved_errno = nix::Error::last_raw(); |
| 1025 | if pid == 0 { |
| 1026 | py_os_after_fork_child(vm); |
| 1027 | } else { |
| 1028 | // Match CPython timing: capture this before parent after-fork hooks |
| 1029 | // in case those hooks start threads. |
| 1030 | let num_os_threads = get_number_of_os_threads(); |
| 1031 | py_os_after_fork_parent(vm); |
| 1032 | // Match CPython timing: warn only after parent callback path resumes world. |
| 1033 | warn_if_multi_threaded("fork", num_os_threads, vm); |
| 1034 | } |
| 1035 | if pid == -1 { |
| 1036 | Err(nix::Error::from_raw(saved_errno).into_pyexception(vm)) |
| 1037 | } else { |
| 1038 | Ok(pid) |
| 1039 | } |
| 1040 | } |
| 1041 | |
| 1042 | #[cfg(not(target_os = "redox"))] |
| 1043 | const MKNOD_DIR_FD: bool = cfg!(not(target_vendor = "apple")); |
no test coverage detected