| // SPDX-License-Identifier: GPL-2.0 | |
| // Copyright (C) 2024 Google LLC. | |
| //! Support for defining statics containing locks. | |
| 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, | |
| }; | |
| /// 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() -> Pin<&'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. | |
| #[inline] | |
| pub fn lock(&'static self) -> GlobalGuard<B> { | |
| GlobalGuard { | |
| inner: self.inner.lock(), | |
| } | |
| } | |
| /// Try to lock this global lock. | |
| #[must_use = "if unused, the lock will be immediately unlocked"] | |
| #[inline] | |
| 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. | |
| #[must_use = "the lock unlocks immediately when the guard is unused"] | |
| 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 | |
| } | |
| } | |
| /// 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() -> Pin<&'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 | |
| }; | |
| } |