Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Finding Inconsistent Lock Order

Lock-order checking is a development aid for discovering an ordering rule that could deadlock under a different schedule. It must never be presented as an active wait-for graph result: DeadlockSource::LockOrderViolation is potential, whereas DeadlockSource::WaitForGraph is an active, validated cycle.

Enable and control it

The builder methods exist only with the lock-order-graph Cargo feature:

[dependencies]
deloxide = { version = "1.1.0", features = ["lock-order-graph"] }

When that feature is compiled, Deloxide::new enables order checking by default. Make the choice visible in development or CI configuration with with_lock_order_checking, and turn it off explicitly for a controlled comparison with no_lock_order_checking.

#![allow(unused)]
fn main() {
extern crate deloxide;
use deloxide::{DeadlockSource, Deloxide};

Deloxide::new()
    .with_lock_order_checking()
    .callback(|info| match info.source {
        DeadlockSource::WaitForGraph => {
            // Active, validated deadlock: preserve evidence and page/escalate.
        }
        DeadlockSource::LockOrderViolation => {
            // Potential ordering cycle: send to code-review/triage workflow.
        }
    })
    .start()
    .expect("detector initialization");

// For a baseline run with the feature compiled:
// Deloxide::new().no_lock_order_checking().start()?;
}

Without the Cargo feature, neither control is available and no historical order graph is maintained. The normal detector can still emit active WaitForGraph reports.

How an edge becomes a finding

Whenever a thread holds A and then acquires B, the order graph records the directed relationship A -> B. It does not need to observe both locks blocked at once.

earlier path:  hold A, then acquire B    records A ──► B
later path:    hold B, then acquire A    would add B ──► A

result:        A ──► B ──► A             potential lock-order cycle

The report contains source: LockOrderViolation, a one-thread contextual thread_cycle, the requested (thread, lock) pair, and lock_order_cycle: Some(...). The historical graph deliberately survives the individual critical sections that created its edges. Consequently it may expose a dangerous inversion that never manifested during a run, but it cannot prove concurrent blockage. An active wait-for graph instead contains current thread-to-incompatible-owner dependencies and is independently validated before producing WaitForGraph.

Development and CI workflow

  1. Enable lock-order-graph in a development/CI feature set and install a callback that records the full DeadlockInfo payload.
  2. Exercise distinct entry points, error/rollback paths, and shutdown paths. These are the places most likely to acquire the same resources in a different order.
  3. Group potential findings by the normalized lock_order_cycle, then identify the acquisition sites for every edge. Treat numeric IDs as run-local evidence; use logs and symbols to name the resources.
  4. Decide whether the paths can hold the same lock instances concurrently. If they cannot, document why and keep a regression test; if they can, impose a consistent acquisition order or remove the nested hold.
  5. Run the focused scenario repeatedly, optionally with stress mode, then run the normal test suite. A later active WaitForGraph report raises the issue from a potential warning to an incident-quality reproduction.

Keep a baseline run with no_lock_order_checking() when measuring the checking cost or isolating a report. Do not use that baseline to dismiss an already observed cycle.

Triage rules

Finding shapeInterpretationNext action
Repeated identical lock_order_cycle across test runs or code pathsStrong evidence of a stable inconsistent policy, still potential rather than active.Assign an owner, map all edges to source, and fix or document a proven non-overlap invariant.
One-off cycle after a rare error/shutdown pathA potential path worth preserving before it disappears.Save the payload/log, create a focused test, and determine whether the instances can overlap.
WaitForGraph also appearsAn active, validated deadlock occurred; it is not “just” a lock-order warning.Follow report reading, capture stacks, and fix immediately.
Only LockOrderViolation appears under stressStress found an order inversion, not a deterministic deadlock.Reduce the scenario and continue scheduled testing; do not claim a production deadlock without active evidence.

Potential findings are most useful before release because they turn scheduling-dependent defects into reviewable lock-order evidence. They complement, and never replace, the current-state wait-for detector.