use std::any::Any;
use std::sync::Arc;
use std::sync::atomic::{AtomicUsize, Ordering};
use std::time::Duration;
use gpu_handle_types::{BackendKind, Error, SyncPoint, SyncWaiter};
#[test]
fn cpu_wait_blocking_immediate() {
SyncPoint::Cpu.wait_blocking().expect("Cpu wait must succeed immediately");
SyncPoint::Noop.wait_blocking().expect("Noop wait must succeed immediately");
}
#[test]
fn cpu_is_signaled_true() {
assert!(SyncPoint::Cpu.is_signaled().expect("Cpu is_signaled never errors"));
assert!(SyncPoint::Noop.is_signaled().expect("Noop is_signaled never errors"));
}
#[test]
fn cpu_wait_async_immediate() {
pollster::block_on(async {
SyncPoint::Cpu.wait().await.expect("Cpu async wait must succeed immediately");
SyncPoint::Noop.wait().await.expect("Noop async wait must succeed immediately");
});
}
struct CountdownWaiter {
flip_after: usize,
probes: AtomicUsize,
}
impl SyncWaiter for CountdownWaiter {
fn wait(&self, _timeout: Duration) -> Result<(), Error> {
let n = self.probes.fetch_add(1, Ordering::SeqCst);
if n >= self.flip_after { Ok(()) } else { Err(Error::Timeout) }
}
fn is_signaled(&self) -> Result<bool, Error> {
let n = self.probes.fetch_add(1, Ordering::SeqCst);
Ok(n >= self.flip_after)
}
fn backend(&self) -> BackendKind {
BackendKind::Cpu
}
fn as_any(&self) -> &dyn Any {
self
}
}
fn sync_point_with_waiter(w: Arc<dyn SyncWaiter>) -> SyncPoint {
SyncPoint::Cuda { event: core::ptr::null_mut(), value: None, waiter: w }
}
#[test]
fn custom_waiter_drives_to_completion_async() {
let w: Arc<dyn SyncWaiter> = Arc::new(CountdownWaiter { flip_after: 4, probes: AtomicUsize::new(0) });
let sp = sync_point_with_waiter(w);
pollster::block_on(async {
sp.wait_with_timeout_async(Duration::from_secs(5)).await.expect("countdown waiter must signal within 5 s");
});
}
struct NeverWaiter;
impl SyncWaiter for NeverWaiter {
fn wait(&self, _timeout: Duration) -> Result<(), Error> {
Err(Error::Timeout)
}
fn is_signaled(&self) -> Result<bool, Error> {
Ok(false)
}
fn backend(&self) -> BackendKind {
BackendKind::Cpu
}
fn as_any(&self) -> &dyn Any {
self
}
}
#[test]
fn timeout_surfaces_on_unsignalled_waiter_async() {
let sp = sync_point_with_waiter(Arc::new(NeverWaiter));
let result = pollster::block_on(sp.wait_with_timeout_async(Duration::from_millis(50)));
match result {
Err(Error::Timeout) => {}
other => panic!("expected Error::Timeout, got {other:?}"),
}
}
#[test]
fn timeout_surfaces_on_unsignalled_waiter_blocking() {
let sp = sync_point_with_waiter(Arc::new(NeverWaiter));
let result = sp.wait_with_timeout(Duration::from_millis(50));
match result {
Err(Error::Timeout) => {}
other => panic!("expected Error::Timeout, got {other:?}"),
}
}
struct AlwaysSignalledWaiter;
impl SyncWaiter for AlwaysSignalledWaiter {
fn wait(&self, _timeout: Duration) -> Result<(), Error> {
Ok(())
}
fn is_signaled(&self) -> Result<bool, Error> {
Ok(true)
}
fn backend(&self) -> BackendKind {
BackendKind::Cpu
}
fn as_any(&self) -> &dyn Any {
self
}
}
#[test]
fn repeated_is_signaled_is_stable() {
let sp = sync_point_with_waiter(Arc::new(AlwaysSignalledWaiter));
for _ in 0..16 {
assert!(sp.is_signaled().expect("settled waiter never errors"));
}
}