Skip to main content

kernel/sync/lock/
global.rs

1// SPDX-License-Identifier: GPL-2.0
2
3// Copyright (C) 2024 Google LLC.
4
5//! Support for defining statics containing locks.
6
7use crate::{
8    str::{CStr, CStrExt as _},
9    sync::lock::{Backend, Guard, Lock},
10    sync::{LockClassKey, LockedBy},
11    types::Opaque,
12};
13use 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.
22pub 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.
36pub struct GlobalLock<B: GlobalLockBackend> {
37    inner: Lock<B::Item, B::Backend>,
38}
39
40impl<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"]
101pub struct GlobalGuard<B: GlobalLockBackend> {
102    inner: Guard<'static, B::Item, B::Backend>,
103}
104
105impl<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
113impl<B: GlobalLockBackend> core::ops::DerefMut for GlobalGuard<B>
114where
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.
125pub 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`.
131unsafe impl<T, B> Send for GlobalLockedBy<T, B>
132where
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`.
140unsafe impl<T, B> Sync for GlobalLockedBy<T, B>
141where
142    T: ?Sized,
143    B: GlobalLockBackend,
144    LockedBy<T, B::Item>: Sync,
145{
146}
147
148impl<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
160impl<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]
261macro_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}
298pub use global_lock;
299
300#[doc(hidden)]
301#[macro_export]
302macro_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}