use core::ops::Deref;
use core::sync::atomic::{AtomicU32, Ordering};
use libc::{syscall, SYS_futex};
#[repr(C)]
pub struct Futex(AtomicU32);
pub type Atomic = AtomicU32;
pub type Primitive = u32;
pub type SmallFutex = Futex;
pub type SmallAtomic = Atomic;
pub type SmallPrimitive = Primitive;
impl Futex {
#[inline]
pub const fn new(initial_value: u32) -> Self {
Self(AtomicU32::new(initial_value))
}
#[inline]
pub fn wait(&self, expected_start_value: u32) {
unsafe {
syscall(
SYS_futex,
core::ptr::from_ref(&self.0),
libc::FUTEX_WAIT_BITSET | libc::FUTEX_PRIVATE_FLAG,
expected_start_value,
core::ptr::null::<()>(),
core::ptr::null::<u32>(), // This argument is unused for FUTEX_WAIT_BITSET.
!0u32, // A full bitmask, to make it behave like a regular FUTEX_WAIT.
);
}
}
#[inline]
pub fn wake(&self) -> bool {
let ptr = &self.0 as *const AtomicU32;
const OP: libc::c_int = libc::FUTEX_WAKE | libc::FUTEX_PRIVATE_FLAG;
unsafe { libc::syscall(libc::SYS_futex, ptr, OP, 1) > 0 }
}
#[inline]
pub fn wake_all(&self) {
let ptr = &raw const self.0;
let op = libc::FUTEX_WAKE | libc::FUTEX_PRIVATE_FLAG;
unsafe {
syscall(libc::SYS_futex, ptr, op, i32::MAX);
}
}
}
impl Deref for Futex {
type Target = Atomic;
#[inline]
fn deref(&self) -> &Self::Target {
&self.0
}
}
|