use std::sync::atomic::AtomicU32;
use std::time::Duration;
#[cfg(target_os = "linux")]
pub(crate) fn futex_wait(
futex_word: &AtomicU32,
expected: u32,
timeout: Option<Duration>,
) -> bool {
use std::sync::atomic::Ordering;
const FUTEX_WAIT_PRIVATE: i32 = 128;
if futex_word.load(Ordering::Relaxed) != expected {
return true;
}
let timeout_ts = timeout.map(|d| libc::timespec {
tv_sec: d.as_secs() as libc::time_t,
tv_nsec: d.subsec_nanos() as libc::c_long,
});
let timeout_ptr = match &timeout_ts {
Some(ts) => ts as *const libc::timespec,
None => std::ptr::null(),
};
let ret = unsafe {
libc::syscall(
libc::SYS_futex,
futex_word as *const AtomicU32 as *const u32,
FUTEX_WAIT_PRIVATE,
expected as i32,
timeout_ptr,
std::ptr::null::<u32>(),
0i32,
)
};
if ret == 0 {
return true; }
let e = std::io::Error::last_os_error().raw_os_error().unwrap_or(0);
e != libc::ETIMEDOUT
}
#[cfg(target_os = "linux")]
pub(crate) fn futex_wake(futex_word: &AtomicU32, count: u32) {
const FUTEX_WAKE_PRIVATE: i32 = 128 | 1;
let nr_wake = count.min(i32::MAX as u32) as i32;
unsafe {
libc::syscall(
libc::SYS_futex,
futex_word as *const AtomicU32 as *const u32,
FUTEX_WAKE_PRIVATE,
nr_wake,
std::ptr::null::<libc::timespec>(),
std::ptr::null::<u32>(),
0i32,
);
}
}
#[cfg(not(target_os = "linux"))]
pub(crate) fn futex_wait(
futex_word: &AtomicU32,
expected: u32,
timeout: Option<Duration>,
) -> bool {
use std::sync::atomic::Ordering;
if futex_word.load(Ordering::Relaxed) != expected {
return true;
}
let sleep = timeout
.unwrap_or(Duration::from_millis(1))
.min(Duration::from_millis(1));
std::thread::park_timeout(sleep);
let timed_out = timeout.map(|d| sleep >= d).unwrap_or(false);
!timed_out
}
#[cfg(not(target_os = "linux"))]
pub(crate) fn futex_wake(_futex_word: &AtomicU32, _count: u32) {
}