Skip to main content

ksync/
lockdep_tracked.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::raw_lock::{ConstRawLock, ExclusiveLockPolicy, LockPolicy, RawLock};
6use core::ffi::c_void;
7use core::marker::PhantomData;
8use pin_init::{PinInit, pin_data, pin_init};
9
10#[cfg(feature = "lock_dep")]
11unsafe extern "C" {
12    fn cpp_lock_dep_acquire(
13        lock: *mut c_void,
14        class_id: *const c_void,
15        entry_storage: *mut c_void,
16        flags: lockdep::LockFlags,
17    );
18    fn cpp_lock_dep_release(entry_storage: *mut c_void, flags: lockdep::LockFlags);
19    fn cpp_lock_validate_release(entry_storage: *mut c_void, flags: lockdep::LockFlags);
20    fn cpp_lock_validate_acquire(entry_storage: *mut c_void, flags: lockdep::LockFlags);
21}
22
23/// Opaque stack entry storage for a lockdep `AcquiredLockEntry`.
24#[cfg(feature = "lock_dep")]
25#[derive(Default)]
26#[repr(C, align(8))]
27struct LockEntryStorage(zr::OpaqueBytes<40>);
28
29/// Guard state for a [`LockdepTracked`] lock acquisition, combining lockdep's stack entry storage
30/// with the underlying policy's `GuardState`.
31#[derive(Default)]
32#[repr(C)]
33pub struct LockdepTrackedGuardState<S> {
34    #[cfg(feature = "lock_dep")]
35    entry: LockEntryStorage,
36    state: S,
37}
38
39/// Wraps a [`RawLock`] and [`LockPolicy`] with optional lockdep tracking state.
40#[pin_data]
41#[repr(C)]
42pub struct LockdepTracked<
43    L: RawLock,
44    P = <L as RawLock>::DefaultPolicy,
45    const LOCK_FLAGS: lockdep::LockFlags = { lockdep::LOCK_FLAGS_NONE },
46> {
47    #[cfg(any(feature = "lock_dep", feature = "lock_metadata_only"))]
48    class_id: *const c_void,
49    #[pin]
50    lock: L,
51    _policy: PhantomData<P>,
52}
53
54impl<L: RawLock, P, const LOCK_FLAGS: lockdep::LockFlags> LockdepTracked<L, P, LOCK_FLAGS> {
55    /// Flags specifying validation rules for the lock class.
56    pub const LOCK_FLAGS: lockdep::LockFlags = LOCK_FLAGS;
57}
58
59impl<L: ConstRawLock, P, const LOCK_FLAGS: lockdep::LockFlags> LockdepTracked<L, P, LOCK_FLAGS> {
60    #[allow(clippy::declare_interior_mutable_const)]
61    pub const INIT: Self = Self::const_init(core::ptr::null());
62
63    /// Statically initializes a `LockdepTracked` lock in constant context.
64    pub const fn const_init(_class_id: *const c_void) -> Self {
65        Self {
66            #[cfg(any(feature = "lock_dep", feature = "lock_metadata_only"))]
67            class_id: _class_id,
68            lock: L::INIT,
69            _policy: PhantomData,
70        }
71    }
72}
73
74impl<L: ConstRawLock, P, const LOCK_FLAGS: lockdep::LockFlags> Default
75    for LockdepTracked<L, P, LOCK_FLAGS>
76{
77    fn default() -> Self {
78        Self::INIT
79    }
80}
81
82impl<L: RawLock, P, const LOCK_FLAGS: lockdep::LockFlags> core::ops::Deref
83    for LockdepTracked<L, P, LOCK_FLAGS>
84{
85    type Target = L;
86
87    #[inline]
88    fn deref(&self) -> &Self::Target {
89        &self.lock
90    }
91}
92
93// SAFETY: `LockdepTracked` is safe to share across threads when the underlying lock `L` is `Sync`.
94unsafe impl<L: RawLock + Sync, P, const LOCK_FLAGS: lockdep::LockFlags> Sync
95    for LockdepTracked<L, P, LOCK_FLAGS>
96{
97}
98// SAFETY: `LockdepTracked` is safe to send across threads when the underlying lock `L` is `Send`.
99unsafe impl<L: RawLock + Send, P, const LOCK_FLAGS: lockdep::LockFlags> Send
100    for LockdepTracked<L, P, LOCK_FLAGS>
101{
102}
103
104// SAFETY: `LockdepTracked` delegates mutual exclusion to `P` (which implements `LockPolicy<L>`)
105// while recording lockdep validation state on acquire and release.
106unsafe impl<
107    L: RawLock,
108    P: LockPolicy<L>,
109    LP: ExclusiveLockPolicy<L>,
110    const LOCK_FLAGS: lockdep::LockFlags,
111> LockPolicy<LockdepTracked<L, LP, LOCK_FLAGS>> for LockdepTracked<L, P, LOCK_FLAGS>
112{
113    type AcquireArgs = P::AcquireArgs;
114    type GuardState = LockdepTrackedGuardState<P::GuardState>;
115
116    #[inline]
117    unsafe fn pre_validate(
118        lock: &LockdepTracked<L, LP, LOCK_FLAGS>,
119        state: &mut Self::GuardState,
120        args: Self::AcquireArgs,
121    ) {
122        // SAFETY: Caller upholds the `LockPolicy::pre_validate` contract.
123        unsafe {
124            P::pre_validate(&lock.lock, &mut state.state, args);
125        }
126    }
127
128    #[inline]
129    unsafe fn pre_reacquire(
130        lock: &LockdepTracked<L, LP, LOCK_FLAGS>,
131        state: &mut Self::GuardState,
132    ) {
133        // SAFETY: Caller upholds the `LockPolicy::pre_reacquire` contract.
134        unsafe {
135            P::pre_reacquire(&lock.lock, &mut state.state);
136        }
137    }
138
139    #[inline]
140    unsafe fn acquire(
141        lock: &LockdepTracked<L, LP, LOCK_FLAGS>,
142        state: &mut Self::GuardState,
143        args: Self::AcquireArgs,
144    ) {
145        // SAFETY: Caller upholds the `LockPolicy::acquire` contract.
146        unsafe {
147            Self::pre_validate(lock, state, args);
148            Self::post_validate_acquire(lock, state, args);
149        }
150    }
151
152    #[inline]
153    unsafe fn post_validate_acquire(
154        lock: &LockdepTracked<L, LP, LOCK_FLAGS>,
155        state: &mut Self::GuardState,
156        args: Self::AcquireArgs,
157    ) {
158        #[cfg(feature = "lock_dep")]
159        // SAFETY: `lock` is initialized, `lock.class_id` is null or a valid `LockClassId`, and the
160        // caller guarantees `state` is pinned on the stack for the duration of the lock hold.
161        unsafe {
162            cpp_lock_dep_acquire(
163                lock.lock.as_mut_ptr(),
164                lock.class_id,
165                state.entry.0.get() as *mut c_void,
166                LOCK_FLAGS,
167            );
168        }
169        // SAFETY: Caller upholds the `LockPolicy::post_validate_acquire` contract.
170        unsafe {
171            P::post_validate_acquire(&lock.lock, &mut state.state, args);
172        }
173    }
174
175    #[inline]
176    unsafe fn reacquire(lock: &LockdepTracked<L, LP, LOCK_FLAGS>, state: &mut Self::GuardState) {
177        // SAFETY: Caller upholds the `LockPolicy::reacquire` contract.
178        unsafe {
179            Self::pre_reacquire(lock, state);
180            Self::post_validate_reacquire(lock, state);
181        }
182    }
183
184    #[inline]
185    unsafe fn post_validate_reacquire(
186        lock: &LockdepTracked<L, LP, LOCK_FLAGS>,
187        state: &mut Self::GuardState,
188    ) {
189        #[cfg(feature = "lock_dep")]
190        // SAFETY: `lock` is initialized, `lock.class_id` is null or a valid `LockClassId`, and the
191        // caller guarantees `state` is pinned on the stack for the duration of the lock hold.
192        unsafe {
193            cpp_lock_dep_acquire(
194                lock.lock.as_mut_ptr(),
195                lock.class_id,
196                state.entry.0.get() as *mut c_void,
197                LOCK_FLAGS,
198            );
199        }
200        // SAFETY: Caller upholds the `LockPolicy::post_validate_reacquire` contract.
201        unsafe {
202            P::post_validate_reacquire(&lock.lock, &mut state.state);
203        }
204    }
205
206    #[inline]
207    unsafe fn untrack(lock: &LockdepTracked<L, LP, LOCK_FLAGS>, state: &mut Self::GuardState) {
208        #[cfg(feature = "lock_dep")]
209        // SAFETY: Caller guarantees `state` was initialized by `acquire` and is currently held.
210        unsafe {
211            cpp_lock_validate_release(state.entry.0.get() as *mut c_void, LOCK_FLAGS);
212        }
213        // SAFETY: Caller upholds the `LockPolicy::untrack` contract.
214        unsafe {
215            P::untrack(&lock.lock, &mut state.state);
216        }
217    }
218
219    #[inline]
220    unsafe fn retrack(lock: &LockdepTracked<L, LP, LOCK_FLAGS>, state: &mut Self::GuardState) {
221        // SAFETY: Caller upholds the `LockPolicy::retrack` contract.
222        unsafe {
223            P::retrack(&lock.lock, &mut state.state);
224        }
225        #[cfg(feature = "lock_dep")]
226        // SAFETY: Caller guarantees `state` was previously untracked by `untrack` while held.
227        unsafe {
228            cpp_lock_validate_acquire(state.entry.0.get() as *mut c_void, LOCK_FLAGS);
229        }
230    }
231
232    #[inline]
233    unsafe fn release(lock: &LockdepTracked<L, LP, LOCK_FLAGS>, state: &mut Self::GuardState) {
234        #[cfg(feature = "lock_dep")]
235        // SAFETY: The caller guarantees `state` matches the slot initialized in `acquire` and
236        // that the current thread holds the lock.
237        unsafe {
238            cpp_lock_dep_release(state.entry.0.get() as *mut c_void, LOCK_FLAGS);
239        }
240        // SAFETY: Caller upholds the `LockPolicy::release` contract.
241        unsafe {
242            P::release(&lock.lock, &mut state.state);
243        }
244    }
245}
246
247// SAFETY: `LockdepTracked` delegates lock acquisition and release to `P`, which guarantees
248// exclusive mutual exclusion on `L`.
249unsafe impl<
250    L: RawLock,
251    P: ExclusiveLockPolicy<L>,
252    LP: ExclusiveLockPolicy<L>,
253    const LOCK_FLAGS: lockdep::LockFlags,
254> ExclusiveLockPolicy<LockdepTracked<L, LP, LOCK_FLAGS>> for LockdepTracked<L, P, LOCK_FLAGS>
255{
256}
257
258/// Implements `LockPolicy<LockdepTracked<L, LP, LOCK_FLAGS>>` and
259/// `ExclusiveLockPolicy<LockdepTracked<L, LP, LOCK_FLAGS>>` for a concrete policy type `$policy`
260/// by delegating to `LockdepTracked<L, $policy, LOCK_FLAGS>`.
261#[cfg(feature = "kernel")]
262macro_rules! impl_lockdep_tracked_lock_policy {
263    ($policy:ty) => {
264        // SAFETY: Delegates to `LockdepTracked<L, $policy, LOCK_FLAGS>`, which performs lockdep
265        // validation and forwards mutual exclusion to `$policy`.
266        unsafe impl<
267            L: RawLock,
268            LP: $crate::ExclusiveLockPolicy<L>,
269            const LOCK_FLAGS: lockdep::LockFlags,
270        > LockPolicy<LockdepTracked<L, LP, LOCK_FLAGS>> for $policy
271        where
272            $policy: LockPolicy<L>,
273        {
274            type AcquireArgs = <$policy as LockPolicy<L>>::AcquireArgs;
275            type GuardState =
276                $crate::LockdepTrackedGuardState<<$policy as LockPolicy<L>>::GuardState>;
277
278            #[inline]
279            unsafe fn pre_validate(
280                lock: &LockdepTracked<L, LP, LOCK_FLAGS>,
281                state: &mut Self::GuardState,
282                args: Self::AcquireArgs,
283            ) {
284                // SAFETY: Caller upholds the `LockPolicy::pre_validate` contract.
285                unsafe {
286                    <LockdepTracked<L, $policy, LOCK_FLAGS> as LockPolicy<
287                        LockdepTracked<L, LP, LOCK_FLAGS>,
288                    >>::pre_validate(lock, state, args);
289                }
290            }
291
292            #[inline]
293            unsafe fn pre_reacquire(
294                lock: &LockdepTracked<L, LP, LOCK_FLAGS>,
295                state: &mut Self::GuardState,
296            ) {
297                // SAFETY: Caller upholds the `LockPolicy::pre_reacquire` contract.
298                unsafe {
299                    <LockdepTracked<L, $policy, LOCK_FLAGS> as LockPolicy<
300                        LockdepTracked<L, LP, LOCK_FLAGS>,
301                    >>::pre_reacquire(lock, state);
302                }
303            }
304
305            #[inline]
306            unsafe fn acquire(
307                lock: &LockdepTracked<L, LP, LOCK_FLAGS>,
308                state: &mut Self::GuardState,
309                args: Self::AcquireArgs,
310            ) {
311                // SAFETY: Caller upholds the `LockPolicy::acquire` contract.
312                unsafe {
313                    <LockdepTracked<L, $policy, LOCK_FLAGS> as LockPolicy<
314                        LockdepTracked<L, LP, LOCK_FLAGS>,
315                    >>::acquire(lock, state, args);
316                }
317            }
318
319            #[inline]
320            unsafe fn post_validate_acquire(
321                lock: &LockdepTracked<L, LP, LOCK_FLAGS>,
322                state: &mut Self::GuardState,
323                args: Self::AcquireArgs,
324            ) {
325                // SAFETY: Caller upholds the `LockPolicy::post_validate_acquire` contract.
326                unsafe {
327                    <LockdepTracked<L, $policy, LOCK_FLAGS> as LockPolicy<
328                        LockdepTracked<L, LP, LOCK_FLAGS>,
329                    >>::post_validate_acquire(lock, state, args);
330                }
331            }
332
333            #[inline]
334            unsafe fn reacquire(
335                lock: &LockdepTracked<L, LP, LOCK_FLAGS>,
336                state: &mut Self::GuardState,
337            ) {
338                // SAFETY: Caller upholds the `LockPolicy::reacquire` contract.
339                unsafe {
340                    <LockdepTracked<L, $policy, LOCK_FLAGS> as LockPolicy<
341                        LockdepTracked<L, LP, LOCK_FLAGS>,
342                    >>::reacquire(lock, state);
343                }
344            }
345
346            #[inline]
347            unsafe fn post_validate_reacquire(
348                lock: &LockdepTracked<L, LP, LOCK_FLAGS>,
349                state: &mut Self::GuardState,
350            ) {
351                // SAFETY: Caller upholds the `LockPolicy::post_validate_reacquire` contract.
352                unsafe {
353                    <LockdepTracked<L, $policy, LOCK_FLAGS> as LockPolicy<
354                        LockdepTracked<L, LP, LOCK_FLAGS>,
355                    >>::post_validate_reacquire(lock, state);
356                }
357            }
358
359            #[inline]
360            unsafe fn untrack(
361                lock: &LockdepTracked<L, LP, LOCK_FLAGS>,
362                state: &mut Self::GuardState,
363            ) {
364                // SAFETY: Caller upholds the `LockPolicy::untrack` contract.
365                unsafe {
366                    <LockdepTracked<L, $policy, LOCK_FLAGS> as LockPolicy<
367                        LockdepTracked<L, LP, LOCK_FLAGS>,
368                    >>::untrack(lock, state);
369                }
370            }
371
372            #[inline]
373            unsafe fn retrack(
374                lock: &LockdepTracked<L, LP, LOCK_FLAGS>,
375                state: &mut Self::GuardState,
376            ) {
377                // SAFETY: Caller upholds the `LockPolicy::retrack` contract.
378                unsafe {
379                    <LockdepTracked<L, $policy, LOCK_FLAGS> as LockPolicy<
380                        LockdepTracked<L, LP, LOCK_FLAGS>,
381                    >>::retrack(lock, state);
382                }
383            }
384
385            #[inline]
386            unsafe fn release(
387                lock: &LockdepTracked<L, LP, LOCK_FLAGS>,
388                state: &mut Self::GuardState,
389            ) {
390                // SAFETY: Caller upholds the `LockPolicy::release` contract.
391                unsafe {
392                    <LockdepTracked<L, $policy, LOCK_FLAGS> as LockPolicy<
393                        LockdepTracked<L, LP, LOCK_FLAGS>,
394                    >>::release(lock, state);
395                }
396            }
397        }
398
399        // SAFETY: Delegates to `LockdepTracked<L, $policy, LOCK_FLAGS>`, and `$policy` guarantees
400        // exclusive mutual exclusion on `L`.
401        unsafe impl<
402            L: RawLock,
403            LP: $crate::ExclusiveLockPolicy<L>,
404            const LOCK_FLAGS: lockdep::LockFlags,
405        > $crate::ExclusiveLockPolicy<LockdepTracked<L, LP, LOCK_FLAGS>> for $policy
406        where
407            $policy: $crate::ExclusiveLockPolicy<L>,
408        {
409        }
410    };
411}
412
413#[cfg(feature = "kernel")]
414pub(crate) use impl_lockdep_tracked_lock_policy;
415
416// SAFETY: `LockdepTracked` wraps physical lock `L` and forwards `as_mut_ptr` to uniquely identify
417// it.
418unsafe impl<L: RawLock, P: ExclusiveLockPolicy<L>, const LOCK_FLAGS: lockdep::LockFlags> RawLock
419    for LockdepTracked<L, P, LOCK_FLAGS>
420{
421    type DefaultPolicy = Self;
422
423    #[inline]
424    unsafe fn init(class_id: *const c_void) -> impl PinInit<Self, core::convert::Infallible> {
425        pin_init!(Self {
426            // SAFETY: The caller guarantees `class_id` is null or a valid static `LockClassId`.
427            lock <- unsafe { L::init(class_id) },
428            #[cfg(any(feature = "lock_dep", feature = "lock_metadata_only"))]
429            class_id,
430            _policy: PhantomData,
431        })
432    }
433
434    #[inline]
435    fn as_mut_ptr(&self) -> *mut c_void {
436        self.lock.as_mut_ptr()
437    }
438}
439
440impl<L: ConstRawLock, P: ExclusiveLockPolicy<L>, const LOCK_FLAGS: lockdep::LockFlags> ConstRawLock
441    for LockdepTracked<L, P, LOCK_FLAGS>
442{
443    const INIT: Self = Self::INIT;
444}