Skip to main content

ksync/
kmutex.rs

1// Copyright 2026 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5use crate::{LockPolicy, LockToken, RawLock, RawMutex};
6use core::marker::PhantomData;
7use core::pin::Pin;
8use lockdep::LockClass;
9use pin_init::{PinInit, pin_data, pin_init, pin_init_from_closure, pinned_drop};
10
11#[cfg(feature = "kernel")]
12unsafe extern "C" {
13    fn cpp_lock_validate_release(entry_storage: *mut core::ffi::c_void);
14    fn cpp_lock_validate_acquire(entry_storage: *mut core::ffi::c_void);
15}
16
17/// A safe, Zircon-compatible mutual exclusion lock supporting compile-time order validation.
18///
19/// `KMutex` wraps a platform-specific `RawLock` abstraction. It is pinned in memory to support FFI
20/// loop-detector active list registrations safely under the lock class `Class`.
21#[repr(transparent)] // Ensure KMutex has the same layout as the underlying RawLock M.
22#[pin_data]
23pub struct KMutex<Class: LockClass, M: RawLock = RawMutex> {
24    #[pin]
25    mutex: M,
26    _marker: PhantomData<Class>,
27}
28
29impl<Class: LockClass, M: RawLock> KMutex<Class, M> {
30    /// Create a new KMutex with a pre-initialized raw lock.
31    pub const fn new(mutex: M) -> Self {
32        Self { mutex, _marker: PhantomData }
33    }
34
35    /// Safe dynamic initialization of the validation lock inside pin context.
36    pub fn init() -> impl PinInit<Self, core::convert::Infallible> {
37        pin_init!(Self {
38            mutex <- unsafe { M::init(Self::class_id()) },
39            _marker: PhantomData,
40        })
41    }
42
43    /// Acquires the lock, using the default policy, and registers the active loop node.
44    #[inline]
45    pub fn lock(&self) -> impl PinInit<KMutexGuard<'_, Class, M>, core::convert::Infallible>
46    where
47        <M as RawLock>::DefaultPolicy: LockPolicy<M, AcquireArgs = ()>,
48    {
49        KMutexGuard::new(self)
50    }
51
52    /// Acquires the lock with arguments, using the default policy, and registers the active loop
53    /// node.
54    #[inline]
55    pub fn lock_with(
56        &self,
57        args: <<M as RawLock>::DefaultPolicy as LockPolicy<M>>::AcquireArgs,
58    ) -> impl PinInit<KMutexGuard<'_, Class, M>, core::convert::Infallible> {
59        KMutexGuard::new_with_args(self, args)
60    }
61
62    /// Acquires the lock, using the specified policy, and registers the active loop node.
63    #[inline]
64    pub fn lock_policy<P: LockPolicy<M, AcquireArgs = ()>>(
65        &self,
66    ) -> impl PinInit<KMutexGuard<'_, Class, M, P>, core::convert::Infallible> {
67        KMutexGuard::new(self)
68    }
69
70    /// Acquires the lock with arguments, using the specified policy, and registers the active loop
71    /// node.
72    #[inline]
73    pub fn lock_policy_with<P: LockPolicy<M>>(
74        &self,
75        args: P::AcquireArgs,
76    ) -> impl PinInit<KMutexGuard<'_, Class, M, P>, core::convert::Infallible> {
77        KMutexGuard::new_with_args(self, args)
78    }
79
80    /// Acquires this lock and aliases it with `alias`, returning a guard that proves ownership
81    /// of both `Class` and `AliasClass`.
82    #[inline]
83    pub fn aliased_lock<'a, AliasClass: LockClass, M2: RawLock>(
84        &'a self,
85        alias: &'a KMutex<AliasClass, M2>,
86    ) -> impl PinInit<KMutexAliasedGuard<'a, Class, AliasClass, M, M2>, core::convert::Infallible>
87    where
88        <M as RawLock>::DefaultPolicy: LockPolicy<M, AcquireArgs = ()>,
89    {
90        KMutexAliasedGuard::new(self, alias)
91    }
92
93    /// Acquires this lock with arguments and aliases it with `alias`, returning a guard that proves
94    /// ownership of both `Class` and `AliasClass`.
95    #[inline]
96    pub fn aliased_lock_with<'a, AliasClass: LockClass, M2: RawLock>(
97        &'a self,
98        alias: &'a KMutex<AliasClass, M2>,
99        args: <<M as RawLock>::DefaultPolicy as LockPolicy<M>>::AcquireArgs,
100    ) -> impl PinInit<KMutexAliasedGuard<'a, Class, AliasClass, M, M2>, core::convert::Infallible>
101    {
102        KMutexAliasedGuard::new_with_args(self, alias, args)
103    }
104
105    /// Acquires this lock with policy `P` and aliases it with `alias`.
106    #[inline]
107    pub fn aliased_lock_policy<
108        'a,
109        AliasClass: LockClass,
110        M2: RawLock,
111        P: LockPolicy<M, AcquireArgs = ()>,
112    >(
113        &'a self,
114        alias: &'a KMutex<AliasClass, M2>,
115    ) -> impl PinInit<KMutexAliasedGuard<'a, Class, AliasClass, M, M2, P>, core::convert::Infallible>
116    {
117        KMutexAliasedGuard::new(self, alias)
118    }
119
120    /// Acquires this lock with policy `P` and arguments and aliases it with `alias`.
121    #[inline]
122    pub fn aliased_lock_policy_with<'a, AliasClass: LockClass, M2: RawLock, P: LockPolicy<M>>(
123        &'a self,
124        alias: &'a KMutex<AliasClass, M2>,
125        args: P::AcquireArgs,
126    ) -> impl PinInit<KMutexAliasedGuard<'a, Class, AliasClass, M, M2, P>, core::convert::Infallible>
127    {
128        KMutexAliasedGuard::new_with_args(self, alias, args)
129    }
130
131    /// Returns a reference to the underlying raw lock.
132    #[cfg(any(test, ktest))]
133    #[inline]
134    pub fn raw_mutex(&self) -> &M {
135        &self.mutex
136    }
137
138    const fn class_id() -> *const core::ffi::c_void {
139        if cfg!(feature = "lock_dep") { Class::ID } else { core::ptr::null() }
140    }
141}
142
143impl<Class: LockClass, M: RawLock> core::fmt::Debug for KMutex<Class, M> {
144    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
145        f.debug_struct("KMutex").field("class", &core::any::type_name::<Class>()).finish()
146    }
147}
148
149/// A validation guard representing exclusive lock ownership and active list participation.
150///
151/// The guard is pinned in memory to ensure that its `lock_entry` pointer remains safe and valid
152/// inside the C++ loop detector active thread list.
153#[repr(C)]
154#[pin_data(PinnedDrop)]
155pub struct KMutexGuard<
156    'a,
157    Class: LockClass,
158    M: RawLock = RawMutex,
159    P: LockPolicy<M> = <M as RawLock>::DefaultPolicy,
160> {
161    mutex: &'a KMutex<Class, M>,
162
163    #[pin]
164    lock_entry: M::LockEntry,
165
166    state: P::GuardState,
167
168    token: LockToken<'a, Class>,
169}
170
171impl<'a, Class: LockClass, M: RawLock, P: LockPolicy<M>> KMutexGuard<'a, Class, M, P> {
172    /// Creates a new stack-pinned validation guard initialization block.
173    pub fn new(mutex: &'a KMutex<Class, M>) -> impl PinInit<Self, core::convert::Infallible>
174    where
175        P: LockPolicy<M, AcquireArgs = ()>,
176    {
177        Self::new_with_args(mutex, ())
178    }
179
180    /// Creates a new stack-pinned validation guard initialization block with policy acquire
181    /// arguments.
182    pub fn new_with_args(
183        mutex: &'a KMutex<Class, M>,
184        args: P::AcquireArgs,
185    ) -> impl PinInit<Self, core::convert::Infallible> {
186        // SAFETY: The closure correctly initializes all fields of the allocated `KMutexGuard`
187        // and satisfies all safety requirements of `pin_init_from_closure`.
188        unsafe {
189            pin_init_from_closure(move |this: *mut Self| -> Result<(), core::convert::Infallible> {
190                // SAFETY: `this` is a valid pointer to uninitialized memory allocated for
191                // `KMutexGuard`.
192
193                let mutex_addr = core::ptr::addr_of_mut!((*this).mutex);
194                core::ptr::write(mutex_addr, mutex);
195
196                let entry_addr = core::ptr::addr_of_mut!((*this).lock_entry);
197                core::ptr::write(entry_addr, M::LockEntry::default());
198
199                let state = P::acquire(&mutex.mutex, entry_addr, args);
200
201                let state_addr = core::ptr::addr_of_mut!((*this).state);
202                core::ptr::write(state_addr, state);
203
204                let token_addr = core::ptr::addr_of_mut!((*this).token);
205                core::ptr::write(token_addr, LockToken::new());
206
207                Ok(())
208            })
209        }
210    }
211
212    /// Returns a shared reference to the lock proof `LockToken`.
213    #[inline]
214    pub fn token(&self) -> &LockToken<'a, Class> {
215        &self.token
216    }
217
218    /// Returns a mutable reference to the lock proof `LockToken` inside this pinned projection.
219    #[inline]
220    pub fn token_mut(self: Pin<&mut Self>) -> &mut LockToken<'a, Class> {
221        // SAFETY: Modifying the non-pinned raw `token` field does not violate pinning invariants
222        // since the token has no drop logic or pointer-location sensitivity.
223        let me = unsafe { self.get_unchecked_mut() };
224        &mut me.token
225    }
226
227    /// Temporarily releases the lock before executing the given callable `f` and then
228    /// re-acquires the lock.
229    #[inline]
230    pub fn call_unlocked<R, F: FnOnce() -> R>(self: Pin<&mut Self>, f: F) -> R {
231        // SAFETY: `lock_entry` is pinned on the stack and valid.
232        unsafe {
233            let me = self.get_unchecked_mut();
234            let entry_addr = &mut me.lock_entry as *mut _;
235            P::release(&me.mutex.mutex, entry_addr, me.state);
236            let result = f();
237            P::reacquire(&me.mutex.mutex, entry_addr, &mut me.state);
238            result
239        }
240    }
241
242    /// Calls a closure while temporarily disabling lockdep tracking for the lock held by this
243    /// guard.
244    #[inline]
245    pub fn call_untracked<R, F: FnOnce(&mut LockToken<'a, Class>) -> R>(
246        self: Pin<&mut Self>,
247        f: F,
248    ) -> R {
249        #[cfg(feature = "kernel")]
250        // SAFETY: `lock_entry` is pinned on the stack and valid.
251        unsafe {
252            let me = self.get_unchecked_mut();
253            let entry_addr = &mut me.lock_entry as *mut _ as *mut core::ffi::c_void;
254            cpp_lock_validate_release(entry_addr);
255            let result = f(&mut me.token);
256            cpp_lock_validate_acquire(entry_addr);
257            result
258        }
259        #[cfg(not(feature = "kernel"))]
260        {
261            let me = unsafe { self.get_unchecked_mut() };
262            f(&mut me.token)
263        }
264    }
265}
266
267#[pinned_drop]
268impl<'a, Class: LockClass, M: RawLock, P: LockPolicy<M>> PinnedDrop
269    for KMutexGuard<'a, Class, M, P>
270{
271    // SAFETY: The stack slot `lock_entry` remains valid and pinned on the stack until this drop
272    // block completes. Accessing the fields directly to release the raw lock and remove the
273    // active list node is safe and correct under the current thread context.
274    fn drop(self: Pin<&mut Self>) {
275        unsafe {
276            let me = self.get_unchecked_mut();
277            let entry_addr = &mut me.lock_entry as *mut _;
278            P::release(&me.mutex.mutex, entry_addr, me.state);
279        }
280    }
281}
282
283/// Type tag to indicate aliased lock acquisition.
284pub struct AliasedLock;
285
286/// Acquires an aliased lock on two `KMutex` instances that reference the same underlying lock.
287///
288/// Only `lock1` is physically acquired, but the resulting guard holds proof tokens for both
289/// `Class1` and `Class2`.
290#[inline]
291pub fn aliased_lock<'a, Class1: LockClass, Class2: LockClass, M1: RawLock, M2: RawLock>(
292    lock1: &'a KMutex<Class1, M1>,
293    lock2: &'a KMutex<Class2, M2>,
294) -> impl PinInit<KMutexAliasedGuard<'a, Class1, Class2, M1, M2>, core::convert::Infallible>
295where
296    <M1 as RawLock>::DefaultPolicy: LockPolicy<M1, AcquireArgs = ()>,
297{
298    KMutexAliasedGuard::new(lock1, lock2)
299}
300
301/// Acquires an aliased lock with arguments on two `KMutex` instances that reference the same
302/// underlying lock.
303#[inline]
304pub fn aliased_lock_with<'a, Class1: LockClass, Class2: LockClass, M1: RawLock, M2: RawLock>(
305    lock1: &'a KMutex<Class1, M1>,
306    lock2: &'a KMutex<Class2, M2>,
307    args: <<M1 as RawLock>::DefaultPolicy as LockPolicy<M1>>::AcquireArgs,
308) -> impl PinInit<KMutexAliasedGuard<'a, Class1, Class2, M1, M2>, core::convert::Infallible> {
309    KMutexAliasedGuard::new_with_args(lock1, lock2, args)
310}
311
312/// Acquires an aliased lock with a specific policy on two `KMutex` instances that reference the
313/// same underlying lock.
314#[inline]
315pub fn aliased_lock_policy<
316    'a,
317    Class1: LockClass,
318    Class2: LockClass,
319    M1: RawLock,
320    M2: RawLock,
321    P: LockPolicy<M1, AcquireArgs = ()>,
322>(
323    lock1: &'a KMutex<Class1, M1>,
324    lock2: &'a KMutex<Class2, M2>,
325) -> impl PinInit<KMutexAliasedGuard<'a, Class1, Class2, M1, M2, P>, core::convert::Infallible> {
326    KMutexAliasedGuard::new(lock1, lock2)
327}
328
329/// Acquires an aliased lock with a specific policy and arguments on two `KMutex` instances that
330/// reference the same underlying lock.
331#[inline]
332pub fn aliased_lock_policy_with<
333    'a,
334    Class1: LockClass,
335    Class2: LockClass,
336    M1: RawLock,
337    M2: RawLock,
338    P: LockPolicy<M1>,
339>(
340    lock1: &'a KMutex<Class1, M1>,
341    lock2: &'a KMutex<Class2, M2>,
342    args: P::AcquireArgs,
343) -> impl PinInit<KMutexAliasedGuard<'a, Class1, Class2, M1, M2, P>, core::convert::Infallible> {
344    KMutexAliasedGuard::new_with_args(lock1, lock2, args)
345}
346
347/// A validation guard representing ownership of two aliased locks simultaneously.
348///
349/// Only the first lock is physically acquired, but proof tokens for both lock classes (`Class1` and
350/// `Class2`) are provided.
351#[pin_data]
352pub struct KMutexAliasedGuard<
353    'a,
354    Class1: LockClass,
355    Class2: LockClass,
356    M1: RawLock = RawMutex,
357    M2: RawLock = M1,
358    P: LockPolicy<M1> = <M1 as RawLock>::DefaultPolicy,
359> {
360    #[pin]
361    inner: KMutexGuard<'a, Class1, M1, P>,
362
363    token2: LockToken<'a, Class2>,
364
365    _phantom: PhantomData<&'a KMutex<Class2, M2>>,
366}
367
368impl<'a, Class1: LockClass, Class2: LockClass, M1: RawLock, M2: RawLock, P: LockPolicy<M1>>
369    KMutexAliasedGuard<'a, Class1, Class2, M1, M2, P>
370{
371    /// Creates a new stack-pinned aliased validation guard initialization block.
372    pub fn new(
373        lock1: &'a KMutex<Class1, M1>,
374        lock2: &'a KMutex<Class2, M2>,
375    ) -> impl PinInit<Self, core::convert::Infallible>
376    where
377        P: LockPolicy<M1, AcquireArgs = ()>,
378    {
379        Self::new_with_args(lock1, lock2, ())
380    }
381
382    /// Creates a new stack-pinned aliased validation guard initialization block with policy acquire
383    /// arguments.
384    pub fn new_with_args(
385        lock1: &'a KMutex<Class1, M1>,
386        _lock2: &'a KMutex<Class2, M2>,
387        args: P::AcquireArgs,
388    ) -> impl PinInit<Self, core::convert::Infallible> {
389        if core::mem::size_of::<M2>() > 0 {
390            debug_assert_eq!(
391                lock1.mutex.as_mut_ptr(),
392                _lock2.mutex.as_mut_ptr(),
393                "AliasedLock requires lock1 and lock2 to point to the same physical lock"
394            );
395        }
396        pin_init!(Self {
397            inner <- KMutexGuard::new_with_args(lock1, args),
398            // SAFETY: `inner` holds the underlying mutex, which is aliased to represent `Class2`.
399            token2: unsafe { LockToken::new() },
400            _phantom: PhantomData,
401        })
402    }
403
404    /// Returns shared references to both lock proof tokens `(Class1, Class2)`.
405    #[inline]
406    pub fn tokens(&self) -> (&LockToken<'a, Class1>, &LockToken<'a, Class2>) {
407        (self.inner.token(), &self.token2)
408    }
409
410    /// Returns simultaneous mutable references to both proof tokens `(Class1, Class2)`.
411    #[inline]
412    pub fn tokens_mut(
413        self: Pin<&mut Self>,
414    ) -> (&mut LockToken<'a, Class1>, &mut LockToken<'a, Class2>) {
415        let me = unsafe { self.get_unchecked_mut() };
416        let inner_pin = unsafe { Pin::new_unchecked(&mut me.inner) };
417        (inner_pin.token_mut(), &mut me.token2)
418    }
419
420    /// Returns a shared reference to the primary lock proof token (`Class1`).
421    #[inline]
422    pub fn token(&self) -> &LockToken<'a, Class1> {
423        self.inner.token()
424    }
425
426    /// Returns a mutable reference to the primary lock proof token (`Class1`).
427    #[inline]
428    pub fn token_mut(self: Pin<&mut Self>) -> &mut LockToken<'a, Class1> {
429        let me = unsafe { self.get_unchecked_mut() };
430        let inner_pin = unsafe { Pin::new_unchecked(&mut me.inner) };
431        inner_pin.token_mut()
432    }
433
434    /// Returns a pinned mutable reference to the primary inner `KMutexGuard`.
435    #[inline]
436    pub fn inner_guard(self: Pin<&mut Self>) -> Pin<&mut KMutexGuard<'a, Class1, M1, P>> {
437        let me = unsafe { self.get_unchecked_mut() };
438        unsafe { Pin::new_unchecked(&mut me.inner) }
439    }
440
441    /// Temporarily releases the lock before executing the given callable `f` and then
442    /// re-acquires the lock.
443    #[inline]
444    pub fn call_unlocked<R, F: FnOnce() -> R>(self: Pin<&mut Self>, f: F) -> R {
445        let me = unsafe { self.get_unchecked_mut() };
446        let inner_pin = unsafe { Pin::new_unchecked(&mut me.inner) };
447        inner_pin.call_unlocked(f)
448    }
449
450    /// Calls a closure while temporarily disabling lockdep tracking for the lock held by this
451    /// guard.
452    #[inline]
453    pub fn call_untracked<
454        R,
455        F: FnOnce(&mut LockToken<'a, Class1>, &mut LockToken<'a, Class2>) -> R,
456    >(
457        self: Pin<&mut Self>,
458        f: F,
459    ) -> R {
460        let me = unsafe { self.get_unchecked_mut() };
461        let token2 = &mut me.token2;
462        let inner_pin = unsafe { Pin::new_unchecked(&mut me.inner) };
463        inner_pin.call_untracked(|token1| f(token1, token2))
464    }
465}
466
467#[cfg(not(feature = "kernel"))]
468#[cfg(test)]
469mod tests {
470    use super::*;
471    use crate::{KCell, guarded};
472    use lockdep::LockClass;
473    use pin_init::{pin_init, stack_pin_init};
474
475    struct MyClass;
476    impl LockClass for MyClass {
477        const ID: *mut core::ffi::c_void = core::ptr::null_mut();
478    }
479
480    #[pin_init::pin_data]
481    struct MyStruct {
482        #[pin]
483        mu: KMutex<MyClass>,
484        data1: KCell<u32, MyClass>,
485        data2: KCell<i32, MyClass>,
486    }
487
488    #[test]
489    fn test_basic_token_access() {
490        stack_pin_init!(let s = pin_init!(MyStruct {
491            mu <- KMutex::init(),
492            data1: KCell::new(10),
493            data2: KCell::new(-5),
494        }));
495
496        lock!(let mut guard = s.mu.lock());
497
498        unsafe {
499            assert_eq!(*s.data1.get(guard.token()), 10);
500            assert_eq!(*s.data2.get(guard.token()), -5);
501        }
502        unsafe {
503            let token_mut = guard.as_mut().token_mut();
504            *s.data1.get_mut(token_mut) = 20;
505            assert_eq!(*s.data1.get(guard.token()), 20);
506        }
507    }
508
509    #[guarded]
510    struct MyGuardedStruct {
511        #[mutex]
512        mu: KMutex,
513        #[guarded_by(mu)]
514        data1: u32,
515        #[guarded_by(mu)]
516        data2: i32,
517    }
518
519    #[test]
520    fn test_macro_guarded() {
521        stack_pin_init!(let s = pin_init!(MyGuardedStruct {
522            mu <- KMutex::init(),
523            data1: 100.into(),
524            data2: (-50).into(),
525        }));
526
527        {
528            lock!(let mut guard = s.lock_mu());
529
530            // Safe individual field access
531            assert_eq!(*guard.data1(), 100);
532            assert_eq!(*guard.data2(), -50);
533
534            *guard.as_mut().data1_mut() = 200;
535            assert_eq!(*guard.data1(), 200);
536
537            // Safe disjoint/split access
538            let fields = guard.as_mut().fields_mut();
539            *fields.data1 += 50;
540            *fields.data2 += 50;
541        }
542
543        // Verify fields
544        lock!(let guard = s.lock_mu());
545        assert_eq!(*guard.data1(), 250);
546        assert_eq!(*guard.data2(), 0);
547    }
548
549    #[test]
550    fn test_kmutex_init() {
551        stack_pin_init!(let mu = KMutex::<MyClass>::init());
552        lock!(mu.lock());
553    }
554
555    #[test]
556    fn test_kmutex_debug() {
557        extern crate std;
558        stack_pin_init!(let mu = KMutex::<MyClass>::init());
559        let debug_str = std::format!("{:?}", mu);
560        assert!(debug_str.contains("KMutex"));
561    }
562
563    #[guarded]
564    struct MyMultiGuardedStruct {
565        #[mutex]
566        mu1: KMutex,
567        #[mutex]
568        mu2: KMutex,
569        #[guarded_by(mu1)]
570        data1: u32,
571        #[guarded_by(mu2)]
572        data2: i32,
573    }
574
575    #[test]
576    fn test_macro_multi_guarded() {
577        stack_pin_init!(let s = pin_init!(MyMultiGuardedStruct {
578            mu1 <- KMutex::init(),
579            mu2 <- KMutex::init(),
580            data1: 10.into(),
581            data2: 20.into(),
582        }));
583
584        lock!(let mut guard1 = s.lock_mu1());
585        lock!(let mut guard2 = s.lock_mu2());
586
587        assert_eq!(*guard1.data1(), 10);
588        assert_eq!(*guard2.data2(), 20);
589        *guard1.as_mut().data1_mut() = 15;
590        *guard2.as_mut().data2_mut() = 25;
591        assert_eq!(*guard1.data1(), 15);
592        assert_eq!(*guard2.data2(), 25);
593    }
594
595    #[guarded]
596    struct MyDefaultGuardedStruct {
597        #[mutex]
598        mu: KMutex,
599        #[guarded_by(mu)]
600        data: u32,
601    }
602
603    #[test]
604    fn test_derive_default_guarded() {
605        stack_pin_init!(let s = pin_init!(MyDefaultGuardedStruct {
606            mu <- KMutex::init(),
607            data: 0.into(),
608        }));
609        lock!(let guard = s.lock_mu());
610        assert_eq!(*guard.data(), 0);
611    }
612
613    #[guarded]
614    struct MyGenericGuardedStruct<T> {
615        #[mutex]
616        mu: KMutex,
617        #[guarded_by(mu)]
618        data: T,
619    }
620
621    #[test]
622    fn test_macro_generic_guarded() {
623        stack_pin_init!(let s = pin_init!(MyGenericGuardedStruct::<u32> {
624            mu <- KMutex::init(),
625            data: 0.into(),
626        }));
627        lock!(let mut guard = s.lock_mu());
628        assert_eq!(*guard.data(), 0);
629
630        *guard.as_mut().data_mut() = 42;
631        assert_eq!(*guard.data(), 42);
632
633        let fields = guard.as_mut().fields_mut();
634        *fields.data = 100;
635
636        let fields_shared = guard.fields();
637        assert_eq!(*fields_shared.data, 100);
638    }
639
640    #[guarded]
641    struct MyExplicitParentGuardedStruct {
642        #[mutex]
643        mu: KMutex,
644        #[guarded_by(mu)]
645        data: u32,
646        pub label: &'static str,
647    }
648
649    impl MyExplicitParentGuardedStruct {
650        pub fn has_label(&self) -> bool {
651            !self.label.is_empty()
652        }
653    }
654
655    impl<'a> MyExplicitParentGuardedStructMuGuard<'a> {
656        pub fn process_with_context(self: Pin<&mut Self>) {
657            let me = unsafe { self.get_unchecked_mut() };
658            let has_label = me.parent.has_label();
659            let label = me.parent.label;
660            if has_label && label == "apply_update" {
661                unsafe {
662                    let mut_self = Pin::new_unchecked(me);
663                    let fields = mut_self.fields_mut();
664                    *fields.data = 100;
665                }
666            }
667        }
668    }
669
670    #[test]
671    fn test_macro_guard_explicit_parent_access() {
672        stack_pin_init!(let s = pin_init!(MyExplicitParentGuardedStruct {
673            mu <- KMutex::init(),
674            data: 0.into(),
675            label: "apply_update",
676        }));
677
678        {
679            lock!(let mut guard = s.lock_mu());
680            guard.as_mut().process_with_context();
681        }
682
683        lock!(let guard = s.lock_mu());
684        assert_eq!(*guard.data(), 100);
685    }
686
687    #[test]
688    fn test_call_unlocked() {
689        stack_pin_init!(let s = pin_init!(MyGuardedStruct {
690            mu <- KMutex::init(),
691            data1: 10.into(),
692            data2: 20.into(),
693        }));
694
695        lock!(let mut guard = s.lock_mu());
696        assert_eq!(*guard.data1(), 10);
697
698        let unlocked_result = guard.as_mut().call_unlocked(|| {
699            // During call_unlocked, the lock is temporarily released.
700            42
701        });
702        assert_eq!(unlocked_result, 42);
703
704        // After call_unlocked returns, the lock is held again and fields can be accessed/modified.
705        *guard.as_mut().data1_mut() = 99;
706        assert_eq!(*guard.data1(), 99);
707    }
708
709    #[guarded]
710    struct AliasedTargetStruct {
711        #[mutex(MyGuardedStructMuClass)]
712        mu: KMutex<crate::PhantomMutex>,
713        #[guarded_by(mu)]
714        value: u32,
715    }
716
717    #[test]
718    fn test_aliased_lock_basic() {
719        stack_pin_init!(let s = pin_init!(MyGuardedStruct {
720            mu <- KMutex::init(),
721            data1: 100.into(),
722            data2: 200.into(),
723        }));
724
725        stack_pin_init!(let target = pin_init!(AliasedTargetStruct {
726            mu: KMutex::new(crate::PhantomMutex),
727            value: 300.into(),
728        }));
729
730        {
731            lock!(let mut guard = aliased_lock(&s.mu, &target.mu));
732
733            // Access fields of s and target using tokens() pair
734            let (t1, t2) = guard.tokens();
735            assert_eq!(*s.guard_mu(t1).data1(), 100);
736            assert_eq!(*s.guard_mu(t1).data2(), 200);
737            assert_eq!(*target.guard_mu(t2).value(), 300);
738
739            // Disjoint simultaneous mutable access to both structs
740            let (t1_mut, t2_mut) = guard.as_mut().tokens_mut();
741            *s.guard_mu_mut(t1_mut).data1_mut() = 101;
742            *target.guard_mu_mut(t2_mut).value_mut() = 301;
743
744            // Call unlocked on aliased guard
745            let res = guard.as_mut().call_unlocked(|| 1234);
746            assert_eq!(res, 1234);
747
748            // Verify mutations persist
749            let (t1, t2) = guard.tokens();
750            assert_eq!(*s.guard_mu(t1).data1(), 101);
751            assert_eq!(*target.guard_mu(t2).value(), 301);
752        }
753
754        // Verify state with regular lock
755        lock!(let guard = s.lock_mu());
756        assert_eq!(*guard.data1(), 101);
757    }
758
759    #[test]
760    fn test_aliased_lock_macro_method() {
761        stack_pin_init!(let s = pin_init!(MyGuardedStruct {
762            mu <- KMutex::init(),
763            data1: 10.into(),
764            data2: 20.into(),
765        }));
766
767        stack_pin_init!(let target = pin_init!(AliasedTargetStruct {
768            mu: KMutex::new(crate::PhantomMutex),
769            value: 30.into(),
770        }));
771
772        {
773            lock!(let mut guard = s.lock_mu_aliased(&target.mu));
774            let (_t1, t2) = guard.tokens();
775            assert_eq!(*target.guard_mu(t2).value(), 30);
776            let (_t1_mut, t2_mut) = guard.as_mut().tokens_mut();
777            *target.guard_mu_mut(t2_mut).value_mut() = 35;
778        }
779
780        lock!(let guard = s.lock_mu());
781        assert_eq!(*target.guard_mu(guard.token()).value(), 35);
782    }
783
784    #[guarded]
785    struct FlaggedMutexStruct {
786        #[mutex(flags = lockdep::LOCK_FLAGS_ACTIVE_LIST_DISABLED)]
787        seek_lock: KMutex,
788        #[guarded_by(seek_lock)]
789        seek: u64,
790    }
791
792    #[test]
793    fn test_flagged_mutex_struct() {
794        stack_pin_init!(let s = pin_init!(FlaggedMutexStruct {
795            seek_lock <- KMutex::init(),
796            seek: 0.into(),
797        }));
798
799        lock!(let mut guard = s.lock_seek_lock());
800        assert_eq!(*guard.seek(), 0);
801        *guard.as_mut().seek_mut() = 1024;
802        assert_eq!(*guard.seek(), 1024);
803    }
804}