| 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 | |
| 8 | use crate::prelude::*; |
| 9 | use crate::types::Opaque; |
| 10 | use pin_init; |
| 11 | |
| 12 | mod arc; |
| 13 | mod condvar; |
| 14 | pub mod lock; |
| 15 | mod locked_by; |
| 16 | pub mod poll; |
| 17 | pub mod rcu; |
| 18 | |
| 19 | pub use arc::{Arc, ArcBorrow, UniqueArc}; |
| 20 | pub use condvar::{new_condvar, CondVar, CondVarTimeoutResult}; |
| 21 | pub use lock::global::{global_lock, GlobalGuard, GlobalLock, GlobalLockBackend, GlobalLockedBy}; |
| 22 | pub use lock::mutex::{new_mutex, Mutex, MutexGuard}; |
| 23 | pub use lock::spinlock::{new_spinlock, SpinLock, SpinLockGuard}; |
| 24 | pub 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)] |
| 29 | pub 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. |
| 36 | unsafe impl Sync for LockClassKey {} |
| 37 | |
| 38 | impl 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] |
| 82 | impl 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] |
| 93 | macro_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] |
| 107 | macro_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 | } |
| 115 | |