pub use std::sync::Arc;
pub use tokio::sync::{Mutex, Notify, RwLock, broadcast, mpsc, oneshot};
#[cfg(all(target_os = "linux", feature = "linux-rt"))]
pub type PriorityInheritanceMutex<T> = pi_mutex::PiMutex<T>;
#[cfg(not(all(target_os = "linux", feature = "linux-rt")))]
pub type PriorityInheritanceMutex<T> = parking_lot::Mutex<T>;
pub fn is_pi_mutex_active() -> bool {
cfg!(all(target_os = "linux", feature = "linux-rt"))
}
#[cfg(all(target_os = "linux", feature = "linux-rt"))]
mod pi_mutex {
use std::cell::UnsafeCell;
use std::ops::{Deref, DerefMut};
pub struct PiMutex<T> {
inner: UnsafeCell<libc::pthread_mutex_t>,
data: UnsafeCell<T>,
}
unsafe impl<T: Send> Send for PiMutex<T> {}
unsafe impl<T: Send> Sync for PiMutex<T> {}
impl<T> PiMutex<T> {
pub fn new(value: T) -> Self {
let mutex = UnsafeCell::new(unsafe { std::mem::zeroed() });
unsafe {
let mut attr: libc::pthread_mutexattr_t = std::mem::zeroed();
let r = libc::pthread_mutexattr_init(&mut attr);
assert_eq!(r, 0, "pthread_mutexattr_init failed");
let r = libc::pthread_mutexattr_setprotocol(&mut attr, libc::PTHREAD_PRIO_INHERIT);
assert_eq!(r, 0, "pthread_mutexattr_setprotocol PRIO_INHERIT failed");
let r = libc::pthread_mutex_init(mutex.get(), &attr);
assert_eq!(r, 0, "pthread_mutex_init failed");
libc::pthread_mutexattr_destroy(&mut attr);
}
Self {
inner: mutex,
data: UnsafeCell::new(value),
}
}
pub fn lock(&self) -> PiMutexGuard<'_, T> {
unsafe {
let r = libc::pthread_mutex_lock(self.inner.get());
assert_eq!(r, 0, "pthread_mutex_lock failed");
}
PiMutexGuard { mutex: self }
}
}
impl<T> Drop for PiMutex<T> {
fn drop(&mut self) {
unsafe {
libc::pthread_mutex_destroy(self.inner.get());
}
}
}
pub struct PiMutexGuard<'a, T> {
mutex: &'a PiMutex<T>,
}
impl<T> Deref for PiMutexGuard<'_, T> {
type Target = T;
fn deref(&self) -> &T {
unsafe { &*self.mutex.data.get() }
}
}
impl<T> DerefMut for PiMutexGuard<'_, T> {
fn deref_mut(&mut self) -> &mut T {
unsafe { &mut *self.mutex.data.get() }
}
}
impl<T> Drop for PiMutexGuard<'_, T> {
fn drop(&mut self) {
unsafe {
libc::pthread_mutex_unlock(self.mutex.inner.get());
}
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn pi_mutex_lock_unlock() {
let m: PriorityInheritanceMutex<i32> = PriorityInheritanceMutex::new(42);
{
let g = m.lock();
assert_eq!(*g, 42);
}
let g = m.lock();
assert_eq!(*g, 42);
}
#[test]
fn is_pi_mutex_active_returns_bool() {
let _b = is_pi_mutex_active();
}
}