Linux Audio

Check our new training course

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