Skip to main content

concurrent/
chainlock_transaction.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 core::cell::Cell;
6use core::fmt;
7use core::marker::{PhantomData, PhantomPinned};
8use core::mem::offset_of;
9use core::ptr::NonNull;
10use core::sync::atomic::{AtomicU32, AtomicU64, Ordering};
11
12//
13// # General Chain Lock Transaction Facility
14//
15// Chain lock transactions are a layer on top of chain locks that track the state necessary for
16// entities (i.e. CPUs) to acquire a series of one or more chain locks and correctly handle
17// arbitration with other entities contending for the same locks. The base transaction facility
18// provides the main hooks required by the general chain lock implementation, and has compile-time
19// enabled state for debugging and performance tracing to help diagnose issues with chain lock
20// usage.
21//
22
23const UNLOCKED_TOKEN_VALUE: u64 = 0;
24const RESERVED_TOKEN_VALUES: u64 = 10000;
25const INITIAL_TOKEN_VALUE: u64 = RESERVED_TOKEN_VALUES + 1;
26const MAX_TOKEN_VALUE: u64 = u64::MAX;
27
28// SAFETY: `concurrent_chainlock_transaction_token_generator` is defined in
29// `chainlock_transaction_common.cc` with C linkage (`extern "C"`) as a lock-free
30// `std::atomic<uint64_t>` with static storage duration, verified by `static_assert` in C++ to have
31// the exact size and alignment of `u64` / `AtomicU64`.
32unsafe extern "C" {
33    // Shared global atomic token generator defined in `chainlock_transaction_common.cc` so that
34    // C++ and Rust transactions allocate tokens from the same monotonic generator and can
35    // interoperate on the same `ChainLock` instances.
36    static concurrent_chainlock_transaction_token_generator: AtomicU64;
37}
38
39/// Zero-sized capability token proving that a transaction of type `T` is currently active on the
40/// calling execution context.
41pub struct ChainLockTransactionToken<T> {
42    // Safety invariant: A `ChainLockTransactionToken<T>` value may only exist on an execution
43    // context while a transaction of type `T` is registered as the active transaction on that
44    // context and remains alive and pinned at its memory address. `*mut T` makes the token
45    // `!Send`, `!Sync`, and invariant in `T`.
46    _private: PhantomData<*mut T>,
47}
48
49impl<T> fmt::Debug for ChainLockTransactionToken<T> {
50    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
51        f.debug_struct("ChainLockTransactionToken").finish()
52    }
53}
54
55impl<T> ChainLockTransactionToken<T> {
56    #[inline]
57    pub(crate) const fn new() -> Self {
58        Self { _private: PhantomData }
59    }
60}
61
62/// A transaction generation token used to identify the owning transaction of a `ChainLock` and
63/// arbitrate priority when contention occurs.
64#[repr(transparent)]
65#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord)]
66pub struct Token(u64);
67
68impl Token {
69    /// Token value representing an unlocked `ChainLock`.
70    pub const UNLOCKED: Self = Self(UNLOCKED_TOKEN_VALUE);
71
72    /// Maximum possible token value, representing the lowest possible transaction priority.
73    pub const MAX: Self = Self(MAX_TOKEN_VALUE);
74
75    /// Creates a new unlocked token.
76    #[inline]
77    pub const fn new() -> Self {
78        Self::UNLOCKED
79    }
80
81    #[inline]
82    pub(crate) const fn from_raw(value: u64) -> Self {
83        Self(value)
84    }
85
86    /// Returns `true` if this token is valid (i.e., not the unlocked token value).
87    #[inline]
88    pub const fn is_valid(&self) -> bool {
89        self.value() != UNLOCKED_TOKEN_VALUE
90    }
91
92    /// Returns `true` if this token is a reserved token (e.g., per-CPU token used during
93    /// context switch state save/restore).
94    #[inline]
95    pub const fn is_reserved(&self) -> bool {
96        self.is_valid() && self.value() <= RESERVED_TOKEN_VALUES
97    }
98
99    /// Returns the raw 64-bit integer value of this token.
100    #[inline]
101    pub const fn value(&self) -> u64 {
102        self.0
103    }
104}
105
106/// Atomic storage for a [`Token`].
107#[repr(transparent)]
108#[derive(Debug, Default)]
109pub struct AtomicToken(AtomicU64);
110
111impl AtomicToken {
112    /// Creates a new [`AtomicToken`] initialized with `token`.
113    #[inline]
114    pub const fn new(token: Token) -> Self {
115        Self(AtomicU64::new(token.value()))
116    }
117
118    /// Loads a [`Token`] from the atomic variable.
119    #[inline]
120    pub fn load(&self, order: Ordering) -> Token {
121        Token::from_raw(self.0.load(order))
122    }
123
124    /// Stores a [`Token`] into the atomic variable.
125    #[inline]
126    pub fn store(&self, token: Token, order: Ordering) {
127        self.0.store(token.value(), order);
128    }
129
130    /// Stores `new` into the atomic variable if the current value is `current`.
131    #[inline]
132    pub fn compare_exchange(
133        &self,
134        current: Token,
135        new: Token,
136        success: Ordering,
137        failure: Ordering,
138    ) -> Result<Token, Token> {
139        self.0
140            .compare_exchange(current.value(), new.value(), success, failure)
141            .map(Token::from_raw)
142            .map_err(Token::from_raw)
143    }
144}
145
146/// Saved transaction state returned by
147/// [`ChainLockTransaction::save_state_and_use_reserved_token`] and
148/// [`ChainLockTransaction::save_state_initial`], used to restore an active transaction across
149/// context switches.
150#[repr(C)]
151pub struct SavedState<E: TransactionHooks> {
152    // Safety invariant: Points to the `ChainLockTransaction<E>` from which this `SavedState` was
153    // created via `with_replacement`. Callers of `restore_state` must ensure that transaction is
154    // still alive and pinned at this address.
155    transaction: NonNull<ChainLockTransaction<E>>,
156    token: Token,
157}
158
159impl<E: TransactionHooks> Clone for SavedState<E> {
160    #[inline]
161    fn clone(&self) -> Self {
162        *self
163    }
164}
165
166impl<E: TransactionHooks> Copy for SavedState<E> {}
167
168impl<E: TransactionHooks> fmt::Debug for SavedState<E> {
169    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
170        f.debug_struct("SavedState")
171            .field("transaction", &self.transaction)
172            .field("token", &self.token)
173            .finish()
174    }
175}
176
177impl<E: TransactionHooks> SavedState<E> {
178    /// Returns the saved transaction token.
179    #[inline]
180    pub const fn token(&self) -> Token {
181        self.token
182    }
183
184    /// Returns the non-null pointer to the saved transaction.
185    #[inline]
186    pub const fn transaction(&self) -> NonNull<ChainLockTransaction<E>> {
187        self.transaction
188    }
189
190    #[inline]
191    pub(crate) fn with_replacement(
192        transaction: &ChainLockTransaction<E>,
193        replacement: Token,
194    ) -> Self {
195        let token = transaction.token();
196        transaction.replace_token(replacement);
197        Self { transaction: NonNull::from(transaction), token }
198    }
199}
200
201/// Non-terminal control flow action returned by a transaction attempt closure.
202#[derive(Clone, Copy, Debug, PartialEq, Eq)]
203pub enum Action {
204    /// Unwind held locks, execute the backoff protocol, and re-enter the transaction attempt.
205    Backoff,
206    /// Reset finalization state and re-enter the transaction attempt with the same token.
207    Restart,
208}
209
210/// Marker type indicating completion of a transaction with no return value.
211#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
212pub struct DoneType;
213
214/// Constant value of [`DoneType`] indicating transaction completion.
215pub const DONE: DoneType = DoneType;
216
217/// Result of a single execution of a transaction attempt closure passed to `until_done`.
218#[derive(Debug, PartialEq, Eq)]
219pub enum TransactionResult<T = ()> {
220    /// The transaction must back off or restart and re-execute the closure.
221    Action(Action),
222    /// The transaction completed with the terminal value `T`.
223    Value(T),
224}
225
226impl TransactionResult<()> {
227    /// Convenience constant for completing a `()`-returning transaction.
228    pub const DONE: Self = Self::Value(());
229}
230
231impl<T> TransactionResult<T> {
232    /// Convenience constant for requesting a transaction backoff.
233    pub const BACKOFF: Self = Self::Action(Action::Backoff);
234
235    /// Convenience constant for requesting a transaction restart.
236    pub const RESTART: Self = Self::Action(Action::Restart);
237
238    /// Returns `true` if this result is an [`Action`].
239    #[inline]
240    pub const fn is_action(&self) -> bool {
241        matches!(self, Self::Action(_))
242    }
243
244    /// Returns the [`Action`] contained in this result.
245    ///
246    /// # Panics
247    ///
248    /// Panics if `!self.is_action()`.
249    #[inline]
250    pub fn action(&self) -> Action {
251        match self {
252            Self::Action(action) => *action,
253            Self::Value(_) => unreachable!(),
254        }
255    }
256
257    /// Consumes this result and returns the terminal value `T`.
258    ///
259    /// # Panics
260    ///
261    /// Panics if `self.is_action()`.
262    #[inline]
263    pub fn take_value(self) -> T {
264        match self {
265            Self::Value(value) => value,
266            Self::Action(_) => unreachable!(),
267        }
268    }
269}
270
271impl<T> From<Action> for TransactionResult<T> {
272    #[inline]
273    fn from(action: Action) -> Self {
274        Self::Action(action)
275    }
276}
277
278impl From<DoneType> for TransactionResult<()> {
279    #[inline]
280    fn from(_: DoneType) -> Self {
281        Self::Value(())
282    }
283}
284
285/// Trait implemented by return types of closures passed to `ChainLockTransaction::until_done`.
286///
287/// The callable passed to [`ChainLockTransaction::until_done`] may return:
288/// 1. [`TransactionResult<()>`] (a `()`-returning transaction),
289/// 2. [`TransactionResult<T>`] (a transaction returning user-defined type `T`), or
290/// 3. [`DoneType`] (an infallible transaction with implied return type `()`).
291pub trait IntoTransactionResult {
292    /// The terminal value type returned by `until_done` when the transaction completes.
293    type Output;
294
295    /// Converts the closure return value into a [`TransactionResult`].
296    fn into_transaction_result(self) -> TransactionResult<Self::Output>;
297}
298
299impl IntoTransactionResult for DoneType {
300    type Output = ();
301
302    #[inline]
303    fn into_transaction_result(self) -> TransactionResult<()> {
304        TransactionResult::Value(())
305    }
306}
307
308impl<T> IntoTransactionResult for TransactionResult<T> {
309    type Output = T;
310
311    #[inline]
312    fn into_transaction_result(self) -> TransactionResult<T> {
313        self
314    }
315}
316
317/// Lifecycle state of a [`ChainLockTransaction`].
318#[repr(i32)]
319#[derive(Clone, Copy, Debug, PartialEq, Eq)]
320pub enum State {
321    /// Transaction has started and may acquire locks or back off.
322    Started = 0,
323    /// Transaction has acquired all needed locks and been finalized.
324    Finalized = 1,
325    /// Transaction is complete.
326    Complete = 2,
327}
328
329/// Trait for contention state stored inside a [`ChainLock`](crate::ChainLock).
330pub trait ContentionState: Default {
331    /// Constant initial value for `const fn` construction of `ChainLock`.
332    const INIT: Self;
333}
334
335impl ContentionState for AtomicU32 {
336    const INIT: Self = AtomicU32::new(0);
337}
338
339impl ContentionState for AtomicU64 {
340    const INIT: Self = AtomicU64::new(0);
341}
342
343impl ContentionState for () {
344    const INIT: Self = ();
345}
346
347/// Trait representing a chain lock transaction type used by [`ChainLock`](crate::ChainLock) and
348/// [`ChainLockGuard`](crate::ChainLockGuard).
349///
350/// This is automatically implemented by [`ChainLockTransaction<E>`] for any [`TransactionHooks`]
351/// implementation `E`.
352pub trait Transaction: Sized {
353    /// State used by `ChainLock` to store contended lock state for backoff mitigation.
354    type ContentionState: ContentionState;
355
356    /// Returns a pointer to the active transaction for the current execution context, or `None` if
357    /// no transaction is active.
358    fn active() -> core::option::Option<NonNull<Self>>;
359
360    /// Returns a shared reference to the active transaction, asserting in debug builds that a
361    /// transaction is currently active.
362    fn active_ref(token: &ChainLockTransactionToken<Self>) -> &Self;
363
364    /// Performs an architecture-specific CPU relax/yield operation.
365    fn yield_cpu();
366
367    /// Returns the current [`Token`] of this transaction.
368    fn token(&self) -> Token;
369
370    /// Asserts that this transaction has not been finalized (when debug accounting is enabled).
371    fn assert_not_finalized(&self);
372
373    /// Asserts that this transaction currently holds `expected` locks (when debug accounting is
374    /// enabled).
375    fn assert_num_locks_held(&self, expected: u32);
376
377    /// Accounting hook invoked when a `ChainLock` is acquired by this transaction.
378    fn on_acquire(&self, token: &ChainLockTransactionToken<Self>);
379
380    /// Accounting hook invoked when a `ChainLock` is released by this transaction.
381    fn on_release(&self, token: &ChainLockTransactionToken<Self>);
382
383    /// Accounting/tracing hook invoked when contention is encountered while acquiring a
384    /// `ChainLock`.
385    fn on_contention(&self, token: &ChainLockTransactionToken<Self>);
386
387    /// Contention hook invoked when a `ChainLock` encounters a higher-priority owner.
388    ///
389    /// Returns `true` if backoff was recorded and the caller should unwind, or `false` if the
390    /// lock's token changed and acquisition should be retried.
391    fn record_backoff_or_retry(
392        &self,
393        observed_token: Token,
394        lock_state: &AtomicToken,
395        contention_state: &Self::ContentionState,
396        token: &ChainLockTransactionToken<Self>,
397    ) -> bool;
398
399    /// Contention hook invoked when releasing a `ChainLock` to sample contention state, invoke
400    /// `do_release`, and notify backed-off contenders.
401    fn release_and_notify<F: FnOnce()>(
402        &self,
403        contention_state: &Self::ContentionState,
404        do_release: F,
405        token: &ChainLockTransactionToken<Self>,
406    );
407}
408
409/// Storage trait for debug lock accounting in [`ChainLockTransaction`].
410pub trait AccountingStorage: Default {
411    /// Whether debug lock accounting is enabled.
412    const ENABLED: bool;
413
414    /// Creates a new accounting storage instance with the given initial `locks_held` and
415    /// `finalized` state.
416    fn new(locks_held: u32, finalized: bool) -> Self;
417
418    /// Returns the number of locks currently held by the transaction.
419    fn locks_held(&self) -> u32;
420
421    /// Returns whether the transaction is finalized.
422    fn finalized(&self) -> bool;
423
424    /// Increments the count of locks held by the transaction.
425    fn on_acquire(&self);
426
427    /// Decrements the count of locks held by the transaction.
428    fn on_release(&self);
429
430    /// Updates whether the transaction is finalized.
431    fn set_finalized(&self, finalized: bool);
432}
433
434/// Storage for debug accounting when `DebugAccountingEnabled` is `true`.
435#[repr(C)]
436#[derive(Default)]
437pub struct AccountingStorageEnabled {
438    locks_held: Cell<u32>,
439    finalized: Cell<bool>,
440}
441
442impl AccountingStorage for AccountingStorageEnabled {
443    const ENABLED: bool = true;
444
445    #[inline]
446    fn new(locks_held: u32, finalized: bool) -> Self {
447        Self { locks_held: Cell::new(locks_held), finalized: Cell::new(finalized) }
448    }
449
450    #[inline]
451    fn locks_held(&self) -> u32 {
452        self.locks_held.get()
453    }
454
455    #[inline]
456    fn finalized(&self) -> bool {
457        self.finalized.get()
458    }
459
460    #[inline]
461    fn on_acquire(&self) {
462        self.locks_held.set(self.locks_held.get() + 1);
463    }
464
465    #[inline]
466    fn on_release(&self) {
467        self.locks_held.set(self.locks_held.get() - 1);
468    }
469
470    #[inline]
471    fn set_finalized(&self, finalized: bool) {
472        self.finalized.set(finalized);
473    }
474}
475
476/// Zero-sized storage for debug accounting when `DebugAccountingEnabled` is `false`.
477#[repr(C)]
478#[derive(Default)]
479pub struct AccountingStorageDisabled;
480
481impl AccountingStorage for AccountingStorageDisabled {
482    const ENABLED: bool = false;
483
484    #[inline]
485    fn new(_locks_held: u32, _finalized: bool) -> Self {
486        Self
487    }
488
489    #[inline]
490    fn locks_held(&self) -> u32 {
491        0
492    }
493
494    #[inline]
495    fn finalized(&self) -> bool {
496        false
497    }
498
499    #[inline]
500    fn on_acquire(&self) {}
501
502    #[inline]
503    fn on_release(&self) {}
504
505    #[inline]
506    fn set_finalized(&self, _finalized: bool) {}
507}
508
509/// Storage trait for contention spin tracing in `ChainLockTransaction`.
510pub trait TraceStorage<C: Copy> {
511    /// Whether contention spin tracing is enabled.
512    const ENABLED: bool;
513
514    /// Creates a new trace storage instance with the given `callsite_info`.
515    fn new(callsite_info: C) -> Self;
516
517    /// Records the start of contention if not already recorded.
518    fn on_contention<E: TransactionHooks<CallsiteInfo = C>>(&self);
519
520    /// Emits the contention trace event if contention occurred during this transaction.
521    fn on_finalized<E: TransactionHooks<CallsiteInfo = C>>(&self);
522
523    /// Updates the callsite info when restarting a transaction.
524    fn set_callsite_info(&self, callsite_info: C);
525}
526
527/// Extra state when contention tracing is enabled.
528#[repr(C)]
529pub struct TraceStorageEnabled<C: Copy> {
530    contention_start_ticks: Cell<i64>,
531    callsite_info: Cell<C>,
532}
533
534impl<C: Copy> TraceStorageEnabled<C> {
535    const INVALID_TICKS: i64 = 0;
536}
537
538impl<C: Copy + Default> Default for TraceStorageEnabled<C> {
539    fn default() -> Self {
540        Self {
541            contention_start_ticks: Cell::new(Self::INVALID_TICKS),
542            callsite_info: Cell::new(C::default()),
543        }
544    }
545}
546
547impl<C: Copy> TraceStorage<C> for TraceStorageEnabled<C> {
548    const ENABLED: bool = true;
549
550    #[inline]
551    fn new(callsite_info: C) -> Self {
552        Self {
553            contention_start_ticks: Cell::new(Self::INVALID_TICKS),
554            callsite_info: Cell::new(callsite_info),
555        }
556    }
557
558    #[inline]
559    fn on_contention<E: TransactionHooks<CallsiteInfo = C>>(&self) {
560        if self.contention_start_ticks.get() == Self::INVALID_TICKS {
561            self.contention_start_ticks.set(E::get_current_ticks());
562        }
563    }
564
565    #[inline]
566    fn on_finalized<E: TransactionHooks<CallsiteInfo = C>>(&self) {
567        let start_ticks = self.contention_start_ticks.get();
568        if start_ticks != Self::INVALID_TICKS {
569            E::on_finalized(start_ticks, self.callsite_info.get());
570            self.contention_start_ticks.set(Self::INVALID_TICKS);
571        }
572    }
573
574    #[inline]
575    fn set_callsite_info(&self, callsite_info: C) {
576        self.callsite_info.set(callsite_info);
577    }
578}
579
580/// Zero-sized storage when contention tracing is disabled.
581#[repr(C)]
582#[derive(Default)]
583pub struct TraceStorageDisabled;
584
585impl<C: Copy> TraceStorage<C> for TraceStorageDisabled {
586    const ENABLED: bool = false;
587
588    #[inline]
589    fn new(_callsite_info: C) -> Self {
590        Self
591    }
592
593    #[inline]
594    fn on_contention<E: TransactionHooks<CallsiteInfo = C>>(&self) {}
595
596    #[inline]
597    fn on_finalized<E: TransactionHooks<CallsiteInfo = C>>(&self) {}
598
599    #[inline]
600    fn set_callsite_info(&self, _callsite_info: C) {}
601}
602
603/// Helper type for selecting storage types from compile-time `bool` constants.
604pub struct Bool<const B: bool>;
605
606/// Maps a compile-time `bool` to [`AccountingStorageEnabled`] or [`AccountingStorageDisabled`].
607pub trait AccountingSelector {
608    /// Selected accounting storage type.
609    type Storage: AccountingStorage;
610}
611
612impl AccountingSelector for Bool<true> {
613    type Storage = AccountingStorageEnabled;
614}
615
616impl AccountingSelector for Bool<false> {
617    type Storage = AccountingStorageDisabled;
618}
619
620/// Type alias selecting [`AccountingStorageEnabled`] when `ENABLED` is `true`, or
621/// [`AccountingStorageDisabled`] when `ENABLED` is `false`.
622pub type SelectAccounting<const ENABLED: bool> = <Bool<ENABLED> as AccountingSelector>::Storage;
623
624/// Maps a compile-time `bool` to [`TraceStorageEnabled<C>`] or [`TraceStorageDisabled`].
625pub trait TracingSelector<C: Copy> {
626    /// Selected trace storage type.
627    type Storage: TraceStorage<C>;
628}
629
630impl<C: Copy> TracingSelector<C> for Bool<true> {
631    type Storage = TraceStorageEnabled<C>;
632}
633
634impl<C: Copy> TracingSelector<C> for Bool<false> {
635    type Storage = TraceStorageDisabled;
636}
637
638/// Type alias selecting [`TraceStorageEnabled<C>`] when `ENABLED` is `true`, or
639/// [`TraceStorageDisabled`] when `ENABLED` is `false`.
640pub type SelectTracing<const ENABLED: bool, C> = <Bool<ENABLED> as TracingSelector<C>>::Storage;
641
642/// Trait implemented by environment-specific state savers (such as IRQ-save and preempt-disable
643/// guards) managed by [`ChainLockTransaction::until_done`].
644pub trait StateSaver<T> {
645    /// Relaxes the saved state (e.g., unregistering the transaction, re-enabling interrupts /
646    /// preemption, waiting for conflict resolution, re-disabling interrupts / preemption, and
647    /// re-registering the transaction) during a backoff cycle.
648    fn relax(&mut self, transaction: &T);
649}
650
651/// Trait implemented by compile-time state option tags passed to
652/// [`ChainLockTransaction::until_done`].
653pub trait StateOption<T> {
654    /// The RAII [`StateSaver`] type instantiated for this option.
655    type Saver: StateSaver<T>;
656
657    /// Saves the environment state for the duration of the transaction and returns the RAII
658    /// [`StateSaver`].
659    fn save_state(&self) -> Self::Saver;
660}
661
662/// Wrapper for a transaction state option tag.
663#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
664pub struct Option<O>(pub O);
665
666impl<O> Option<O> {
667    /// Creates a new `Option` wrapping `option`.
668    #[inline]
669    pub const fn new(option: O) -> Self {
670        Self(option)
671    }
672}
673
674impl<T, O: StateOption<T>> StateOption<T> for Option<O> {
675    type Saver = O::Saver;
676
677    #[inline]
678    fn save_state(&self) -> Self::Saver {
679        self.0.save_state()
680    }
681}
682
683/// Environment-specific hooks required by [`ChainLockTransaction`].
684///
685/// # Safety
686///
687/// Implementors must ensure that:
688/// - [`Self::active`] returns the exact pointer most recently passed to [`Self::set_active`] on
689///   the current execution context (or `None` if [`Self::set_active`] has not been called or was
690///   most recently called with `None` on the current execution context).
691/// - The storage backing [`Self::active`] and [`Self::set_active`] is strictly local to the
692///   current execution context (e.g., per-CPU or thread-local storage) and is never shared across
693///   concurrently executing contexts.
694pub unsafe trait TransactionHooks: Sized + 'static {
695    /// State used by `ChainLock` to store contended lock state for backoff mitigation
696    /// (e.g., `AtomicU32` for `cpu_mask_t` in the Zircon kernel).
697    type ContentionState: ContentionState;
698
699    /// Debugging/tracing information that identifies the code location of the transaction.
700    type CallsiteInfo: Copy;
701
702    /// Storage for debug lock accounting (`SelectAccounting<ENABLED>`).
703    type Accounting: AccountingStorage;
704
705    /// Storage for contention spin tracing (`SelectTracing<ENABLED, Self::CallsiteInfo>`).
706    type Tracing: TraceStorage<Self::CallsiteInfo>;
707
708    /// Additional environment-specific state stored in each transaction instance
709    /// (e.g., `Cell<u64>` for `conflict_id_` in the Zircon kernel, or `()` when none is needed).
710    type ExtraState: Default;
711
712    /// Returns a pointer to the active chain lock transaction for the current execution context
713    /// (e.g., current CPU), or `None` if none is active.
714    fn active() -> core::option::Option<NonNull<ChainLockTransaction<Self>>>;
715
716    /// Sets the active chain lock transaction for the current execution context.
717    ///
718    /// # Safety
719    ///
720    /// The caller must ensure that `transaction` is either `None` or points to a valid
721    /// `ChainLockTransaction<Self>` that remains alive and pinned at its memory address for as
722    /// long as it remains registered as the active transaction on the current execution context.
723    unsafe fn set_active(transaction: core::option::Option<NonNull<ChainLockTransaction<Self>>>);
724
725    /// Performs an architecture-specific CPU relax/yield operation.
726    fn yield_cpu();
727
728    /// Allocates a reserved token for use with
729    /// [`ChainLockTransaction::save_state_and_use_reserved_token`] and
730    /// [`ChainLockTransaction::save_state_initial`].
731    fn allocate_reserved_token() -> Token;
732
733    /// Gets the current monotonic ticks for contention spin tracing.
734    #[inline]
735    fn get_current_ticks() -> i64 {
736        0
737    }
738
739    /// Emits a trace event or updates counters when a contended transaction is finalized.
740    #[inline]
741    fn on_finalized(_contention_start_ticks: i64, _callsite_info: Self::CallsiteInfo) {}
742
743    /// Updates counters or state when a transaction backs off (invoked after incrementing
744    /// `backoff_count`).
745    #[inline]
746    fn on_backoff(_transaction: &ChainLockTransaction<Self>) {}
747
748    /// Handles backoff mitigation when contention with a higher-priority transaction is observed.
749    ///
750    /// Returns `true` if the backoff was recorded and the caller should unwind held locks, or
751    /// `false` if the lock's token changed and the caller should retry acquisition.
752    fn record_backoff_or_retry(
753        transaction: &ChainLockTransaction<Self>,
754        observed_token: Token,
755        lock_state: &AtomicToken,
756        contention_state: &Self::ContentionState,
757    ) -> bool;
758
759    /// Carefully sequences the operations required to release a `ChainLock` and notify backed-off
760    /// contenders.
761    fn release_and_notify<F: FnOnce()>(
762        transaction: &ChainLockTransaction<Self>,
763        contention_state: &Self::ContentionState,
764        do_release: F,
765    );
766}
767
768/// Environment-independent framework for chain lock transactions.
769///
770/// Chain lock transactions are a layer on top of chain locks that track the state necessary for
771/// entities (i.e. CPUs) to acquire a series of one or more chain locks and correctly handle
772/// arbitration with other entities contending for the same locks.
773#[repr(C)]
774pub struct ChainLockTransaction<E: TransactionHooks> {
775    token: Cell<Token>,
776    state: Cell<State>,
777    accounting: E::Accounting,
778    tracing: E::Tracing,
779    backoff_count: Cell<u64>,
780    extra: E::ExtraState,
781    _pin: PhantomData<(*mut (), PhantomPinned)>,
782}
783
784impl<E: TransactionHooks> ChainLockTransaction<E> {
785    /// Token value representing an unlocked `ChainLock`.
786    pub const UNLOCKED_TOKEN_VALUE: u64 = UNLOCKED_TOKEN_VALUE;
787
788    /// Number of reserved token values (`1..=RESERVED_TOKEN_VALUES`).
789    pub const RESERVED_TOKEN_VALUES: u64 = RESERVED_TOKEN_VALUES;
790
791    /// Initial value for the global dynamic transaction token generator.
792    pub const INITIAL_TOKEN_VALUE: u64 = INITIAL_TOKEN_VALUE;
793
794    /// Maximum possible token value, used transiently during lock release.
795    pub const MAX_TOKEN_VALUE: u64 = MAX_TOKEN_VALUE;
796
797    /// Whether debug lock accounting is enabled for this transaction type.
798    pub const DEBUG_ACCOUNTING_ENABLED: bool = E::Accounting::ENABLED;
799
800    /// Whether contention spin tracing is enabled for this transaction type.
801    pub const CONTENTION_TRACING_ENABLED: bool = E::Tracing::ENABLED;
802
803    /// Constant value of [`DoneType`] for completing a `()`-returning transaction.
804    pub const DONE: DoneType = DONE;
805
806    /// Returns the current [`Token`] of this transaction.
807    #[inline]
808    pub fn token(&self) -> Token {
809        self.token.get()
810    }
811
812    /// Allocates the next monotonically increasing dynamic transaction [`Token`] from the global
813    /// token generator.
814    #[inline]
815    pub fn next_token() -> Token {
816        // SAFETY: Accessing the extern static `concurrent_chainlock_transaction_token_generator`
817        // and calling `fetch_add` on it is sound because it is defined in C++ with static storage
818        // duration as a lock-free 64-bit atomic integer.
819        let raw = unsafe {
820            concurrent_chainlock_transaction_token_generator.fetch_add(1, Ordering::Relaxed)
821        };
822        Token::from_raw(raw)
823    }
824
825    /// Returns the reserved [`Token`] for `reserved_index` (e.g., a CPU number).
826    ///
827    /// Asserts in debug builds that `reserved_index < Self::RESERVED_TOKEN_VALUES`.
828    #[inline]
829    pub fn reserved_token(reserved_index: usize) -> Token {
830        debug_assert!((reserved_index as u64) < Self::RESERVED_TOKEN_VALUES);
831        Token::from_raw((reserved_index as u64) + 1)
832    }
833
834    /// Returns the current [`State`] of this transaction.
835    #[inline]
836    pub fn state(&self) -> State {
837        self.state.get()
838    }
839
840    /// Updates the [`State`] of this transaction.
841    #[inline]
842    pub(crate) fn set_state(&self, state: State) {
843        self.state.set(state);
844    }
845
846    // Replace a token value when saving or restoring transaction state. Both tokens must be valid
847    // and one or the other must be reserved.
848    #[inline]
849    pub(crate) fn replace_token(&self, replacement: Token) {
850        let current = self.token.get();
851        debug_assert!(current.is_valid());
852        debug_assert!(replacement.is_valid());
853        debug_assert_ne!(current.is_reserved(), replacement.is_reserved());
854        self.token.set(replacement);
855    }
856
857    /// Provides a common sequence for executing a chain lock transaction and the required
858    /// backoff arbitration logic.
859    ///
860    /// The caller is responsible for providing three arguments:
861    /// 1. An implementation of [`StateOption<Self>`] (such as [`Option<O>`]): Used to instantiate
862    ///    the environment-provided [`StateSaver`] type, indicating the relevant states to save,
863    ///    such as IRQ enable flags, preemption flags, etc., and restore after each transaction
864    ///    attempt.
865    /// 2. An instance of [`E::CallsiteInfo`](TransactionHooks::CallsiteInfo): Used for debugging
866    ///    and tracing to identify the code location of the transaction.
867    /// 3. A callable implementing a single transaction attempt: This can be a function or closure
868    ///    accepting a [`&ChainLockTransactionToken<Self>`](ChainLockTransactionToken) and
869    ///    returning a type implementing [`IntoTransactionResult`].
870    ///
871    /// The callable should match one of the following signatures:
872    /// a. `FnMut(&ChainLockTransactionToken<Self>) -> TransactionResult<()>`: A transaction that
873    ///    has a return type `()`.
874    /// b. `FnMut(&ChainLockTransactionToken<Self>) -> TransactionResult<T>`: A transaction that
875    ///    has a user-defined return type `T`.
876    /// c. `FnMut(&ChainLockTransactionToken<Self>) -> DoneType`: A transaction that has an implied
877    ///    return type `()`.
878    ///
879    /// The overall return type of `until_done` is either `T` or `()`, depending on the signature
880    /// of `callable`, as described above.
881    ///
882    /// A basic transaction is structured as follows:
883    ///
884    /// 1. Define a callable that will be executed until the transaction is complete. In this
885    ///    example, the callable will return `zx_status_t` when the transaction is complete, which
886    ///    will become the return value of `until_done`.
887    ///
888    /// ```ignore
889    /// let do_transaction =
890    ///     |token: &ChainLockTransactionToken| -> TransactionResult<zx_status_t> {
891    ///         if !object.get_lock().acquire_or_backoff(token) {
892    ///             return Action::Backoff.into(); // Execute the backoff protocol and re-enter.
893    ///         }
894    ///
895    ///         if restart_transaction_condition {
896    ///             object.get_lock().release(token);
897    ///             return Action::Restart.into(); // Restart the transaction and re-enter.
898    ///         }
899    ///
900    ///         if !locked_operation_on_object(object, token) {
901    ///             object.get_lock().release(token);
902    ///             // Complete the transaction, returning the error to the caller.
903    ///             return TransactionResult::Value(ZX_ERR_BAD_STATE);
904    ///         }
905    ///
906    ///         object.get_lock().release(token);
907    ///         // Complete the transaction, returning success to the caller.
908    ///         TransactionResult::Value(ZX_OK)
909    ///     };
910    /// ```
911    ///
912    /// In cases where the user return type is `()`, the callable can return
913    /// [`ChainLockTransaction::DONE`] (or `DONE.into()` / [`TransactionResult::DONE`]) to complete
914    /// the transaction.
915    ///
916    /// 2. Execute the transaction using the given options and callable. In this example, the
917    ///    constant `STATE_OPTION_A` is a value of type [`Option<O>`] with an environment-specific
918    ///    option value to pass to the state saver. The callable is invoked cyclically, with
919    ///    intervening backoffs, until a terminal value (of a user-defined return type in this
920    ///    case) is returned.
921    ///
922    /// ```ignore
923    /// return ChainLockTransaction::until_done(
924    ///     STATE_OPTION_A,
925    ///     clt_callsite!("foo"),
926    ///     do_transaction,
927    /// );
928    /// ```
929    #[inline]
930    pub fn until_done<O, F, R>(
931        option: O,
932        callsite_info: E::CallsiteInfo,
933        mut callable: F,
934    ) -> R::Output
935    where
936        O: StateOption<Self>,
937        F: FnMut(&ChainLockTransactionToken<Self>) -> R,
938        R: IntoTransactionResult,
939    {
940        // Instantiate the state saver type with the supplied option to take care of state save,
941        // restore, and relax operations.
942        //
943        // Declared before `transaction` so that in Rust's reverse-declaration drop order,
944        // `transaction` is dropped (and unregistered) BEFORE `state_saver` restores interrupts /
945        // preemption state.
946        let mut state_saver = option.save_state();
947
948        // Instantiate the transaction to store the transaction state and register it as the
949        // active transaction once placed in its stack slot.
950        let transaction = Self::new_unregistered(callsite_info, 0, false);
951        // SAFETY: `transaction` remains alive and unmoved in its stack slot for the duration of
952        // `until_done`, and `token` does not escape `until_done`. `register` asserts that no other
953        // transaction is currently active on the current execution context.
954        let token = unsafe { transaction.register() };
955
956        // Execute the callable until it returns a terminal value indicating the transaction is
957        // complete.
958        loop {
959            // Execute the transaction and get the returned result.
960            let result = callable(&token).into_transaction_result();
961
962            // If the result is not an action it is a terminal value. Complete the transaction and
963            // return the user defined value, if any.
964            match result {
965                TransactionResult::Value(value) => {
966                    if transaction.state() == State::Started {
967                        Self::finalize(&token);
968                    }
969                    transaction.set_state(State::Complete);
970                    return value;
971                }
972                TransactionResult::Action(Action::Backoff) => {
973                    debug_assert_eq!(transaction.state(), State::Started);
974                    transaction.assert_num_locks_held(0);
975                    transaction.assert_not_finalized();
976                    transaction.backoff_count.set(transaction.backoff_count.get() + 1);
977                    E::on_backoff(&transaction); // Notify after updating backoff_count.
978                    state_saver.relax(&transaction);
979                    debug_assert_eq!(E::active(), Some(NonNull::from(&transaction)));
980                }
981                TransactionResult::Action(Action::Restart) => {
982                    debug_assert_eq!(transaction.state(), State::Finalized);
983                    transaction.restart(callsite_info, &token);
984                }
985            }
986        }
987    }
988
989    /// Returns the number of times this transaction has backed off.
990    #[inline]
991    pub fn backoff_count(&self) -> u64 {
992        self.backoff_count.get()
993    }
994
995    /// Returns a reference to the environment-specific extra state (e.g., `conflict_id_` in the
996    /// kernel).
997    #[inline]
998    pub const fn extra(&self) -> &E::ExtraState {
999        &self.extra
1000    }
1001
1002    /// Asserts that at least one lock is currently held by this transaction (when debug accounting
1003    /// is enabled).
1004    #[inline]
1005    pub fn assert_at_least_one_lock_held(&self) {
1006        if Self::DEBUG_ACCOUNTING_ENABLED {
1007            assert!(self.accounting.locks_held() > 0);
1008        }
1009    }
1010
1011    /// Asserts that at most one lock is currently held by this transaction (when debug accounting
1012    /// is enabled).
1013    #[inline]
1014    pub fn assert_at_most_one_lock_held(&self) {
1015        if Self::DEBUG_ACCOUNTING_ENABLED {
1016            assert!(self.accounting.locks_held() <= 1);
1017        }
1018    }
1019
1020    /// Asserts that exactly `expected` locks are currently held by this transaction (when debug
1021    /// accounting is enabled).
1022    #[inline]
1023    pub fn assert_num_locks_held(&self, expected: u32) {
1024        if Self::DEBUG_ACCOUNTING_ENABLED {
1025            let actual = self.accounting.locks_held();
1026            assert_eq!(expected, actual, "expected={expected}, actual={actual}");
1027        }
1028    }
1029
1030    /// Asserts that this transaction has been finalized (when debug accounting is enabled).
1031    #[inline]
1032    pub fn assert_finalized(&self) {
1033        if Self::DEBUG_ACCOUNTING_ENABLED {
1034            assert!(self.accounting.finalized());
1035        }
1036    }
1037
1038    /// Asserts that this transaction has not been finalized (when debug accounting is enabled).
1039    #[inline]
1040    pub fn assert_not_finalized(&self) {
1041        if Self::DEBUG_ACCOUNTING_ENABLED {
1042            assert!(!self.accounting.finalized());
1043        }
1044    }
1045
1046    /// Asserts in debug builds that a transaction is currently active and mints a
1047    /// [`ChainLockTransactionToken<Self>`].
1048    ///
1049    /// # Safety
1050    ///
1051    /// The caller must ensure that a `ChainLockTransaction<E>` is currently registered as active
1052    /// on the current execution context, and that the returned token is not used while that
1053    /// transaction is unregistered or after it is dropped.
1054    #[inline]
1055    pub unsafe fn assert_active() -> ChainLockTransactionToken<Self> {
1056        debug_assert!(E::active().is_some());
1057        ChainLockTransactionToken::new()
1058    }
1059
1060    /// Mints a [`ChainLockTransactionToken<Self>`] without checking at runtime for efficiency in
1061    /// trivial cases.
1062    ///
1063    /// # Safety
1064    ///
1065    /// The caller must ensure that a `ChainLockTransaction<E>` is currently registered as active
1066    /// on the current execution context, and that the returned token is not used while that
1067    /// transaction is unregistered or after it is dropped.
1068    #[inline]
1069    pub unsafe fn mark_active() -> ChainLockTransactionToken<Self> {
1070        ChainLockTransactionToken::new()
1071    }
1072
1073    /// Returns a pointer to the active transaction, or `None` if none is active.
1074    #[inline]
1075    pub fn active() -> core::option::Option<NonNull<Self>> {
1076        E::active()
1077    }
1078
1079    /// Returns a reference to the active transaction. Asserts in debug builds that a transaction
1080    /// is active.
1081    #[inline]
1082    pub fn active_ref(_token: &ChainLockTransactionToken<Self>) -> &Self {
1083        let ptr = E::active();
1084        debug_assert!(ptr.is_some());
1085        // SAFETY: `_token` is a valid `ChainLockTransactionToken<Self>`, which by its safety
1086        // invariant guarantees that `E::active()` is `Some` and points to a valid, initialized
1087        // `ChainLockTransaction<E>` that remains alive and pinned at its memory address on the
1088        // current execution context, with all interior mutations mediated through `Cell`.
1089        unsafe { ptr.unwrap_unchecked().as_ref() }
1090    }
1091
1092    /// Saves the pointer to the current transaction and allocates a reserved token to sync leaf
1093    /// chain locks to during critical sequences.
1094    #[inline]
1095    pub fn save_state_and_use_reserved_token(
1096        token: &ChainLockTransactionToken<Self>,
1097    ) -> SavedState<E> {
1098        let transaction = Self::active_ref(token);
1099        debug_assert!(!transaction.token().is_reserved());
1100        SavedState::with_replacement(transaction, E::allocate_reserved_token())
1101    }
1102
1103    /// Creates a saved state for a bare transaction used to kick off a new thread.
1104    #[inline]
1105    pub fn save_state_initial(&self, _token: &ChainLockTransactionToken<Self>) -> SavedState<E> {
1106        debug_assert_ne!(E::active(), Some(NonNull::from(self)));
1107        SavedState::with_replacement(self, E::allocate_reserved_token())
1108    }
1109
1110    /// Restores the active transaction using the given saved state.
1111    ///
1112    /// # Safety
1113    ///
1114    /// The caller must ensure that `saved_state` was produced by
1115    /// [`Self::save_state_and_use_reserved_token`] or [`Self::save_state_initial`] for a
1116    /// `ChainLockTransaction<E>` instance that remains alive and pinned at its memory address for
1117    /// as long as it remains registered as the active transaction on the current execution
1118    /// context.
1119    #[inline]
1120    pub unsafe fn restore_state(saved_state: SavedState<E>) {
1121        let transaction_ptr = saved_state.transaction();
1122        // SAFETY: The caller guarantees `saved_state` points to a valid, live `Self` instance on
1123        // the current execution context.
1124        let transaction = unsafe { transaction_ptr.as_ref() };
1125        debug_assert!(transaction.token().is_reserved());
1126        transaction.replace_token(saved_state.token());
1127        // SAFETY: The caller guarantees `transaction_ptr` points to a valid `Self` instance that
1128        // remains alive and pinned while registered as active.
1129        unsafe { E::set_active(Some(transaction_ptr)) };
1130    }
1131
1132    /// Directly finalizes the active transaction, ending an active contention tracing duration,
1133    /// if any.
1134    #[inline]
1135    pub fn finalize(token: &ChainLockTransactionToken<Self>) {
1136        let transaction = Self::active_ref(token);
1137        transaction.assert_not_finalized();
1138        transaction.set_finalized(true);
1139    }
1140
1141    /// Restarts this transaction, resetting key state including the callsite info.
1142    #[inline]
1143    pub fn restart(
1144        &self,
1145        callsite_info: E::CallsiteInfo,
1146        _token: &ChainLockTransactionToken<Self>,
1147    ) {
1148        self.assert_finalized();
1149        self.assert_at_most_one_lock_held();
1150        debug_assert!(self.token().is_valid());
1151        self.set_finalized(false);
1152        if Self::CONTENTION_TRACING_ENABLED {
1153            self.tracing.set_callsite_info(callsite_info);
1154        }
1155    }
1156
1157    /// Returns the number of locks currently held by this transaction.
1158    ///
1159    /// Requires `Self::DEBUG_ACCOUNTING_ENABLED` to be `true` at compile time.
1160    #[inline]
1161    pub fn locks_held(&self) -> u32 {
1162        const {
1163            assert!(Self::DEBUG_ACCOUNTING_ENABLED);
1164        }
1165        self.accounting.locks_held()
1166    }
1167
1168    /// Returns whether this transaction is currently finalized.
1169    ///
1170    /// Requires `Self::DEBUG_ACCOUNTING_ENABLED` to be `true` at compile time.
1171    #[inline]
1172    pub fn is_finalized(&self) -> bool {
1173        const {
1174            assert!(Self::DEBUG_ACCOUNTING_ENABLED);
1175        }
1176        self.accounting.finalized()
1177    }
1178
1179    /// Creates an unregistered bare transaction with the given initial state.
1180    ///
1181    /// Because Rust does not guarantee copy elision (RVO) when returning by value, callers
1182    /// creating a bare transaction outside [`Self::until_done`] must place the returned
1183    /// transaction in its stack variable first, and then call [`Self::register`] (or
1184    /// [`Self::restore_state`] with [`Self::save_state_initial`]). Note that `Drop` for
1185    /// [`ChainLockTransaction`] unconditionally calls [`Self::unregister`], so the transaction
1186    /// must be registered as active before it is dropped.
1187    #[inline]
1188    pub fn new_unregistered(
1189        callsite_info: E::CallsiteInfo,
1190        locks_held: u32,
1191        finalized: bool,
1192    ) -> Self {
1193        let state = if finalized { State::Finalized } else { State::Started };
1194        Self {
1195            token: Cell::new(Self::next_token()),
1196            state: Cell::new(state),
1197            accounting: E::Accounting::new(locks_held, finalized),
1198            tracing: E::Tracing::new(callsite_info),
1199            backoff_count: Cell::new(0),
1200            extra: E::ExtraState::default(),
1201            _pin: PhantomData,
1202        }
1203    }
1204
1205    /// Registers `self` as the active transaction for the current execution context and mints a
1206    /// [`ChainLockTransactionToken<Self>`].
1207    ///
1208    /// Asserts that no transaction is currently active.
1209    ///
1210    /// # Safety
1211    ///
1212    /// The caller must ensure that:
1213    /// - `self` remains alive and pinned at its current memory address (i.e. not moved or
1214    ///   forgotten without unregistering) for as long as it remains registered as the active
1215    ///   transaction on the current execution context.
1216    /// - The returned [`ChainLockTransactionToken<Self>`] is not used while `self` is unregistered
1217    ///   or after `self` is dropped.
1218    #[inline]
1219    pub unsafe fn register(&self) -> ChainLockTransactionToken<Self> {
1220        assert!(E::active().is_none());
1221        // SAFETY: The caller guarantees `self` remains alive and pinned at its memory address
1222        // while registered as the active transaction on the current execution context.
1223        unsafe { E::set_active(Some(NonNull::from(self))) };
1224        ChainLockTransactionToken::new()
1225    }
1226
1227    /// Unregisters `self` as the active transaction for the current execution context.
1228    ///
1229    /// Asserts in debug builds that `self` is the currently active transaction.
1230    ///
1231    /// # Safety
1232    ///
1233    /// The caller must ensure that:
1234    /// - `self` is currently the active transaction on the current execution context.
1235    /// - No [`ChainLockTransactionToken<Self>`] associated with `self` is used to access the
1236    ///   active transaction while `self` is unregistered.
1237    #[inline]
1238    pub unsafe fn unregister(&self) {
1239        debug_assert_eq!(E::active(), Some(NonNull::from(self)));
1240        // SAFETY: Passing `None` to `E::set_active` clears the active transaction pointer on the
1241        // current execution context.
1242        unsafe { E::set_active(None) };
1243    }
1244
1245    #[inline]
1246    pub(crate) fn set_finalized(&self, finalized: bool) {
1247        self.set_state(if finalized { State::Finalized } else { State::Started });
1248        if Self::DEBUG_ACCOUNTING_ENABLED {
1249            self.accounting.set_finalized(finalized);
1250        }
1251        if Self::CONTENTION_TRACING_ENABLED && finalized {
1252            self.tracing.on_finalized::<E>();
1253        }
1254    }
1255}
1256
1257impl<E: TransactionHooks> Drop for ChainLockTransaction<E> {
1258    #[inline]
1259    fn drop(&mut self) {
1260        // SAFETY: Unconditionally unregister `self` on drop (matching C++
1261        // `~ChainLockTransaction`), asserting in debug builds that `self` is the active
1262        // transaction. Because `self` is being dropped, no valid
1263        // `ChainLockTransactionToken<Self>` may access it after this point.
1264        unsafe {
1265            self.unregister();
1266        }
1267    }
1268}
1269
1270impl<E: TransactionHooks> Transaction for ChainLockTransaction<E> {
1271    type ContentionState = E::ContentionState;
1272
1273    #[inline]
1274    fn active() -> core::option::Option<NonNull<Self>> {
1275        E::active()
1276    }
1277
1278    #[inline]
1279    fn active_ref(token: &ChainLockTransactionToken<Self>) -> &Self {
1280        Self::active_ref(token)
1281    }
1282
1283    #[inline]
1284    fn yield_cpu() {
1285        E::yield_cpu();
1286    }
1287
1288    #[inline]
1289    fn token(&self) -> Token {
1290        Self::token(self)
1291    }
1292
1293    #[inline]
1294    fn assert_not_finalized(&self) {
1295        Self::assert_not_finalized(self);
1296    }
1297
1298    #[inline]
1299    fn assert_num_locks_held(&self, expected: u32) {
1300        Self::assert_num_locks_held(self, expected);
1301    }
1302
1303    #[inline]
1304    fn on_acquire(&self, _token: &ChainLockTransactionToken<Self>) {
1305        if Self::DEBUG_ACCOUNTING_ENABLED {
1306            self.accounting.on_acquire();
1307        }
1308    }
1309
1310    #[inline]
1311    fn on_release(&self, _token: &ChainLockTransactionToken<Self>) {
1312        if Self::DEBUG_ACCOUNTING_ENABLED {
1313            self.accounting.on_release();
1314        }
1315    }
1316
1317    #[inline]
1318    fn on_contention(&self, _token: &ChainLockTransactionToken<Self>) {
1319        if Self::CONTENTION_TRACING_ENABLED {
1320            self.tracing.on_contention::<E>();
1321        }
1322    }
1323
1324    #[inline]
1325    fn record_backoff_or_retry(
1326        &self,
1327        observed_token: Token,
1328        lock_state: &AtomicToken,
1329        contention_state: &Self::ContentionState,
1330        _token: &ChainLockTransactionToken<Self>,
1331    ) -> bool {
1332        E::record_backoff_or_retry(self, observed_token, lock_state, contention_state)
1333    }
1334
1335    #[inline]
1336    fn release_and_notify<F: FnOnce()>(
1337        &self,
1338        contention_state: &Self::ContentionState,
1339        do_release: F,
1340        _token: &ChainLockTransactionToken<Self>,
1341    ) {
1342        E::release_and_notify(self, contention_state, do_release);
1343    }
1344}
1345
1346// Verify layout parity across all 4 combinations of `(DEBUG_ACCOUNTING_ENABLED,
1347// CONTENTION_TRACING_ENABLED)` for both empty `ExtraState` (`concurrent::ChainLockTransaction`)
1348// and 8-byte `ExtraState` (`::ChainLockTransaction` in `kconcurrent` with `uint64_t
1349// conflict_id_`).
1350#[repr(C)]
1351#[derive(Clone, Copy, Default)]
1352struct DummyKernelCallsiteInfo {
1353    label: *const u8,
1354    line_number: u32,
1355}
1356
1357macro_rules! impl_dummy_hooks {
1358    ($name:ident, $debug:expr, $trace:expr, $extra:ty) => {
1359        struct $name;
1360        // SAFETY: `$name` is an uninstantiated type used solely for compile-time layout
1361        // assertions; `active()` always returns `None` and `set_active()` is never called at
1362        // runtime.
1363        unsafe impl TransactionHooks for $name {
1364            type ContentionState = AtomicU32;
1365            type CallsiteInfo = DummyKernelCallsiteInfo;
1366            type Accounting = SelectAccounting<$debug>;
1367            type Tracing = SelectTracing<$trace, Self::CallsiteInfo>;
1368            type ExtraState = $extra;
1369
1370            fn active() -> core::option::Option<NonNull<ChainLockTransaction<Self>>> {
1371                None
1372            }
1373            unsafe fn set_active(_: core::option::Option<NonNull<ChainLockTransaction<Self>>>) {}
1374            fn yield_cpu() {}
1375            fn allocate_reserved_token() -> Token {
1376                Token::UNLOCKED
1377            }
1378            fn record_backoff_or_retry(
1379                _: &ChainLockTransaction<Self>,
1380                _: Token,
1381                _: &AtomicToken,
1382                _: &Self::ContentionState,
1383            ) -> bool {
1384                true
1385            }
1386            fn release_and_notify<F: FnOnce()>(
1387                _: &ChainLockTransaction<Self>,
1388                _: &Self::ContentionState,
1389                do_release: F,
1390            ) {
1391                do_release();
1392            }
1393        }
1394    };
1395}
1396
1397impl_dummy_hooks!(BaseFalseFalse, false, false, ());
1398impl_dummy_hooks!(BaseTrueFalse, true, false, ());
1399impl_dummy_hooks!(BaseFalseTrue, false, true, ());
1400impl_dummy_hooks!(BaseTrueTrue, true, true, ());
1401
1402impl_dummy_hooks!(KernelFalseFalse, false, false, Cell<u64>);
1403impl_dummy_hooks!(KernelTrueFalse, true, false, Cell<u64>);
1404impl_dummy_hooks!(KernelFalseTrue, false, true, Cell<u64>);
1405impl_dummy_hooks!(KernelTrueTrue, true, true, Cell<u64>);
1406
1407zr::static_assert!(
1408    size_of::<ChainLockTransactionToken<ChainLockTransaction<BaseFalseFalse>>>() == 0
1409);
1410zr::static_assert!(
1411    align_of::<ChainLockTransactionToken<ChainLockTransaction<BaseFalseFalse>>>() == 1
1412);
1413zr::static_assert!(size_of::<Token>() == 8);
1414zr::static_assert!(align_of::<Token>() == 8);
1415zr::static_assert!(size_of::<AtomicToken>() == 8);
1416zr::static_assert!(align_of::<AtomicToken>() == 8);
1417zr::static_assert!(size_of::<SavedState<BaseFalseFalse>>() == 16);
1418zr::static_assert!(align_of::<SavedState<BaseFalseFalse>>() == 8);
1419zr::static_assert!(offset_of!(SavedState<BaseFalseFalse>, transaction) == 0);
1420zr::static_assert!(offset_of!(SavedState<BaseFalseFalse>, token) == 8);
1421zr::static_assert!(size_of::<State>() == 4);
1422zr::static_assert!(align_of::<State>() == 4);
1423
1424zr::static_assert!(size_of::<DummyKernelCallsiteInfo>() == 16);
1425zr::static_assert!(align_of::<DummyKernelCallsiteInfo>() == 8);
1426
1427zr::static_assert!(size_of::<AccountingStorageEnabled>() == 8);
1428zr::static_assert!(align_of::<AccountingStorageEnabled>() == 4);
1429zr::static_assert!(offset_of!(AccountingStorageEnabled, locks_held) == 0);
1430zr::static_assert!(offset_of!(AccountingStorageEnabled, finalized) == 4);
1431
1432// Base `concurrent::ChainLockTransaction` layout assertions:
1433zr::static_assert!(size_of::<ChainLockTransaction<BaseFalseFalse>>() == 24);
1434zr::static_assert!(align_of::<ChainLockTransaction<BaseFalseFalse>>() == 8);
1435zr::static_assert!(offset_of!(ChainLockTransaction<BaseFalseFalse>, token) == 0);
1436zr::static_assert!(offset_of!(ChainLockTransaction<BaseFalseFalse>, state) == 8);
1437zr::static_assert!(offset_of!(ChainLockTransaction<BaseFalseFalse>, backoff_count) == 16);
1438
1439zr::static_assert!(size_of::<ChainLockTransaction<BaseTrueFalse>>() == 32);
1440zr::static_assert!(align_of::<ChainLockTransaction<BaseTrueFalse>>() == 8);
1441zr::static_assert!(offset_of!(ChainLockTransaction<BaseTrueFalse>, token) == 0);
1442zr::static_assert!(offset_of!(ChainLockTransaction<BaseTrueFalse>, state) == 8);
1443zr::static_assert!(offset_of!(ChainLockTransaction<BaseTrueFalse>, accounting) == 12);
1444zr::static_assert!(offset_of!(ChainLockTransaction<BaseTrueFalse>, backoff_count) == 24);
1445
1446zr::static_assert!(size_of::<ChainLockTransaction<BaseFalseTrue>>() == 48);
1447zr::static_assert!(align_of::<ChainLockTransaction<BaseFalseTrue>>() == 8);
1448zr::static_assert!(offset_of!(ChainLockTransaction<BaseFalseTrue>, token) == 0);
1449zr::static_assert!(offset_of!(ChainLockTransaction<BaseFalseTrue>, state) == 8);
1450zr::static_assert!(offset_of!(ChainLockTransaction<BaseFalseTrue>, tracing) == 16);
1451zr::static_assert!(offset_of!(ChainLockTransaction<BaseFalseTrue>, backoff_count) == 40);
1452
1453zr::static_assert!(size_of::<ChainLockTransaction<BaseTrueTrue>>() == 56);
1454zr::static_assert!(align_of::<ChainLockTransaction<BaseTrueTrue>>() == 8);
1455zr::static_assert!(offset_of!(ChainLockTransaction<BaseTrueTrue>, token) == 0);
1456zr::static_assert!(offset_of!(ChainLockTransaction<BaseTrueTrue>, state) == 8);
1457zr::static_assert!(offset_of!(ChainLockTransaction<BaseTrueTrue>, accounting) == 12);
1458zr::static_assert!(offset_of!(ChainLockTransaction<BaseTrueTrue>, tracing) == 24);
1459zr::static_assert!(offset_of!(ChainLockTransaction<BaseTrueTrue>, backoff_count) == 48);
1460
1461// Kernel `::ChainLockTransaction` (with `uint64_t conflict_id_`) layout assertions:
1462zr::static_assert!(size_of::<ChainLockTransaction<KernelFalseFalse>>() == 32);
1463zr::static_assert!(offset_of!(ChainLockTransaction<KernelFalseFalse>, extra) == 24);
1464
1465zr::static_assert!(size_of::<ChainLockTransaction<KernelTrueFalse>>() == 40);
1466zr::static_assert!(offset_of!(ChainLockTransaction<KernelTrueFalse>, extra) == 32);
1467
1468zr::static_assert!(size_of::<ChainLockTransaction<KernelFalseTrue>>() == 56);
1469zr::static_assert!(offset_of!(ChainLockTransaction<KernelFalseTrue>, extra) == 48);
1470
1471zr::static_assert!(size_of::<ChainLockTransaction<KernelTrueTrue>>() == 64);
1472zr::static_assert!(offset_of!(ChainLockTransaction<KernelTrueTrue>, extra) == 56);