Skip to content

x.atomics #

v-atomics

Low-level atomic operations for V with explicit i386 support (MMX required on i386).

Native atomic primitives for V implemented with inline assembly, without relying on C FFI.

This repository is an experiment in providing low-level atomic operations directly in V, using V's inline assembly support.

At the moment, all operations provide sequentially consistent semantics.

Motivation

In the current V ecosystem, atomic operations are implemented via calls into C.

While this approach works, it introduces an additional dependency on the C toolchain and headers and limits control over the exact machine instructions being emitted.

x.atomics explores an alternative: native atomic operations implemented directly in V, using architecture-specific inline assembly and explicit semantics.

The current focus of this project is:

  • correctness of basic atomic primitives;
  • predictable and inspectable code generation;
  • sequentially consistent behavior for all operations.

In future versions, the set of supported atomic operations will be expanded, and additional memory orderings will be introduced.


Scope and Guarantees

  • atomic operations on integer types implemented in V with inline assembly;
  • architecture-specific implementations (per-platform atomics.<arch>.v files);
  • sequential consistency for all exposed operations.

Memory Model

All operations in this library are intended to be sequentially consistent:

  • operations appear to be globally ordered;
  • no weaker semantics (relaxed, acquire, release) are currently implemented;
  • when weaker variants are added in the future, they will be explicitly named and documented.

Examples

See the examples directory for complete runnable examples.

Basic Usage

import x.atomics

fn main() {
    mut value := i32(0)

    // Atomically store a value
    atomics.store_i32(&value, 42)

    // Atomically load the value
    loaded := atomics.load_i32(&value)

    // Atomic add: returns the new value after addition
    new_value := atomics.add_i32(&value, 10)

    // Atomic swap: returns the old value
    old := atomics.swap_i32(&value, 100)
}

Compare-and-Swap (CAS)

import x.atomics

fn main() {
    mut flag := u32(0)

    // CAS: if flag == 0, set it to 1; returns true on success
    if atomics.cas_u32(&flag, 0, 1) {
        println('Successfully changed flag from 0 to 1')
    }
}

Available Operations

Operation i32 i64 u32 u64
load_* yes yes yes yes
store_* yes yes yes yes
add_* yes yes yes yes
swap_* yes yes yes yes
cas_* yes yes yes yes

fn add_i32 #

fn add_i32(dest &i32, delta i32) i32

add_i32 atomically adds delta to the value at dest and returns the new value. The operation is performed with sequential consistency. Panics if dest is not 4-byte aligned.

fn add_i64 #

fn add_i64(dest &i64, delta i64) i64

add_i64 atomically adds delta to the value at dest and returns the new value. The operation is performed with sequential consistency. Panics if dest is not 8-byte aligned.

fn add_u32 #

fn add_u32(dest &u32, delta u32) u32

add_u32 atomically adds delta to the value at dest and returns the new value. The operation is performed with sequential consistency. Panics if dest is not 4-byte aligned.

fn add_u64 #

fn add_u64(dest &u64, delta u64) u64

add_u64 atomically adds delta to the value at dest and returns the new value. The operation is performed with sequential consistency. Panics if dest is not 8-byte aligned.

fn cas_i32 #

fn cas_i32(addr &i32, old i32, new i32) bool

cas_i32 performs a compare-and-swap operation. If the current value at addr equals old, it atomically stores new. Returns true if the swap was performed, false otherwise. The operation is performed with sequential consistency. Panics if addr is not 4-byte aligned.

fn cas_i64 #

fn cas_i64(addr &i64, old i64, new i64) bool

cas_i64 performs a compare-and-swap operation. If the current value at addr equals old, it atomically stores new. Returns true if the swap was performed, false otherwise. The operation is performed with sequential consistency. Panics if addr is not 8-byte aligned.

fn cas_u32 #

fn cas_u32(addr &u32, old u32, new u32) bool

cas_u32 performs a compare-and-swap operation. If the current value at addr equals old, it atomically stores new. Returns true if the swap was performed, false otherwise. The operation is performed with sequential consistency. Panics if addr is not 4-byte aligned.

fn cas_u64 #

fn cas_u64(addr &u64, old u64, new u64) bool

cas_u64 performs a compare-and-swap operation. If the current value at addr equals old, it atomically stores new. Returns true if the swap was performed, false otherwise. The operation is performed with sequential consistency. Panics if addr is not 8-byte aligned.

fn load_i32 #

fn load_i32(num &i32) i32

load_i32 atomically loads and returns the value at num. The operation is performed with sequential consistency. Panics if num is not 4-byte aligned.

fn load_i64 #

fn load_i64(num &i64) i64

load_i64 atomically loads and returns the value at num. The operation is performed with sequential consistency. Panics if num is not 8-byte aligned.

fn load_u32 #

fn load_u32(num &u32) u32

load_u32 atomically loads and returns the value at num. The operation is performed with sequential consistency. Panics if num is not 4-byte aligned.

fn load_u64 #

fn load_u64(num &u64) u64

load_u64 atomically loads and returns the value at num. The operation is performed with sequential consistency. Panics if num is not 8-byte aligned.

fn store_i32 #

fn store_i32(dest &i32, value i32)

store_i32 atomically stores value at dest. The operation is performed with sequential consistency. Panics if dest is not 4-byte aligned.

fn store_i64 #

fn store_i64(dest &i64, value i64)

store_i64 atomically stores value at dest. The operation is performed with sequential consistency. Panics if dest is not 8-byte aligned.

fn store_u32 #

fn store_u32(dest &u32, value u32)

store_u32 atomically stores value at dest. The operation is performed with sequential consistency. Panics if dest is not 4-byte aligned.

fn store_u64 #

fn store_u64(dest &u64, value u64)

store_u64 atomically stores value at dest. The operation is performed with sequential consistency. Panics if dest is not 8-byte aligned.

fn swap_i32 #

fn swap_i32(dest &i32, new i32) i32

swap_i32 atomically stores new value at dest and returns the old value. The operation is performed with sequential consistency. Panics if dest is not 4-byte aligned.

fn swap_i64 #

fn swap_i64(dest &i64, value i64) i64

swap_i64 atomically stores value at dest and returns the old value. The operation is performed with sequential consistency. Panics if dest is not 8-byte aligned.

fn swap_u32 #

fn swap_u32(dest &u32, new u32) u32

swap_u32 atomically stores new value at dest and returns the old value. The operation is performed with sequential consistency. Panics if dest is not 4-byte aligned.

fn swap_u64 #

fn swap_u64(dest &u64, value u64) u64

swap_u64 atomically stores value at dest and returns the old value. The operation is performed with sequential consistency. Panics if dest is not 8-byte aligned.