// SPDX-License-Identifier: GPL-2.0 // Copyright (C) 2024 Google LLC. //! Support for defining statics containing locks. use crate::{ str::CStr, sync::lock::{Backend, Guard, Lock}, sync::{LockClassKey, LockedBy}, types::Opaque,};use core::{ cell::UnsafeCell, marker::{PhantomData, PhantomPinned},}; /// Trait implemented for marker types for global locks.////// See [`global_lock!`] for examples.pub trait GlobalLockBackend { /// The name for this global lock. const NAME: &'static CStr; /// Item type stored in this global lock. type Item: 'static; /// The backend used for this global lock. type Backend: Backend + 'static; /// The class for this global lock. fn get_lock_class() -> &'static LockClassKey;} /// Type used for global locks.////// See [`global_lock!`] for examples.pub struct GlobalLock<B: GlobalLockBackend> { inner: Lock<B::Item, B::Backend>,} impl<B: GlobalLockBackend> GlobalLock<B> { /// Creates a global lock. /// /// # Safety /// /// * Before any other method on this lock is called, [`Self::init`] must be called. /// * The type `B` must not be used with any other lock. pub const unsafe fn new(data: B::Item) -> Self { Self { inner: Lock { state: Opaque::uninit(), data: UnsafeCell::new(data), _pin: PhantomPinned, }, } } /// Initializes a global lock. /// /// # Safety /// /// Must not be called more than once on a given lock. pub unsafe fn init(&'static self) { // SAFETY: The pointer to `state` is valid for the duration of this call, and both `name` // and `key` are valid indefinitely. The `state` is pinned since we have a `'static` // reference to `self`. // // We have exclusive access to the `state` since the caller of `new` promised to call // `init` before using any other methods. As `init` can only be called once, all other // uses of this lock must happen after this call. unsafe { B::Backend::init( self.inner.state.get(), B::NAME.as_char_ptr(), B::get_lock_class().as_ptr(), ) } } /// Lock this global lock. pub fn lock(&'static self) -> GlobalGuard<B> { GlobalGuard { inner: self.inner.lock(), } } /// Try to lock this global lock. pub fn try_lock(&'static self) -> Option<GlobalGuard<B>> { Some(GlobalGuard { inner: self.inner.try_lock()?, }) }} /// A guard for a [`GlobalLock`].////// See [`global_lock!`] for examples.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> { fn deref_mut(&mut self) -> &mut Self::Target { &mut self.inner }} /// A version of [`LockedBy`] for a [`GlobalLock`].////// See [`global_lock!`] for examples.pub struct GlobalLockedBy<T: ?Sized, B: GlobalLockBackend> { _backend: PhantomData<B>, value: UnsafeCell<T>,} // SAFETY: The same thread-safety rules as `LockedBy` apply to `GlobalLockedBy`.unsafe impl<T, B> Send for GlobalLockedBy<T, B>where T: ?Sized, B: GlobalLockBackend, LockedBy<T, B::Item>: Send,{} // SAFETY: The same thread-safety rules as `LockedBy` apply to `GlobalLockedBy`.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> { /// Create a new [`GlobalLockedBy`]. /// /// The provided value will be protected by the global lock indicated by `B`. pub fn new(val: T) -> Self { Self { value: UnsafeCell::new(val), _backend: PhantomData, } }} impl<T: ?Sized, B: GlobalLockBackend> GlobalLockedBy<T, B> { /// Access the value immutably. /// /// The caller must prove shared access to the lock. pub fn as_ref<'a>(&'a self, _guard: &'a GlobalGuard<B>) -> &'a T { // SAFETY: The lock is globally unique, so there can only be one guard. unsafe { &*self.value.get() } } /// Access the value mutably. /// /// The caller must prove shared exclusive to the lock. pub fn as_mut<'a>(&'a self, _guard: &'a mut GlobalGuard<B>) -> &'a mut T { // SAFETY: The lock is globally unique, so there can only be one guard. unsafe { &mut *self.value.get() } } /// Access the value mutably directly. /// /// The caller has exclusive access to this `GlobalLockedBy`, so they do not need to hold the /// lock. pub fn get_mut(&mut self) -> &mut T { self.value.get_mut() }} /// Defines a global lock.////// The global mutex must be initialized before first use. Usually this is done by calling/// [`GlobalLock::init`] in the module initializer.////// # Examples////// A global counter:////// ```/// # mod ex {/// # use kernel::prelude::*;/// kernel::sync::global_lock! {/// // SAFETY: Initialized in module initializer before first use./// unsafe(uninit) static MY_COUNTER: Mutex<u32> = 0;/// }////// fn increment_counter() -> u32 {/// let mut guard = MY_COUNTER.lock();/// *guard += 1;/// *guard/// }////// impl kernel::Module for MyModule {/// fn init(_module: &'static ThisModule) -> Result<Self> {/// // SAFETY: Called exactly once./// unsafe { MY_COUNTER.init() };////// Ok(MyModule {})/// }/// }/// # struct MyModule {}/// # }/// ```////// A global mutex used to protect all instances of a given struct:////// ```/// # mod ex {/// # use kernel::prelude::*;/// use kernel::sync::{GlobalGuard, GlobalLockedBy};////// kernel::sync::global_lock! {/// // SAFETY: Initialized in module initializer before first use./// unsafe(uninit) static MY_MUTEX: Mutex<()> = ();/// }////// /// All instances of this struct are protected by `MY_MUTEX`./// struct MyStruct {/// my_counter: GlobalLockedBy<u32, MY_MUTEX>,/// }////// impl MyStruct {/// /// Increment the counter in this instance./// ////// /// The caller must hold the `MY_MUTEX` mutex./// fn increment(&self, guard: &mut GlobalGuard<MY_MUTEX>) -> u32 {/// let my_counter = self.my_counter.as_mut(guard);/// *my_counter += 1;/// *my_counter/// }/// }////// impl kernel::Module for MyModule {/// fn init(_module: &'static ThisModule) -> Result<Self> {/// // SAFETY: Called exactly once./// unsafe { MY_MUTEX.init() };////// Ok(MyModule {})/// }/// }/// # struct MyModule {}/// # }/// ```#[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() -> &'static $crate::sync::LockClassKey { $crate::static_lock_class!() } } $(#[$meta])* $pub static $name: $crate::sync::lock::GlobalLock<$name> = { // Defined here to be outside the unsafe scope. let init: $valuety = $value; // SAFETY: // * The user of this macro promises to initialize the macro before use. // * We are only generating one static with this backend type. 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 };}
// SPDX-License-Identifier: GPL-2.0
// Copyright (C) 2024 Google LLC.
//! Support for defining statics containing locks.
use crate::{
str::CStr,
sync::lock::{Backend, Guard, Lock},
sync::{LockClassKey, LockedBy},
types::Opaque,
};
use core::{
cell::UnsafeCell,
marker::{PhantomData, PhantomPinned},
};
/// Trait implemented for marker types for global locks.
///
/// See [`global_lock!`] for examples.
pub trait GlobalLockBackend {
/// The name for this global lock.
const NAME: &'static CStr;
/// Item type stored in this global lock.
type Item: 'static;
/// The backend used for this global lock.
type Backend: Backend + 'static;
/// The class for this global lock.
fn get_lock_class() -> &'static LockClassKey;
}
/// Type used for global locks.
///
/// See [`global_lock!`] for examples.
pub struct GlobalLock<B: GlobalLockBackend> {
inner: Lock<B::Item, B::Backend>,
}
impl<B: GlobalLockBackend> GlobalLock<B> {
/// Creates a global lock.
///
/// # Safety
///
/// * Before any other method on this lock is called, [`Self::init`] must be called.
/// * The type `B` must not be used with any other lock.
pub const unsafe fn new(data: B::Item) -> Self {
Self {
inner: Lock {
state: Opaque::uninit(),
data: UnsafeCell::new(data),
_pin: PhantomPinned,
},
}
}
/// Initializes a global lock.
///
/// # Safety
///
/// Must not be called more than once on a given lock.
pub unsafe fn init(&'static self) {
// SAFETY: The pointer to `state` is valid for the duration of this call, and both `name`
// and `key` are valid indefinitely. The `state` is pinned since we have a `'static`
// reference to `self`.
//
// We have exclusive access to the `state` since the caller of `new` promised to call
// `init` before using any other methods. As `init` can only be called once, all other
// uses of this lock must happen after this call.
unsafe {
B::Backend::init(
self.inner.state.get(),
B::NAME.as_char_ptr(),
B::get_lock_class().as_ptr(),
)
}
}
/// Lock this global lock.
pub fn lock(&'static self) -> GlobalGuard<B> {
GlobalGuard {
inner: self.inner.lock(),
}
}
/// Try to lock this global lock.
pub fn try_lock(&'static self) -> Option<GlobalGuard<B>> {
Some(GlobalGuard {
inner: self.inner.try_lock()?,
})
}
}
/// A guard for a [`GlobalLock`].
///
/// See [`global_lock!`] for examples.
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> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.inner
}
}
/// A version of [`LockedBy`] for a [`GlobalLock`].
///
/// See [`global_lock!`] for examples.
pub struct GlobalLockedBy<T: ?Sized, B: GlobalLockBackend> {
_backend: PhantomData<B>,
value: UnsafeCell<T>,
}
// SAFETY: The same thread-safety rules as `LockedBy` apply to `GlobalLockedBy`.
unsafe impl<T, B> Send for GlobalLockedBy<T, B>
where
T: ?Sized,
B: GlobalLockBackend,
LockedBy<T, B::Item>: Send,
{
}
// SAFETY: The same thread-safety rules as `LockedBy` apply to `GlobalLockedBy`.
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> {
/// Create a new [`GlobalLockedBy`].
///
/// The provided value will be protected by the global lock indicated by `B`.
pub fn new(val: T) -> Self {
Self {
value: UnsafeCell::new(val),
_backend: PhantomData,
}
}
}
impl<T: ?Sized, B: GlobalLockBackend> GlobalLockedBy<T, B> {
/// Access the value immutably.
///
/// The caller must prove shared access to the lock.
pub fn as_ref<'a>(&'a self, _guard: &'a GlobalGuard<B>) -> &'a T {
// SAFETY: The lock is globally unique, so there can only be one guard.
unsafe { &*self.value.get() }
}
/// Access the value mutably.
///
/// The caller must prove shared exclusive to the lock.
pub fn as_mut<'a>(&'a self, _guard: &'a mut GlobalGuard<B>) -> &'a mut T {
// SAFETY: The lock is globally unique, so there can only be one guard.
unsafe { &mut *self.value.get() }
}
/// Access the value mutably directly.
///
/// The caller has exclusive access to this `GlobalLockedBy`, so they do not need to hold the
/// lock.
pub fn get_mut(&mut self) -> &mut T {
self.value.get_mut()
}
}
/// Defines a global lock.
///
/// The global mutex must be initialized before first use. Usually this is done by calling
/// [`GlobalLock::init`] in the module initializer.
///
/// # Examples
///
/// A global counter:
///
/// ```
/// # mod ex {
/// # use kernel::prelude::*;
/// kernel::sync::global_lock! {
/// // SAFETY: Initialized in module initializer before first use.
/// unsafe(uninit) static MY_COUNTER: Mutex<u32> = 0;
/// }
///
/// fn increment_counter() -> u32 {
/// let mut guard = MY_COUNTER.lock();
/// *guard += 1;
/// *guard
/// }
///
/// impl kernel::Module for MyModule {
/// fn init(_module: &'static ThisModule) -> Result<Self> {
/// // SAFETY: Called exactly once.
/// unsafe { MY_COUNTER.init() };
///
/// Ok(MyModule {})
/// }
/// }
/// # struct MyModule {}
/// # }
/// ```
///
/// A global mutex used to protect all instances of a given struct:
///
/// ```
/// # mod ex {
/// # use kernel::prelude::*;
/// use kernel::sync::{GlobalGuard, GlobalLockedBy};
///
/// kernel::sync::global_lock! {
/// // SAFETY: Initialized in module initializer before first use.
/// unsafe(uninit) static MY_MUTEX: Mutex<()> = ();
/// }
///
/// /// All instances of this struct are protected by `MY_MUTEX`.
/// struct MyStruct {
/// my_counter: GlobalLockedBy<u32, MY_MUTEX>,
/// }
///
/// impl MyStruct {
/// /// Increment the counter in this instance.
/// ///
/// /// The caller must hold the `MY_MUTEX` mutex.
/// fn increment(&self, guard: &mut GlobalGuard<MY_MUTEX>) -> u32 {
/// let my_counter = self.my_counter.as_mut(guard);
/// *my_counter += 1;
/// *my_counter
/// }
/// }
///
/// impl kernel::Module for MyModule {
/// fn init(_module: &'static ThisModule) -> Result<Self> {
/// // SAFETY: Called exactly once.
/// unsafe { MY_MUTEX.init() };
///
/// Ok(MyModule {})
/// }
/// }
/// # struct MyModule {}
/// # }
/// ```
#[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() -> &'static $crate::sync::LockClassKey {
$crate::static_lock_class!()
}
}
$(#[$meta])*
$pub static $name: $crate::sync::lock::GlobalLock<$name> = {
// Defined here to be outside the unsafe scope.
let init: $valuety = $value;
// SAFETY:
// * The user of this macro promises to initialize the macro before use.
// * We are only generating one static with this backend type.
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
};
}