FILE
global.rs
File preview with syntax highlighting.
linux-6.19.14/rust/kernel/sync/lock/global.rs
1// SPDX-License-Identifier: GPL-2.0 2 3// Copyright (C) 2024 Google LLC. 4 5//! Support for defining statics containing locks. 6 7use crate::{ 8 str::{CStr, CStrExt as _}, 9 sync::lock::{Backend, Guard, Lock}, 10 sync::{LockClassKey, LockedBy}, 11 types::Opaque, 12}; 13use core::{ 14 cell::UnsafeCell, 15 marker::{PhantomData, PhantomPinned}, 16 pin::Pin, 17}; 18 19/// Trait implemented for marker types for global locks. 20/// 21/// See [`global_lock!`] for examples. 22pub trait GlobalLockBackend { 23 /// The name for this global lock. 24 const NAME: &'static CStr; 25 /// Item type stored in this global lock. 26 type Item: 'static; 27 /// The backend used for this global lock. 28 type Backend: Backend + 'static; 29 /// The class for this global lock. 30 fn get_lock_class() -> Pin<&'static LockClassKey>; 31} 32 33/// Type used for global locks. 34/// 35/// See [`global_lock!`] for examples. 36pub struct GlobalLock<B: GlobalLockBackend> { 37 inner: Lock<B::Item, B::Backend>, 38} 39 40impl<B: GlobalLockBackend> GlobalLock<B> { 41 /// Creates a global lock. 42 /// 43 /// # Safety 44 /// 45 /// * Before any other method on this lock is called, [`Self::init`] must be called. 46 /// * The type `B` must not be used with any other lock. 47 pub const unsafe fn new(data: B::Item) -> Self { 48 Self { 49 inner: Lock { 50 state: Opaque::uninit(), 51 data: UnsafeCell::new(data), 52 _pin: PhantomPinned, 53 }, 54 } 55 } 56 57 /// Initializes a global lock. 58 /// 59 /// # Safety 60 /// 61 /// Must not be called more than once on a given lock. 62 pub unsafe fn init(&'static self) { 63 // SAFETY: The pointer to `state` is valid for the duration of this call, and both `name` 64 // and `key` are valid indefinitely. The `state` is pinned since we have a `'static` 65 // reference to `self`. 66 // 67 // We have exclusive access to the `state` since the caller of `new` promised to call 68 // `init` before using any other methods. As `init` can only be called once, all other 69 // uses of this lock must happen after this call. 70 unsafe { 71 B::Backend::init( 72 self.inner.state.get(), 73 B::NAME.as_char_ptr(), 74 B::get_lock_class().as_ptr(), 75 ) 76 } 77 } 78 79 /// Lock this global lock. 80 pub fn lock(&'static self) -> GlobalGuard<B> { 81 GlobalGuard { 82 inner: self.inner.lock(), 83 } 84 } 85 86 /// Try to lock this global lock. 87 pub fn try_lock(&'static self) -> Option<GlobalGuard<B>> { 88 Some(GlobalGuard { 89 inner: self.inner.try_lock()?, 90 }) 91 } 92} 93 94/// A guard for a [`GlobalLock`]. 95/// 96/// See [`global_lock!`] for examples. 97pub struct GlobalGuard<B: GlobalLockBackend> { 98 inner: Guard<'static, B::Item, B::Backend>, 99} 100 101impl<B: GlobalLockBackend> core::ops::Deref for GlobalGuard<B> { 102 type Target = B::Item; 103 104 fn deref(&self) -> &Self::Target { 105 &self.inner 106 } 107} 108 109impl<B: GlobalLockBackend> core::ops::DerefMut for GlobalGuard<B> 110where 111 B::Item: Unpin, 112{ 113 fn deref_mut(&mut self) -> &mut Self::Target { 114 &mut self.inner 115 } 116} 117 118/// A version of [`LockedBy`] for a [`GlobalLock`]. 119/// 120/// See [`global_lock!`] for examples. 121pub struct GlobalLockedBy<T: ?Sized, B: GlobalLockBackend> { 122 _backend: PhantomData<B>, 123 value: UnsafeCell<T>, 124} 125 126// SAFETY: The same thread-safety rules as `LockedBy` apply to `GlobalLockedBy`. 127unsafe impl<T, B> Send for GlobalLockedBy<T, B> 128where 129 T: ?Sized, 130 B: GlobalLockBackend, 131 LockedBy<T, B::Item>: Send, 132{ 133} 134 135// SAFETY: The same thread-safety rules as `LockedBy` apply to `GlobalLockedBy`. 136unsafe impl<T, B> Sync for GlobalLockedBy<T, B> 137where 138 T: ?Sized, 139 B: GlobalLockBackend, 140 LockedBy<T, B::Item>: Sync, 141{ 142} 143 144impl<T, B: GlobalLockBackend> GlobalLockedBy<T, B> { 145 /// Create a new [`GlobalLockedBy`]. 146 /// 147 /// The provided value will be protected by the global lock indicated by `B`. 148 pub fn new(val: T) -> Self { 149 Self { 150 value: UnsafeCell::new(val), 151 _backend: PhantomData, 152 } 153 } 154} 155 156impl<T: ?Sized, B: GlobalLockBackend> GlobalLockedBy<T, B> { 157 /// Access the value immutably. 158 /// 159 /// The caller must prove shared access to the lock. 160 pub fn as_ref<'a>(&'a self, _guard: &'a GlobalGuard<B>) -> &'a T { 161 // SAFETY: The lock is globally unique, so there can only be one guard. 162 unsafe { &*self.value.get() } 163 } 164 165 /// Access the value mutably. 166 /// 167 /// The caller must prove shared exclusive to the lock. 168 pub fn as_mut<'a>(&'a self, _guard: &'a mut GlobalGuard<B>) -> &'a mut T { 169 // SAFETY: The lock is globally unique, so there can only be one guard. 170 unsafe { &mut *self.value.get() } 171 } 172 173 /// Access the value mutably directly. 174 /// 175 /// The caller has exclusive access to this `GlobalLockedBy`, so they do not need to hold the 176 /// lock. 177 pub fn get_mut(&mut self) -> &mut T { 178 self.value.get_mut() 179 } 180} 181 182/// Defines a global lock. 183/// 184/// The global mutex must be initialized before first use. Usually this is done by calling 185/// [`GlobalLock::init`] in the module initializer. 186/// 187/// # Examples 188/// 189/// A global counter: 190/// 191/// ``` 192/// # mod ex { 193/// # use kernel::prelude::*; 194/// kernel::sync::global_lock! { 195/// // SAFETY: Initialized in module initializer before first use. 196/// unsafe(uninit) static MY_COUNTER: Mutex<u32> = 0; 197/// } 198/// 199/// fn increment_counter() -> u32 { 200/// let mut guard = MY_COUNTER.lock(); 201/// *guard += 1; 202/// *guard 203/// } 204/// 205/// impl kernel::Module for MyModule { 206/// fn init(_module: &'static ThisModule) -> Result<Self> { 207/// // SAFETY: Called exactly once. 208/// unsafe { MY_COUNTER.init() }; 209/// 210/// Ok(MyModule {}) 211/// } 212/// } 213/// # struct MyModule {} 214/// # } 215/// ``` 216/// 217/// A global mutex used to protect all instances of a given struct: 218/// 219/// ``` 220/// # mod ex { 221/// # use kernel::prelude::*; 222/// use kernel::sync::{GlobalGuard, GlobalLockedBy}; 223/// 224/// kernel::sync::global_lock! { 225/// // SAFETY: Initialized in module initializer before first use. 226/// unsafe(uninit) static MY_MUTEX: Mutex<()> = (); 227/// } 228/// 229/// /// All instances of this struct are protected by `MY_MUTEX`. 230/// struct MyStruct { 231/// my_counter: GlobalLockedBy<u32, MY_MUTEX>, 232/// } 233/// 234/// impl MyStruct { 235/// /// Increment the counter in this instance. 236/// /// 237/// /// The caller must hold the `MY_MUTEX` mutex. 238/// fn increment(&self, guard: &mut GlobalGuard<MY_MUTEX>) -> u32 { 239/// let my_counter = self.my_counter.as_mut(guard); 240/// *my_counter += 1; 241/// *my_counter 242/// } 243/// } 244/// 245/// impl kernel::Module for MyModule { 246/// fn init(_module: &'static ThisModule) -> Result<Self> { 247/// // SAFETY: Called exactly once. 248/// unsafe { MY_MUTEX.init() }; 249/// 250/// Ok(MyModule {}) 251/// } 252/// } 253/// # struct MyModule {} 254/// # } 255/// ``` 256#[macro_export] 257macro_rules! global_lock { 258 { 259 $(#[$meta:meta])* $pub:vis 260 unsafe(uninit) static $name:ident: $kind:ident<$valuety:ty> = $value:expr; 261 } => { 262 #[doc = ::core::concat!( 263 "Backend type used by [`", 264 ::core::stringify!($name), 265 "`](static@", 266 ::core::stringify!($name), 267 ")." 268 )] 269 #[allow(non_camel_case_types, unreachable_pub)] 270 $pub enum $name {} 271 272 impl $crate::sync::lock::GlobalLockBackend for $name { 273 const NAME: &'static $crate::str::CStr = $crate::c_str!(::core::stringify!($name)); 274 type Item = $valuety; 275 type Backend = $crate::global_lock_inner!(backend $kind); 276 277 fn get_lock_class() -> Pin<&'static $crate::sync::LockClassKey> { 278 $crate::static_lock_class!() 279 } 280 } 281 282 $(#[$meta])* 283 $pub static $name: $crate::sync::lock::GlobalLock<$name> = { 284 // Defined here to be outside the unsafe scope. 285 let init: $valuety = $value; 286 287 // SAFETY: 288 // * The user of this macro promises to initialize the macro before use. 289 // * We are only generating one static with this backend type. 290 unsafe { $crate::sync::lock::GlobalLock::new(init) } 291 }; 292 }; 293} 294pub use global_lock; 295 296#[doc(hidden)] 297#[macro_export] 298macro_rules! global_lock_inner { 299 (backend Mutex) => { 300 $crate::sync::lock::mutex::MutexBackend 301 }; 302 (backend SpinLock) => { 303 $crate::sync::lock::spinlock::SpinLockBackend 304 }; 305}
~/
Read-only file preview.