File Index
Files and directories
Sign in
FILE

global.rs

File preview with syntax highlighting.

linux-6.19.14/rust/kernel/sync/lock/global.rs RUST
  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    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.
 97pub struct GlobalGuard<B: GlobalLockBackend> {
 98    inner: Guard<'static, B::Item, B::Backend>,
 99}
100
101impl<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
109impl<B: GlobalLockBackend> core::ops::DerefMut for GlobalGuard<B>
110where
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.
121pub 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`.
127unsafe impl<T, B> Send for GlobalLockedBy<T, B>
128where
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`.
136unsafe impl<T, B> Sync for GlobalLockedBy<T, B>
137where
138    T: ?Sized,
139    B: GlobalLockBackend,
140    LockedBy<T, B::Item>: Sync,
141{
142}
143
144impl<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
156impl<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]
257macro_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}
294pub use global_lock;
295
296#[doc(hidden)]
297#[macro_export]
298macro_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}
~/ Read-only file preview.