Resume all suspended threads (`start_the_world`).
(&self, vm: &VirtualMachine)
| 388 | |
| 389 | /// Resume all suspended threads (`start_the_world`). |
| 390 | pub fn start_the_world(&self, vm: &VirtualMachine) { |
| 391 | use thread::{THREAD_DETACHED, THREAD_SUSPENDED}; |
| 392 | let requester = self.requester.load(Ordering::Relaxed); |
| 393 | stw_trace(format_args!("start begin requester={requester}")); |
| 394 | let registry = vm.state.thread_frames.lock(); |
| 395 | // Clear the request flag BEFORE waking threads. Otherwise a thread |
| 396 | // returning from allow_threads → attach_thread could observe |
| 397 | // `requested == true`, re-suspend itself, and stay parked forever. |
| 398 | // Keep this write under the registry lock to serialize with new |
| 399 | // thread-slot initialization. |
| 400 | self.requested.store(false, Ordering::Release); |
| 401 | self.world_stopped.store(false, Ordering::Release); |
| 402 | for (&id, slot) in registry.iter() { |
| 403 | if id == requester { |
| 404 | continue; |
| 405 | } |
| 406 | slot.stop_requested.store(false, Ordering::Release); |
| 407 | let state = slot.state.load(Ordering::Relaxed); |
| 408 | debug_assert!( |
| 409 | state == THREAD_SUSPENDED, |
| 410 | "non-requester thread not suspended at start-the-world: id={id} state={state}" |
| 411 | ); |
| 412 | if state == THREAD_SUSPENDED { |
| 413 | slot.state.store(THREAD_DETACHED, Ordering::Release); |
| 414 | slot.thread.unpark(); |
| 415 | } |
| 416 | } |
| 417 | drop(registry); |
| 418 | self.thread_countdown.store(0, Ordering::Release); |
| 419 | self.requester.store(0, Ordering::Relaxed); |
| 420 | #[cfg(debug_assertions)] |
| 421 | self.debug_assert_all_non_requester_detached(vm); |
| 422 | stw_trace(format_args!("start end requester={requester}")); |
| 423 | } |
| 424 | |
| 425 | /// Reset after fork in the child (only one thread alive). |
| 426 | pub fn reset_after_fork(&self) { |
no test coverage detected