kernel/sync.rs
1// SPDX-License-Identifier: GPL-2.0
2
3//! Synchronisation primitives.
4//!
5//! This module contains the kernel APIs related to synchronisation that have been ported or
6//! wrapped for usage by Rust code in the kernel.
7
8use crate::prelude::*;
9use crate::types::Opaque;
10use pin_init;
11
12mod arc;
13mod condvar;
14pub mod lock;
15mod locked_by;
16pub mod poll;
17pub mod rcu;
18
19pub use arc::{Arc, ArcBorrow, UniqueArc};
20pub use condvar::{new_condvar, CondVar, CondVarTimeoutResult};
21pub use lock::global::{global_lock, GlobalGuard, GlobalLock, GlobalLockBackend, GlobalLockedBy};
22pub use lock::mutex::{new_mutex, Mutex, MutexGuard};
23pub use lock::spinlock::{new_spinlock, SpinLock, SpinLockGuard};
24pub use locked_by::LockedBy;
25
26/// Represents a lockdep class. It's a wrapper around C's `lock_class_key`.
27#[repr(transparent)]
28#[pin_data(PinnedDrop)]
29pub struct LockClassKey {
30 #[pin]
31 inner: Opaque<bindings::lock_class_key>,
32}
33
34// SAFETY: `bindings::lock_class_key` is designed to be used concurrently from multiple threads and
35// provides its own synchronization.
36unsafe impl Sync for LockClassKey {}
37
38impl LockClassKey {
39 /// Initializes a dynamically allocated lock class key. In the common case of using a
40 /// statically allocated lock class key, the static_lock_class! macro should be used instead.
41 ///
42 /// # Example
43 /// ```
44 /// # use kernel::c_str;
45 /// # use kernel::alloc::KBox;
46 /// # use kernel::types::ForeignOwnable;
47 /// # use kernel::sync::{LockClassKey, SpinLock};
48 /// # use pin_init::stack_pin_init;
49 ///
50 /// let key = KBox::pin_init(LockClassKey::new_dynamic(), GFP_KERNEL)?;
51 /// let key_ptr = key.into_foreign();
52 ///
53 /// {
54 /// stack_pin_init!(let num: SpinLock<u32> = SpinLock::new(
55 /// 0,
56 /// c_str!("my_spinlock"),
57 /// // SAFETY: `key_ptr` is returned by the above `into_foreign()`, whose
58 /// // `from_foreign()` has not yet been called.
59 /// unsafe { <Pin<KBox<LockClassKey>> as ForeignOwnable>::borrow(key_ptr) }
60 /// ));
61 /// }
62 ///
63 /// // SAFETY: We dropped `num`, the only use of the key, so the result of the previous
64 /// // `borrow` has also been dropped. Thus, it's safe to use from_foreign.
65 /// unsafe { drop(<Pin<KBox<LockClassKey>> as ForeignOwnable>::from_foreign(key_ptr)) };
66 ///
67 /// # Ok::<(), Error>(())
68 /// ```
69 pub fn new_dynamic() -> impl PinInit<Self> {
70 pin_init!(Self {
71 // SAFETY: lockdep_register_key expects an uninitialized block of memory
72 inner <- Opaque::ffi_init(|slot| unsafe { bindings::lockdep_register_key(slot) })
73 })
74 }
75
76 pub(crate) fn as_ptr(&self) -> *mut bindings::lock_class_key {
77 self.inner.get()
78 }
79}
80
81#[pinned_drop]
82impl PinnedDrop for LockClassKey {
83 fn drop(self: Pin<&mut Self>) {
84 // SAFETY: self.as_ptr was registered with lockdep and self is pinned, so the address
85 // hasn't changed. Thus, it's safe to pass to unregister.
86 unsafe { bindings::lockdep_unregister_key(self.as_ptr()) }
87 }
88}
89
90/// Defines a new static lock class and returns a pointer to it.
91#[doc(hidden)]
92#[macro_export]
93macro_rules! static_lock_class {
94 () => {{
95 static CLASS: $crate::sync::LockClassKey =
96 // SAFETY: lockdep expects uninitialized memory when it's handed a statically allocated
97 // lock_class_key
98 unsafe { ::core::mem::MaybeUninit::uninit().assume_init() };
99 $crate::prelude::Pin::static_ref(&CLASS)
100 }};
101}
102
103/// Returns the given string, if one is provided, otherwise generates one based on the source code
104/// location.
105#[doc(hidden)]
106#[macro_export]
107macro_rules! optional_name {
108 () => {
109 $crate::c_str!(::core::concat!(::core::file!(), ":", ::core::line!()))
110 };
111 ($name:literal) => {
112 $crate::c_str!($name)
113 };
114}