use crate::{
str::{CStr, CStrExt as _},
sync::lock::{Backend, Guard, Lock},
sync::{LockClassKey, LockedBy},
types::Opaque,
};
use core::{
cell::UnsafeCell,
marker::{PhantomData, PhantomPinned},
pin::Pin,
};
pub trait GlobalLockBackend {
const NAME: &'static CStr;
type Item: 'static;
type Backend: Backend + 'static;
fn get_lock_class() -> Pin<&'static LockClassKey>;
}
pub struct GlobalLock<B: GlobalLockBackend> {
inner: Lock<B::Item, B::Backend>,
}
impl<B: GlobalLockBackend> GlobalLock<B> {
pub const unsafe fn new(data: B::Item) -> Self {
Self {
inner: Lock {
state: Opaque::uninit(),
data: UnsafeCell::new(data),
_pin: PhantomPinned,
},
}
}
pub unsafe fn init(&'static self) {
unsafe {
B::Backend::init(
self.inner.state.get(),
B::NAME.as_char_ptr(),
B::get_lock_class().as_ptr(),
)
}
}
#[inline]
pub fn lock(&'static self) -> GlobalGuard<B> {
GlobalGuard {
inner: self.inner.lock(),
}
}
#[inline]
pub fn try_lock(&'static self) -> Option<GlobalGuard<B>> {
Some(GlobalGuard {
inner: self.inner.try_lock()?,
})
}
}
pub struct GlobalGuard<B: GlobalLockBackend> {
inner: Guard<'static, B::Item, B::Backend>,
}
impl<B: GlobalLockBackend> core::ops::Deref for GlobalGuard<B> {
type Target = B::Item;
fn deref(&self) -> &Self::Target {
&self.inner
}
}
impl<B: GlobalLockBackend> core::ops::DerefMut for GlobalGuard<B>
where
B::Item: Unpin,
{
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.inner
}
}
pub struct GlobalLockedBy<T: ?Sized, B: GlobalLockBackend> {
_backend: PhantomData<B>,
value: UnsafeCell<T>,
}
unsafe impl<T, B> Send for GlobalLockedBy<T, B>
where
T: ?Sized,
B: GlobalLockBackend,
LockedBy<T, B::Item>: Send,
{
}
unsafe impl<T, B> Sync for GlobalLockedBy<T, B>
where
T: ?Sized,
B: GlobalLockBackend,
LockedBy<T, B::Item>: Sync,
{
}
impl<T, B: GlobalLockBackend> GlobalLockedBy<T, B> {
pub fn new(val: T) -> Self {
Self {
value: UnsafeCell::new(val),
_backend: PhantomData,
}
}
}
impl<T: ?Sized, B: GlobalLockBackend> GlobalLockedBy<T, B> {
pub fn as_ref<'a>(&'a self, _guard: &'a GlobalGuard<B>) -> &'a T {
unsafe { &*self.value.get() }
}
pub fn as_mut<'a>(&'a self, _guard: &'a mut GlobalGuard<B>) -> &'a mut T {
unsafe { &mut *self.value.get() }
}
pub fn get_mut(&mut self) -> &mut T {
self.value.get_mut()
}
}
#[macro_export]
macro_rules! global_lock {
{
$(#[$meta:meta])* $pub:vis
unsafe(uninit) static $name:ident: $kind:ident<$valuety:ty> = $value:expr;
} => {
#[doc = ::core::concat!(
"Backend type used by [`",
::core::stringify!($name),
"`](static@",
::core::stringify!($name),
")."
)]
#[allow(non_camel_case_types, unreachable_pub)]
$pub enum $name {}
impl $crate::sync::lock::GlobalLockBackend for $name {
const NAME: &'static $crate::str::CStr = $crate::c_str!(::core::stringify!($name));
type Item = $valuety;
type Backend = $crate::global_lock_inner!(backend $kind);
fn get_lock_class() -> Pin<&'static $crate::sync::LockClassKey> {
$crate::static_lock_class!()
}
}
$(#[$meta])*
$pub static $name: $crate::sync::lock::GlobalLock<$name> = {
let init: $valuety = $value;
unsafe { $crate::sync::lock::GlobalLock::new(init) }
};
};
}
pub use global_lock;
#[doc(hidden)]
#[macro_export]
macro_rules! global_lock_inner {
(backend Mutex) => {
$crate::sync::lock::mutex::MutexBackend
};
(backend SpinLock) => {
$crate::sync::lock::spinlock::SpinLockBackend
};
}