301 lines · 8.4 KB · Rust
RawDownload
// SPDX-License-Identifier: GPL-2.0 // Copyright (C) 2024 Google LLC. //! Support for defining statics containing locks. use crate::{    str::CStr,    sync::lock::{Backend, Guard, Lock},    sync::{LockClassKey, LockedBy},    types::Opaque,};use core::{    cell::UnsafeCell,    marker::{PhantomData, PhantomPinned},}; /// Trait implemented for marker types for global locks.////// See [`global_lock!`] for examples.pub trait GlobalLockBackend {    /// The name for this global lock.    const NAME: &'static CStr;    /// Item type stored in this global lock.    type Item: 'static;    /// The backend used for this global lock.    type Backend: Backend + 'static;    /// The class for this global lock.    fn get_lock_class() -> &'static LockClassKey;} /// Type used for global locks.////// See [`global_lock!`] for examples.pub struct GlobalLock<B: GlobalLockBackend> {    inner: Lock<B::Item, B::Backend>,} impl<B: GlobalLockBackend> GlobalLock<B> {    /// Creates a global lock.    ///    /// # Safety    ///    /// * Before any other method on this lock is called, [`Self::init`] must be called.    /// * The type `B` must not be used with any other lock.    pub const unsafe fn new(data: B::Item) -> Self {        Self {            inner: Lock {                state: Opaque::uninit(),                data: UnsafeCell::new(data),                _pin: PhantomPinned,            },        }    }     /// Initializes a global lock.    ///    /// # Safety    ///    /// Must not be called more than once on a given lock.    pub unsafe fn init(&'static self) {        // SAFETY: The pointer to `state` is valid for the duration of this call, and both `name`        // and `key` are valid indefinitely. The `state` is pinned since we have a `'static`        // reference to `self`.        //        // We have exclusive access to the `state` since the caller of `new` promised to call        // `init` before using any other methods. As `init` can only be called once, all other        // uses of this lock must happen after this call.        unsafe {            B::Backend::init(                self.inner.state.get(),                B::NAME.as_char_ptr(),                B::get_lock_class().as_ptr(),            )        }    }     /// Lock this global lock.    pub fn lock(&'static self) -> GlobalGuard<B> {        GlobalGuard {            inner: self.inner.lock(),        }    }     /// Try to lock this global lock.    pub fn try_lock(&'static self) -> Option<GlobalGuard<B>> {        Some(GlobalGuard {            inner: self.inner.try_lock()?,        })    }} /// A guard for a [`GlobalLock`].////// See [`global_lock!`] for examples.pub struct GlobalGuard<B: GlobalLockBackend> {    inner: Guard<'static, B::Item, B::Backend>,} impl<B: GlobalLockBackend> core::ops::Deref for GlobalGuard<B> {    type Target = B::Item;     fn deref(&self) -> &Self::Target {        &self.inner    }} impl<B: GlobalLockBackend> core::ops::DerefMut for GlobalGuard<B> {    fn deref_mut(&mut self) -> &mut Self::Target {        &mut self.inner    }} /// A version of [`LockedBy`] for a [`GlobalLock`].////// See [`global_lock!`] for examples.pub struct GlobalLockedBy<T: ?Sized, B: GlobalLockBackend> {    _backend: PhantomData<B>,    value: UnsafeCell<T>,} // SAFETY: The same thread-safety rules as `LockedBy` apply to `GlobalLockedBy`.unsafe impl<T, B> Send for GlobalLockedBy<T, B>where    T: ?Sized,    B: GlobalLockBackend,    LockedBy<T, B::Item>: Send,{} // SAFETY: The same thread-safety rules as `LockedBy` apply to `GlobalLockedBy`.unsafe impl<T, B> Sync for GlobalLockedBy<T, B>where    T: ?Sized,    B: GlobalLockBackend,    LockedBy<T, B::Item>: Sync,{} impl<T, B: GlobalLockBackend> GlobalLockedBy<T, B> {    /// Create a new [`GlobalLockedBy`].    ///    /// The provided value will be protected by the global lock indicated by `B`.    pub fn new(val: T) -> Self {        Self {            value: UnsafeCell::new(val),            _backend: PhantomData,        }    }} impl<T: ?Sized, B: GlobalLockBackend> GlobalLockedBy<T, B> {    /// Access the value immutably.    ///    /// The caller must prove shared access to the lock.    pub fn as_ref<'a>(&'a self, _guard: &'a GlobalGuard<B>) -> &'a T {        // SAFETY: The lock is globally unique, so there can only be one guard.        unsafe { &*self.value.get() }    }     /// Access the value mutably.    ///    /// The caller must prove shared exclusive to the lock.    pub fn as_mut<'a>(&'a self, _guard: &'a mut GlobalGuard<B>) -> &'a mut T {        // SAFETY: The lock is globally unique, so there can only be one guard.        unsafe { &mut *self.value.get() }    }     /// Access the value mutably directly.    ///    /// The caller has exclusive access to this `GlobalLockedBy`, so they do not need to hold the    /// lock.    pub fn get_mut(&mut self) -> &mut T {        self.value.get_mut()    }} /// Defines a global lock.////// The global mutex must be initialized before first use. Usually this is done by calling/// [`GlobalLock::init`] in the module initializer.////// # Examples////// A global counter:////// ```/// # mod ex {/// # use kernel::prelude::*;/// kernel::sync::global_lock! {///     // SAFETY: Initialized in module initializer before first use.///     unsafe(uninit) static MY_COUNTER: Mutex<u32> = 0;/// }////// fn increment_counter() -> u32 {///     let mut guard = MY_COUNTER.lock();///     *guard += 1;///     *guard/// }////// impl kernel::Module for MyModule {///     fn init(_module: &'static ThisModule) -> Result<Self> {///         // SAFETY: Called exactly once.///         unsafe { MY_COUNTER.init() };//////         Ok(MyModule {})///     }/// }/// # struct MyModule {}/// # }/// ```////// A global mutex used to protect all instances of a given struct:////// ```/// # mod ex {/// # use kernel::prelude::*;/// use kernel::sync::{GlobalGuard, GlobalLockedBy};////// kernel::sync::global_lock! {///     // SAFETY: Initialized in module initializer before first use.///     unsafe(uninit) static MY_MUTEX: Mutex<()> = ();/// }////// /// All instances of this struct are protected by `MY_MUTEX`./// struct MyStruct {///     my_counter: GlobalLockedBy<u32, MY_MUTEX>,/// }////// impl MyStruct {///     /// Increment the counter in this instance.///     //////     /// The caller must hold the `MY_MUTEX` mutex.///     fn increment(&self, guard: &mut GlobalGuard<MY_MUTEX>) -> u32 {///         let my_counter = self.my_counter.as_mut(guard);///         *my_counter += 1;///         *my_counter///     }/// }////// impl kernel::Module for MyModule {///     fn init(_module: &'static ThisModule) -> Result<Self> {///         // SAFETY: Called exactly once.///         unsafe { MY_MUTEX.init() };//////         Ok(MyModule {})///     }/// }/// # struct MyModule {}/// # }/// ```#[macro_export]macro_rules! global_lock {    {        $(#[$meta:meta])* $pub:vis        unsafe(uninit) static $name:ident: $kind:ident<$valuety:ty> = $value:expr;    } => {        #[doc = ::core::concat!(            "Backend type used by [`",            ::core::stringify!($name),            "`](static@",            ::core::stringify!($name),            ")."        )]        #[allow(non_camel_case_types, unreachable_pub)]        $pub enum $name {}         impl $crate::sync::lock::GlobalLockBackend for $name {            const NAME: &'static $crate::str::CStr = $crate::c_str!(::core::stringify!($name));            type Item = $valuety;            type Backend = $crate::global_lock_inner!(backend $kind);             fn get_lock_class() -> &'static $crate::sync::LockClassKey {                $crate::static_lock_class!()            }        }         $(#[$meta])*        $pub static $name: $crate::sync::lock::GlobalLock<$name> = {            // Defined here to be outside the unsafe scope.            let init: $valuety = $value;             // SAFETY:            // * The user of this macro promises to initialize the macro before use.            // * We are only generating one static with this backend type.            unsafe { $crate::sync::lock::GlobalLock::new(init) }        };    };}pub use global_lock; #[doc(hidden)]#[macro_export]macro_rules! global_lock_inner {    (backend Mutex) => {        $crate::sync::lock::mutex::MutexBackend    };    (backend SpinLock) => {        $crate::sync::lock::spinlock::SpinLockBackend    };}