deloxide 1.1.0

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

Rust is Deloxide's primary interface, but C applications can use the same
detector and tracked synchronization through `include/deloxide.h`.

## Build and link

Build the library and C API:

```console
cargo build --release --features c-api
```

Add other features when needed:

```console
cargo build --release --features \
  c-api,logging-and-visualization,lock-order-graph,stress-test
```

Include `include/deloxide.h` and link the produced static or dynamic `deloxide`
library. Exact filenames and platform libraries depend on the target. The
repository's [`c_examples/basic_mutex.c`](../../c_examples/basic_mutex.c) is the
smallest buildable example.

## Initialization and callback

Initialize once before creating tracked objects:

```c
#include "deloxide.h"
#include <stdio.h>

static void on_deadlock(const char *json) {
    fprintf(stderr, "Deloxide report: %s\n", json);
}

int main(void) {
    int rc = deloxide_init(NULL, on_deadlock);
    if (rc != 0) {
        fprintf(stderr, "deloxide_init failed: %d\n", rc);
        return 1;
    }

    /* create locks and threads */
    return 0;
}
```

The callback receives a borrowed NUL-terminated JSON string. Copy it if another
thread must retain it; do not free it or keep the pointer after the callback
returns. Keep callback work bounded.

Initialization returns `0` on success and `1` if it has already run. Invalid log
paths and logger failures use negative codes. Passing a non-null log path without
the logging feature returns `-3`; the public header currently omits that code.

## Mutex

```c
void *mutex = deloxide_create_mutex();
if (mutex == NULL) return 1;

if (deloxide_lock_mutex(mutex) != 0) return 1;
/* protected work */
if (deloxide_unlock_mutex(mutex) != 0) return 1;

deloxide_destroy_mutex(mutex);
```

`LOCK_MUTEX(mutex)` and `UNLOCK_MUTEX(mutex)` provide checked convenience macros
that terminate on failure. Destroy a mutex only after every thread has stopped
using it.

## RwLock

```c
void *state = deloxide_create_rwlock();
if (state == NULL) return 1;

if (deloxide_rw_lock_read(state) != 0) return 1;
/* read shared state */
if (deloxide_rw_unlock_read(state) != 0) return 1;

if (deloxide_rw_lock_write(state) != 0) return 1;
/* update shared state */
if (deloxide_rw_unlock_write(state) != 0) return 1;

deloxide_destroy_rwlock(state);
```

The `RWLOCK_READ`, `RWUNLOCK_READ`, `RWLOCK_WRITE`, and `RWUNLOCK_WRITE` macros
are the shorter checked form. A thread may hold read guards for different RwLocks,
but it must release each matching guard correctly.

## Condition variables

A Deloxide condition variable waits with a Deloxide mutex:

```c
void *mutex = deloxide_create_mutex();
void *ready = deloxide_create_condvar();

if (deloxide_lock_mutex(mutex) != 0) return 1;
while (!predicate_is_ready()) {
    int rc = deloxide_condvar_wait(ready, mutex);
    if (rc != 0) return 1;
}
if (deloxide_unlock_mutex(mutex) != 0) return 1;

deloxide_destroy_condvar(ready);
deloxide_destroy_mutex(mutex);
```

`deloxide_condvar_wait_timeout` returns `1` when the timeout expires and `0` when
notified. Negative values indicate invalid handles, a mutex not held by the
caller, or another wait failure. Notify with
`deloxide_condvar_notify_one` or `deloxide_condvar_notify_all`.

## Tracked threads

Any native thread using a Deloxide lock contributes synchronization events.
Register lifecycle events when logs should also show the thread relationship:

```c
uintptr_t tid = deloxide_get_thread_id();
deloxide_register_thread_spawn(tid, parent_tid);

/* thread work */

deloxide_register_thread_exit(tid);
```

On POSIX, `DEFINE_TRACKED_THREAD(worker)` and
`CREATE_TRACKED_THREAD(thread, worker, arg)` wrap this protocol around
`pthread_create`. Those macros are not available on Windows; call the manual
registration functions from the Windows thread entry point.

## Logging, visualization, and stress

With `logging-and-visualization`, pass a log path to `deloxide_init`, flush it
with `deloxide_flush_logs`, and open it with `deloxide_showcase` or
`deloxide_showcase_current`.

With `stress-test`, C can enable random scheduling delays with
`deloxide_enable_random_stress`, enable targeted component delays with
`deloxide_enable_component_stress`, and return to normal scheduling with
`deloxide_disable_stress`.

The C header is the exact API reference. This chapter focuses on correct
lifecycle and common usage rather than duplicating every status-code comment.