@@ -98,20 +98,31 @@ pub fn cleanup_current_thread_frames(vm: &VirtualMachine) {
9898}
9999
100100/// Reinitialize frame slot after fork. Called in child process.
101- /// Creates a fresh slot and registers it for the current thread.
101+ /// Creates a fresh slot and registers it for the current thread,
102+ /// preserving the current thread's frames from `vm.frames`.
102103#[ cfg( feature = "threading" ) ]
103104pub fn reinit_frame_slot_after_fork ( vm : & VirtualMachine ) {
104105 let current_ident = crate :: stdlib:: thread:: get_ident ( ) ;
105- let new_slot = Arc :: new ( parking_lot:: Mutex :: new ( Vec :: new ( ) ) ) ;
106+ // Preserve the current thread's frames across fork
107+ let current_frames: Vec < FrameRef > = vm. frames . borrow ( ) . clone ( ) ;
108+ let new_slot = Arc :: new ( parking_lot:: Mutex :: new ( current_frames) ) ;
106109
107- // Try to update the global registry. If we can't get the lock
108- // (parent thread might have been holding it during fork), skip.
109- if let Some ( mut registry) = vm. state . thread_frames . try_lock ( ) {
110- registry. clear ( ) ;
111- registry. insert ( current_ident, new_slot. clone ( ) ) ;
112- }
110+ // After fork, only the current thread exists. If the lock was held by
111+ // another thread during fork, force unlock it.
112+ let mut registry = match vm. state . thread_frames . try_lock ( ) {
113+ Some ( guard) => guard,
114+ None => {
115+ // SAFETY: After fork in child process, only the current thread
116+ // exists. The lock holder no longer exists.
117+ unsafe { vm. state . thread_frames . force_unlock ( ) } ;
118+ vm. state . thread_frames . lock ( )
119+ }
120+ } ;
121+ registry. clear ( ) ;
122+ registry. insert ( current_ident, new_slot. clone ( ) ) ;
123+ drop ( registry) ;
113124
114- // Always update thread-local to point to the new slot
125+ // Update thread-local to point to the new slot
115126 CURRENT_FRAME_SLOT . with ( |s| {
116127 * s. borrow_mut ( ) = Some ( new_slot) ;
117128 } ) ;
0 commit comments