#[guarded]Expand description
Instruments a struct with lock-class registration, KCell/KOnceCell field wrapping, and
type-safe lock guard accessors.
§Attributes
#[mutex]/#[mutex(CustomClass, flags = ...)]: Marks aKMutex,KSpinlock, orKMonitoredSpinlockfield and generates a lock class andlock_<name>()/guard_<name>()methods.#[brwlock]/#[brwlock(flags = ...)]: Marks aBrwLockPifield and generates a lock class andread_<name>()/write_<name>()/guard_read_<name>()/guard_write_<name>()methods.#[guarded_by(lock1)]or#[guarded_by(lock1, lock2, ...)]: Wraps a field inKCell(or parameterizes aKOnceCell<T>field) with the lock class (or tuple of lock classes) of the specified lock(s).- Single-lock (
#[guarded_by(mu1)]): Holdingmu1grants both shared (&T) and exclusive (&mut T) access viaguard.field(),guard.as_mut().field_mut(), andguard.as_mut().fields_mut().field. - Multi-lock (
#[guarded_by(mu1, mu2, ...)]): Holding any one of the guarding locks grants shared read access (&T) viaguard.field(),guard.fields().field, andguard.as_mut().fields_mut().field(which projects the field as&Trather than&mut T). Mutating the field requires holding all guarding locks simultaneously and passing the remaining lock guards or tokens toguard.as_mut().field_mut(&mut other_guard, ...).
- Single-lock (
§Generated Code Example (Multi-Lock Field)
Given the following input struct:
ⓘ
#[guarded]
struct Example {
#[mutex]
mu1: KMutex,
#[mutex]
mu2: KMutex,
#[guarded_by(mu1)]
single: u32,
#[guarded_by(mu1, mu2)]
shared: u64,
}#[guarded] expands to the following (simplified for mu1; mu2 is generated symmetrically):
ⓘ
#[derive(Default, Debug, Clone, Copy)]
struct ExampleMu1Class;
#[derive(Default, Debug, Clone, Copy)]
struct ExampleMu2Class;
#[::pin_init::pin_data]
struct Example {
#[pin]
mu1: KMutex<ExampleMu1Class, ::ksync::RawMutex>,
#[pin]
mu2: KMutex<ExampleMu2Class, ::ksync::RawMutex>,
single: ::ksync::KCell<u32, ExampleMu1Class>,
shared: ::ksync::KCell<u64, (ExampleMu1Class, ExampleMu2Class)>,
}
// Read-only projection (`g1.fields()`): all fields guarded by `mu1` are `&'b T`.
struct ExampleMu1Fields<'b> {
single: &'b u32,
shared: &'b u64,
_marker: ::core::marker::PhantomData<(&'b (),)>,
}
// Mutable projection (`g1.as_mut().fields_mut()`):
// - Single-lock `single` is projected mutably (`&'b mut u32`).
// - Multi-lock `shared` is projected immutably (`&'b u64`) because holding only `mu1`
// only suffices to read `shared`.
struct ExampleMu1FieldsMut<'b> {
single: &'b mut u32,
shared: &'b u64,
_marker: ::core::marker::PhantomData<(&'b (),)>,
}
impl<'a, P: ::ksync::ExclusiveLockPolicy<::ksync::RawMutex>> ExampleMu1Guard<'a, P> {
fn single(&self) -> &u32 {
unsafe { self.parent.single.get(self.inner.token()) }
}
fn single_mut<'f>(self: ::core::pin::Pin<&'f mut Self>) -> &'f mut u32 {
let me = unsafe { self.get_unchecked_mut() };
let inner_pin = unsafe { ::core::pin::Pin::new_unchecked(&mut me.inner) };
let self_token = inner_pin.token_mut();
let token = self_token;
unsafe { me.parent.single.get_mut(token) }
}
// Holding `mu1` alone is sufficient to read `shared`:
fn shared(&self) -> &u64 {
unsafe { self.parent.shared.get(self.inner.token()) }
}
// Mutating `shared` requires `self` (`mu1`) plus an exclusive token/guard for `mu2`:
fn shared_mut<'f>(
self: ::core::pin::Pin<&'f mut Self>,
mu2_token: &'f mut impl ::ksync::ExclusiveLockToken<Example, ExampleMu2Class>,
) -> &'f mut u64 {
let me = unsafe { self.get_unchecked_mut() };
let inner_pin = unsafe { ::core::pin::Pin::new_unchecked(&mut me.inner) };
let self_token = inner_pin.token_mut();
let token = {
// Runtime check that `mu2_token` belongs to the same `Example` instance
// (`me.parent`). When both guards are locked on the same `Example` reference in
// an inlined scope, the compiler constant-folds this pointer comparison away.
assert!(
::core::ptr::eq(
::core::ptr::from_ref(me.parent),
::ksync::ExclusiveLockToken::parent(mu2_token),
),
"Lock guard belongs to a different struct instance",
);
self_token.join(::ksync::ExclusiveLockToken::lock_token_mut(mu2_token))
};
unsafe { me.parent.shared.get_mut(token) }
}
}