(vm: &VirtualMachine)
| 776 | } |
| 777 | |
| 778 | fn py_os_after_fork_child(vm: &VirtualMachine) { |
| 779 | #[cfg(feature = "threading")] |
| 780 | vm.state.stop_the_world.reset_after_fork(); |
| 781 | |
| 782 | // Phase 1: Reset all internal locks FIRST. |
| 783 | // After fork(), locks held by dead parent threads would deadlock |
| 784 | // if we try to acquire them. This must happen before anything else. |
| 785 | #[cfg(feature = "threading")] |
| 786 | reinit_locks_after_fork(vm); |
| 787 | |
| 788 | // Reinit per-object IO buffer locks on std streams. |
| 789 | // BufferedReader/Writer/TextIOWrapper use PyThreadMutex which can be |
| 790 | // held by dead parent threads, causing deadlocks on any IO in the child. |
| 791 | #[cfg(feature = "threading")] |
| 792 | unsafe { |
| 793 | crate::stdlib::_io::reinit_std_streams_after_fork(vm) |
| 794 | }; |
| 795 | |
| 796 | // Phase 2: Reset low-level atomic state (no locks needed). |
| 797 | crate::signal::clear_after_fork(); |
| 798 | crate::stdlib::_signal::_signal::clear_wakeup_fd_after_fork(); |
| 799 | |
| 800 | // Reset weakref stripe locks that may have been held during fork. |
| 801 | #[cfg(feature = "threading")] |
| 802 | crate::object::reset_weakref_locks_after_fork(); |
| 803 | |
| 804 | // Phase 3: Clean up thread state. Locks are now reinit'd so we can |
| 805 | // acquire them normally instead of using try_lock(). |
| 806 | #[cfg(feature = "threading")] |
| 807 | crate::stdlib::_thread::after_fork_child(vm); |
| 808 | |
| 809 | // CPython parity: reinit import lock ownership metadata in child |
| 810 | // and release the lock acquired by PyOS_BeforeFork(). |
| 811 | #[cfg(feature = "threading")] |
| 812 | unsafe { |
| 813 | crate::stdlib::_imp::after_fork_child_imp_lock_release() |
| 814 | }; |
| 815 | |
| 816 | // Initialize signal handlers for the child's main thread. |
| 817 | // When forked from a worker thread, the OnceCell is empty. |
| 818 | vm.signal_handlers |
| 819 | .get_or_init(crate::signal::new_signal_handlers); |
| 820 | |
| 821 | // Phase 4: Run Python-level at-fork callbacks. |
| 822 | let after_forkers_child: Vec<PyObjectRef> = vm.state.after_forkers_child.lock().clone(); |
| 823 | run_at_forkers(after_forkers_child, false, vm); |
| 824 | } |
| 825 | |
| 826 | /// Reset all parking_lot-based locks in the interpreter state after fork(). |
| 827 | /// |
no test coverage detected