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:
cargo build --release --features c-api
Add other features when needed:
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 is the
smallest buildable example.
Initialization and callback
Initialize once before creating tracked objects:
#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
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
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:
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:
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.