xref: /linux/rust/kernel/sync/lock/global.rs (revision 4f9786035f9e519db41375818e1d0b5f20da2f10)
18eea62ffSAlice Ryhl // SPDX-License-Identifier: GPL-2.0
28eea62ffSAlice Ryhl 
38eea62ffSAlice Ryhl // Copyright (C) 2024 Google LLC.
48eea62ffSAlice Ryhl 
58eea62ffSAlice Ryhl //! Support for defining statics containing locks.
68eea62ffSAlice Ryhl 
78eea62ffSAlice Ryhl use crate::{
88eea62ffSAlice Ryhl     str::CStr,
98eea62ffSAlice Ryhl     sync::lock::{Backend, Guard, Lock},
108eea62ffSAlice Ryhl     sync::{LockClassKey, LockedBy},
118eea62ffSAlice Ryhl     types::Opaque,
128eea62ffSAlice Ryhl };
138eea62ffSAlice Ryhl use core::{
148eea62ffSAlice Ryhl     cell::UnsafeCell,
158eea62ffSAlice Ryhl     marker::{PhantomData, PhantomPinned},
16*f73ca66fSMitchell Levy     pin::Pin,
178eea62ffSAlice Ryhl };
188eea62ffSAlice Ryhl 
198eea62ffSAlice Ryhl /// Trait implemented for marker types for global locks.
208eea62ffSAlice Ryhl ///
218eea62ffSAlice Ryhl /// See [`global_lock!`] for examples.
228eea62ffSAlice Ryhl pub trait GlobalLockBackend {
238eea62ffSAlice Ryhl     /// The name for this global lock.
248eea62ffSAlice Ryhl     const NAME: &'static CStr;
258eea62ffSAlice Ryhl     /// Item type stored in this global lock.
268eea62ffSAlice Ryhl     type Item: 'static;
278eea62ffSAlice Ryhl     /// The backend used for this global lock.
288eea62ffSAlice Ryhl     type Backend: Backend + 'static;
298eea62ffSAlice Ryhl     /// The class for this global lock.
get_lock_class() -> Pin<&'static LockClassKey>30*f73ca66fSMitchell Levy     fn get_lock_class() -> Pin<&'static LockClassKey>;
318eea62ffSAlice Ryhl }
328eea62ffSAlice Ryhl 
338eea62ffSAlice Ryhl /// Type used for global locks.
348eea62ffSAlice Ryhl ///
358eea62ffSAlice Ryhl /// See [`global_lock!`] for examples.
368eea62ffSAlice Ryhl pub struct GlobalLock<B: GlobalLockBackend> {
378eea62ffSAlice Ryhl     inner: Lock<B::Item, B::Backend>,
388eea62ffSAlice Ryhl }
398eea62ffSAlice Ryhl 
408eea62ffSAlice Ryhl impl<B: GlobalLockBackend> GlobalLock<B> {
418eea62ffSAlice Ryhl     /// Creates a global lock.
428eea62ffSAlice Ryhl     ///
438eea62ffSAlice Ryhl     /// # Safety
448eea62ffSAlice Ryhl     ///
458eea62ffSAlice Ryhl     /// * Before any other method on this lock is called, [`Self::init`] must be called.
468eea62ffSAlice Ryhl     /// * The type `B` must not be used with any other lock.
new(data: B::Item) -> Self478eea62ffSAlice Ryhl     pub const unsafe fn new(data: B::Item) -> Self {
488eea62ffSAlice Ryhl         Self {
498eea62ffSAlice Ryhl             inner: Lock {
508eea62ffSAlice Ryhl                 state: Opaque::uninit(),
518eea62ffSAlice Ryhl                 data: UnsafeCell::new(data),
528eea62ffSAlice Ryhl                 _pin: PhantomPinned,
538eea62ffSAlice Ryhl             },
548eea62ffSAlice Ryhl         }
558eea62ffSAlice Ryhl     }
568eea62ffSAlice Ryhl 
578eea62ffSAlice Ryhl     /// Initializes a global lock.
588eea62ffSAlice Ryhl     ///
598eea62ffSAlice Ryhl     /// # Safety
608eea62ffSAlice Ryhl     ///
618eea62ffSAlice Ryhl     /// Must not be called more than once on a given lock.
init(&'static self)628eea62ffSAlice Ryhl     pub unsafe fn init(&'static self) {
638eea62ffSAlice Ryhl         // SAFETY: The pointer to `state` is valid for the duration of this call, and both `name`
648eea62ffSAlice Ryhl         // and `key` are valid indefinitely. The `state` is pinned since we have a `'static`
658eea62ffSAlice Ryhl         // reference to `self`.
668eea62ffSAlice Ryhl         //
678eea62ffSAlice Ryhl         // We have exclusive access to the `state` since the caller of `new` promised to call
688eea62ffSAlice Ryhl         // `init` before using any other methods. As `init` can only be called once, all other
698eea62ffSAlice Ryhl         // uses of this lock must happen after this call.
708eea62ffSAlice Ryhl         unsafe {
718eea62ffSAlice Ryhl             B::Backend::init(
728eea62ffSAlice Ryhl                 self.inner.state.get(),
738eea62ffSAlice Ryhl                 B::NAME.as_char_ptr(),
748eea62ffSAlice Ryhl                 B::get_lock_class().as_ptr(),
758eea62ffSAlice Ryhl             )
768eea62ffSAlice Ryhl         }
778eea62ffSAlice Ryhl     }
788eea62ffSAlice Ryhl 
798eea62ffSAlice Ryhl     /// Lock this global lock.
lock(&'static self) -> GlobalGuard<B>808eea62ffSAlice Ryhl     pub fn lock(&'static self) -> GlobalGuard<B> {
818eea62ffSAlice Ryhl         GlobalGuard {
828eea62ffSAlice Ryhl             inner: self.inner.lock(),
838eea62ffSAlice Ryhl         }
848eea62ffSAlice Ryhl     }
858eea62ffSAlice Ryhl 
868eea62ffSAlice Ryhl     /// Try to lock this global lock.
try_lock(&'static self) -> Option<GlobalGuard<B>>878eea62ffSAlice Ryhl     pub fn try_lock(&'static self) -> Option<GlobalGuard<B>> {
888eea62ffSAlice Ryhl         Some(GlobalGuard {
898eea62ffSAlice Ryhl             inner: self.inner.try_lock()?,
908eea62ffSAlice Ryhl         })
918eea62ffSAlice Ryhl     }
928eea62ffSAlice Ryhl }
938eea62ffSAlice Ryhl 
948eea62ffSAlice Ryhl /// A guard for a [`GlobalLock`].
958eea62ffSAlice Ryhl ///
968eea62ffSAlice Ryhl /// See [`global_lock!`] for examples.
978eea62ffSAlice Ryhl pub struct GlobalGuard<B: GlobalLockBackend> {
988eea62ffSAlice Ryhl     inner: Guard<'static, B::Item, B::Backend>,
998eea62ffSAlice Ryhl }
1008eea62ffSAlice Ryhl 
1018eea62ffSAlice Ryhl impl<B: GlobalLockBackend> core::ops::Deref for GlobalGuard<B> {
1028eea62ffSAlice Ryhl     type Target = B::Item;
1038eea62ffSAlice Ryhl 
deref(&self) -> &Self::Target1048eea62ffSAlice Ryhl     fn deref(&self) -> &Self::Target {
1058eea62ffSAlice Ryhl         &self.inner
1068eea62ffSAlice Ryhl     }
1078eea62ffSAlice Ryhl }
1088eea62ffSAlice Ryhl 
1098eea62ffSAlice Ryhl impl<B: GlobalLockBackend> core::ops::DerefMut for GlobalGuard<B> {
deref_mut(&mut self) -> &mut Self::Target1108eea62ffSAlice Ryhl     fn deref_mut(&mut self) -> &mut Self::Target {
1118eea62ffSAlice Ryhl         &mut self.inner
1128eea62ffSAlice Ryhl     }
1138eea62ffSAlice Ryhl }
1148eea62ffSAlice Ryhl 
1158eea62ffSAlice Ryhl /// A version of [`LockedBy`] for a [`GlobalLock`].
1168eea62ffSAlice Ryhl ///
1178eea62ffSAlice Ryhl /// See [`global_lock!`] for examples.
1188eea62ffSAlice Ryhl pub struct GlobalLockedBy<T: ?Sized, B: GlobalLockBackend> {
1198eea62ffSAlice Ryhl     _backend: PhantomData<B>,
1208eea62ffSAlice Ryhl     value: UnsafeCell<T>,
1218eea62ffSAlice Ryhl }
1228eea62ffSAlice Ryhl 
1238eea62ffSAlice Ryhl // SAFETY: The same thread-safety rules as `LockedBy` apply to `GlobalLockedBy`.
1248eea62ffSAlice Ryhl unsafe impl<T, B> Send for GlobalLockedBy<T, B>
1258eea62ffSAlice Ryhl where
1268eea62ffSAlice Ryhl     T: ?Sized,
1278eea62ffSAlice Ryhl     B: GlobalLockBackend,
1288eea62ffSAlice Ryhl     LockedBy<T, B::Item>: Send,
1298eea62ffSAlice Ryhl {
1308eea62ffSAlice Ryhl }
1318eea62ffSAlice Ryhl 
1328eea62ffSAlice Ryhl // SAFETY: The same thread-safety rules as `LockedBy` apply to `GlobalLockedBy`.
1338eea62ffSAlice Ryhl unsafe impl<T, B> Sync for GlobalLockedBy<T, B>
1348eea62ffSAlice Ryhl where
1358eea62ffSAlice Ryhl     T: ?Sized,
1368eea62ffSAlice Ryhl     B: GlobalLockBackend,
1378eea62ffSAlice Ryhl     LockedBy<T, B::Item>: Sync,
1388eea62ffSAlice Ryhl {
1398eea62ffSAlice Ryhl }
1408eea62ffSAlice Ryhl 
1418eea62ffSAlice Ryhl impl<T, B: GlobalLockBackend> GlobalLockedBy<T, B> {
1428eea62ffSAlice Ryhl     /// Create a new [`GlobalLockedBy`].
1438eea62ffSAlice Ryhl     ///
1448eea62ffSAlice Ryhl     /// The provided value will be protected by the global lock indicated by `B`.
new(val: T) -> Self1458eea62ffSAlice Ryhl     pub fn new(val: T) -> Self {
1468eea62ffSAlice Ryhl         Self {
1478eea62ffSAlice Ryhl             value: UnsafeCell::new(val),
1488eea62ffSAlice Ryhl             _backend: PhantomData,
1498eea62ffSAlice Ryhl         }
1508eea62ffSAlice Ryhl     }
1518eea62ffSAlice Ryhl }
1528eea62ffSAlice Ryhl 
1538eea62ffSAlice Ryhl impl<T: ?Sized, B: GlobalLockBackend> GlobalLockedBy<T, B> {
1548eea62ffSAlice Ryhl     /// Access the value immutably.
1558eea62ffSAlice Ryhl     ///
1568eea62ffSAlice Ryhl     /// The caller must prove shared access to the lock.
as_ref<'a>(&'a self, _guard: &'a GlobalGuard<B>) -> &'a T1578eea62ffSAlice Ryhl     pub fn as_ref<'a>(&'a self, _guard: &'a GlobalGuard<B>) -> &'a T {
1588eea62ffSAlice Ryhl         // SAFETY: The lock is globally unique, so there can only be one guard.
1598eea62ffSAlice Ryhl         unsafe { &*self.value.get() }
1608eea62ffSAlice Ryhl     }
1618eea62ffSAlice Ryhl 
1628eea62ffSAlice Ryhl     /// Access the value mutably.
1638eea62ffSAlice Ryhl     ///
1648eea62ffSAlice Ryhl     /// The caller must prove shared exclusive to the lock.
as_mut<'a>(&'a self, _guard: &'a mut GlobalGuard<B>) -> &'a mut T1658eea62ffSAlice Ryhl     pub fn as_mut<'a>(&'a self, _guard: &'a mut GlobalGuard<B>) -> &'a mut T {
1668eea62ffSAlice Ryhl         // SAFETY: The lock is globally unique, so there can only be one guard.
1678eea62ffSAlice Ryhl         unsafe { &mut *self.value.get() }
1688eea62ffSAlice Ryhl     }
1698eea62ffSAlice Ryhl 
1708eea62ffSAlice Ryhl     /// Access the value mutably directly.
1718eea62ffSAlice Ryhl     ///
1728eea62ffSAlice Ryhl     /// The caller has exclusive access to this `GlobalLockedBy`, so they do not need to hold the
1738eea62ffSAlice Ryhl     /// lock.
get_mut(&mut self) -> &mut T1748eea62ffSAlice Ryhl     pub fn get_mut(&mut self) -> &mut T {
1758eea62ffSAlice Ryhl         self.value.get_mut()
1768eea62ffSAlice Ryhl     }
1778eea62ffSAlice Ryhl }
1788eea62ffSAlice Ryhl 
1798eea62ffSAlice Ryhl /// Defines a global lock.
1808eea62ffSAlice Ryhl ///
1818eea62ffSAlice Ryhl /// The global mutex must be initialized before first use. Usually this is done by calling
1828eea62ffSAlice Ryhl /// [`GlobalLock::init`] in the module initializer.
1838eea62ffSAlice Ryhl ///
1848eea62ffSAlice Ryhl /// # Examples
1858eea62ffSAlice Ryhl ///
1868eea62ffSAlice Ryhl /// A global counter:
1878eea62ffSAlice Ryhl ///
1888eea62ffSAlice Ryhl /// ```
1898eea62ffSAlice Ryhl /// # mod ex {
1908eea62ffSAlice Ryhl /// # use kernel::prelude::*;
1918eea62ffSAlice Ryhl /// kernel::sync::global_lock! {
1928eea62ffSAlice Ryhl ///     // SAFETY: Initialized in module initializer before first use.
1938eea62ffSAlice Ryhl ///     unsafe(uninit) static MY_COUNTER: Mutex<u32> = 0;
1948eea62ffSAlice Ryhl /// }
1958eea62ffSAlice Ryhl ///
1968eea62ffSAlice Ryhl /// fn increment_counter() -> u32 {
1978eea62ffSAlice Ryhl ///     let mut guard = MY_COUNTER.lock();
1988eea62ffSAlice Ryhl ///     *guard += 1;
1998eea62ffSAlice Ryhl ///     *guard
2008eea62ffSAlice Ryhl /// }
2018eea62ffSAlice Ryhl ///
2028eea62ffSAlice Ryhl /// impl kernel::Module for MyModule {
2038eea62ffSAlice Ryhl ///     fn init(_module: &'static ThisModule) -> Result<Self> {
2048eea62ffSAlice Ryhl ///         // SAFETY: Called exactly once.
2058eea62ffSAlice Ryhl ///         unsafe { MY_COUNTER.init() };
2068eea62ffSAlice Ryhl ///
2078eea62ffSAlice Ryhl ///         Ok(MyModule {})
2088eea62ffSAlice Ryhl ///     }
2098eea62ffSAlice Ryhl /// }
2108eea62ffSAlice Ryhl /// # struct MyModule {}
2118eea62ffSAlice Ryhl /// # }
2128eea62ffSAlice Ryhl /// ```
2138eea62ffSAlice Ryhl ///
2148eea62ffSAlice Ryhl /// A global mutex used to protect all instances of a given struct:
2158eea62ffSAlice Ryhl ///
2168eea62ffSAlice Ryhl /// ```
2178eea62ffSAlice Ryhl /// # mod ex {
2188eea62ffSAlice Ryhl /// # use kernel::prelude::*;
2198eea62ffSAlice Ryhl /// use kernel::sync::{GlobalGuard, GlobalLockedBy};
2208eea62ffSAlice Ryhl ///
2218eea62ffSAlice Ryhl /// kernel::sync::global_lock! {
2228eea62ffSAlice Ryhl ///     // SAFETY: Initialized in module initializer before first use.
2238eea62ffSAlice Ryhl ///     unsafe(uninit) static MY_MUTEX: Mutex<()> = ();
2248eea62ffSAlice Ryhl /// }
2258eea62ffSAlice Ryhl ///
2268eea62ffSAlice Ryhl /// /// All instances of this struct are protected by `MY_MUTEX`.
2278eea62ffSAlice Ryhl /// struct MyStruct {
2288eea62ffSAlice Ryhl ///     my_counter: GlobalLockedBy<u32, MY_MUTEX>,
2298eea62ffSAlice Ryhl /// }
2308eea62ffSAlice Ryhl ///
2318eea62ffSAlice Ryhl /// impl MyStruct {
2328eea62ffSAlice Ryhl ///     /// Increment the counter in this instance.
2338eea62ffSAlice Ryhl ///     ///
2348eea62ffSAlice Ryhl ///     /// The caller must hold the `MY_MUTEX` mutex.
2358eea62ffSAlice Ryhl ///     fn increment(&self, guard: &mut GlobalGuard<MY_MUTEX>) -> u32 {
2368eea62ffSAlice Ryhl ///         let my_counter = self.my_counter.as_mut(guard);
2378eea62ffSAlice Ryhl ///         *my_counter += 1;
2388eea62ffSAlice Ryhl ///         *my_counter
2398eea62ffSAlice Ryhl ///     }
2408eea62ffSAlice Ryhl /// }
2418eea62ffSAlice Ryhl ///
2428eea62ffSAlice Ryhl /// impl kernel::Module for MyModule {
2438eea62ffSAlice Ryhl ///     fn init(_module: &'static ThisModule) -> Result<Self> {
2448eea62ffSAlice Ryhl ///         // SAFETY: Called exactly once.
2458eea62ffSAlice Ryhl ///         unsafe { MY_MUTEX.init() };
2468eea62ffSAlice Ryhl ///
2478eea62ffSAlice Ryhl ///         Ok(MyModule {})
2488eea62ffSAlice Ryhl ///     }
2498eea62ffSAlice Ryhl /// }
2508eea62ffSAlice Ryhl /// # struct MyModule {}
2518eea62ffSAlice Ryhl /// # }
2528eea62ffSAlice Ryhl /// ```
2538eea62ffSAlice Ryhl #[macro_export]
2548eea62ffSAlice Ryhl macro_rules! global_lock {
2558eea62ffSAlice Ryhl     {
2568eea62ffSAlice Ryhl         $(#[$meta:meta])* $pub:vis
2578eea62ffSAlice Ryhl         unsafe(uninit) static $name:ident: $kind:ident<$valuety:ty> = $value:expr;
2588eea62ffSAlice Ryhl     } => {
2598eea62ffSAlice Ryhl         #[doc = ::core::concat!(
2608eea62ffSAlice Ryhl             "Backend type used by [`",
2618eea62ffSAlice Ryhl             ::core::stringify!($name),
2628eea62ffSAlice Ryhl             "`](static@",
2638eea62ffSAlice Ryhl             ::core::stringify!($name),
2648eea62ffSAlice Ryhl             ")."
2658eea62ffSAlice Ryhl         )]
2668eea62ffSAlice Ryhl         #[allow(non_camel_case_types, unreachable_pub)]
2678eea62ffSAlice Ryhl         $pub enum $name {}
2688eea62ffSAlice Ryhl 
2698eea62ffSAlice Ryhl         impl $crate::sync::lock::GlobalLockBackend for $name {
2708eea62ffSAlice Ryhl             const NAME: &'static $crate::str::CStr = $crate::c_str!(::core::stringify!($name));
2718eea62ffSAlice Ryhl             type Item = $valuety;
2728eea62ffSAlice Ryhl             type Backend = $crate::global_lock_inner!(backend $kind);
2738eea62ffSAlice Ryhl 
274*f73ca66fSMitchell Levy             fn get_lock_class() -> Pin<&'static $crate::sync::LockClassKey> {
2758eea62ffSAlice Ryhl                 $crate::static_lock_class!()
2768eea62ffSAlice Ryhl             }
2778eea62ffSAlice Ryhl         }
2788eea62ffSAlice Ryhl 
2798eea62ffSAlice Ryhl         $(#[$meta])*
2808eea62ffSAlice Ryhl         $pub static $name: $crate::sync::lock::GlobalLock<$name> = {
2818eea62ffSAlice Ryhl             // Defined here to be outside the unsafe scope.
2828eea62ffSAlice Ryhl             let init: $valuety = $value;
2838eea62ffSAlice Ryhl 
2848eea62ffSAlice Ryhl             // SAFETY:
2858eea62ffSAlice Ryhl             // * The user of this macro promises to initialize the macro before use.
2868eea62ffSAlice Ryhl             // * We are only generating one static with this backend type.
2878eea62ffSAlice Ryhl             unsafe { $crate::sync::lock::GlobalLock::new(init) }
2888eea62ffSAlice Ryhl         };
2898eea62ffSAlice Ryhl     };
2908eea62ffSAlice Ryhl }
2918eea62ffSAlice Ryhl pub use global_lock;
2928eea62ffSAlice Ryhl 
2938eea62ffSAlice Ryhl #[doc(hidden)]
2948eea62ffSAlice Ryhl #[macro_export]
2958eea62ffSAlice Ryhl macro_rules! global_lock_inner {
2968eea62ffSAlice Ryhl     (backend Mutex) => {
2978eea62ffSAlice Ryhl         $crate::sync::lock::mutex::MutexBackend
2988eea62ffSAlice Ryhl     };
2998eea62ffSAlice Ryhl     (backend SpinLock) => {
3008eea62ffSAlice Ryhl         $crate::sync::lock::spinlock::SpinLockBackend
3018eea62ffSAlice Ryhl     };
3028eea62ffSAlice Ryhl }
303