use core::sync::atomic::AtomicU32;
use core::time::Duration;
use rustix::thread::{FutexFlags, FutexOperation};
use rustix::time::{ClockId, Timespec};
pub fn futex_wait(futex: &AtomicU32, expected: u32, timeout: Option<Duration>) -> bool {
use core::ptr::{null, null_mut};
use core::sync::atomic::Ordering::Relaxed;
let timespec = timeout.and_then(|d| {
Some({
let now = rustix::time::clock_gettime(ClockId::Monotonic);
let plus = Duration::new(now.tv_sec as u64, now.tv_nsec as _).checked_add(d)?;
Timespec {
tv_sec: plus.as_secs() as i64,
tv_nsec: plus.subsec_nanos() as _,
}
})
});
loop {
if futex.load(Relaxed) != expected {
return true;
}
let r = unsafe {
rustix::thread::futex(
futex.as_mut_ptr(),
FutexOperation::WaitBitset,
FutexFlags::PRIVATE,
expected,
timespec.as_ref().map_or(null(), |t| t as *const _),
null_mut(),
!0u32, )
};
match r {
Err(rustix::io::Errno::TIMEDOUT) => return false,
Err(rustix::io::Errno::INTR) => continue,
_ => return true,
}
}
}
pub fn futex_wake(futex: &AtomicU32) -> bool {
use core::ptr::{null, null_mut};
unsafe {
rustix::thread::futex(
futex.as_mut_ptr(),
FutexOperation::Wake,
FutexFlags::PRIVATE,
1,
null(),
null_mut(),
0,
)
.is_ok()
}
}
pub fn futex_wake_all(futex: &AtomicU32) {
use core::ptr::{null, null_mut};
unsafe {
rustix::thread::futex(
futex.as_mut_ptr(),
FutexOperation::Wake,
FutexFlags::PRIVATE,
i32::MAX as u32,
null(),
null_mut(),
0,
)
.ok();
}
}