Linux Audio

Check our new training course

Loading...
Note: File does not exist in v6.2.
  1// SPDX-License-Identifier: GPL-2.0
  2
  3//! A kernel mutex.
  4//!
  5//! This module allows Rust code to use the kernel's `struct mutex`.
  6
  7use crate::bindings;
  8
  9/// Creates a [`Mutex`] initialiser with the given name and a newly-created lock class.
 10///
 11/// It uses the name if one is given, otherwise it generates one based on the file name and line
 12/// number.
 13#[macro_export]
 14macro_rules! new_mutex {
 15    ($inner:expr $(, $name:literal)? $(,)?) => {
 16        $crate::sync::Mutex::new(
 17            $inner, $crate::optional_name!($($name)?), $crate::static_lock_class!())
 18    };
 19}
 20pub use new_mutex;
 21
 22/// A mutual exclusion primitive.
 23///
 24/// Exposes the kernel's [`struct mutex`]. When multiple threads attempt to lock the same mutex,
 25/// only one at a time is allowed to progress, the others will block (sleep) until the mutex is
 26/// unlocked, at which point another thread will be allowed to wake up and make progress.
 27///
 28/// Since it may block, [`Mutex`] needs to be used with care in atomic contexts.
 29///
 30/// Instances of [`Mutex`] need a lock class and to be pinned. The recommended way to create such
 31/// instances is with the [`pin_init`](crate::pin_init) and [`new_mutex`] macros.
 32///
 33/// # Examples
 34///
 35/// The following example shows how to declare, allocate and initialise a struct (`Example`) that
 36/// contains an inner struct (`Inner`) that is protected by a mutex.
 37///
 38/// ```
 39/// use kernel::sync::{new_mutex, Mutex};
 40///
 41/// struct Inner {
 42///     a: u32,
 43///     b: u32,
 44/// }
 45///
 46/// #[pin_data]
 47/// struct Example {
 48///     c: u32,
 49///     #[pin]
 50///     d: Mutex<Inner>,
 51/// }
 52///
 53/// impl Example {
 54///     fn new() -> impl PinInit<Self> {
 55///         pin_init!(Self {
 56///             c: 10,
 57///             d <- new_mutex!(Inner { a: 20, b: 30 }),
 58///         })
 59///     }
 60/// }
 61///
 62/// // Allocate a boxed `Example`.
 63/// let e = Box::pin_init(Example::new())?;
 64/// assert_eq!(e.c, 10);
 65/// assert_eq!(e.d.lock().a, 20);
 66/// assert_eq!(e.d.lock().b, 30);
 67/// # Ok::<(), Error>(())
 68/// ```
 69///
 70/// The following example shows how to use interior mutability to modify the contents of a struct
 71/// protected by a mutex despite only having a shared reference:
 72///
 73/// ```
 74/// use kernel::sync::Mutex;
 75///
 76/// struct Example {
 77///     a: u32,
 78///     b: u32,
 79/// }
 80///
 81/// fn example(m: &Mutex<Example>) {
 82///     let mut guard = m.lock();
 83///     guard.a += 10;
 84///     guard.b += 20;
 85/// }
 86/// ```
 87///
 88/// [`struct mutex`]: srctree/include/linux/mutex.h
 89pub type Mutex<T> = super::Lock<T, MutexBackend>;
 90
 91/// A kernel `struct mutex` lock backend.
 92pub struct MutexBackend;
 93
 94// SAFETY: The underlying kernel `struct mutex` object ensures mutual exclusion.
 95unsafe impl super::Backend for MutexBackend {
 96    type State = bindings::mutex;
 97    type GuardState = ();
 98
 99    unsafe fn init(
100        ptr: *mut Self::State,
101        name: *const core::ffi::c_char,
102        key: *mut bindings::lock_class_key,
103    ) {
104        // SAFETY: The safety requirements ensure that `ptr` is valid for writes, and `name` and
105        // `key` are valid for read indefinitely.
106        unsafe { bindings::__mutex_init(ptr, name, key) }
107    }
108
109    unsafe fn lock(ptr: *mut Self::State) -> Self::GuardState {
110        // SAFETY: The safety requirements of this function ensure that `ptr` points to valid
111        // memory, and that it has been initialised before.
112        unsafe { bindings::mutex_lock(ptr) };
113    }
114
115    unsafe fn unlock(ptr: *mut Self::State, _guard_state: &Self::GuardState) {
116        // SAFETY: The safety requirements of this function ensure that `ptr` is valid and that the
117        // caller is the owner of the mutex.
118        unsafe { bindings::mutex_unlock(ptr) };
119    }
120}