1 // SPDX-License-Identifier: GPL-2.0 2 3 // Copyright (C) 2024 Google LLC. 4 5 //! Support for defining statics containing locks. 6 7 use crate::{ 8 str::CStr, 9 sync::lock::{Backend, Guard, Lock}, 10 sync::{LockClassKey, LockedBy}, 11 types::Opaque, 12 }; 13 use 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. 22 pub 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. get_lock_class() -> Pin<&'static LockClassKey>30 fn get_lock_class() -> Pin<&'static LockClassKey>; 31 } 32 33 /// Type used for global locks. 34 /// 35 /// See [`global_lock!`] for examples. 36 pub struct GlobalLock<B: GlobalLockBackend> { 37 inner: Lock<B::Item, B::Backend>, 38 } 39 40 impl<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. new(data: B::Item) -> Self47 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. init(&'static self)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. lock(&'static self) -> GlobalGuard<B>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. try_lock(&'static self) -> Option<GlobalGuard<B>>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. 97 pub struct GlobalGuard<B: GlobalLockBackend> { 98 inner: Guard<'static, B::Item, B::Backend>, 99 } 100 101 impl<B: GlobalLockBackend> core::ops::Deref for GlobalGuard<B> { 102 type Target = B::Item; 103 deref(&self) -> &Self::Target104 fn deref(&self) -> &Self::Target { 105 &self.inner 106 } 107 } 108 109 impl<B: GlobalLockBackend> core::ops::DerefMut for GlobalGuard<B> { deref_mut(&mut self) -> &mut Self::Target110 fn deref_mut(&mut self) -> &mut Self::Target { 111 &mut self.inner 112 } 113 } 114 115 /// A version of [`LockedBy`] for a [`GlobalLock`]. 116 /// 117 /// See [`global_lock!`] for examples. 118 pub struct GlobalLockedBy<T: ?Sized, B: GlobalLockBackend> { 119 _backend: PhantomData<B>, 120 value: UnsafeCell<T>, 121 } 122 123 // SAFETY: The same thread-safety rules as `LockedBy` apply to `GlobalLockedBy`. 124 unsafe impl<T, B> Send for GlobalLockedBy<T, B> 125 where 126 T: ?Sized, 127 B: GlobalLockBackend, 128 LockedBy<T, B::Item>: Send, 129 { 130 } 131 132 // SAFETY: The same thread-safety rules as `LockedBy` apply to `GlobalLockedBy`. 133 unsafe impl<T, B> Sync for GlobalLockedBy<T, B> 134 where 135 T: ?Sized, 136 B: GlobalLockBackend, 137 LockedBy<T, B::Item>: Sync, 138 { 139 } 140 141 impl<T, B: GlobalLockBackend> GlobalLockedBy<T, B> { 142 /// Create a new [`GlobalLockedBy`]. 143 /// 144 /// The provided value will be protected by the global lock indicated by `B`. new(val: T) -> Self145 pub fn new(val: T) -> Self { 146 Self { 147 value: UnsafeCell::new(val), 148 _backend: PhantomData, 149 } 150 } 151 } 152 153 impl<T: ?Sized, B: GlobalLockBackend> GlobalLockedBy<T, B> { 154 /// Access the value immutably. 155 /// 156 /// The caller must prove shared access to the lock. as_ref<'a>(&'a self, _guard: &'a GlobalGuard<B>) -> &'a T157 pub fn as_ref<'a>(&'a self, _guard: &'a GlobalGuard<B>) -> &'a T { 158 // SAFETY: The lock is globally unique, so there can only be one guard. 159 unsafe { &*self.value.get() } 160 } 161 162 /// Access the value mutably. 163 /// 164 /// The caller must prove shared exclusive to the lock. as_mut<'a>(&'a self, _guard: &'a mut GlobalGuard<B>) -> &'a mut T165 pub fn as_mut<'a>(&'a self, _guard: &'a mut GlobalGuard<B>) -> &'a mut T { 166 // SAFETY: The lock is globally unique, so there can only be one guard. 167 unsafe { &mut *self.value.get() } 168 } 169 170 /// Access the value mutably directly. 171 /// 172 /// The caller has exclusive access to this `GlobalLockedBy`, so they do not need to hold the 173 /// lock. get_mut(&mut self) -> &mut T174 pub fn get_mut(&mut self) -> &mut T { 175 self.value.get_mut() 176 } 177 } 178 179 /// Defines a global lock. 180 /// 181 /// The global mutex must be initialized before first use. Usually this is done by calling 182 /// [`GlobalLock::init`] in the module initializer. 183 /// 184 /// # Examples 185 /// 186 /// A global counter: 187 /// 188 /// ``` 189 /// # mod ex { 190 /// # use kernel::prelude::*; 191 /// kernel::sync::global_lock! { 192 /// // SAFETY: Initialized in module initializer before first use. 193 /// unsafe(uninit) static MY_COUNTER: Mutex<u32> = 0; 194 /// } 195 /// 196 /// fn increment_counter() -> u32 { 197 /// let mut guard = MY_COUNTER.lock(); 198 /// *guard += 1; 199 /// *guard 200 /// } 201 /// 202 /// impl kernel::Module for MyModule { 203 /// fn init(_module: &'static ThisModule) -> Result<Self> { 204 /// // SAFETY: Called exactly once. 205 /// unsafe { MY_COUNTER.init() }; 206 /// 207 /// Ok(MyModule {}) 208 /// } 209 /// } 210 /// # struct MyModule {} 211 /// # } 212 /// ``` 213 /// 214 /// A global mutex used to protect all instances of a given struct: 215 /// 216 /// ``` 217 /// # mod ex { 218 /// # use kernel::prelude::*; 219 /// use kernel::sync::{GlobalGuard, GlobalLockedBy}; 220 /// 221 /// kernel::sync::global_lock! { 222 /// // SAFETY: Initialized in module initializer before first use. 223 /// unsafe(uninit) static MY_MUTEX: Mutex<()> = (); 224 /// } 225 /// 226 /// /// All instances of this struct are protected by `MY_MUTEX`. 227 /// struct MyStruct { 228 /// my_counter: GlobalLockedBy<u32, MY_MUTEX>, 229 /// } 230 /// 231 /// impl MyStruct { 232 /// /// Increment the counter in this instance. 233 /// /// 234 /// /// The caller must hold the `MY_MUTEX` mutex. 235 /// fn increment(&self, guard: &mut GlobalGuard<MY_MUTEX>) -> u32 { 236 /// let my_counter = self.my_counter.as_mut(guard); 237 /// *my_counter += 1; 238 /// *my_counter 239 /// } 240 /// } 241 /// 242 /// impl kernel::Module for MyModule { 243 /// fn init(_module: &'static ThisModule) -> Result<Self> { 244 /// // SAFETY: Called exactly once. 245 /// unsafe { MY_MUTEX.init() }; 246 /// 247 /// Ok(MyModule {}) 248 /// } 249 /// } 250 /// # struct MyModule {} 251 /// # } 252 /// ``` 253 #[macro_export] 254 macro_rules! global_lock { 255 { 256 $(#[$meta:meta])* $pub:vis 257 unsafe(uninit) static $name:ident: $kind:ident<$valuety:ty> = $value:expr; 258 } => { 259 #[doc = ::core::concat!( 260 "Backend type used by [`", 261 ::core::stringify!($name), 262 "`](static@", 263 ::core::stringify!($name), 264 ")." 265 )] 266 #[allow(non_camel_case_types, unreachable_pub)] 267 $pub enum $name {} 268 269 impl $crate::sync::lock::GlobalLockBackend for $name { 270 const NAME: &'static $crate::str::CStr = $crate::c_str!(::core::stringify!($name)); 271 type Item = $valuety; 272 type Backend = $crate::global_lock_inner!(backend $kind); 273 274 fn get_lock_class() -> Pin<&'static $crate::sync::LockClassKey> { 275 $crate::static_lock_class!() 276 } 277 } 278 279 $(#[$meta])* 280 $pub static $name: $crate::sync::lock::GlobalLock<$name> = { 281 // Defined here to be outside the unsafe scope. 282 let init: $valuety = $value; 283 284 // SAFETY: 285 // * The user of this macro promises to initialize the macro before use. 286 // * We are only generating one static with this backend type. 287 unsafe { $crate::sync::lock::GlobalLock::new(init) } 288 }; 289 }; 290 } 291 pub use global_lock; 292 293 #[doc(hidden)] 294 #[macro_export] 295 macro_rules! global_lock_inner { 296 (backend Mutex) => { 297 $crate::sync::lock::mutex::MutexBackend 298 }; 299 (backend SpinLock) => { 300 $crate::sync::lock::spinlock::SpinLockBackend 301 }; 302 } 303