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