Skip to main content

ChainLockTransaction

Struct ChainLockTransaction 

Source
pub struct ChainLockTransaction<E: TransactionHooks> { /* private fields */ }
Expand description

Environment-independent framework for chain lock transactions.

Chain lock transactions are a layer on top of chain locks that track the state necessary for entities (i.e. CPUs) to acquire a series of one or more chain locks and correctly handle arbitration with other entities contending for the same locks.

Implementations§

Source§

impl<E: TransactionHooks> ChainLockTransaction<E>

Source

pub const UNLOCKED_TOKEN_VALUE: u64 = UNLOCKED_TOKEN_VALUE

Token value representing an unlocked ChainLock.

Source

pub const RESERVED_TOKEN_VALUES: u64 = RESERVED_TOKEN_VALUES

Number of reserved token values (1..=RESERVED_TOKEN_VALUES).

Source

pub const INITIAL_TOKEN_VALUE: u64 = INITIAL_TOKEN_VALUE

Initial value for the global dynamic transaction token generator.

Source

pub const MAX_TOKEN_VALUE: u64 = MAX_TOKEN_VALUE

Maximum possible token value, used transiently during lock release.

Source

pub const DEBUG_ACCOUNTING_ENABLED: bool = <E::Accounting>::ENABLED

Whether debug lock accounting is enabled for this transaction type.

Source

pub const CONTENTION_TRACING_ENABLED: bool = <E::Tracing>::ENABLED

Whether contention spin tracing is enabled for this transaction type.

Source

pub const DONE: DoneType = DONE

Constant value of DoneType for completing a ()-returning transaction.

Source

pub fn token(&self) -> Token

Returns the current Token of this transaction.

Source

pub fn next_token() -> Token

Allocates the next monotonically increasing dynamic transaction Token from the global token generator.

Source

pub fn reserved_token(reserved_index: usize) -> Token

Returns the reserved Token for reserved_index (e.g., a CPU number).

Asserts in debug builds that reserved_index < Self::RESERVED_TOKEN_VALUES.

Source

pub fn state(&self) -> State

Returns the current State of this transaction.

Source

pub fn until_done<O, F, R>( option: O, callsite_info: E::CallsiteInfo, callable: F, ) -> R::Output
where O: StateOption<Self>, F: FnMut(&ChainLockTransactionToken<Self>) -> R, R: IntoTransactionResult,

Provides a common sequence for executing a chain lock transaction and the required backoff arbitration logic.

The caller is responsible for providing three arguments:

  1. An implementation of StateOption<Self> (such as Option<O>): Used to instantiate the environment-provided StateSaver type, indicating the relevant states to save, such as IRQ enable flags, preemption flags, etc., and restore after each transaction attempt.
  2. An instance of E::CallsiteInfo: Used for debugging and tracing to identify the code location of the transaction.
  3. A callable implementing a single transaction attempt: This can be a function or closure accepting a &ChainLockTransactionToken<Self> and returning a type implementing IntoTransactionResult.

The callable should match one of the following signatures: a. FnMut(&ChainLockTransactionToken<Self>) -> TransactionResult<()>: A transaction that has a return type (). b. FnMut(&ChainLockTransactionToken<Self>) -> TransactionResult<T>: A transaction that has a user-defined return type T. c. FnMut(&ChainLockTransactionToken<Self>) -> DoneType: A transaction that has an implied return type ().

The overall return type of until_done is either T or (), depending on the signature of callable, as described above.

A basic transaction is structured as follows:

  1. Define a callable that will be executed until the transaction is complete. In this example, the callable will return zx_status_t when the transaction is complete, which will become the return value of until_done.
ⓘ
let do_transaction =
    |token: &ChainLockTransactionToken| -> TransactionResult<zx_status_t> {
        if !object.get_lock().acquire_or_backoff(token) {
            return Action::Backoff.into(); // Execute the backoff protocol and re-enter.
        }

        if restart_transaction_condition {
            object.get_lock().release(token);
            return Action::Restart.into(); // Restart the transaction and re-enter.
        }

        if !locked_operation_on_object(object, token) {
            object.get_lock().release(token);
            // Complete the transaction, returning the error to the caller.
            return TransactionResult::Value(ZX_ERR_BAD_STATE);
        }

        object.get_lock().release(token);
        // Complete the transaction, returning success to the caller.
        TransactionResult::Value(ZX_OK)
    };

In cases where the user return type is (), the callable can return ChainLockTransaction::DONE (or DONE.into() / TransactionResult::DONE) to complete the transaction.

  1. Execute the transaction using the given options and callable. In this example, the constant STATE_OPTION_A is a value of type Option<O> with an environment-specific option value to pass to the state saver. The callable is invoked cyclically, with intervening backoffs, until a terminal value (of a user-defined return type in this case) is returned.
ⓘ
return ChainLockTransaction::until_done(
    STATE_OPTION_A,
    clt_callsite!("foo"),
    do_transaction,
);
Source

pub fn backoff_count(&self) -> u64

Returns the number of times this transaction has backed off.

Source

pub const fn extra(&self) -> &E::ExtraState

Returns a reference to the environment-specific extra state (e.g., conflict_id_ in the kernel).

Source

pub fn assert_at_least_one_lock_held(&self)

Asserts that at least one lock is currently held by this transaction (when debug accounting is enabled).

Source

pub fn assert_at_most_one_lock_held(&self)

Asserts that at most one lock is currently held by this transaction (when debug accounting is enabled).

Source

pub fn assert_num_locks_held(&self, expected: u32)

Asserts that exactly expected locks are currently held by this transaction (when debug accounting is enabled).

Source

pub fn assert_finalized(&self)

Asserts that this transaction has been finalized (when debug accounting is enabled).

Source

pub fn assert_not_finalized(&self)

Asserts that this transaction has not been finalized (when debug accounting is enabled).

Source

pub unsafe fn assert_active() -> ChainLockTransactionToken<Self>

Asserts in debug builds that a transaction is currently active and mints a ChainLockTransactionToken<Self>.

§Safety

The caller must ensure that a ChainLockTransaction<E> is currently registered as active on the current execution context, and that the returned token is not used while that transaction is unregistered or after it is dropped.

Source

pub unsafe fn mark_active() -> ChainLockTransactionToken<Self>

Mints a ChainLockTransactionToken<Self> without checking at runtime for efficiency in trivial cases.

§Safety

The caller must ensure that a ChainLockTransaction<E> is currently registered as active on the current execution context, and that the returned token is not used while that transaction is unregistered or after it is dropped.

Source

pub fn active() -> Option<NonNull<Self>>

Returns a pointer to the active transaction, or None if none is active.

Source

pub fn active_ref(_token: &ChainLockTransactionToken<Self>) -> &Self

Returns a reference to the active transaction. Asserts in debug builds that a transaction is active.

Source

pub fn save_state_and_use_reserved_token( token: &ChainLockTransactionToken<Self>, ) -> SavedState<E>

Saves the pointer to the current transaction and allocates a reserved token to sync leaf chain locks to during critical sequences.

Source

pub fn save_state_initial( &self, _token: &ChainLockTransactionToken<Self>, ) -> SavedState<E>

Creates a saved state for a bare transaction used to kick off a new thread.

Source

pub unsafe fn restore_state(saved_state: SavedState<E>)

Restores the active transaction using the given saved state.

§Safety

The caller must ensure that saved_state was produced by Self::save_state_and_use_reserved_token or Self::save_state_initial for a ChainLockTransaction<E> instance that remains alive and pinned at its memory address for as long as it remains registered as the active transaction on the current execution context.

Source

pub fn finalize(token: &ChainLockTransactionToken<Self>)

Directly finalizes the active transaction, ending an active contention tracing duration, if any.

Source

pub fn restart( &self, callsite_info: E::CallsiteInfo, _token: &ChainLockTransactionToken<Self>, )

Restarts this transaction, resetting key state including the callsite info.

Source

pub fn locks_held(&self) -> u32

Returns the number of locks currently held by this transaction.

Requires Self::DEBUG_ACCOUNTING_ENABLED to be true at compile time.

Source

pub fn is_finalized(&self) -> bool

Returns whether this transaction is currently finalized.

Requires Self::DEBUG_ACCOUNTING_ENABLED to be true at compile time.

Source

pub fn new_unregistered( callsite_info: E::CallsiteInfo, locks_held: u32, finalized: bool, ) -> Self

Creates an unregistered bare transaction with the given initial state.

Because Rust does not guarantee copy elision (RVO) when returning by value, callers creating a bare transaction outside Self::until_done must place the returned transaction in its stack variable first, and then call Self::register (or Self::restore_state with Self::save_state_initial). Note that Drop for ChainLockTransaction unconditionally calls Self::unregister, so the transaction must be registered as active before it is dropped.

Source

pub unsafe fn register(&self) -> ChainLockTransactionToken<Self>

Registers self as the active transaction for the current execution context and mints a ChainLockTransactionToken<Self>.

Asserts that no transaction is currently active.

§Safety

The caller must ensure that:

  • self remains alive and pinned at its current memory address (i.e. not moved or forgotten without unregistering) for as long as it remains registered as the active transaction on the current execution context.
  • The returned ChainLockTransactionToken<Self> is not used while self is unregistered or after self is dropped.
Source

pub unsafe fn unregister(&self)

Unregisters self as the active transaction for the current execution context.

Asserts in debug builds that self is the currently active transaction.

§Safety

The caller must ensure that:

  • self is currently the active transaction on the current execution context.
  • No ChainLockTransactionToken<Self> associated with self is used to access the active transaction while self is unregistered.

Trait Implementations§

Source§

impl<E: TransactionHooks> Drop for ChainLockTransaction<E>

Source§

fn drop(&mut self)

Executes the destructor for this type. Read more
§

fn pin_drop(self: Pin<&mut Self>)

🔬This is a nightly-only experimental API. (pin_ergonomics)
Execute the destructor for this type, but different to Drop::drop, it requires self to be pinned. Read more
Source§

impl<E: TransactionHooks> Transaction for ChainLockTransaction<E>

Source§

type ContentionState = <E as TransactionHooks>::ContentionState

State used by ChainLock to store contended lock state for backoff mitigation.
Source§

fn active() -> Option<NonNull<Self>>

Returns a pointer to the active transaction for the current execution context, or None if no transaction is active.
Source§

fn active_ref(token: &ChainLockTransactionToken<Self>) -> &Self

Returns a shared reference to the active transaction, asserting in debug builds that a transaction is currently active.
Source§

fn yield_cpu()

Performs an architecture-specific CPU relax/yield operation.
Source§

fn token(&self) -> Token

Returns the current Token of this transaction.
Source§

fn assert_not_finalized(&self)

Asserts that this transaction has not been finalized (when debug accounting is enabled).
Source§

fn assert_num_locks_held(&self, expected: u32)

Asserts that this transaction currently holds expected locks (when debug accounting is enabled).
Source§

fn on_acquire(&self, _token: &ChainLockTransactionToken<Self>)

Accounting hook invoked when a ChainLock is acquired by this transaction.
Source§

fn on_release(&self, _token: &ChainLockTransactionToken<Self>)

Accounting hook invoked when a ChainLock is released by this transaction.
Source§

fn on_contention(&self, _token: &ChainLockTransactionToken<Self>)

Accounting/tracing hook invoked when contention is encountered while acquiring a ChainLock.
Source§

fn record_backoff_or_retry( &self, observed_token: Token, lock_state: &AtomicToken, contention_state: &Self::ContentionState, _token: &ChainLockTransactionToken<Self>, ) -> bool

Contention hook invoked when a ChainLock encounters a higher-priority owner. Read more
Source§

fn release_and_notify<F: FnOnce()>( &self, contention_state: &Self::ContentionState, do_release: F, _token: &ChainLockTransactionToken<Self>, )

Contention hook invoked when releasing a ChainLock to sample contention state, invoke do_release, and notify backed-off contenders.

Auto Trait Implementations§

§

impl<E> !Freeze for ChainLockTransaction<E>

§

impl<E> !RefUnwindSafe for ChainLockTransaction<E>

§

impl<E> !Send for ChainLockTransaction<E>

§

impl<E> !Sync for ChainLockTransaction<E>

§

impl<E> !Unpin for ChainLockTransaction<E>

§

impl<E> UnsafeUnpin for ChainLockTransaction<E>
where <E as TransactionHooks>::Accounting: UnsafeUnpin, <E as TransactionHooks>::Tracing: UnsafeUnpin, <E as TransactionHooks>::ExtraState: UnsafeUnpin,

§

impl<E> UnwindSafe for ChainLockTransaction<E>
where <E as TransactionHooks>::Accounting: UnwindSafe, <E as TransactionHooks>::Tracing: UnwindSafe, <E as TransactionHooks>::ExtraState: UnwindSafe,

Blanket Implementations§

§

impl<T> Any for T
where T: 'static + ?Sized,

§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
§

impl<T> Borrow<T> for T
where T: ?Sized,

§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
§

impl<T> BorrowMut<T> for T
where T: ?Sized,

§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
§

impl<T> From<T> for T

§

fn from(t: T) -> T

Returns the argument unchanged.

§

impl<T, U> Into<U> for T
where U: From<T>,

§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of [From]<T> for U chooses to do.

Source§

impl<T> ToMutPtr for T
where T: ?Sized,

Source§

type Target = T

The target type of the pointer.
Source§

fn to_mut_ptr(&self) -> *mut T

Casts the reference to a mutable raw pointer.
§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

§

type Error = !

The type returned in the event of a conversion error.
§

fn try_from(value: U) -> Result<T, !>

Performs the conversion.
§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.