1use 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#[repr(transparent)] #[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 pub const fn new(mutex: M) -> Self {
32 Self { mutex, _marker: PhantomData }
33 }
34
35 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 #[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 #[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 #[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 #[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 #[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 #[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 #[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 #[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 #[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#[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 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 pub fn new_with_args(
183 mutex: &'a KMutex<Class, M>,
184 args: P::AcquireArgs,
185 ) -> impl PinInit<Self, core::convert::Infallible> {
186 unsafe {
189 pin_init_from_closure(move |this: *mut Self| -> Result<(), core::convert::Infallible> {
190 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 #[inline]
214 pub fn token(&self) -> &LockToken<'a, Class> {
215 &self.token
216 }
217
218 #[inline]
220 pub fn token_mut(self: Pin<&mut Self>) -> &mut LockToken<'a, Class> {
221 let me = unsafe { self.get_unchecked_mut() };
224 &mut me.token
225 }
226
227 #[inline]
230 pub fn call_unlocked<R, F: FnOnce() -> R>(self: Pin<&mut Self>, f: F) -> R {
231 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 #[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 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 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
283pub struct AliasedLock;
285
286#[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#[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#[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#[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#[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 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 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 token2: unsafe { LockToken::new() },
400 _phantom: PhantomData,
401 })
402 }
403
404 #[inline]
406 pub fn tokens(&self) -> (&LockToken<'a, Class1>, &LockToken<'a, Class2>) {
407 (self.inner.token(), &self.token2)
408 }
409
410 #[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 #[inline]
422 pub fn token(&self) -> &LockToken<'a, Class1> {
423 self.inner.token()
424 }
425
426 #[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 #[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 #[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 #[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 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 let fields = guard.as_mut().fields_mut();
539 *fields.data1 += 50;
540 *fields.data2 += 50;
541 }
542
543 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 42
701 });
702 assert_eq!(unlocked_result, 42);
703
704 *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 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 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 let res = guard.as_mut().call_unlocked(|| 1234);
746 assert_eq!(res, 1234);
747
748 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 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}