Troubleshooting by Symptom
Start by deciding whether the expected outcome is an active WaitForGraph callback or a potential LockOrderViolation. A hang with neither can be contention, a missed notification, I/O, starvation, or an untracked synchronization path.
| Symptom | Likely cause | Confirming check | Next action |
|---|---|---|---|
| No callback fires | No active cycle exists, a raw/third-party lock is outside Deloxide, or the test never reached the contested acquisition. | Add barriers and record lock attempts; capture stacks; verify every relevant primitive is a Deloxide wrapper. | Review non-cycle hangs and make the callback explicit with Deloxide::callback. |
| Callback fires but no log exists | Logging feature/path is absent, disabled, or unwritable; callback delivery does not require a log. | Check the logging-and-visualization feature and the configured with_log path. | Preserve the callback payload now; enable a writable timestamped log path for the next run. |
| Visualization opens an empty or stale log | The wrong file was selected or buffered entries were not the active log when it was opened. | Confirm the configured log path and call showcase_this, which flushes the active log first. | Use showcase_this() for the current run, or showcase with the exact completed file. |
| Only lock-order findings appear | The order graph saw an inversion, but the tested schedule has not produced concurrent blocking. | source is LockOrderViolation and lock_order_cycle is Some(...); there is no active WaitForGraph. | Follow lock-order triage; reproduce under stress without calling it an outage yet. |
| RwLock report includes the same thread | A thread held a read guard and requested a write guard on that same RwLock. | Map the report’s (thread, lock) pair and inspect guard lifetimes around RwLock::write. | Release the read guard and revalidate before writing; see read-to-write self-deadlock. |
| Condvar test hangs without a cycle | A missed notification, false predicate, or external wait is blocking progress rather than tracked lock ownership. | Log predicate changes, wait registration, and notification order; use a parent watchdog. | Use the predicate loop and notifier protocol in Condvar wait and mutex reacquisition. |
| Benchmark overhead is higher than expected | Optional logging, lock-order checking, or stress mode changed the measured feature set/workload. | Print Cargo features and configuration; compare the same scenario with no_lock_order_checking, no logging, and no stress. | Benchmark the exact production feature set; keep stress out of production measurements. |
| Second initialization appears ignored | Rust initialization is process-wide; the first callback/configuration remains installed. C deloxide_init also returns 1 once already initialized. | Locate the first Deloxide::start or C initialization call in the process. | Configure once before workers start; use an isolated process for configurations that must differ. |
| C thread relationships are missing | Worker threads were created without the tracked thread wrapper/registration, or were not registered before using tracked locks. | Check that each pthread uses DEFINE_TRACKED_THREAD and CREATE_TRACKED_THREAD, or calls deloxide_register_thread_spawn/deloxide_register_thread_exit. | Follow the C guide and register the parent-child relationship before lock activity. |
When escalating an issue, attach source, the full DeadlockInfo payload, the test command and feature set, relevant thread stacks, and the exact log file if enabled. That evidence lets another engineer distinguish an active cycle from a potential ordering pattern without reproducing the entire production workload first.