use std::future::Future;
use std::pin::Pin;
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::{Arc, Mutex};
use std::task::{Context, Poll, Waker};
use std::time::Duration;
mod common;
struct WakeShared {
ready: AtomicBool,
waker: Mutex<Option<Waker>>,
}
struct ForeignWake {
shared: Arc<WakeShared>,
}
impl Future for ForeignWake {
type Output = u32;
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<u32> {
if self.shared.ready.load(Ordering::Acquire) {
return Poll::Ready(42);
}
*self.shared.waker.lock().unwrap() = Some(cx.waker().clone());
if self.shared.ready.load(Ordering::Acquire) {
return Poll::Ready(42);
}
Poll::Pending
}
}
#[test]
fn task_woken_from_foreign_thread_resolves() {
let value = common::block_on(|| async {
let shared = Arc::new(WakeShared {
ready: AtomicBool::new(false),
waker: Mutex::new(None),
});
let foreign = Arc::clone(&shared);
std::thread::spawn(move || {
loop {
if let Some(waker) = foreign.waker.lock().unwrap().clone() {
foreign.ready.store(true, Ordering::Release);
waker.wake();
return;
}
std::thread::yield_now();
}
});
let woken = ForeignWake { shared };
let result: Option<u32> = runite::select! {
v = woken => Some(v),
_ = runite::time::sleep(Duration::from_secs(5)) => None,
};
result.expect("cross-thread wake was never delivered")
});
assert_eq!(value, 42);
}
#[test]
fn task_waker_clone_drop_is_thread_safe() {
let ok = common::block_on(|| async {
let slot: Arc<Mutex<Option<Waker>>> = Arc::new(Mutex::new(None));
std::future::poll_fn(|cx| {
*slot.lock().unwrap() = Some(cx.waker().clone());
Poll::Ready(())
})
.await;
let waker = slot.lock().unwrap().clone().unwrap();
let mut handles = Vec::new();
for _ in 0..8 {
let w = waker.clone();
handles.push(std::thread::spawn(move || {
for _ in 0..10_000 {
let c = w.clone();
drop(c);
}
}));
}
for h in handles {
h.join().unwrap();
}
true
});
assert!(ok);
}