@@ -77,23 +77,20 @@ mod native {
7777 debug ! ( ?boxed_worker, "Spawning worker on SharedRuntime" ) ;
7878 let mut pausable_worker = PausableWorker :: new ( boxed_worker) ;
7979
80- // Lock runtime first to synchronize with before_fork (which does
81- // runtime.take() then workers.lock()), following the documented mutex
82- // lock order. If the runtime has been taken (fork window), skip starting
83- // the worker; after_fork_parent/child will start it on the new runtime.
84- let runtime_handle = self
85- . runtime
86- . lock_or_panic ( )
87- . as_ref ( )
88- . map ( |rt| rt. handle ( ) . clone ( ) ) ;
89- // Hold the workers lock while starting the worker to avoid a race with
90- // before_fork: without this, before_fork could run after the worker is
91- // started but before it's added to the list, not pausing the worker
92- // before the runtime is dropped.
80+ // Lock runtime first, then workers, following the documented mutex
81+ // lock order (matches before_fork). Both guards are held across
82+ // start+push so that before_fork cannot interleave between them:
83+ // otherwise before_fork could take the runtime, drop it, and miss
84+ // our (not-yet-pushed) worker, leaving us with a worker running on
85+ // a torn-down runtime that before_fork never paused. If the
86+ // runtime has been taken (fork window already passed), we skip
87+ // starting; after_fork_parent/child will start the worker on the
88+ // new runtime.
89+ let runtime_guard = self . runtime . lock_or_panic ( ) ;
9390 let mut workers_guard = self . workers . lock_or_panic ( ) ;
9491
95- if let Some ( ref handle ) = runtime_handle {
96- if let Err ( e) = pausable_worker. start ( tokio_spawn_fn ( handle) ) {
92+ if let Some ( rt ) = runtime_guard . as_ref ( ) {
93+ if let Err ( e) = pausable_worker. start ( tokio_spawn_fn ( rt . handle ( ) ) ) {
9794 return Err ( e. into ( ) ) ;
9895 }
9996 }
0 commit comments