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