xref: /linux/rust/kernel/sync/lock/global.rs (revision 37a93dd5c49b5fda807fd204edf2547c3493319c)
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     #[inline]
89     pub fn try_lock(&'static self) -> Option<GlobalGuard<B>> {
90         Some(GlobalGuard {
91             inner: self.inner.try_lock()?,
92         })
93     }
94 }
95 
96 /// A guard for a [`GlobalLock`].
97 ///
98 /// See [`global_lock!`] for examples.
99 pub struct GlobalGuard<B: GlobalLockBackend> {
100     inner: Guard<'static, B::Item, B::Backend>,
101 }
102 
103 impl<B: GlobalLockBackend> core::ops::Deref for GlobalGuard<B> {
104     type Target = B::Item;
105 
106     fn deref(&self) -> &Self::Target {
107         &self.inner
108     }
109 }
110 
111 impl<B: GlobalLockBackend> core::ops::DerefMut for GlobalGuard<B>
112 where
113     B::Item: Unpin,
114 {
115     fn deref_mut(&mut self) -> &mut Self::Target {
116         &mut self.inner
117     }
118 }
119 
120 /// A version of [`LockedBy`] for a [`GlobalLock`].
121 ///
122 /// See [`global_lock!`] for examples.
123 pub struct GlobalLockedBy<T: ?Sized, B: GlobalLockBackend> {
124     _backend: PhantomData<B>,
125     value: UnsafeCell<T>,
126 }
127 
128 // SAFETY: The same thread-safety rules as `LockedBy` apply to `GlobalLockedBy`.
129 unsafe impl<T, B> Send for GlobalLockedBy<T, B>
130 where
131     T: ?Sized,
132     B: GlobalLockBackend,
133     LockedBy<T, B::Item>: Send,
134 {
135 }
136 
137 // SAFETY: The same thread-safety rules as `LockedBy` apply to `GlobalLockedBy`.
138 unsafe impl<T, B> Sync for GlobalLockedBy<T, B>
139 where
140     T: ?Sized,
141     B: GlobalLockBackend,
142     LockedBy<T, B::Item>: Sync,
143 {
144 }
145 
146 impl<T, B: GlobalLockBackend> GlobalLockedBy<T, B> {
147     /// Create a new [`GlobalLockedBy`].
148     ///
149     /// The provided value will be protected by the global lock indicated by `B`.
150     pub fn new(val: T) -> Self {
151         Self {
152             value: UnsafeCell::new(val),
153             _backend: PhantomData,
154         }
155     }
156 }
157 
158 impl<T: ?Sized, B: GlobalLockBackend> GlobalLockedBy<T, B> {
159     /// Access the value immutably.
160     ///
161     /// The caller must prove shared access to the lock.
162     pub fn as_ref<'a>(&'a self, _guard: &'a GlobalGuard<B>) -> &'a T {
163         // SAFETY: The lock is globally unique, so there can only be one guard.
164         unsafe { &*self.value.get() }
165     }
166 
167     /// Access the value mutably.
168     ///
169     /// The caller must prove shared exclusive to the lock.
170     pub fn as_mut<'a>(&'a self, _guard: &'a mut GlobalGuard<B>) -> &'a mut T {
171         // SAFETY: The lock is globally unique, so there can only be one guard.
172         unsafe { &mut *self.value.get() }
173     }
174 
175     /// Access the value mutably directly.
176     ///
177     /// The caller has exclusive access to this `GlobalLockedBy`, so they do not need to hold the
178     /// lock.
179     pub fn get_mut(&mut self) -> &mut T {
180         self.value.get_mut()
181     }
182 }
183 
184 /// Defines a global lock.
185 ///
186 /// The global mutex must be initialized before first use. Usually this is done by calling
187 /// [`GlobalLock::init`] in the module initializer.
188 ///
189 /// # Examples
190 ///
191 /// A global counter:
192 ///
193 /// ```
194 /// # mod ex {
195 /// # use kernel::prelude::*;
196 /// kernel::sync::global_lock! {
197 ///     // SAFETY: Initialized in module initializer before first use.
198 ///     unsafe(uninit) static MY_COUNTER: Mutex<u32> = 0;
199 /// }
200 ///
201 /// fn increment_counter() -> u32 {
202 ///     let mut guard = MY_COUNTER.lock();
203 ///     *guard += 1;
204 ///     *guard
205 /// }
206 ///
207 /// impl kernel::Module for MyModule {
208 ///     fn init(_module: &'static ThisModule) -> Result<Self> {
209 ///         // SAFETY: Called exactly once.
210 ///         unsafe { MY_COUNTER.init() };
211 ///
212 ///         Ok(MyModule {})
213 ///     }
214 /// }
215 /// # struct MyModule {}
216 /// # }
217 /// ```
218 ///
219 /// A global mutex used to protect all instances of a given struct:
220 ///
221 /// ```
222 /// # mod ex {
223 /// # use kernel::prelude::*;
224 /// use kernel::sync::{GlobalGuard, GlobalLockedBy};
225 ///
226 /// kernel::sync::global_lock! {
227 ///     // SAFETY: Initialized in module initializer before first use.
228 ///     unsafe(uninit) static MY_MUTEX: Mutex<()> = ();
229 /// }
230 ///
231 /// /// All instances of this struct are protected by `MY_MUTEX`.
232 /// struct MyStruct {
233 ///     my_counter: GlobalLockedBy<u32, MY_MUTEX>,
234 /// }
235 ///
236 /// impl MyStruct {
237 ///     /// Increment the counter in this instance.
238 ///     ///
239 ///     /// The caller must hold the `MY_MUTEX` mutex.
240 ///     fn increment(&self, guard: &mut GlobalGuard<MY_MUTEX>) -> u32 {
241 ///         let my_counter = self.my_counter.as_mut(guard);
242 ///         *my_counter += 1;
243 ///         *my_counter
244 ///     }
245 /// }
246 ///
247 /// impl kernel::Module for MyModule {
248 ///     fn init(_module: &'static ThisModule) -> Result<Self> {
249 ///         // SAFETY: Called exactly once.
250 ///         unsafe { MY_MUTEX.init() };
251 ///
252 ///         Ok(MyModule {})
253 ///     }
254 /// }
255 /// # struct MyModule {}
256 /// # }
257 /// ```
258 #[macro_export]
259 macro_rules! global_lock {
260     {
261         $(#[$meta:meta])* $pub:vis
262         unsafe(uninit) static $name:ident: $kind:ident<$valuety:ty> = $value:expr;
263     } => {
264         #[doc = ::core::concat!(
265             "Backend type used by [`",
266             ::core::stringify!($name),
267             "`](static@",
268             ::core::stringify!($name),
269             ")."
270         )]
271         #[allow(non_camel_case_types, unreachable_pub)]
272         $pub enum $name {}
273 
274         impl $crate::sync::lock::GlobalLockBackend for $name {
275             const NAME: &'static $crate::str::CStr = $crate::c_str!(::core::stringify!($name));
276             type Item = $valuety;
277             type Backend = $crate::global_lock_inner!(backend $kind);
278 
279             fn get_lock_class() -> Pin<&'static $crate::sync::LockClassKey> {
280                 $crate::static_lock_class!()
281             }
282         }
283 
284         $(#[$meta])*
285         $pub static $name: $crate::sync::lock::GlobalLock<$name> = {
286             // Defined here to be outside the unsafe scope.
287             let init: $valuety = $value;
288 
289             // SAFETY:
290             // * The user of this macro promises to initialize the macro before use.
291             // * We are only generating one static with this backend type.
292             unsafe { $crate::sync::lock::GlobalLock::new(init) }
293         };
294     };
295 }
296 pub use global_lock;
297 
298 #[doc(hidden)]
299 #[macro_export]
300 macro_rules! global_lock_inner {
301     (backend Mutex) => {
302         $crate::sync::lock::mutex::MutexBackend
303     };
304     (backend SpinLock) => {
305         $crate::sync::lock::spinlock::SpinLockBackend
306     };
307 }
308