axiom-spinlock

Crates.ioaxiom-spinlock
lib.rsaxiom-spinlock
version0.1.0
created_at2025-10-29 17:33:19.405447+00
updated_at2025-10-29 17:33:19.405447+00
descriptionA lightweight, no_std-compatible spinlock and exponential backoff implementation for low-level concurrent systems.
homepage
repositoryhttps://github.com/LOKESH-999/axiom-spinlock
max_upload_size
id1907015
size25,410
LOKESH (LOKESH-999)

documentation

https://docs.rs/axiom-spinlock

README

axiom-spinlock 🌀

A lightweight, no_std-compatible spinlock and exponential backoff implementation for low-level concurrent systems.

This crate provides a minimal, efficient spin-based mutual exclusion primitive (SpinLock<T>) together with an adaptive exponential BackOff utility to reduce contention in busy-wait loops.

The implementation focuses on environments where blocking is not an option (kernels, embedded runtimes, custom executors), so it avoids OS-level mutexes and context switching.


Highlights

  • no_std compatible (uses core only).
  • Optional std feature (default) to enable thread yielding.
  • SpinLock<T>: atomic test-and-set spinlock with RAII guard (SpinGuard).
  • BackOff: exponential backoff with configurable start, relax/reset and optional std yielding.
  • Small, well-tested, and appropriate for short critical sections.

Crate name

This repository builds the crate axiom-spinlock (see Cargo.toml).


Quick examples

Using SpinLock:

use axiom_spinlock::SpinLock;

let lock = SpinLock::new(0);
{
    let mut guard = lock.lock();
    *guard += 1;
} // unlocked when `guard` is dropped
assert_eq!(*lock.lock(), 1);

// convenience API
lock.with_lock(|v| *v += 1);

Using BackOff:

use axiom_spinlock::BackOff;

let backoff = BackOff::new();
for _ in 0..5 {
    backoff.wait();
}

API overview

SpinLock

A minimal spin-based mutual exclusion primitive:

  • const fn new(data: T) -> Self — create a new lock.
  • fn lock(&self) -> SpinGuard<'_, T> — acquire the lock (blocks by spinning); returns a guard that releases on drop.
  • unsafe fn unlock(&self) — unsafely release the lock (only call if you own the lock).
  • fn try_lock(&self) -> Option<SpinGuard<'_, T>> — try to acquire without blocking.
  • fn try_lock_for(&self, spins: usize) -> Option<SpinGuard<'_, T>> — attempt to acquire within a fixed number of spin attempts.
  • fn is_locked(&self) -> bool — check whether the lock is currently held.
  • fn with_lock<R>(&self, f: impl FnOnce(&mut T) -> R) -> R — convenience wrapper to run a closure while holding the lock.

Notes:

  • The lock uses an AtomicBool with Acquire/Release ordering.
  • The guard implements Deref and DerefMut for ergonomic access.
  • SpinLock is marked Send/Sync when T: Send.
  • Not reentrant and not fair — starvation is possible under heavy contention.

BackOff

A simple exponential backoff manager used to reduce contention in spin loops.

  • const fn new() -> BackOff — default start value.
  • const fn new_with(start: u32) -> BackOff — create with custom start.
  • fn wait(&self) — perform one backoff step (spins, doubles internal counter up to MAX_SPIN, optionally yields with std).
  • fn relax(&self) — reduce current spin intensity.
  • fn current(&self) -> u32 — get current spin iteration value.
  • fn reset(&self) — reset to default start.
  • fn reset_to(&self, spin: u32) — reset to explicit value.
  • #[cfg(feature = "std")] fn yield_now(&self) — explicit yield (only when compiled with std).

Implementation details:

  • Uses core::hint::spin_loop() to inform the CPU of busy-wait.
  • When built with the std feature (the crate defaults to enabling this), std::thread::yield_now() is called once contention exceeds a threshold.

Example program (from src/main.rs)

The repository includes an example program that creates a static SpinLock<i64> and spawns 100 threads, each incrementing the shared counter 1_000_000 times. This is useful to stress-test the lock, but be aware it is CPU-intensive.

To run the example (default features include std):

cargo run --release

Expect the program to be CPU-bound and run for a while depending on your CPU.


Building & testing

Build the project:

cargo build

Run tests (crate default features include std — if you want to test no_std behavior you must change features accordingly):

cargo test

Features

  • std (default): Enables std::thread::yield_now() during prolonged backoff and allows examples/tests that spawn threads.

The crate is implemented to be usable without std by disabling this feature in embedded or kernel contexts.


Safety notes & recommended usage

  • Use SpinLock only for short critical sections.
  • Avoid holding a spinlock during blocking operations or long computations.
  • SpinLock is not reentrant.
  • unlock() is unsafe and should only be used by code that truly owns the lock.

Contributing


Acknowledgements

This crate is intentionally small and targeted for embedded/low-level use cases. It pairs a tiny spinlock with a configurable backoff to provide a lightweight synchronization primitive where OS-level primitives are unavailable or undesired.


Commit count: 0

cargo fmt