From 57ac0d8ae4fb0ea8adf14ec248fe2efe486a714f Mon Sep 17 00:00:00 2001 From: Patrick Pelissier Date: Mon, 10 Jul 2017 20:50:52 +0200 Subject: [PATCH] Add implementation of atomic based on mutex. --- README.md | 2 +- m-atomic.h | 112 ++++++++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 112 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index d577384f..2ffd39da 100644 --- a/README.md +++ b/README.md @@ -90,7 +90,7 @@ Other headers offering other functionality are: * m-core.h: header for meta-programming with the C preprocessor. * m-mutex.h: header for providing a very thin layer across multiple implementation of mutex/threads. * m-algo.h: header for providing various generic algorithms to the previous containers. -* m-atomic.h: header for ensuring compatibility between C's stdatmic.h and C++'s atomic header. +* m-atomic.h: header for ensuring compatibility between C's stdatomic.h and C++'s atomic header. Provide also an implementation over mutex if neither are available. * m-mempool.h: header for creating specialized & fast memory allocator. Each containers define their iterators. diff --git a/m-atomic.h b/m-atomic.h index 8c79a275..3bdd882a 100644 --- a/m-atomic.h +++ b/m-atomic.h @@ -86,10 +86,120 @@ using std::atomic_flag_test_and_set_explicit; using std::atomic_flag_clear; using std::atomic_flag_clear_explicit; -#else +#elif (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L) \ + || ( defined(__GNUC__) && !defined(__clang__) ) \ + || (defined(__clang__) && __clang_major__ >= 4) +/* CLANG 3.5 has issues with GCC's stdatomic.h + and doesn't provide its own stdatomic.h */ #include +#else + +/* No atomic.h, nor stdatomic.h + Write a compatible slin layer using mutex. */ +#include "m-mutex.h" + +/* The structure is quite large... */ +#define _Atomic(T) \ + struct { \ + volatile T __val; \ + T __zero; \ + T __previous; \ + bool __cmp; \ + m_mutex_t __lock; \ + } + +/* Even memory order is defined, only the strongest constraint exist */ +typedef enum { + memory_order_relaxed, + memory_order_consume, + memory_order_acquire, + memory_order_release, + memory_order_acq_rel, + memory_order_seq_cst +} memory_order; + +typedef _Atomic(bool) atomic_bool; +typedef _Atomic(char) atomic_char; +typedef _Atomic(short) atomic_short; +typedef _Atomic(int) atomic_int; +typedef _Atomic(long) atomic_long; +typedef _Atomic(long long) atomic_llong; +typedef _Atomic(unsigned char) atomic_uchar; +typedef _Atomic(signed char) atomic_schar; +typedef _Atomic(unsigned short) atomic_ushort; +typedef _Atomic(unsigned int) atomic_uint; +typedef _Atomic(unsigned long) atomic_ulong; +typedef _Atomic(unsigned long long) atomic_ullong; +typedef _Atomic(intptr_t) atomic_intptr_t; +typedef _Atomic(uintptr_t) atomic_uintptr_t; +typedef _Atomic(size_t) atomic_size_t; +typedef _Atomic(ptrdiff_t) atomic_ptrdiff_t; +/* TODO: Test if stdint.h was included? + typedef _Atomic(intmax_t) atomic_intmax_t; + typedef _Atomic(uintmax_t) atomic_uintmax_t;*/ + +/* Unlock the mutex and return the given value */ +static inline long long atomic_fetch_unlock (m_mutex_t *lock, long long val) +{ + m_mutex_unlock (*lock); + return val; +} + +#define atomic_fetch_op(ptr, val, op) \ + (m_mutex_lock((ptr)->__lock), \ + (ptr)->__previous = (ptr)->__val, \ + (ptr)->__val op (val), \ + atomic_fetch_unlock(&(ptr)->__lock, (ptr)->__previous-(ptr)->__zero)+(ptr)->__zero) + +#define atomic_fetch_add(ptr, val) atomic_fetch_op(ptr, val, +=) +#define atomic_fetch_sub(ptr, val) atomic_fetch_op(ptr, val, -=) +#define atomic_fetch_or(ptr, val) atomic_fetch_op(ptr, val, |=) +#define atomic_fetch_xor(ptr, val) atomic_fetch_op(ptr, val, ^=) +#define atomic_fetch_and(ptr, val) atomic_fetch_op(ptr, val, &=) +#define atomic_exchange(ptr, val) atomic_fetch_op(ptr, val, =) + +#define ATOMIC_VAR_INIT(val) { val, 0, 0, 0, M_MUTEXI_INIT_VALUE } + +#define atomic_init(ptr, val) \ + (m_mutex_init((ptr)->__lock), (ptr)->__val = val, (ptr)->__zero = 0) + +#define atomic_load(ptr) \ + (m_mutex_lock((ptr)->__lock), \ + (ptr)->__previous = (ptr)->__val, \ + atomic_fetch_unlock(&(ptr)->__lock, (ptr)->__previous-(ptr)->__zero)+(ptr)->__zero) + +#define atomic_store(ptr, val) \ + (m_mutex_lock((ptr)->__lock), \ + (ptr)->__val = val, \ + m_mutex_unlock((ptr)->__lock)) + +#define atomic_compare_exchange_strong(ptr, exp, val) \ + (m_mutex_lock((ptr)->__lock), \ + (ptr)->__cmp = (ptr)->__val == *(exp), \ + ((ptr)->__cmp != 0 && ((ptr)->__val = (val))), \ + ((ptr)->__cmp == 0 && (*(exp) = (ptr)->__val)), \ + atomic_fetch_unlock(&(ptr)->__lock, (ptr)->__cmp)) + +#define atomic_fetch_add_explicit(ptr, val, mem) atomic_fetch_op(ptr, val, +=) +#define atomic_fetch_sub_explicit(ptr, val, mem) atomic_fetch_op(ptr, val, -=) +#define atomic_fetch_or_explicit(ptr, val, mem) atomic_fetch_op(ptr, val, |=) +#define atomic_fetch_xor_explicit(ptr, val, mem) atomic_fetch_op(ptr, val, ^=) +#define atomic_fetch_and_explicit(ptr, val, mem) atomic_fetch_op(ptr, val, &=) +#define atomic_exchange_explicit(ptr, val, mem) atomic_fetch_op(ptr, val, =) +#define atomic_load_explicit(ptr, mem) atomic_load(ptr) +#define atomic_store_explicit(ptr, val, mem) atomic_store(ptr, val) +#define kill_dependency(ptr) atomic_load(ptr) +#define atomic_thread_fence(mem) (void) 0 +#define atomic_signal_fence(mem) (void) 0 +#define atomic_is_lock_free(ptr) false +#define atomic_compare_exchange_strong_explicit(ptr, exp, val, mem) atomic_compare_exchange_strong(ptr, exp, val) +#define atomic_compare_exchange_weak_explicit(ptr, exp, val, mem) atomic_compare_exchange_strong(ptr, exp, val) +#define atomic_compare_exchange_weak(ptr, exp, val) atomic_compare_exchange_strong(ptr, exp, val) + +/* TODO: Missing atomic_flag */ + #endif #endif