19dc04365SWedson Almeida Filho // SPDX-License-Identifier: GPL-2.0 29dc04365SWedson Almeida Filho 39dc04365SWedson Almeida Filho //! Synchronisation primitives. 49dc04365SWedson Almeida Filho //! 59dc04365SWedson Almeida Filho //! This module contains the kernel APIs related to synchronisation that have been ported or 69dc04365SWedson Almeida Filho //! wrapped for usage by Rust code in the kernel. 79dc04365SWedson Almeida Filho 8*f73ca66fSMitchell Levy use crate::prelude::*; 9*f73ca66fSMitchell Levy use crate::types::Opaque; 106ea5aa08SWedson Almeida Filho use pin_init; 116ea5aa08SWedson Almeida Filho 129dc04365SWedson Almeida Filho mod arc; 1319096bceSWedson Almeida Filho mod condvar; 1476d4bd59SWedson Almeida Filho pub mod lock; 157b1f55e3SWedson Almeida Filho mod locked_by; 16ac681835SAlice Ryhl pub mod poll; 1751158207SWedson Almeida Filho pub mod rcu; 189dc04365SWedson Almeida Filho 1970e42ebbSWedson Almeida Filho pub use arc::{Arc, ArcBorrow, UniqueArc}; 20e283ee23SAlice Ryhl pub use condvar::{new_condvar, CondVar, CondVarTimeoutResult}; 218eea62ffSAlice Ryhl pub use lock::global::{global_lock, GlobalGuard, GlobalLock, GlobalLockBackend, GlobalLockedBy}; 2237624ddeSLyude Paul pub use lock::mutex::{new_mutex, Mutex, MutexGuard}; 23eb5ccb03SLyude Paul pub use lock::spinlock::{new_spinlock, SpinLock, SpinLockGuard}; 247b1f55e3SWedson Almeida Filho pub use locked_by::LockedBy; 256ea5aa08SWedson Almeida Filho 266ea5aa08SWedson Almeida Filho /// Represents a lockdep class. It's a wrapper around C's `lock_class_key`. 276ea5aa08SWedson Almeida Filho #[repr(transparent)] 28*f73ca66fSMitchell Levy #[pin_data(PinnedDrop)] 29*f73ca66fSMitchell Levy pub struct LockClassKey { 30*f73ca66fSMitchell Levy #[pin] 31*f73ca66fSMitchell Levy inner: Opaque<bindings::lock_class_key>, 32*f73ca66fSMitchell Levy } 336ea5aa08SWedson Almeida Filho 346ea5aa08SWedson Almeida Filho // SAFETY: `bindings::lock_class_key` is designed to be used concurrently from multiple threads and 356ea5aa08SWedson Almeida Filho // provides its own synchronization. 366ea5aa08SWedson Almeida Filho unsafe impl Sync for LockClassKey {} 376ea5aa08SWedson Almeida Filho 386ea5aa08SWedson Almeida Filho impl LockClassKey { 39*f73ca66fSMitchell Levy /// Initializes a dynamically allocated lock class key. In the common case of using a 40*f73ca66fSMitchell Levy /// statically allocated lock class key, the static_lock_class! macro should be used instead. 41*f73ca66fSMitchell Levy /// 42*f73ca66fSMitchell Levy /// # Example 43*f73ca66fSMitchell Levy /// ``` 44*f73ca66fSMitchell Levy /// # use kernel::c_str; 45*f73ca66fSMitchell Levy /// # use kernel::alloc::KBox; 46*f73ca66fSMitchell Levy /// # use kernel::types::ForeignOwnable; 47*f73ca66fSMitchell Levy /// # use kernel::sync::{LockClassKey, SpinLock}; 48*f73ca66fSMitchell Levy /// # use pin_init::stack_pin_init; 49*f73ca66fSMitchell Levy /// 50*f73ca66fSMitchell Levy /// let key = KBox::pin_init(LockClassKey::new_dynamic(), GFP_KERNEL)?; 51*f73ca66fSMitchell Levy /// let key_ptr = key.into_foreign(); 52*f73ca66fSMitchell Levy /// 53*f73ca66fSMitchell Levy /// { 54*f73ca66fSMitchell Levy /// stack_pin_init!(let num: SpinLock<u32> = SpinLock::new( 55*f73ca66fSMitchell Levy /// 0, 56*f73ca66fSMitchell Levy /// c_str!("my_spinlock"), 57*f73ca66fSMitchell Levy /// // SAFETY: `key_ptr` is returned by the above `into_foreign()`, whose 58*f73ca66fSMitchell Levy /// // `from_foreign()` has not yet been called. 59*f73ca66fSMitchell Levy /// unsafe { <Pin<KBox<LockClassKey>> as ForeignOwnable>::borrow(key_ptr) } 60*f73ca66fSMitchell Levy /// )); 61*f73ca66fSMitchell Levy /// } 62*f73ca66fSMitchell Levy /// 63*f73ca66fSMitchell Levy /// // SAFETY: We dropped `num`, the only use of the key, so the result of the previous 64*f73ca66fSMitchell Levy /// // `borrow` has also been dropped. Thus, it's safe to use from_foreign. 65*f73ca66fSMitchell Levy /// unsafe { drop(<Pin<KBox<LockClassKey>> as ForeignOwnable>::from_foreign(key_ptr)) }; 66*f73ca66fSMitchell Levy /// 67*f73ca66fSMitchell Levy /// # Ok::<(), Error>(()) 68*f73ca66fSMitchell Levy /// ``` new_dynamic() -> impl PinInit<Self>69*f73ca66fSMitchell Levy pub fn new_dynamic() -> impl PinInit<Self> { 70*f73ca66fSMitchell Levy pin_init!(Self { 71*f73ca66fSMitchell Levy // SAFETY: lockdep_register_key expects an uninitialized block of memory 72*f73ca66fSMitchell Levy inner <- Opaque::ffi_init(|slot| unsafe { bindings::lockdep_register_key(slot) }) 73*f73ca66fSMitchell Levy }) 74*f73ca66fSMitchell Levy } 756ea5aa08SWedson Almeida Filho as_ptr(&self) -> *mut bindings::lock_class_key76*f73ca66fSMitchell Levy pub(crate) fn as_ptr(&self) -> *mut bindings::lock_class_key { 77*f73ca66fSMitchell Levy self.inner.get() 78*f73ca66fSMitchell Levy } 79*f73ca66fSMitchell Levy } 80*f73ca66fSMitchell Levy 81*f73ca66fSMitchell Levy #[pinned_drop] 82*f73ca66fSMitchell Levy impl PinnedDrop for LockClassKey { drop(self: Pin<&mut Self>)83*f73ca66fSMitchell Levy fn drop(self: Pin<&mut Self>) { 84*f73ca66fSMitchell Levy // SAFETY: self.as_ptr was registered with lockdep and self is pinned, so the address 85*f73ca66fSMitchell Levy // hasn't changed. Thus, it's safe to pass to unregister. 866ea5aa08SWedson Almeida Filho unsafe { bindings::lockdep_unregister_key(self.as_ptr()) } 876ea5aa08SWedson Almeida Filho } 886ea5aa08SWedson Almeida Filho } 896ea5aa08SWedson Almeida Filho 906ea5aa08SWedson Almeida Filho /// Defines a new static lock class and returns a pointer to it. 916ea5aa08SWedson Almeida Filho #[doc(hidden)] 926ea5aa08SWedson Almeida Filho #[macro_export] 936ea5aa08SWedson Almeida Filho macro_rules! static_lock_class { 94966944f3SMitchell Levy () => {{ 95966944f3SMitchell Levy static CLASS: $crate::sync::LockClassKey = 96966944f3SMitchell Levy // SAFETY: lockdep expects uninitialized memory when it's handed a statically allocated 97966944f3SMitchell Levy // lock_class_key 98*f73ca66fSMitchell Levy unsafe { ::core::mem::MaybeUninit::uninit().assume_init() }; 996ea5aa08SWedson Almeida Filho $crate::prelude::Pin::static_ref(&CLASS) 1006ea5aa08SWedson Almeida Filho }}; 1016ea5aa08SWedson Almeida Filho } 1026ea5aa08SWedson Almeida Filho 1036ea5aa08SWedson Almeida Filho /// Returns the given string, if one is provided, otherwise generates one based on the source code 1046ea5aa08SWedson Almeida Filho /// location. 1056ea5aa08SWedson Almeida Filho #[doc(hidden)] 1066ea5aa08SWedson Almeida Filho #[macro_export] 1076ea5aa08SWedson Almeida Filho macro_rules! optional_name { 1086ea5aa08SWedson Almeida Filho () => { 1096ea5aa08SWedson Almeida Filho $crate::c_str!(::core::concat!(::core::file!(), ":", ::core::line!())) 1106ea5aa08SWedson Almeida Filho }; 1116ea5aa08SWedson Almeida Filho ($name:literal) => { 1126ea5aa08SWedson Almeida Filho $crate::c_str!($name) 1136ea5aa08SWedson Almeida Filho }; 114 } 115