#[cfg(not(target_os = "macos"))]
use core::ffi::c_int;
#[cfg(feature = "named")]
use core::marker::PhantomData;
#[cfg(all(feature = "unnamed", not(target_os = "macos")))]
use core::pin::Pin;
use core::{cell::UnsafeCell,
fmt::{self, Debug, Display, Formatter},
ptr};
#[derive(Copy, Clone)]
pub struct SemaphoreRef<'l>(Kind<'l>);
#[derive(Copy, Clone)]
enum Kind<'l> {
#[cfg(all(feature = "unnamed", not(target_os = "macos")))]
Unnamed(Pin<&'l UnsafeCell<libc::sem_t>>),
#[cfg(feature = "named")]
Named(
*mut libc::sem_t,
PhantomData<&'l UnsafeCell<libc::sem_t>>,
),
}
unsafe impl Sync for SemaphoreRef<'_> {}
unsafe impl Send for SemaphoreRef<'_> {}
macro_rules! mem_sync_of_wait_et_al {
() => {
"\n\nThis synchronizes memory with respect to other threads on all successful calls. \
That is a primary use-case so that other threads' memory writes to other objects, \
sequenced before [`Self::post()`], will be visible to the current thread \
after returning from this. If this returns an error, it is unspecified whether the \
invocation causes memory to be synchronized. (See: [POSIX's requirements](\
https://pubs.opengroup.org/onlinepubs/9799919799/basedefs/V1_chap04.html#tag_04_15_02).)"
}
}
impl<'l> SemaphoreRef<'l> {
#![cfg_attr(
not(all(feature = "unnamed", not(target_os = "macos"))),
allow(single_use_lifetimes)
)]
#[cfg(all(feature = "unnamed", not(target_os = "macos")))]
pub(crate) unsafe fn unnamed(inited: Pin<&'l UnsafeCell<libc::sem_t>>) -> Self {
Self(Kind::Unnamed(inited))
}
#[cfg(feature = "named")]
pub(crate) unsafe fn named(opened: *mut libc::sem_t) -> Self {
Self(Kind::Named(opened, PhantomData))
}
fn raw(&self) -> *mut libc::sem_t {
match self.0 {
#[cfg(all(feature = "unnamed", not(target_os = "macos")))]
Kind::Unnamed(cell) => cell.get(),
#[cfg(feature = "named")]
Kind::Named(ptr, _) => ptr,
}
}
#[inline]
pub fn post(&self) -> Result<(), ()> {
let r = unsafe { libc::sem_post(self.raw()) };
if r == 0 {
Ok(())
} else {
Err(()) }
}
#[doc = mem_sync_of_wait_et_al!()]
#[inline]
pub fn wait(&self) -> Result<(), ()> {
let r = unsafe { libc::sem_wait(self.raw()) };
if r == 0 {
Ok(())
} else {
Err(()) }
}
#[doc = mem_sync_of_wait_et_al!()]
#[inline]
pub fn try_wait(&self) -> Result<(), ()> {
let r = unsafe { libc::sem_trywait(self.raw()) };
if r == 0 {
Ok(())
} else {
Err(()) }
}
#[cfg(not(target_os = "macos"))]
#[must_use]
#[inline]
pub fn get_value(&self) -> c_int {
let mut sval = c_int::MIN;
let r = unsafe { libc::sem_getvalue(self.raw(), &mut sval) };
debug_assert_eq!(r, 0, "the semaphore should be valid");
sval
}
}
impl PartialEq for SemaphoreRef<'_> {
#[inline]
fn eq(&self, other: &Self) -> bool { ptr::eq(self.raw(), other.raw()) }
}
impl Eq for SemaphoreRef<'_> {}
impl Debug for SemaphoreRef<'_> {
#[inline]
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
f.debug_tuple("SemaphoreRef").field(&self.raw()).finish()
}
}
#[cfg(not(target_os = "macos"))]
impl Display for SemaphoreRef<'_> {
#[inline]
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
write!(f, "<Semaphore value:{}>", self.get_value())
}
}
#[cfg(target_os = "macos")]
impl Display for SemaphoreRef<'_> {
#[inline]
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { write!(f, "<Semaphore inited>") }
}