use core::cell::UnsafeCell;
use core::mem;
#[cfg(windows)]
use winapi::um::synchapi::{AcquireSRWLockExclusive, DeleteCriticalSection, EnterCriticalSection,
InitializeCriticalSection, LeaveCriticalSection,
ReleaseSRWLockExclusive};
#[cfg(unix)]
use libc;
mod raw {
#[cfg(unix)]
pub use libc::pthread_mutex_t;
#[cfg(windows)]
pub use winapi::um::minwinbase::CRITICAL_SECTION;
#[cfg(windows)]
pub use winapi::um::synchapi::SRWLOCK;
#[cfg(any(target_os = "macos", target_os = "ios"))]
#[repr(C)]
pub struct OSSpinLock(pub i32);
}
use RawMutex;
pub trait UnsafeRawOsMutex {
unsafe fn init(_mutex: *mut Self) {}
unsafe fn destroy(_mutex: *mut Self) {}
unsafe fn lock(mutex: *mut Self);
unsafe fn unlock(mutex: *mut Self);
}
pub struct RawOsMutex<T: UnsafeRawOsMutex> {
#[doc(hidden)]
pub __inner: UnsafeCell<T>,
}
unsafe impl<T: UnsafeRawOsMutex> Send for RawOsMutex<T> {}
unsafe impl<T: UnsafeRawOsMutex> Sync for RawOsMutex<T> {}
impl<T: UnsafeRawOsMutex> RawMutex for RawOsMutex<T> {
unsafe fn init(&mut self) {
T::init(self.__inner.get());
}
unsafe fn lock(&self) {
T::lock(self.__inner.get());
}
unsafe fn unlock(&self) {
T::unlock(self.__inner.get());
}
unsafe fn destroy(&self) {
T::destroy(self.__inner.get());
}
}
#[macro_export]
macro_rules! raw_os_mutex_new {
($e:expr) => {
$crate::RawOsMutex {
__inner: $crate::UnsafeCell::new($e),
}
};
}
#[cfg(windows)]
pub type SRWLOCK = RawOsMutex<raw::SRWLOCK>;
#[cfg(windows)]
impl UnsafeRawOsMutex for raw::SRWLOCK {
#[inline]
unsafe fn lock(mutex: *mut Self) {
AcquireSRWLockExclusive(mutex);
}
#[inline]
unsafe fn unlock(mutex: *mut Self) {
ReleaseSRWLockExclusive(mutex);
}
}
#[cfg(windows)]
#[doc(hidden)]
pub use winapi::um::synchapi::SRWLOCK_INIT;
#[cfg(windows)]
#[macro_export]
macro_rules! srwlock_new {
() => {
raw_os_mutex_new!($crate::SRWLOCK_INIT)
};
}
#[cfg(windows)]
impl Default for SRWLOCK {
#[inline]
fn default() -> Self {
srwlock_new!()
}
}
#[cfg(windows)]
#[allow(non_camel_case_types)]
pub type CRITICAL_SECTION = RawOsMutex<raw::CRITICAL_SECTION>;
#[cfg(windows)]
impl UnsafeRawOsMutex for raw::CRITICAL_SECTION {
#[inline]
unsafe fn init(mutex: *mut Self) {
InitializeCriticalSection(mutex);
}
#[inline]
unsafe fn lock(mutex: *mut Self) {
EnterCriticalSection(mutex);
}
#[inline]
unsafe fn unlock(mutex: *mut Self) {
LeaveCriticalSection(mutex);
}
#[inline]
unsafe fn destroy(mutex: *mut Self) {
DeleteCriticalSection(mutex);
}
}
#[cfg(windows)]
impl Default for CRITICAL_SECTION {
#[inline]
fn default() -> Self {
unsafe { mem::uninitialized() }
}
}
#[cfg(unix)]
#[doc(hidden)]
pub use libc::PTHREAD_MUTEX_INITIALIZER;
#[cfg(unix)]
#[allow(non_camel_case_types)]
pub type pthread_mutex_t = RawOsMutex<raw::pthread_mutex_t>;
#[cfg(unix)]
impl UnsafeRawOsMutex for raw::pthread_mutex_t {
unsafe fn init(mutex: *mut Self) {
let mut attr: libc::pthread_mutexattr_t = mem::uninitialized();
let r = libc::pthread_mutexattr_init(&mut attr);
debug_assert_eq!(r, 0);
let r = libc::pthread_mutexattr_settype(&mut attr, libc::PTHREAD_MUTEX_NORMAL);
debug_assert_eq!(r, 0);
let r = libc::pthread_mutex_init(mutex, &attr);
debug_assert_eq!(r, 0);
let r = libc::pthread_mutexattr_destroy(&mut attr);
debug_assert_eq!(r, 0);
}
#[inline]
unsafe fn lock(mutex: *mut Self) {
libc::pthread_mutex_lock(mutex);
}
#[inline]
unsafe fn unlock(mutex: *mut Self) {
libc::pthread_mutex_unlock(mutex);
}
#[inline]
unsafe fn destroy(mutex: *mut Self) {
libc::pthread_mutex_destroy(mutex);
}
}
#[cfg(unix)]
#[macro_export]
macro_rules! pthread_mutex_new {
() => {
raw_os_mutex_new!($crate::PTHREAD_MUTEX_INITIALIZER)
};
($e:expr) => {
raw_os_mutex_new!($e)
};
}
#[cfg(unix)]
impl Default for pthread_mutex_t {
#[inline]
fn default() -> Self {
pthread_mutex_new!()
}
}
#[cfg(any(target_os = "macos", target_os = "ios"))]
#[doc(hidden)]
pub const OS_SPINLOCK_INIT: raw::OSSpinLock = raw::OSSpinLock(0);
#[cfg(any(target_os = "macos", target_os = "ios"))]
#[link(name = "System")]
extern "C" {
fn OSSpinLockLock(lock: *mut raw::OSSpinLock);
fn OSSpinLockUnlock(lock: *mut raw::OSSpinLock);
}
#[cfg(any(target_os = "macos", target_os = "ios"))]
pub type OSSpinLock = RawOsMutex<raw::OSSpinLock>;
#[cfg(any(target_os = "macos", target_os = "ios"))]
impl UnsafeRawOsMutex for raw::OSSpinLock {
#[inline]
unsafe fn lock(mutex: *mut Self) {
OSSpinLockLock(mutex);
}
#[inline]
unsafe fn unlock(mutex: *mut Self) {
OSSpinLockUnlock(mutex);
}
}
#[cfg(any(target_os = "macos", target_os = "ios"))]
#[macro_export]
macro_rules! osspinlock_new {
() => {
raw_os_mutex_new!($crate::OS_SPINLOCK_INIT)
};
}
#[cfg(any(target_os = "macos", target_os = "ios"))]
impl Default for OSSpinLock {
#[inline]
fn default() -> Self {
osspinlock_new!()
}
}