/// Trait implemented for marker types for global locks. /// /// See [`global_lock!`] for examples. pubtrait GlobalLockBackend { /// The name for this global lock. const NAME: &'static CStr; /// Item type stored in this global lock. type Item: 'static; /// The backend used for this global lock. type Backend: Backend + 'static; /// The class for this global lock. fn get_lock_class() -> Pin<&'static LockClassKey>;
}
/// Type used for global locks. /// /// See [`global_lock!`] for examples. pubstruct GlobalLock<B: GlobalLockBackend> {
inner: Lock<B::Item, B::Backend>,
}
impl<B: GlobalLockBackend> GlobalLock<B> { /// Creates a global lock. /// /// # Safety /// /// * Before any other method on this lock is called, [`Self::init`] must be called. /// * The type `B` must not be used with any other lock. pubconstunsafefn new(data: B::Item) -> Self { Self {
inner: Lock {
state: Opaque::uninit(),
data: UnsafeCell::new(data),
_pin: PhantomPinned,
},
}
}
/// Initializes a global lock. /// /// # Safety /// /// Must not be called more than once on a given lock. pubunsafefn init(&'static self) { // SAFETY: The pointer to `state` is valid for the duration of this call, and both `name` // and `key` are valid indefinitely. The `state` is pinned since we have a `'static` // reference to `self`. // // We have exclusive access to the `state` since the caller of `new` promised to call // `init` before using any other methods. As `init` can only be called once, all other // uses of this lock must happen after this call. unsafe {
B::Backend::init( self.inner.state.get(),
B::NAME.as_char_ptr(),
B::get_lock_class().as_ptr(),
)
}
}
/// Lock this global lock. pubfn lock(&'static self) -> GlobalGuard<B> {
GlobalGuard {
inner: self.inner.lock(),
}
}
/// Try to lock this global lock. pubfn try_lock(&'static self) -> Option<GlobalGuard<B>> {
Some(GlobalGuard {
inner: self.inner.try_lock()?,
})
}
}
/// A guard for a [`GlobalLock`]. /// /// See [`global_lock!`] for examples. pubstruct GlobalGuard<B: GlobalLockBackend> {
inner: Guard<'static, B::Item, B::Backend>,
}
impl<B: GlobalLockBackend> core::ops::Deref for GlobalGuard<B> { type Target = B::Item;
/// A version of [`LockedBy`] for a [`GlobalLock`]. /// /// See [`global_lock!`] for examples. pubstruct GlobalLockedBy<T: ?Sized, B: GlobalLockBackend> {
_backend: PhantomData<B>,
value: UnsafeCell<T>,
}
// SAFETY: The same thread-safety rules as `LockedBy` apply to `GlobalLockedBy`. unsafeimpl<T, B> Send for GlobalLockedBy<T, B> where
T: ?Sized,
B: GlobalLockBackend,
LockedBy<T, B::Item>: Send,
{
}
// SAFETY: The same thread-safety rules as `LockedBy` apply to `GlobalLockedBy`. unsafeimpl<T, B> Sync for GlobalLockedBy<T, B> where
T: ?Sized,
B: GlobalLockBackend,
LockedBy<T, B::Item>: Sync,
{
}
impl<T, B: GlobalLockBackend> GlobalLockedBy<T, B> { /// Create a new [`GlobalLockedBy`]. /// /// The provided value will be protected by the global lock indicated by `B`. pubfn new(val: T) -> Self { Self {
value: UnsafeCell::new(val),
_backend: PhantomData,
}
}
}
impl<T: ?Sized, B: GlobalLockBackend> GlobalLockedBy<T, B> { /// Access the value immutably. /// /// The caller must prove shared access to the lock. pubfn as_ref<'a>(&'a self, _guard: &'a GlobalGuard<B>) -> &'a T { // SAFETY: The lock is globally unique, so there can only be one guard. unsafe { &*self.value.get() }
}
/// Access the value mutably. /// /// The caller must prove shared exclusive to the lock. pubfn as_mut<'a>(&'a self, _guard: &'a mut GlobalGuard<B>) -> &'n>a mut T { // SAFETY: The lock is globally unique, so there can only be one guard. unsafe { &mut *self.value.get() }
}
/// Access the value mutably directly. /// /// The caller has exclusive access to this `GlobalLockedBy`, so they do not need to hold the /// lock. pubfn get_mut(&mutself) -> &mut T { self.value.get_mut()
}
}
/// Defines a global lock. /// /// The global mutex must be initialized before first use. Usually this is done by calling /// [`GlobalLock::init`] in the module initializer. /// /// # Examples /// /// A global counter: /// /// ``` /// # mod ex { /// # use kernel::prelude::*; /// kernel::sync::global_lock! { /// // SAFETY: Initialized in module initializer before first use. /// unsafe(uninit) static MY_COUNTER: Mutex<u32> = 0; /// } /// /// fn increment_counter() -> u32 { /// let mut guard = MY_COUNTER.lock(); /// *guard += 1; /// *guard /// } /// /// impl kernel::Module for MyModule { /// fn init(_module: &'static ThisModule) -> Result<Self> { /// // SAFETY: Called exactly once. /// unsafe { MY_COUNTER.init() }; /// /// Ok(MyModule {}) /// } /// } /// # struct MyModule {} /// # } /// ``` /// /// A global mutex used to protect all instances of a given struct: /// /// ``` /// # mod ex { /// # use kernel::prelude::*; /// use kernel::sync::{GlobalGuard, GlobalLockedBy}; /// /// kernel::sync::global_lock! { /// // SAFETY: Initialized in module initializer before first use. /// unsafe(uninit) static MY_MUTEX: Mutex<()> = (); /// } /// /// /// All instances of this struct are protected by `MY_MUTEX`. /// struct MyStruct { /// my_counter: GlobalLockedBy<u32, MY_MUTEX>, /// } /// /// impl MyStruct { /// /// Increment the counter in this instance. /// /// /// /// The caller must hold the `MY_MUTEX` mutex. /// fn increment(&self, guard: &mut GlobalGuard<MY_MUTEX>) -> u32 { /// let my_counter = self.my_counter.as_mut(guard); /// *my_counter += 1; /// *my_counter /// } /// } /// /// impl kernel::Module for MyModule { /// fn init(_module: &'static ThisModule) -> Result<Self> { /// // SAFETY: Called exactly once. /// unsafe { MY_MUTEX.init() }; /// /// Ok(MyModule {}) /// } /// } /// # struct MyModule {} /// # } /// ``` #[macro_export]
macro_rules! global_lock {
{
$(#[$meta:meta])* $pub:vis unsafe(uninit) static $name:ident: $kind:ident<$valuety:ty> = $value:expr;
} => { #[doc = ::core::concat!( "Backend type used by [`",
::core::stringify!($name), "`](static@",
::core::stringify!($name), ")."
)] #[allow(non_camel_case_types, unreachable_pub)]
$pubenum $name {}
impl $crate::sync::lock::GlobalLockBackend for $name { const NAME: &'static $crate::str::CStr = $crate::c_str!(::core::stringify!($name)); type Item = $valuety; type Backend = $crate::global_lock_inner!(backend $kind);
$(#[$meta])*
$pubstatic $name: $crate::sync::lock::GlobalLock<$name> = { // Defined here to be outside the unsafe scope. let init: $valuety = $value;
// SAFETY: // * The user of this macro promises to initialize the macro before use. // * We are only generating one static with this backend type. unsafe { $crate::sync::lock::GlobalLock::new(init) }
};
};
} pubuse global_lock;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.