138 lines
5 KiB
C
138 lines
5 KiB
C
// stdatomic.h — C11 atomic operations, single-core stubs.
|
|
//
|
|
// The W65816 is a uniprocessor with no preemption from a kernel scheduler
|
|
// (we run bare on the IIgs, optionally under GS/OS which doesn't yield
|
|
// inside a process). All `atomic_*` operations lower to plain ops; the
|
|
// `memory_order_*` constants are accepted and ignored.
|
|
//
|
|
// This header provides the C11 API surface so portable code that uses
|
|
// `_Atomic int` / `atomic_fetch_add` / etc. compiles cleanly. Real
|
|
// multi-core atomicity is not modeled.
|
|
|
|
#ifndef _STDATOMIC_H
|
|
#define _STDATOMIC_H
|
|
|
|
#include <stddef.h>
|
|
#include <stdint.h>
|
|
|
|
typedef enum {
|
|
memory_order_relaxed,
|
|
memory_order_consume,
|
|
memory_order_acquire,
|
|
memory_order_release,
|
|
memory_order_acq_rel,
|
|
memory_order_seq_cst
|
|
} memory_order;
|
|
|
|
#define ATOMIC_BOOL_LOCK_FREE 1
|
|
#define ATOMIC_CHAR_LOCK_FREE 1
|
|
#define ATOMIC_CHAR16_T_LOCK_FREE 1
|
|
#define ATOMIC_CHAR32_T_LOCK_FREE 1
|
|
#define ATOMIC_WCHAR_T_LOCK_FREE 1
|
|
#define ATOMIC_SHORT_LOCK_FREE 1
|
|
#define ATOMIC_INT_LOCK_FREE 1
|
|
#define ATOMIC_LONG_LOCK_FREE 1
|
|
#define ATOMIC_LLONG_LOCK_FREE 1
|
|
#define ATOMIC_POINTER_LOCK_FREE 1
|
|
|
|
#define ATOMIC_VAR_INIT(v) (v)
|
|
#define ATOMIC_FLAG_INIT { 0 }
|
|
|
|
// Atomic flag — a boolean-valued atomic flag.
|
|
typedef struct { volatile unsigned char _v; } atomic_flag;
|
|
|
|
static inline int atomic_flag_test_and_set_explicit(volatile atomic_flag *o,
|
|
memory_order m) {
|
|
(void)m;
|
|
int r = o->_v;
|
|
o->_v = 1;
|
|
return r;
|
|
}
|
|
static inline int atomic_flag_test_and_set(volatile atomic_flag *o) {
|
|
return atomic_flag_test_and_set_explicit(o, memory_order_seq_cst);
|
|
}
|
|
static inline void atomic_flag_clear_explicit(volatile atomic_flag *o,
|
|
memory_order m) {
|
|
(void)m;
|
|
o->_v = 0;
|
|
}
|
|
static inline void atomic_flag_clear(volatile atomic_flag *o) {
|
|
atomic_flag_clear_explicit(o, memory_order_seq_cst);
|
|
}
|
|
|
|
// Thread-fence — no-op on a uniprocessor with no kernel preemption.
|
|
static inline void atomic_thread_fence(memory_order m) { (void)m; }
|
|
static inline void atomic_signal_fence(memory_order m) { (void)m; }
|
|
|
|
// _Atomic(T) is just T on this target. Generic load/store/RMW macros
|
|
// delegate to plain ops. Uses __typeof__ to preserve type info.
|
|
#define atomic_init(obj, val) (*(obj) = (val))
|
|
#define atomic_is_lock_free(obj) ((void)(obj), 1)
|
|
#define atomic_store(obj, val) (*(obj) = (val))
|
|
#define atomic_store_explicit(obj, val, m) ((void)(m), *(obj) = (val))
|
|
#define atomic_load(obj) (*(obj))
|
|
#define atomic_load_explicit(obj, m) ((void)(m), *(obj))
|
|
#define atomic_exchange(obj, val) ({ \
|
|
__typeof__(*(obj)) _old = *(obj); \
|
|
*(obj) = (val); \
|
|
_old; })
|
|
#define atomic_exchange_explicit(obj, val, m) \
|
|
((void)(m), atomic_exchange(obj, val))
|
|
#define atomic_compare_exchange_strong(obj, expected, desired) ({ \
|
|
int _ok = (*(obj) == *(expected)); \
|
|
if (_ok) *(obj) = (desired); else *(expected) = *(obj); \
|
|
_ok; })
|
|
#define atomic_compare_exchange_weak(obj, expected, desired) \
|
|
atomic_compare_exchange_strong(obj, expected, desired)
|
|
#define atomic_compare_exchange_strong_explicit(obj, expected, desired, ms, mf) \
|
|
((void)(ms), (void)(mf), \
|
|
atomic_compare_exchange_strong(obj, expected, desired))
|
|
#define atomic_compare_exchange_weak_explicit(obj, expected, desired, ms, mf) \
|
|
((void)(ms), (void)(mf), \
|
|
atomic_compare_exchange_weak(obj, expected, desired))
|
|
#define atomic_fetch_add(obj, val) ({ \
|
|
__typeof__(*(obj)) _old = *(obj); \
|
|
*(obj) += (val); \
|
|
_old; })
|
|
#define atomic_fetch_add_explicit(obj, val, m) \
|
|
((void)(m), atomic_fetch_add(obj, val))
|
|
#define atomic_fetch_sub(obj, val) ({ \
|
|
__typeof__(*(obj)) _old = *(obj); \
|
|
*(obj) -= (val); \
|
|
_old; })
|
|
#define atomic_fetch_sub_explicit(obj, val, m) \
|
|
((void)(m), atomic_fetch_sub(obj, val))
|
|
#define atomic_fetch_or(obj, val) ({ \
|
|
__typeof__(*(obj)) _old = *(obj); \
|
|
*(obj) |= (val); \
|
|
_old; })
|
|
#define atomic_fetch_or_explicit(obj, val, m) \
|
|
((void)(m), atomic_fetch_or(obj, val))
|
|
#define atomic_fetch_and(obj, val) ({ \
|
|
__typeof__(*(obj)) _old = *(obj); \
|
|
*(obj) &= (val); \
|
|
_old; })
|
|
#define atomic_fetch_and_explicit(obj, val, m) \
|
|
((void)(m), atomic_fetch_and(obj, val))
|
|
#define atomic_fetch_xor(obj, val) ({ \
|
|
__typeof__(*(obj)) _old = *(obj); \
|
|
*(obj) ^= (val); \
|
|
_old; })
|
|
#define atomic_fetch_xor_explicit(obj, val, m) \
|
|
((void)(m), atomic_fetch_xor(obj, val))
|
|
|
|
// _Atomic-qualified typedefs that portable C11 code expects.
|
|
typedef _Bool atomic_bool;
|
|
typedef char atomic_char;
|
|
typedef signed char atomic_schar;
|
|
typedef unsigned char atomic_uchar;
|
|
typedef short atomic_short;
|
|
typedef unsigned short atomic_ushort;
|
|
typedef int atomic_int;
|
|
typedef unsigned int atomic_uint;
|
|
typedef long atomic_long;
|
|
typedef unsigned long atomic_ulong;
|
|
typedef long long atomic_llong;
|
|
typedef unsigned long long atomic_ullong;
|
|
|
|
#endif
|