use crate::platform::{FutexFlags, TimeSpec};
use crate::Error;
use core::sync::atomic::AtomicU32;
use linux_rust_bindings::futex::{FUTEX_WAIT, FUTEX_WAKE};
use sc::syscall;
#[inline]
pub fn futex_wait(
uaddr: &AtomicU32,
val: u32,
flags: FutexFlags,
timeout: Option<TimeSpec>,
) -> Result<(), Error> {
let res = unsafe {
syscall!(
FUTEX,
core::ptr::from_ref::<AtomicU32>(uaddr),
FUTEX_WAIT & flags.bits().0,
val,
timeout
.as_ref()
.map_or_else(core::ptr::null, core::ptr::from_ref::<TimeSpec>),
0,
0
)
};
bail_on_below_zero!(res, "`FUTEX` (wait) syscall failed");
Ok(())
}
#[inline]
pub fn futex_wake(uaddr: &AtomicU32, num_waiters: i32) -> Result<usize, Error> {
let res = unsafe {
syscall!(
FUTEX,
core::ptr::from_ref::<AtomicU32>(uaddr),
FUTEX_WAKE,
num_waiters,
0,
0,
0
)
};
bail_on_below_zero!(res, "`FUTEX` (wake) syscall failed");
Ok(res)
}
#[cfg(test)]
mod tests {
#[test]
#[cfg(feature = "alloc")]
fn test_futex_wait_wake() {
use crate::futex::{futex_wait, futex_wake};
use crate::platform::FutexFlags;
use core::sync::atomic::AtomicU32;
use core::time::Duration;
let rf = alloc::sync::Arc::new(AtomicU32::new(15));
let rf_c = rf.clone();
std::thread::spawn(move || {
std::thread::sleep(Duration::from_millis(5));
futex_wake(rf.as_ref(), i32::MAX).unwrap();
});
futex_wait(rf_c.as_ref(), 15, FutexFlags::empty(), None).unwrap();
}
}