// 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 { inner: Lock, } impl GlobalLock { /// 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 { GlobalGuard { inner: self.inner.lock(), } } /// Try to lock this global lock. pub fn try_lock(&'static self) -> Option> { Some(GlobalGuard { inner: self.inner.try_lock()?, }) } } /// A guard for a [`GlobalLock`]. /// /// See [`global_lock!`] for examples. pub struct GlobalGuard { inner: Guard<'static, B::Item, B::Backend>, } impl core::ops::Deref for GlobalGuard { type Target = B::Item; fn deref(&self) -> &Self::Target { &self.inner } } impl core::ops::DerefMut for GlobalGuard { 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 { _backend: PhantomData, value: UnsafeCell, } // SAFETY: The same thread-safety rules as `LockedBy` apply to `GlobalLockedBy`. unsafe impl Send for GlobalLockedBy where T: ?Sized, B: GlobalLockBackend, LockedBy: Send, { } // SAFETY: The same thread-safety rules as `LockedBy` apply to `GlobalLockedBy`. unsafe impl Sync for GlobalLockedBy where T: ?Sized, B: GlobalLockBackend, LockedBy: Sync, { } impl GlobalLockedBy { /// 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 GlobalLockedBy { /// Access the value immutably. /// /// The caller must prove shared access to the lock. pub fn as_ref<'a>(&'a self, _guard: &'a GlobalGuard) -> &'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) -> &'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 = 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 { /// // 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, /// } /// /// impl MyStruct { /// /// Increment the counter in this instance. /// /// /// /// The caller must hold the `MY_MUTEX` mutex. /// fn increment(&self, guard: &mut GlobalGuard) -> 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 { /// // 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 }; }