# Busy Waiting

> ForkUnion for Rust

Here's what "busy waiting" looks like in C++:

```cpp
while (!has_work_to_do())
    std::this_thread::yield();
```

On Linux, the `std::this_thread::yield()` translates into a `sched_yield` system call, which means context switching to the kernel and back.
Instead, you can replace the `standard_yield_t` wrapper with a platform-specific micro-wait instruction, which is much cheaper.
Those instructions, like [`WFET` on Arm](https://developer.arm.com/documentation/ddi0602/2025-03/Base-Instructions/WFET--Wait-for-event-with-timeout-), generally hint the CPU to transition to a low-power state.

| Wrapper           | ISA          | Instruction         | Privileges |
| :---------------- | :----------- | :------------------ | :--------- |
| `x86_pause_t`     | x86          | `PAUSE`             | R3         |
| `x86_tpause_t`    | x86+WAITPKG  | `UMONITOR`+`UMWAIT` | R3         |
| `arm64_yield_t`   | AArch64      | `YIELD`             | EL0        |
| `arm64_wfe_t`     | AArch64      | `LDAXR`+`WFE`       | EL0        |
| `arm64_wfet_t`    | AArch64+WFXT | `WFET`              | EL0        |
| `riscv64_pause_t` | RISC-V       | `PAUSE`             | U          |
| `riscv64_wrs_t`   | RISC-V+Zawrs | `WRS.STO`/`WRS.NTO` | U          |

No kernel calls.
No futexes.
Works in tight loops.

The `UMWAIT`, `WFE`, `WFET`, and `WRS` wrappers go a step further than a spin hint: they sleep the core until a store to the watched line, capped by a timeout only where the loop guards more than one word, so the pool parks a worker in a low-power state rather than burning the core.
`spin_mutex<fu::preferred_yield_t>` takes the same wrappers, while the default `spin_mutex_t` yields to the scheduler and Rust's `SpinMutex` spins on `core::hint::spin_loop` - a futex-free `std::mutex` alternative, and the lock used in the NUMA example above.
On WebAssembly threads the waiter is `wasm_wait_t`: a 32- or 64-bit watch sleeps in `memory.atomic.wait` until a `wasm_atomic_ref` releasing write notifies or 1 µs passes, so pair the two; uncapped waits and 1- or 2-byte watches spin.

`use forkunion::BasicSpinMutex;`

`use forkunion::BasicSpinMutexGuard;`

`use forkunion::*;`

## SpinMutex

A type alias for the most commonly used spin mutex configuration.

```rust
pub type SpinMutex<T> = BasicSpinMutex<T, true>;
```

This is equivalent to `BasicSpinMutex<T, true>`, which enables CPU-specific pause instructions
for efficient busy-waiting.

Examples: ```
use forkunion::*;

let mutex = SpinMutex::new(42);
let mut guard = mutex.lock();
*guard = 100;
```

## BasicSpinMutex

A generic spin mutex that uses CPU-specific pause instructions for efficient busy-waiting.

```rust
pub struct BasicSpinMutex<T, const PAUSE: bool>
```

This is a low-level synchronization primitive that spins on a busy loop rather than blocking the
thread. It's most appropriate for very short critical sections where the cost of context
switching would be higher than busy-waiting.

The generic parameter `P` allows customization of the pause behavior:

- `true` enables CPU-specific pause instructions, recommended for most use cases

- `false` disables pause instructions, which may be useful in specialized scenarios

Examples: ```
use forkunion::*;

// Create a spin mutex with pause instructions enabled
let mutex = BasicSpinMutex::&#x3C;i32, true>::new(42);

// Lock, access data, and unlock
{
    let mut guard = mutex.lock();
    *guard = 100;
} // Lock is automatically released when guard goes out of scope

// Verify the value was changed
assert_eq!(*mutex.lock(), 100);
```

Fast for short critical sections but spins continuously. Use when latency matters more than CPU
usage. Avoid for long critical sections or high contention scenarios.

Implements: `Send`, `Sync`

## new

Creates a new spin mutex in the unlocked state.

```rust
pub const fn new(data: T) -> Self
```

Arguments: - `data` - The value to be protected by the mutex

Examples: ```
use forkunion::*;

let mutex = BasicSpinMutex::&#x3C;i32, true>::new(0);
```

## lock

Acquires the lock, returning a guard that provides access to the protected data.

```rust
pub fn lock(&self) -> BasicSpinMutexGuard<'_, T, PAUSE>
```

This method will spin until the lock is acquired. If the lock is already held, it will
busy-wait using CPU-specific pause instructions when `PAUSE` is true.

Examples: ```
use forkunion::*;

let mutex = BasicSpinMutex::&#x3C;i32, true>::new(0);
let mut guard = mutex.lock();
*guard = 42;
```

## lock_if_free

Attempts to acquire the lock without blocking.

```rust
pub fn lock_if_free(&self) -> Option<BasicSpinMutexGuard<'_, T, PAUSE>>
```

Returns `Some(guard)` if the lock was successfully acquired, or `None` if the lock is
currently held by another thread.

Examples: ```
use forkunion::*;

let mutex = BasicSpinMutex::&#x3C;i32, true>::new(0);

if let Some(mut guard) = mutex.lock_if_free() {
    *guard = 42;
    println!("Lock acquired and value set");
} else {
    println!("Lock is currently held by another thread");
};
```

## is_locked

Checks if the mutex is currently locked.

```rust
pub fn is_locked(&self) -> bool
```

This method provides a non-blocking way to check the lock state, but should be used
carefully as the state can change immediately after this call returns.

Examples: ```
use forkunion::*;

let mutex = BasicSpinMutex::&#x3C;i32, true>::new(0);
assert!(!mutex.is_locked());

{
    let _guard = mutex.lock();
    assert!(mutex.is_locked());
}

assert!(!mutex.is_locked());
```

## into_inner

Consumes the mutex and returns the protected data.

```rust
pub fn into_inner(self) -> T
```

This method bypasses the locking mechanism entirely, since we already own it exclusively.

Examples: ```
use forkunion::*;

let mutex = BasicSpinMutex::&#x3C;i32, true>::new(42);
let data = mutex.into_inner();
assert_eq!(data, 42);
```

## get_mut

Gets a mutable reference to the protected data.

```rust
pub fn get_mut(&mut self) -> &mut T
```

Since this requires a mutable reference to the mutex, no locking is needed as we have
exclusive access.

Examples: ```
use forkunion::*;

let mut mutex = BasicSpinMutex::&#x3C;i32, true>::new(0);
*mutex.get_mut() = 42;
assert_eq!(*mutex.lock(), 42);
```

## BasicSpinMutexGuard

A guard providing access to the data protected by a [`BasicSpinMutex`](#BasicSpinMutex).

```rust
pub struct BasicSpinMutexGuard<'a, T, const PAUSE: bool>
```

The lock is automatically released when this guard is dropped.

Implements: `Deref`, `DerefMut`, `Drop`

## get

Returns a reference to the protected data.

```rust
pub fn get(&self) -> &T
```

This method is rarely needed since the guard implements `Deref`.

## get_mut

Returns a mutable reference to the protected data.

```rust
pub fn get_mut(&mut self) -> &mut T
```

This method is rarely needed since the guard implements `DerefMut`.

