deloxide 1.1.0

Deloxide scrubs your threads clean by detecting deadlocks in real time—keeping your system smooth, safe, and corrosion-free. 🦀🧼🔒
Documentation
# 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`](https://docs.rs/deloxide/1.1.0/deloxide/enum.DeadlockSource.html#variant.LockOrderViolation) is **potential**, whereas [`DeadlockSource::WaitForGraph`](https://docs.rs/deloxide/1.1.0/deloxide/enum.DeadlockSource.html#variant.WaitForGraph) is an active, validated cycle.

## Enable and control it

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

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

When that feature is compiled, [`Deloxide::new`](https://docs.rs/deloxide/1.1.0/deloxide/struct.Deloxide.html#method.new) enables order checking by default. Make the choice visible in development or CI configuration with [`with_lock_order_checking`](https://docs.rs/deloxide/1.1.0/deloxide/struct.Deloxide.html#method.with_lock_order_checking), and turn it off explicitly for a controlled comparison with [`no_lock_order_checking`](https://docs.rs/deloxide/1.1.0/deloxide/struct.Deloxide.html#method.no_lock_order_checking).

```rust,no_run
# 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.

```text
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](stress-testing.md), 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 shape | Interpretation | Next action |
| --- | --- | --- |
| Repeated identical `lock_order_cycle` across test runs or code paths | Strong 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 path | A potential path worth preserving before it disappears. | Save the payload/log, create a focused test, and determine whether the instances can overlap. |
| `WaitForGraph` also appears | An active, validated deadlock occurred; it is not “just” a lock-order warning. | Follow [report reading](reports.md), capture stacks, and fix immediately. |
| Only `LockOrderViolation` appears under stress | Stress 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.