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