use crate::ffi::sync as raw;
use crate::ffi::types::*;
use crate::error::{OsError, Result};
#[inline]
pub fn ulock_wait(operation: u32, addr: *mut u32, value: u32, timeout_us: u32) -> Result<()> {
let r = unsafe { raw::__ulock_wait(operation, addr as *mut c_void, value as u64, timeout_us) };
if r < 0 { Err(OsError::last()) } else { Ok(()) }
}
#[inline]
pub fn ulock_wake(operation: u32, addr: *mut u32) -> Result<u32> {
let r = unsafe { raw::__ulock_wake(operation, addr as *mut c_void, 0) };
if r < 0 { Err(OsError::last()) } else { Ok(r as u32) }
}
pub struct ULock {
state: core::sync::atomic::AtomicU32,
}
impl ULock {
pub const fn new() -> Self {
Self { state: core::sync::atomic::AtomicU32::new(0) }
}
pub fn lock(&self) {
use core::sync::atomic::Ordering::*;
if self.state.compare_exchange(0, 1, Acquire, Relaxed).is_ok() {
return;
}
self.lock_slow();
}
fn lock_slow(&self) {
use core::sync::atomic::Ordering::*;
loop {
let state = self.state.swap(2, Acquire);
if state == 0 { return; }
let addr = self.state.as_ptr();
let _ = ulock_wait(UL_UNFAIR_LOCK, addr, 2, 0);
}
}
pub fn unlock(&self) {
use core::sync::atomic::Ordering::*;
let prev = self.state.swap(0, Release);
if prev == 2 {
let _ = ulock_wake(UL_UNFAIR_LOCK, self.state.as_ptr());
}
}
pub fn try_lock(&self) -> bool {
use core::sync::atomic::Ordering::*;
self.state.compare_exchange(0, 1, Acquire, Relaxed).is_ok()
}
}
pub struct ULockGuard<'a>(&'a ULock);
impl<'a> ULockGuard<'a> {
pub fn acquire(lock: &'a ULock) -> Self {
lock.lock();
Self(lock)
}
}
impl Drop for ULockGuard<'_> {
fn drop(&mut self) { self.0.unlock(); }
}
#[inline]
pub fn futex_wait(addr: *mut u32, expected: u32, timeout_us: u32) -> Result<()> {
ulock_wait(UL_COMPARE_AND_WAIT, addr, expected, timeout_us)
}
#[inline]
pub fn futex_wake(addr: *mut u32) -> Result<u32> {
ulock_wake(UL_COMPARE_AND_WAIT, addr)
}
#[inline]
pub fn futex_wake_all(addr: *mut u32) -> Result<u32> {
ulock_wake(UL_COMPARE_AND_WAIT | ULF_WAKE_ALL, addr)
}