sync: use swap in AtomicWaker::wake (#7450)

This commit is contained in:
Orson Peters
2025-07-09 10:09:34 +00:00
committed by GitHub
parent a7896d07f1
commit 085e616c87
2 changed files with 36 additions and 3 deletions
+4 -3
View File
@@ -316,11 +316,12 @@ impl AtomicWaker {
// memory the `AtomicWaker` is associated with.
match self.state.fetch_or(WAKING, AcqRel) {
WAITING => {
// The waking lock has been acquired.
// SAFETY: the waking lock has been acquired.
let waker = unsafe { self.waker.with_mut(|t| (*t).take()) };
// Release the lock
self.state.fetch_and(!WAKING, Release);
// Release the lock.
let old_state = self.state.swap(WAITING, Release);
debug_assert!(old_state == WAKING);
waker
}
+32
View File
@@ -39,6 +39,38 @@ fn wake_without_register() {
assert!(!waker.is_woken());
}
#[test]
#[cfg_attr(target_family = "wasm", ignore)] // threads not supported
fn failed_wake_synchronizes() {
for _ in 0..1000 {
failed_wake_synchronizes_inner();
}
}
fn failed_wake_synchronizes_inner() {
use futures::task::noop_waker_ref;
use std::sync::atomic::{AtomicBool, Ordering};
static DID_SYNCHRONIZE: AtomicBool = AtomicBool::new(false);
DID_SYNCHRONIZE.store(false, Ordering::Relaxed);
let waker = AtomicWaker::new();
waker.register_by_ref(noop_waker_ref());
std::thread::scope(|s| {
let jh = s.spawn(|| {
DID_SYNCHRONIZE.store(true, Ordering::Relaxed);
waker.take_waker()
});
waker.take_waker();
waker.register_by_ref(noop_waker_ref());
let did_synchronize = DID_SYNCHRONIZE.load(Ordering::Relaxed);
let did_take = jh.join().unwrap().is_some();
assert!(did_synchronize || did_take);
});
}
#[cfg(panic = "unwind")]
#[test]
#[cfg(not(target_family = "wasm"))] // wasm currently doesn't support unwinding