// tiny_atomic.h - Box 1: Atomic Operations (最下層) // Purpose: stdatomic.h のラッパー、memory ordering の抽象化 // Invariant: すべての atomic 操作はこの箱を通して行う(直接 stdatomic を使わない) // Design: static inline でゼロコスト、明確な命名規則 #pragma once #include #include // ========== Box 1: Atomic Operations ========== // 箱理論の最下層。すべての上位 Box がこの箱に依存する。 // 不変条件: Memory ordering を明示的に指定し、外側に弱い順序を漏らさない。 // Memory ordering alias (可読性向上) #define TINY_MO_RELAXED memory_order_relaxed #define TINY_MO_ACQUIRE memory_order_acquire #define TINY_MO_RELEASE memory_order_release #define TINY_MO_ACQ_REL memory_order_acq_rel #define TINY_MO_SEQ_CST memory_order_seq_cst // ========== Load Operations ========== // Load with explicit memory order // Usage: uintptr_t val = tiny_atomic_load_explicit(&atomic_var, TINY_MO_ACQUIRE); static inline uintptr_t tiny_atomic_load_explicit(_Atomic uintptr_t* ptr, memory_order mo) { return atomic_load_explicit(ptr, mo); } // Load with relaxed order (fast, no synchronization) // Usage: uintptr_t val = tiny_atomic_load_relaxed(&atomic_var); static inline uintptr_t tiny_atomic_load_relaxed(_Atomic uintptr_t* ptr) { return atomic_load_explicit(ptr, TINY_MO_RELAXED); } // Load with acquire order (synchronize with release stores) // Usage: uintptr_t val = tiny_atomic_load_acquire(&atomic_var); static inline uintptr_t tiny_atomic_load_acquire(_Atomic uintptr_t* ptr) { return atomic_load_explicit(ptr, TINY_MO_ACQUIRE); } // Load uint32_t variant static inline uint32_t tiny_atomic_load_u32_relaxed(_Atomic uint32_t* ptr) { return atomic_load_explicit(ptr, TINY_MO_RELAXED); } static inline uint32_t tiny_atomic_load_u32_acquire(_Atomic uint32_t* ptr) { return atomic_load_explicit(ptr, TINY_MO_ACQUIRE); } // Load uint8_t variant static inline uint8_t tiny_atomic_load_u8_relaxed(_Atomic uint8_t* ptr) { return atomic_load_explicit(ptr, TINY_MO_RELAXED); } static inline uint8_t tiny_atomic_load_u8_acquire(_Atomic uint8_t* ptr) { return atomic_load_explicit(ptr, TINY_MO_ACQUIRE); } // ========== Store Operations ========== // Store with explicit memory order // Usage: tiny_atomic_store_explicit(&atomic_var, val, TINY_MO_RELEASE); static inline void tiny_atomic_store_explicit(_Atomic uintptr_t* ptr, uintptr_t val, memory_order mo) { atomic_store_explicit(ptr, val, mo); } // Store with relaxed order (fast, no synchronization) // Usage: tiny_atomic_store_relaxed(&atomic_var, val); static inline void tiny_atomic_store_relaxed(_Atomic uintptr_t* ptr, uintptr_t val) { atomic_store_explicit(ptr, val, TINY_MO_RELAXED); } // Store with release order (synchronize with acquire loads) // Usage: tiny_atomic_store_release(&atomic_var, val); static inline void tiny_atomic_store_release(_Atomic uintptr_t* ptr, uintptr_t val) { atomic_store_explicit(ptr, val, TINY_MO_RELEASE); } // Store uint32_t variant static inline void tiny_atomic_store_u32_relaxed(_Atomic uint32_t* ptr, uint32_t val) { atomic_store_explicit(ptr, val, TINY_MO_RELAXED); } static inline void tiny_atomic_store_u32_release(_Atomic uint32_t* ptr, uint32_t val) { atomic_store_explicit(ptr, val, TINY_MO_RELEASE); } // ========== Compare-And-Swap (CAS) ========== // CAS with explicit memory order (success and failure) // Returns: 1 on success (value was expected and updated), 0 on failure // Usage: if (tiny_atomic_cas_explicit(&atomic_var, &expected, desired, TINY_MO_ACQ_REL, TINY_MO_ACQUIRE)) { ... } static inline int tiny_atomic_cas_explicit(_Atomic uintptr_t* ptr, uintptr_t* expected, uintptr_t desired, memory_order success_mo, memory_order failure_mo) { return atomic_compare_exchange_strong_explicit(ptr, expected, desired, success_mo, failure_mo); } // CAS with acquire-release semantics (most common case) // Usage: if (tiny_atomic_cas_acq_rel(&atomic_var, &expected, desired)) { ... } static inline int tiny_atomic_cas_acq_rel(_Atomic uintptr_t* ptr, uintptr_t* expected, uintptr_t desired) { return atomic_compare_exchange_strong_explicit(ptr, expected, desired, TINY_MO_ACQ_REL, TINY_MO_ACQUIRE); } // CAS uint32_t variant static inline int tiny_atomic_cas_u32_acq_rel(_Atomic uint32_t* ptr, uint32_t* expected, uint32_t desired) { return atomic_compare_exchange_strong_explicit(ptr, expected, desired, TINY_MO_ACQ_REL, TINY_MO_ACQUIRE); } // Weak CAS (may spuriously fail, faster on some architectures) // Usage: while (!tiny_atomic_cas_weak_acq_rel(&atomic_var, &expected, desired)) { expected = old_val; } static inline int tiny_atomic_cas_weak_acq_rel(_Atomic uintptr_t* ptr, uintptr_t* expected, uintptr_t desired) { return atomic_compare_exchange_weak_explicit(ptr, expected, desired, TINY_MO_ACQ_REL, TINY_MO_ACQUIRE); } // ========== Exchange ========== // Atomic exchange with explicit memory order // Returns: previous value // Usage: uintptr_t old = tiny_atomic_exchange_explicit(&atomic_var, new_val, TINY_MO_ACQ_REL); static inline uintptr_t tiny_atomic_exchange_explicit(_Atomic uintptr_t* ptr, uintptr_t val, memory_order mo) { return atomic_exchange_explicit(ptr, val, mo); } // Atomic exchange with acquire-release semantics // Usage: uintptr_t old = tiny_atomic_exchange_acq_rel(&atomic_var, new_val); static inline uintptr_t tiny_atomic_exchange_acq_rel(_Atomic uintptr_t* ptr, uintptr_t val) { return atomic_exchange_explicit(ptr, val, TINY_MO_ACQ_REL); } // ========== Fetch-And-Add ========== // Atomic increment (fetch and add 1) // Returns: previous value // Usage: uint32_t old = tiny_atomic_fetch_add_u32_relaxed(&counter, 1); static inline uint32_t tiny_atomic_fetch_add_u32_relaxed(_Atomic uint32_t* ptr, uint32_t val) { return atomic_fetch_add_explicit(ptr, val, TINY_MO_RELAXED); } static inline uint32_t tiny_atomic_fetch_add_u32_acq_rel(_Atomic uint32_t* ptr, uint32_t val) { return atomic_fetch_add_explicit(ptr, val, TINY_MO_ACQ_REL); } // ========== Fetch-And-Sub ========== // Atomic decrement (fetch and sub 1) // Returns: previous value // Usage: uint32_t old = tiny_atomic_fetch_sub_u32_relaxed(&counter, 1); static inline uint32_t tiny_atomic_fetch_sub_u32_relaxed(_Atomic uint32_t* ptr, uint32_t val) { return atomic_fetch_sub_explicit(ptr, val, TINY_MO_RELAXED); } static inline uint32_t tiny_atomic_fetch_sub_u32_acq_rel(_Atomic uint32_t* ptr, uint32_t val) { return atomic_fetch_sub_explicit(ptr, val, TINY_MO_ACQ_REL); } // ========== Convenience Macros ========== // Shorthand for common patterns #define TINY_ATOMIC_INIT(val) ATOMIC_VAR_INIT(val) // Example usage in upper boxes: // // Box 2 (Remote Queue): // _Atomic uintptr_t remote_head = TINY_ATOMIC_INIT(0); // uintptr_t head = tiny_atomic_load_acquire(&remote_head); // tiny_atomic_store_release(&remote_head, new_head); // // Box 3 (Ownership): // _Atomic uint32_t owner_tid = TINY_ATOMIC_INIT(0); // uint32_t expected = 0; // if (tiny_atomic_cas_u32_acq_rel(&owner_tid, &expected, my_tid)) { // // Acquired ownership // }