use crate::error::{Error, Result};
use crate::sys;
use std::cell::UnsafeCell;
use std::ops::{Deref, DerefMut};
use std::ptr;
use std::time::Duration;
pub struct Mutex<T> {
raw: *mut sys::llam_mutex_t,
value: UnsafeCell<T>,
}
unsafe impl<T: Send> Send for Mutex<T> {}
unsafe impl<T: Send> Sync for Mutex<T> {}
impl<T> Mutex<T> {
pub fn new(value: T) -> Result<Self> {
let raw = unsafe { sys::llam_mutex_create() };
if raw.is_null() {
Err(Error::last())
} else {
Ok(Self {
raw,
value: UnsafeCell::new(value),
})
}
}
pub fn lock(&self) -> Result<MutexGuard<'_, T>> {
let rc = unsafe { sys::llam_mutex_lock(self.raw) };
if rc == 0 {
Ok(MutexGuard { mutex: self })
} else {
Err(Error::last())
}
}
pub fn lock_timeout(&self, timeout: Duration) -> Result<MutexGuard<'_, T>> {
self.lock_until(crate::time::deadline_after(timeout))
}
pub fn lock_until(&self, deadline_ns: u64) -> Result<MutexGuard<'_, T>> {
let rc = unsafe { sys::llam_mutex_lock_until(self.raw, deadline_ns) };
if rc == 0 {
Ok(MutexGuard { mutex: self })
} else {
Err(Error::last())
}
}
pub fn try_lock(&self) -> Result<MutexGuard<'_, T>> {
let rc = unsafe { sys::llam_mutex_trylock(self.raw) };
if rc == 0 {
Ok(MutexGuard { mutex: self })
} else {
Err(Error::last())
}
}
fn raw(&self) -> *mut sys::llam_mutex_t {
self.raw
}
}
impl<T> Drop for Mutex<T> {
fn drop(&mut self) {
if !self.raw.is_null() {
unsafe {
let _ = sys::llam_mutex_destroy(self.raw);
}
self.raw = ptr::null_mut();
}
}
}
pub struct MutexGuard<'a, T> {
mutex: &'a Mutex<T>,
}
impl<T> Deref for MutexGuard<'_, T> {
type Target = T;
fn deref(&self) -> &Self::Target {
unsafe { &*self.mutex.value.get() }
}
}
impl<T> DerefMut for MutexGuard<'_, T> {
fn deref_mut(&mut self) -> &mut Self::Target {
unsafe { &mut *self.mutex.value.get() }
}
}
impl<T> Drop for MutexGuard<'_, T> {
fn drop(&mut self) {
unsafe {
let _ = sys::llam_mutex_unlock(self.mutex.raw);
}
}
}
pub struct Condvar {
raw: *mut sys::llam_cond_t,
}
unsafe impl Send for Condvar {}
unsafe impl Sync for Condvar {}
impl Condvar {
pub fn new() -> Result<Self> {
let raw = unsafe { sys::llam_cond_create() };
if raw.is_null() {
Err(Error::last())
} else {
Ok(Self { raw })
}
}
pub fn wait<'a, T>(&self, guard: MutexGuard<'a, T>) -> Result<MutexGuard<'a, T>> {
let mutex = guard.mutex;
std::mem::forget(guard);
let rc = unsafe { sys::llam_cond_wait(self.raw, mutex.raw()) };
if rc == 0 {
Ok(MutexGuard { mutex })
} else {
unsafe {
let _ = sys::llam_mutex_unlock(mutex.raw());
}
Err(Error::last())
}
}
pub fn wait_timeout<'a, T>(
&self,
guard: MutexGuard<'a, T>,
timeout: Duration,
) -> Result<MutexGuard<'a, T>> {
self.wait_until(guard, crate::time::deadline_after(timeout))
}
pub fn wait_until<'a, T>(
&self,
guard: MutexGuard<'a, T>,
deadline_ns: u64,
) -> Result<MutexGuard<'a, T>> {
let mutex = guard.mutex;
std::mem::forget(guard);
let rc = unsafe { sys::llam_cond_wait_until(self.raw, mutex.raw(), deadline_ns) };
if rc == 0 {
Ok(MutexGuard { mutex })
} else {
unsafe {
let _ = sys::llam_mutex_unlock(mutex.raw());
}
Err(Error::last())
}
}
pub fn notify_one(&self) -> Result<()> {
let rc = unsafe { sys::llam_cond_signal(self.raw) };
if rc == 0 {
Ok(())
} else {
Err(Error::last())
}
}
pub fn notify_all(&self) -> Result<()> {
let rc = unsafe { sys::llam_cond_broadcast(self.raw) };
if rc == 0 {
Ok(())
} else {
Err(Error::last())
}
}
}
impl Drop for Condvar {
fn drop(&mut self) {
if !self.raw.is_null() {
unsafe {
let _ = sys::llam_cond_destroy(self.raw);
}
self.raw = ptr::null_mut();
}
}
}