xref: /linux/rust/kernel/sync/lock/global.rs (revision 056a5087d87ead77dedbe9cf5bde53b7cd4b4651)
1 // SPDX-License-Identifier: GPL-2.0
2 
3 // Copyright (C) 2024 Google LLC.
4 
5 //! Support for defining statics containing locks.
6 
7 use crate::{
8     str::{CStr, CStrExt as _},
9     sync::lock::{Backend, Guard, Lock},
10     sync::{LockClassKey, LockedBy},
11     types::Opaque,
12 };
13 use core::{
14     cell::UnsafeCell,
15     marker::{PhantomData, PhantomPinned},
16     pin::Pin,
17 };
18 
19 /// Trait implemented for marker types for global locks.
20 ///
21 /// See [`global_lock!`] for examples.
22 pub trait GlobalLockBackend {
23     /// The name for this global lock.
24     const NAME: &'static CStr;
25     /// Item type stored in this global lock.
26     type Item: 'static;
27     /// The backend used for this global lock.
28     type Backend: Backend + 'static;
29     /// The class for this global lock.
30     fn get_lock_class() -> Pin<&'static LockClassKey>;
31 }
32 
33 /// Type used for global locks.
34 ///
35 /// See [`global_lock!`] for examples.
36 pub struct GlobalLock<B: GlobalLockBackend> {
37     inner: Lock<B::Item, B::Backend>,
38 }
39 
40 impl<B: GlobalLockBackend> GlobalLock<B> {
41     /// Creates a global lock.
42     ///
43     /// # Safety
44     ///
45     /// * Before any other method on this lock is called, [`Self::init`] must be called.
46     /// * The type `B` must not be used with any other lock.
47     pub const unsafe fn new(data: B::Item) -> Self {
48         Self {
49             inner: Lock {
50                 state: Opaque::uninit(),
51                 data: UnsafeCell::new(data),
52                 _pin: PhantomPinned,
53             },
54         }
55     }
56 
57     /// Initializes a global lock.
58     ///
59     /// # Safety
60     ///
61     /// Must not be called more than once on a given lock.
62     pub unsafe fn init(&'static self) {
63         // SAFETY: The pointer to `state` is valid for the duration of this call, and both `name`
64         // and `key` are valid indefinitely. The `state` is pinned since we have a `'static`
65         // reference to `self`.
66         //
67         // We have exclusive access to the `state` since the caller of `new` promised to call
68         // `init` before using any other methods. As `init` can only be called once, all other
69         // uses of this lock must happen after this call.
70         unsafe {
71             B::Backend::init(
72                 self.inner.state.get(),
73                 B::NAME.as_char_ptr(),
74                 B::get_lock_class().as_ptr(),
75             )
76         }
77     }
78 
79     /// Lock this global lock.
80     #[inline]
81     pub fn lock(&'static self) -> GlobalGuard<B> {
82         GlobalGuard {
83             inner: self.inner.lock(),
84         }
85     }
86 
87     /// Try to lock this global lock.
88     #[must_use = "if unused, the lock will be immediately unlocked"]
89     #[inline]
90     pub fn try_lock(&'static self) -> Option<GlobalGuard<B>> {
91         Some(GlobalGuard {
92             inner: self.inner.try_lock()?,
93         })
94     }
95 }
96 
97 /// A guard for a [`GlobalLock`].
98 ///
99 /// See [`global_lock!`] for examples.
100 #[must_use = "the lock unlocks immediately when the guard is unused"]
101 pub struct GlobalGuard<B: GlobalLockBackend> {
102     inner: Guard<'static, B::Item, B::Backend>,
103 }
104 
105 impl<B: GlobalLockBackend> core::ops::Deref for GlobalGuard<B> {
106     type Target = B::Item;
107 
108     fn deref(&self) -> &Self::Target {
109         &self.inner
110     }
111 }
112 
113 impl<B: GlobalLockBackend> core::ops::DerefMut for GlobalGuard<B>
114 where
115     B::Item: Unpin,
116 {
117     fn deref_mut(&mut self) -> &mut Self::Target {
118         &mut self.inner
119     }
120 }
121 
122 /// A version of [`LockedBy`] for a [`GlobalLock`].
123 ///
124 /// See [`global_lock!`] for examples.
125 pub struct GlobalLockedBy<T: ?Sized, B: GlobalLockBackend> {
126     _backend: PhantomData<B>,
127     value: UnsafeCell<T>,
128 }
129 
130 // SAFETY: The same thread-safety rules as `LockedBy` apply to `GlobalLockedBy`.
131 unsafe impl<T, B> Send for GlobalLockedBy<T, B>
132 where
133     T: ?Sized,
134     B: GlobalLockBackend,
135     LockedBy<T, B::Item>: Send,
136 {
137 }
138 
139 // SAFETY: The same thread-safety rules as `LockedBy` apply to `GlobalLockedBy`.
140 unsafe impl<T, B> Sync for GlobalLockedBy<T, B>
141 where
142     T: ?Sized,
143     B: GlobalLockBackend,
144     LockedBy<T, B::Item>: Sync,
145 {
146 }
147 
148 impl<T, B: GlobalLockBackend> GlobalLockedBy<T, B> {
149     /// Create a new [`GlobalLockedBy`].
150     ///
151     /// The provided value will be protected by the global lock indicated by `B`.
152     pub fn new(val: T) -> Self {
153         Self {
154             value: UnsafeCell::new(val),
155             _backend: PhantomData,
156         }
157     }
158 }
159 
160 impl<T: ?Sized, B: GlobalLockBackend> GlobalLockedBy<T, B> {
161     /// Access the value immutably.
162     ///
163     /// The caller must prove shared access to the lock.
164     pub fn as_ref<'a>(&'a self, _guard: &'a GlobalGuard<B>) -> &'a T {
165         // SAFETY: The lock is globally unique, so there can only be one guard.
166         unsafe { &*self.value.get() }
167     }
168 
169     /// Access the value mutably.
170     ///
171     /// The caller must prove shared exclusive to the lock.
172     pub fn as_mut<'a>(&'a self, _guard: &'a mut GlobalGuard<B>) -> &'a mut T {
173         // SAFETY: The lock is globally unique, so there can only be one guard.
174         unsafe { &mut *self.value.get() }
175     }
176 
177     /// Access the value mutably directly.
178     ///
179     /// The caller has exclusive access to this `GlobalLockedBy`, so they do not need to hold the
180     /// lock.
181     pub fn get_mut(&mut self) -> &mut T {
182         self.value.get_mut()
183     }
184 }
185 
186 /// Defines a global lock.
187 ///
188 /// The global mutex must be initialized before first use. Usually this is done by calling
189 /// [`GlobalLock::init`] in the module initializer.
190 ///
191 /// # Examples
192 ///
193 /// A global counter:
194 ///
195 /// ```
196 /// # mod ex {
197 /// # use kernel::prelude::*;
198 /// kernel::sync::global_lock! {
199 ///     // SAFETY: Initialized in module initializer before first use.
200 ///     unsafe(uninit) static MY_COUNTER: Mutex<u32> = 0;
201 /// }
202 ///
203 /// fn increment_counter() -> u32 {
204 ///     let mut guard = MY_COUNTER.lock();
205 ///     *guard += 1;
206 ///     *guard
207 /// }
208 ///
209 /// impl kernel::Module for MyModule {
210 ///     fn init(_module: &'static ThisModule) -> Result<Self> {
211 ///         // SAFETY: Called exactly once.
212 ///         unsafe { MY_COUNTER.init() };
213 ///
214 ///         Ok(MyModule {})
215 ///     }
216 /// }
217 /// # struct MyModule {}
218 /// # }
219 /// ```
220 ///
221 /// A global mutex used to protect all instances of a given struct:
222 ///
223 /// ```
224 /// # mod ex {
225 /// # use kernel::prelude::*;
226 /// use kernel::sync::{GlobalGuard, GlobalLockedBy};
227 ///
228 /// kernel::sync::global_lock! {
229 ///     // SAFETY: Initialized in module initializer before first use.
230 ///     unsafe(uninit) static MY_MUTEX: Mutex<()> = ();
231 /// }
232 ///
233 /// /// All instances of this struct are protected by `MY_MUTEX`.
234 /// struct MyStruct {
235 ///     my_counter: GlobalLockedBy<u32, MY_MUTEX>,
236 /// }
237 ///
238 /// impl MyStruct {
239 ///     /// Increment the counter in this instance.
240 ///     ///
241 ///     /// The caller must hold the `MY_MUTEX` mutex.
242 ///     fn increment(&self, guard: &mut GlobalGuard<MY_MUTEX>) -> u32 {
243 ///         let my_counter = self.my_counter.as_mut(guard);
244 ///         *my_counter += 1;
245 ///         *my_counter
246 ///     }
247 /// }
248 ///
249 /// impl kernel::Module for MyModule {
250 ///     fn init(_module: &'static ThisModule) -> Result<Self> {
251 ///         // SAFETY: Called exactly once.
252 ///         unsafe { MY_MUTEX.init() };
253 ///
254 ///         Ok(MyModule {})
255 ///     }
256 /// }
257 /// # struct MyModule {}
258 /// # }
259 /// ```
260 #[macro_export]
261 macro_rules! global_lock {
262     {
263         $(#[$meta:meta])* $pub:vis
264         unsafe(uninit) static $name:ident: $kind:ident<$valuety:ty> = $value:expr;
265     } => {
266         #[doc = ::core::concat!(
267             "Backend type used by [`",
268             ::core::stringify!($name),
269             "`](static@",
270             ::core::stringify!($name),
271             ")."
272         )]
273         #[allow(non_camel_case_types, unreachable_pub)]
274         $pub enum $name {}
275 
276         impl $crate::sync::lock::GlobalLockBackend for $name {
277             const NAME: &'static $crate::str::CStr = $crate::c_str!(::core::stringify!($name));
278             type Item = $valuety;
279             type Backend = $crate::global_lock_inner!(backend $kind);
280 
281             fn get_lock_class() -> Pin<&'static $crate::sync::LockClassKey> {
282                 $crate::static_lock_class!()
283             }
284         }
285 
286         $(#[$meta])*
287         $pub static $name: $crate::sync::lock::GlobalLock<$name> = {
288             // Defined here to be outside the unsafe scope.
289             let init: $valuety = $value;
290 
291             // SAFETY:
292             // * The user of this macro promises to initialize the macro before use.
293             // * We are only generating one static with this backend type.
294             unsafe { $crate::sync::lock::GlobalLock::new(init) }
295         };
296     };
297 }
298 pub use global_lock;
299 
300 #[doc(hidden)]
301 #[macro_export]
302 macro_rules! global_lock_inner {
303     (backend Mutex) => {
304         $crate::sync::lock::mutex::MutexBackend
305     };
306     (backend SpinLock) => {
307         $crate::sync::lock::spinlock::SpinLockBackend
308     };
309 }
310