(stw: &super::StopTheWorldState)
| 269 | #[cfg(all(unix, feature = "threading"))] |
| 270 | #[cold] |
| 271 | fn do_suspend(stw: &super::StopTheWorldState) { |
| 272 | CURRENT_THREAD_SLOT.with(|slot| { |
| 273 | if let Some(s) = slot.borrow().as_ref() { |
| 274 | // ATTACHED → SUSPENDED |
| 275 | match s.state.compare_exchange( |
| 276 | THREAD_ATTACHED, |
| 277 | THREAD_SUSPENDED, |
| 278 | Ordering::AcqRel, |
| 279 | Ordering::Acquire, |
| 280 | ) { |
| 281 | Ok(_) => { |
| 282 | // Consumed this thread's stop request bit. |
| 283 | s.stop_requested.store(false, Ordering::Release); |
| 284 | } |
| 285 | Err(THREAD_DETACHED) => { |
| 286 | // Leaving VM; caller will re-check on next entry. |
| 287 | super::stw_trace(format_args!("suspend skip DETACHED")); |
| 288 | return; |
| 289 | } |
| 290 | Err(THREAD_SUSPENDED) => { |
| 291 | // Already parked by another path. |
| 292 | s.stop_requested.store(false, Ordering::Release); |
| 293 | super::stw_trace(format_args!("suspend skip already-suspended")); |
| 294 | return; |
| 295 | } |
| 296 | Err(state) => { |
| 297 | debug_assert!(false, "unexpected thread state in suspend: {state}"); |
| 298 | return; |
| 299 | } |
| 300 | } |
| 301 | super::stw_trace(format_args!("suspend ATTACHED->SUSPENDED")); |
| 302 | |
| 303 | // Re-check: if start_the_world already ran (cleared `requested`), |
| 304 | // no one will set us back to DETACHED — we must self-recover. |
| 305 | if !stw.requested.load(Ordering::Acquire) { |
| 306 | s.state.store(THREAD_ATTACHED, Ordering::Release); |
| 307 | s.stop_requested.store(false, Ordering::Release); |
| 308 | super::stw_trace(format_args!("suspend abort requested-cleared")); |
| 309 | return; |
| 310 | } |
| 311 | |
| 312 | // Notify the stop-the-world requester that we've parked |
| 313 | stw.notify_suspended(); |
| 314 | super::stw_trace(format_args!("suspend notified-requester")); |
| 315 | |
| 316 | // Wait until start_the_world sets us back to DETACHED |
| 317 | let wait_yields = wait_while_suspended(s); |
| 318 | stw.add_suspend_wait_yields(wait_yields); |
| 319 | |
| 320 | // Re-attach (DETACHED → ATTACHED), tstate_wait_attach CAS loop. |
| 321 | loop { |
| 322 | match s.state.compare_exchange( |
| 323 | THREAD_DETACHED, |
| 324 | THREAD_ATTACHED, |
| 325 | Ordering::AcqRel, |
| 326 | Ordering::Acquire, |
| 327 | ) { |
| 328 | Ok(_) => break, |
no test coverage detected