#![no_std]
#![deny(missing_docs)]
#[cfg(any(feature = "std", test))]
extern crate std;
#[cfg(any(feature = "std", test))]
use std::prelude::v1::*;
#[cfg(windows)]
extern crate winapi;
#[cfg(unix)]
extern crate libc;
#[macro_use]
extern crate flexible_locks_derive;
#[cfg(feature = "allocator_api")]
extern crate allocator_api;
#[cfg(feature = "parking_lot")]
extern crate parking_lot;
#[doc(hidden)]
pub use core::cell::UnsafeCell;
use core::marker::PhantomData;
use core::ops::{Deref, DerefMut};
use core::ptr;
mod flexible_locks {
pub use super::MutexProtected;
}
mod os;
pub use os::*;
pub trait RawMutex: Send + Sync {
unsafe fn init(&mut self) {}
unsafe fn destroy(&self) {}
unsafe fn lock(&self);
unsafe fn unlock(&self);
}
#[cfg(any(feature = "std", test))]
impl<T: RawMutex> RawMutex for Box<T> {
unsafe fn init(&mut self) {
self.as_mut().init()
}
unsafe fn lock(&self) {
self.as_ref().lock()
}
unsafe fn unlock(&self) {
self.as_ref().unlock()
}
unsafe fn destroy(&self) {
self.as_ref().destroy()
}
}
pub trait MutexProtected {
type MutexType: RawMutex;
type DataType: ?Sized;
fn get_mutex(&self) -> &Self::MutexType;
fn get_mutex_mut(&mut self) -> &mut Self::MutexType;
fn get_data(&self) -> &Self::DataType;
fn get_data_mut(&mut self) -> &mut Self::DataType;
fn into_data(self) -> Self::DataType
where
Self::DataType: Sized;
}
#[doc(hidden)]
#[derive(MutexProtected)]
pub struct MutexWrapper<M: RawMutex, T: ?Sized>(#[mutex] pub M, pub T);
impl<M: RawMutex + Default, T> From<T> for MutexWrapper<M, T> {
fn from(t: T) -> Self {
MutexWrapper(Default::default(), t)
}
}
pub struct Mutex<T: MutexProtected + ?Sized> {
#[doc(hidden)]
pub __wrapper: UnsafeCell<T>,
}
unsafe impl<T: MutexProtected + ?Sized + Send> Send for Mutex<T> {}
unsafe impl<T: MutexProtected + ?Sized + Send> Sync for Mutex<T> {}
#[macro_export]
macro_rules! mutex_new {
($m:expr, $d:expr) => {
$crate::MutexWrap {
__inner: mutex_new!($crate::MutexWrapper($m, $d)),
}
};
($e:expr) => {
$crate::Mutex {
__wrapper: $crate::UnsafeCell::new($e),
}
};
}
impl<T: MutexProtected> Mutex<T>
where
T::DataType: Sized,
{
pub fn new(t: T) -> Self {
let m = mutex_new!(t);
unsafe {
let wrapper: &mut T = &mut *m.__wrapper.get();
wrapper.get_mutex_mut().init();
}
m
}
pub fn into_inner(self) -> T::DataType {
unsafe {
let wrapper = ptr::read(&self.__wrapper);
core::mem::forget(self);
wrapper.into_inner().into_data()
}
}
}
impl<T: MutexProtected> From<T> for Mutex<T>
where
T::DataType: Sized,
{
fn from(t: T) -> Self {
Mutex::<T>::new(t)
}
}
impl<T: MutexProtected<DataType = T> + Sized + Default> Default for Mutex<T> {
fn default() -> Self {
Mutex::<T>::new(Default::default())
}
}
impl<T: MutexProtected + ?Sized> Mutex<T> {
pub fn lock(&self) -> MutexGuard<T> {
unsafe {
let wrapper = &mut *self.__wrapper.get();
wrapper.get_mutex().lock();
MutexGuard::new(wrapper)
}
}
pub fn get_mut(&mut self) -> &mut T::DataType {
let wrapper = unsafe { &mut *self.__wrapper.get() };
T::get_data_mut(wrapper)
}
}
impl<T: MutexProtected + ?Sized> Drop for Mutex<T> {
fn drop(&mut self) {
unsafe {
let wrapper: &T = &*self.__wrapper.get();
wrapper.get_mutex().destroy();
}
}
}
pub struct MutexWrap<M: RawMutex, T: ?Sized> {
#[doc(hidden)]
pub __inner: Mutex<MutexWrapper<M, T>>,
}
impl<M: RawMutex + Default, T> MutexWrap<M, T> {
pub fn new(t: T) -> Self {
MutexWrap {
__inner: Mutex::new(MutexWrapper(Default::default(), t)),
}
}
pub fn into_inner(self) -> T {
self.__inner.into_inner()
}
}
impl<M: RawMutex + Default, T> From<T> for MutexWrap<M, T> {
fn from(t: T) -> Self {
MutexWrap::new(t)
}
}
impl<M: RawMutex + Default, T: Default> Default for MutexWrap<M, T> {
fn default() -> Self {
MutexWrap::new(Default::default())
}
}
impl<M: RawMutex, T: ?Sized> MutexWrap<M, T> {
pub fn lock(&self) -> MutexGuard<MutexWrapper<M, T>> {
self.__inner.lock()
}
pub fn get_mut(&mut self) -> &mut T {
self.__inner.get_mut()
}
}
#[must_use]
pub struct MutexGuard<'a, T: MutexProtected + ?Sized + 'a> {
__wrapper: &'a mut T,
marker: PhantomData<*mut ()>, }
unsafe impl<'a, T: MutexProtected + ?Sized + Sync> Sync for MutexGuard<'a, T> {}
impl<'a, T: MutexProtected + ?Sized + 'a> MutexGuard<'a, T> {
fn new(wrapper: &'a mut T) -> Self {
MutexGuard {
__wrapper: wrapper,
marker: PhantomData,
}
}
}
impl<'a, T: MutexProtected + ?Sized + 'a> Drop for MutexGuard<'a, T> {
fn drop(&mut self) {
unsafe {
self.__wrapper.get_mutex().unlock();
}
}
}
impl<'a, T: MutexProtected + ?Sized + 'a> Deref for MutexGuard<'a, T> {
type Target = T::DataType;
fn deref(&self) -> &T::DataType {
T::get_data(&self.__wrapper)
}
}
impl<'a, T: MutexProtected + ?Sized + 'a> DerefMut for MutexGuard<'a, T> {
fn deref_mut(&mut self) -> &mut T::DataType {
T::get_data_mut(&mut self.__wrapper)
}
}
#[cfg(feature = "parking_lot")]
pub type ParkingLotMutex = parking_lot::Mutex<()>;
#[cfg(feature = "parking_lot")]
impl RawMutex for ParkingLotMutex {
unsafe fn lock(&self) {
self.raw_lock()
}
unsafe fn unlock(&self) {
self.raw_unlock()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[cfg(windows)]
type RawOsMutex = SRWLOCK;
#[cfg(unix)]
type RawOsMutex = pthread_mutex_t;
mod base {
use super::*;
static mut INITIALIZED: usize = 0;
static mut LOCKED: usize = 0;
static mut UNLOCKED: usize = 0;
static mut DESTROYED: usize = 0;
#[derive(PartialEq, Debug, Default)]
struct FakeMutex;
unsafe impl Send for FakeMutex {}
unsafe impl Sync for FakeMutex {}
impl RawMutex for FakeMutex {
unsafe fn init(&mut self) {
INITIALIZED += 1;
}
unsafe fn lock(&self) {
LOCKED += 1;
}
unsafe fn unlock(&self) {
UNLOCKED += 1;
}
unsafe fn destroy(&self) {
DESTROYED += 1;
}
}
#[derive(MutexProtected, PartialEq, Debug, Default)]
struct WithEmbeddedMutex<M: RawMutex>(usize, #[mutex] M, usize);
#[test]
fn smoke() {
macro_rules! smoke_test {
($m:expr, $drop:expr) => {
unsafe {
INITIALIZED = 0;
LOCKED = 0;
UNLOCKED = 0;
DESTROYED = 0;
}
let m = $m;
unsafe {
assert_eq!(INITIALIZED, 1);
assert_eq!(LOCKED, 0);
assert_eq!(UNLOCKED, 0);
assert_eq!(DESTROYED, 0);
}
for i in 0..2 {
let data = m.lock();
unsafe {
assert_eq!(INITIALIZED, 1);
assert_eq!(LOCKED, i + 1);
assert_eq!(UNLOCKED, i);
assert_eq!(DESTROYED, 0);
}
drop(data);
unsafe {
assert_eq!(INITIALIZED, 1);
assert_eq!(LOCKED, i + 1);
assert_eq!(UNLOCKED, i + 1);
assert_eq!(DESTROYED, 0);
}
}
$drop(m);
unsafe {
assert_eq!(INITIALIZED, 1);
assert_eq!(LOCKED, 2);
assert_eq!(UNLOCKED, 2);
assert_eq!(DESTROYED, 1);
}
};
}
smoke_test!(MutexWrap::<FakeMutex, usize>::new(42), drop);
smoke_test!(
MutexWrap::<FakeMutex, usize>::new(42),
|m: MutexWrap<_, _>| assert_eq!(m.into_inner(), 42)
);
smoke_test!(MutexWrap::<Box<FakeMutex>, usize>::new(42), drop);
smoke_test!(
MutexWrap::<Box<FakeMutex>, usize>::new(42),
|m: MutexWrap<_, _>| assert_eq!(m.into_inner(), 42)
);
smoke_test!(Mutex::new(WithEmbeddedMutex(42, FakeMutex, 42)), drop);
smoke_test!(
Mutex::new(WithEmbeddedMutex(42, FakeMutex, 42)),
|m: Mutex<_>| assert_eq!(m.into_inner(), WithEmbeddedMutex(42, FakeMutex, 42))
);
smoke_test!(
Mutex::new(WithEmbeddedMutex(42, Box::new(FakeMutex), 42)),
drop
);
smoke_test!(
Mutex::new(WithEmbeddedMutex(42, Box::new(FakeMutex), 42)),
|m: Mutex<_>| assert_eq!(
m.into_inner(),
WithEmbeddedMutex(42, Box::new(FakeMutex), 42)
)
);
}
}
mod wrap {
use super::*;
type Mutex<T> = super::MutexWrap<RawOsMutex, T>;
include!("tests.rs");
}
mod boxed {
use super::*;
type Mutex<T> = super::MutexWrap<Box<RawOsMutex>, T>;
include!("tests.rs");
}
#[cfg(feature = "parking_lot")]
mod parking_lot {
use super::*;
type Mutex<T> = super::MutexWrap<ParkingLotMutex, T>;
include!("tests.rs");
}
#[cfg(windows)]
mod critical_section {
use super::*;
type Mutex<T> = super::MutexWrap<CRITICAL_SECTION, T>;
include!("tests.rs");
}
#[cfg(any(target_os = "macos", target_os = "ios"))]
mod osspinlock {
use super::*;
type Mutex<T> = super::MutexWrap<OSSpinLock, T>;
include!("tests.rs");
}
}