SkillAgentSearch skills...

Deloxide

Deloxide scrubs your threads clean by detecting deadlocks in real time—keeping your system smooth, safe, and corrosion-free. 🦀🧼🔒

Install / Use

/learn @Emivvvvv/Deloxide
About this skill

Quality Score

0/100

Supported Platforms

Universal

README

<img src='images/deloxide_logo_orange.png' height='25'> Deloxide - Cross-Language Deadlock Detector

Rust License: MIT/Apache-2.0 License: Coffeeware

Deloxide is a cross-language deadlock detection library with visualization support. It tracks mutex and reader-writer lock operations in multi-threaded applications to detect, report, and visualize potential deadlocks in real-time.

Table of Contents

Features

  • Real-time deadlock detection - Detects deadlocks as they happen using a Dual Detection Architecture (WFG + LOG)
  • Zero False Positives - Wait-For Graph (WFG) analysis ensures 100% precision for active deadlocks
  • Optimistic Fast Path - "Always-on" monitoring with negligible overhead
  • Cross-language support - Core implementation in Rust with C bindings
  • Stress Testing Framework - Probabilistic scheduling with Component-Based Targeting
  • Visual Diagnostics - Serverless, privacy-preserving visualization of thread interactions (see example here)
  • Easy integration - Drop-in replacements for parking_lot primitives

[!NOTE] Cross-platform support: Rust API works on Windows, macOS, and Linux. The C API is POSIX-first and ships with pthread-based convenience macros for macOS/Linux; on Windows those macros are disabled (see below) but the core C functions are fully usable.

Building and Installation

Rust

Deloxide is available on crates.io. You can add it as a dependency in your Cargo.toml:

[dependencies]
deloxide = "1.0"

With lock order graph:

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

With stress testing:

[dependencies]
deloxide = { version = "1.0", features = ["stress-test"] }

With logging and visualization:

[dependencies]
deloxide = { version = "1.0", features = ["logging-and-visualization"] }

Or install the CLI tool to showcase deadlock logs directly:

cargo install deloxide
deloxide my_deadlock.log  # Opens visualization in browser

For development builds:

# Standard build
cargo build --release

# With lock order graph feature
cargo build --release --features lock-order-graph

# With stress testing feature
cargo build --release --features stress-test

# With both features
cargo build --release --features lock-order-graph,stress-test

C

For C programs, you'll need to compile the Rust library and link against it:

# Build the Rust library
cargo build --release

# With lock order graph feature
cargo build --release --features lock-order-graph

# With stress testing feature
cargo build --release --features stress-test

# With both features
cargo build --release --features lock-order-graph,stress-test

# Compile your C program with Deloxide
gcc -Iinclude your_program.c -Ltarget/release -ldeloxide -lpthread -o your_program

A Makefile is included in the repository to simplify building and testing with C programs. It handles building the Rust library and compiling the C test programs automatically.

C API portability notes

  • Thread ID size across FFI

    • The C header uses uintptr_t for all thread IDs; the Rust side uses usize. This ensures correct sizes on LP64 (Linux/macOS) and LLP64 (Windows).
  • pthread-based helpers are POSIX-only

    • The convenience macros DEFINE_TRACKED_THREAD and CREATE_TRACKED_THREAD depend on pthread.h and are available only on non-Windows platforms.
    • On Windows, these macros are disabled at compile time. You can still use the full C API by manually registering thread lifecycle events.
  • Manual thread registration (Windows or custom runtimes)

    1. Create your thread using your platform's API.
    2. In the thread entry, call deloxide_register_thread_spawn(child_tid, parent_tid) once. On the thread, get IDs from deloxide_get_thread_id().
    3. Before the thread returns, call deloxide_register_thread_exit(current_tid).

    Minimal example sketch (pseudo-C):

    // In parent, capture parent thread id
    uintptr_t parent_tid = deloxide_get_thread_id();
    // Create thread with OS API (e.g., _beginthreadex / CreateThread)
    // In child thread entry:
    uintptr_t child_tid = deloxide_get_thread_id();
    deloxide_register_thread_spawn(child_tid, parent_tid);
    // ... user work ...
    deloxide_register_thread_exit(child_tid);
    

Quick Start

Rust

Deloxide provides drop-in replacements for parking_lot synchronization primitives with added deadlock detection capabilities. These primitives are API-compatible with parking_lot and serve as near drop-in replacements for std::sync (requiring only the removal of .unwrap() calls since poisoning is not supported).

deloxide::thread

A drop-in replacement for std::thread that automatically tracks thread lifecycle events. All std::thread functions and types are available with added deadlock detection:

// All std::thread items are re-exported
pub use std::thread::{
    AccessError, JoinHandle, LocalKey, Result, Scope, 
    ScopedJoinHandle, Thread, ThreadId, available_parallelism, 
    current, panicking, park, park_timeout, sleep, yield_now,
};

// Custom spawn function with tracking
pub fn spawn<F, T>(f: F) -> JoinHandle<T> 
    where F: FnOnce() -> T + Send + 'static, T: Send + 'static;

// Custom Builder with tracking
pub struct Builder { /* ... */ }

Using tracked threads is identical to using std::thread:

use deloxide::thread;

// Spawn a tracked thread - exactly like std::thread::spawn
let handle = thread::spawn(|| {
    println!("Hello from tracked thread!");
    42
});

// All std::thread functions work
thread::yield_now();
thread::sleep(Duration::from_millis(100));
let current = thread::current();

// Builder pattern supported
let handle = thread::Builder::new()
    .name("worker".to_string())
    .stack_size(32 * 1024)
    .spawn(|| { /* ... */ })
    .unwrap();

// Join works the same way
let result = handle.join().unwrap();
assert_eq!(result, 42);

It automatically registers thread spawn/exit events for deadlock detection, visualization, and debugging purposes.

Deloxide::Mutex

A drop-in replacement for parking_lot::Mutex. It is also a direct alternative to std::sync::Mutex, but without lock poisoning (removing the need for .unwrap() on lock acquisition):

pub struct Mutex<T> {
    id: LockId,
    inner: ParkingLotMutex<T>,
    creator_thread_id: ThreadId,
}

impl<T> Mutex<T> {
    pub fn new(data: T) -> Self;
    pub fn lock(&self) -> MutexGuard<'_, T>;
    pub fn try_lock(&self) -> Option<MutexGuard<'_, T>>;
    pub fn into_inner(self) -> T where T: Sized;
    pub fn get_mut(&mut self) -> &mut T;
    pub fn id(&self) -> LockId;
    pub fn creator_thread_id(&self) -> ThreadId;
}

impl<T: Default> Default for Mutex<T> { /* ... */ }
impl<T> From<T> for Mutex<T> { /* ... */ }

All std::sync::Mutex methods are supported (except poisoning-related ones, as parking_lot doesn't use poisoning).

Deloxide::RwLock

A drop-in replacement for parking_lot::RwLock. It is also a direct alternative to std::sync::RwLock, but without lock poisoning:

pub struct RwLock<T> {
    id: LockId,
    inner: ParkingLotRwLock<T>,
    creator_thread_id: ThreadId,
}

impl<T> RwLock<T> {
    pub fn new(data: T) -> Self;
    pub fn read(&self) -> RwLockReadGuard<'_, T>;
    pub fn write(&self) -> RwLockWriteGuard<'_, T>;
    pub fn try_read(&self) -> Option<RwLockReadGuard<'_, T>>;
    pub fn try_write(&self) -> Option<RwLockWriteGuard<'_, T>>;
    pub fn into_inner(self) -> T where T: Sized;
    pub fn get_mut(&mut self) -> &mut T;
    pub fn id(&self) -> LockId;
    pub fn creator_thread_id(&self) -> ThreadId;
}

impl<T: Default> Default for RwLock<T> { /* ... */ }
impl<T> From<T> for RwLock<T> { /* ... */ }

All std::sync::RwLock methods are supported (except poisoning-related ones).

Deloxide::Condvar

A drop-in replacement for parking_lot::Condvar. It serves as a replacement for std::sync::Condvar but interacts with Deloxide::Mutex.

pub struct Condvar {
    id: CondvarId,
    inner: ParkingLotCondvar,
}

impl Condvar {
    pub fn new() -> Self;
    pub fn wait<T>(&self, guard: &mut MutexGuard<'_, T>);
    pub fn wait_while<T, F>(&self, guard: &mut MutexGuard<'_, T>, condition: F)
        where F: FnMut(&mut T) -> bool;
    pub fn wait_timeout<T>(&self, guard: &mut MutexGuard<'_, T>, timeout: Duration) -> bool;
    pub fn wait_timeout_while<T, F>(&self, guard: &mut MutexGuard<'_, T>, 
        timeout: Duration, condition: F) -> bool
        where F: FnMut(&mut T) -> bool;
    pub fn notify_one(&self);
    pub fn notify_all(&self);
    pub fn id(&self) -> CondvarId;
}

impl Default for Condvar { /* ... */ }

All std::sync::Condvar methods are supported.

Complete Usage Example

Here's a comprehensive example demonstrating all Deloxide primitives in a single scenario:

use deloxide::{Delox
View on GitHub
GitHub Stars24
CategoryDevelopment
Updated1mo ago
Forks0

Languages

Rust

Security Score

95/100

Audited on Feb 24, 2026

No findings