CX Framework
Cross-platform C utility framework
Loading...
Searching...
No Matches
msvc_atomic.h
1#pragma once
2
3#if defined(_M_X64)
4#define CX_MemoryBarrier __faststorefence
5#define CX_ReadWriteBarrier _ReadWriteBarrier
6#elif defined(_M_IX86)
7__forceinline void CX_MemoryBarrier(void)
8{
9 long Barrier;
10
11 _InterlockedOr(&Barrier, 0);
12 return;
13}
14#define CX_ReadWriteBarrier _ReadWriteBarrier
15#else
16#error "Don't know how to create atomics for this platform for MSVC."
17#endif
18
19#include "cx/utils/macros.h"
20
21#define atomicInit(...) {__VA_ARGS__}
22
23typedef enum {
24 ATOMIC_MO_Relaxed,
25 ATOMIC_MO_Acquire,
26 ATOMIC_MO_Release,
27 ATOMIC_MO_AcqRel,
28 ATOMIC_MO_SeqCst
29} AtmoicMemoryOrder;
30
31typedef char _cx_atomic_repr_0_t;
32typedef short _cx_atomic_repr_1_t;
33typedef long _cx_atomic_repr_2_t;
34typedef __int64 _cx_atomic_repr_3_t;
35
36_meta_inline void
37_atomicFence(AtmoicMemoryOrder mo)
38{
39 CX_ReadWriteBarrier();
40# if defined(_M_ARM) || defined(_M_ARM64)
41 /* ARM needs a barrier for everything but relaxed. */
42 if (mo != ATOMIC_MO_Relaxed) {
43 CX_MemoryBarrier();
44 }
45# elif defined(_M_IX86) || defined (_M_X64)
46 /* x86 needs a barrier only for seq_cst. */
47 if (mo == ATOMIC_MO_SeqCst) {
48 CX_MemoryBarrier();
49 }
50# else
51# error "Don't know how to create atomics for this platform for MSVC."
52# endif
53 CX_ReadWriteBarrier();
54}
55#define atomicFence(order) _atomicFence(ATOMIC_MO_##order)
56
57#define CX_ATOMIC_IL_REPR(lg_size) _cx_atomic_repr_ ## lg_size ## _t
58
59#define CX_ATOMIC_IL_NAME(base_name, lg_size) tokconcat( \
60 base_name, CX_ATOMIC_IL_SUFFIX(lg_size))
61
62#define CX_ATOMIC_IL_SUFFIX(lg_size) \
63 tokconcat(CX_ATOMIC_IL_SUFFIX_, lg_size)
64
65#define CX_ATOMIC_IL_SUFFIX_0 8
66#define CX_ATOMIC_IL_SUFFIX_1 16
67#define CX_ATOMIC_IL_SUFFIX_2
68#define CX_ATOMIC_IL_SUFFIX_3 64
69
70#define atomic(type) cx_atomic_##type
71#define atomicLoad(type, atomic_ptr, order) \
72 _atomicLoad_##type(atomic_ptr, ATOMIC_MO_##order)
73#define atomicStore(type, atomic_ptr, val, order) \
74 _atomicStore_##type(atomic_ptr, val, ATOMIC_MO_##order)
75#define atomicExchange(type, atomic_ptr, val, order) \
76 _atomicExchange_##type(atomic_ptr, val, ATOMIC_MO_##order)
77#define atomicCompareExchange(type, semantics, atomic_ptr, expected_ptr,\
78 desired, successorder, failorder) \
79 _atomicCompareExchange_##semantics##_##type(atomic_ptr, \
80 expected_ptr, desired, \
81 ATOMIC_MO_##successorder, ATOMIC_MO_##failorder)
82
83#define atomicFetchAdd(type, atomic_ptr, val, order) \
84 _atomicFetchAdd_##type(atomic_ptr, val, ATOMIC_MO_##order)
85#define atomicFetchSub(type, atomic_ptr, val, order) \
86 _atomicFetchSub_##type(atomic_ptr, val, ATOMIC_MO_##order)
87#define atomicFetchAnd(type, atomic_ptr, val, order) \
88 _atomicFetchAnd_##type(atomic_ptr, val, ATOMIC_MO_##order)
89#define atomicFetchOr(type, atomic_ptr, val, order) \
90 _atomicFetchOr_##type(atomic_ptr, val, ATOMIC_MO_##order)
91#define atomicFetchXor(type, atomic_ptr, val, order) \
92 _atomicFetchXor_##type(atomic_ptr, val, ATOMIC_MO_##order)
93
94#define CX_GENERATE_ATOMICS(type, short_type, lg_size) \
95typedef struct { \
96 CX_ATOMIC_IL_REPR(lg_size) repr; \
97} cx_atomic_##short_type; \
98 \
99_meta_inline type \
100_atomicLoad_##short_type(const cx_atomic_##short_type *a, \
101 AtmoicMemoryOrder mo) { \
102 CX_ATOMIC_IL_REPR(lg_size) ret = a->repr; \
103 if (mo != ATOMIC_MO_Relaxed) { \
104 _atomicFence(ATOMIC_MO_Acquire); \
105 } \
106 return (type) ret; \
107} \
108 \
109_meta_inline void \
110_atomicStore_##short_type(cx_atomic_##short_type *a, \
111 type val, AtmoicMemoryOrder mo) { \
112 if (mo != ATOMIC_MO_Relaxed) { \
113 _atomicFence(ATOMIC_MO_Release); \
114 } \
115 a->repr = (CX_ATOMIC_IL_REPR(lg_size)) val; \
116 if (mo == ATOMIC_MO_SeqCst) { \
117 _atomicFence(ATOMIC_MO_SeqCst); \
118 } \
119} \
120 \
121_meta_inline type \
122_atomicExchange_##short_type(cx_atomic_##short_type *a, type val, \
123 AtmoicMemoryOrder mo) { \
124 return (type)CX_ATOMIC_IL_NAME(_InterlockedExchange, \
125 lg_size)(&a->repr, (CX_ATOMIC_IL_REPR(lg_size))val); \
126} \
127 \
128_meta_inline bool \
129_atomicCompareExchange_weak_##short_type(cx_atomic_##short_type *a, \
130 type *expected, type desired, AtmoicMemoryOrder success_mo, \
131 AtmoicMemoryOrder failure_mo) { \
132 CX_ATOMIC_IL_REPR(lg_size) e = \
133 (CX_ATOMIC_IL_REPR(lg_size))*expected; \
134 CX_ATOMIC_IL_REPR(lg_size) d = \
135 (CX_ATOMIC_IL_REPR(lg_size))desired; \
136 CX_ATOMIC_IL_REPR(lg_size) old = \
137 CX_ATOMIC_IL_NAME(_InterlockedCompareExchange, \
138 lg_size)(&a->repr, d, e); \
139 if (old == e) { \
140 return true; \
141 } else { \
142 *expected = (type)old; \
143 return false; \
144 } \
145} \
146 \
147_meta_inline bool \
148_atomicCompareExchange_strong_##short_type(cx_atomic_##short_type *a, \
149 type *expected, type desired, AtmoicMemoryOrder success_mo, \
150 AtmoicMemoryOrder failure_mo) { \
151 /* We implement the weak version with strong semantics. */ \
152 return _atomicCompareExchange_weak_##short_type(a, expected, \
153 desired, success_mo, failure_mo); \
154}
155
156#define CX_EXTERN_ATOMICS(type, short_type) \
157extern inline type \
158_atomicLoad_##short_type(const cx_atomic_##short_type *a, \
159 AtmoicMemoryOrder mo); \
160 \
161extern inline void \
162_atomicStore_##short_type(cx_atomic_##short_type *a, \
163 type val, AtmoicMemoryOrder mo); \
164 \
165extern inline type \
166_atomicExchange_##short_type(cx_atomic_##short_type *a, type val, \
167 AtmoicMemoryOrder mo); \
168 \
169extern inline bool \
170_atomicCompareExchange_weak_##short_type(cx_atomic_##short_type *a, \
171 type *expected, type desired, AtmoicMemoryOrder success_mo, \
172 AtmoicMemoryOrder failure_mo); \
173 \
174extern inline bool \
175_atomicCompareExchange_strong_##short_type(cx_atomic_##short_type *a, \
176 type *expected, type desired, AtmoicMemoryOrder success_mo, \
177 AtmoicMemoryOrder failure_mo);
178
179#define CX_GENERATE_INT_ATOMICS(type, short_type, lg_size) \
180CX_GENERATE_ATOMICS(type, short_type, lg_size) \
181 \
182_meta_inline type \
183_atomicFetchAdd_##short_type(cx_atomic_##short_type *a, \
184 type val, AtmoicMemoryOrder mo) { \
185 return (type)CX_ATOMIC_IL_NAME(_InterlockedExchangeAdd, \
186 lg_size)(&a->repr, (CX_ATOMIC_IL_REPR(lg_size))val); \
187} \
188 \
189_meta_inline type \
190_atomicFetchSub_##short_type(cx_atomic_##short_type *a, \
191 type val, AtmoicMemoryOrder mo) { \
192 /* \
193 * MSVC warns on negation of unsigned operands, but for us it \
194 * gives exactly the right semantics (MAX_TYPE + 1 - operand). \
195 */ \
196 __pragma(warning(push)) \
197 __pragma(warning(disable: 4146)) \
198 return _atomicFetchAdd_##short_type(a, -val, mo); \
199 __pragma(warning(pop)) \
200} \
201_meta_inline type \
202_atomicFetchAnd_##short_type(cx_atomic_##short_type *a, \
203 type val, AtmoicMemoryOrder mo) { \
204 return (type)CX_ATOMIC_IL_NAME(_InterlockedAnd, lg_size)( \
205 &a->repr, (CX_ATOMIC_IL_REPR(lg_size))val); \
206} \
207_meta_inline type \
208_atomicFetchOr_##short_type(cx_atomic_##short_type *a, \
209 type val, AtmoicMemoryOrder mo) { \
210 return (type)CX_ATOMIC_IL_NAME(_InterlockedOr, lg_size)( \
211 &a->repr, (CX_ATOMIC_IL_REPR(lg_size))val); \
212} \
213_meta_inline type \
214_atomicFetchXor_##short_type(cx_atomic_##short_type *a, \
215 type val, AtmoicMemoryOrder mo) { \
216 return (type)CX_ATOMIC_IL_NAME(_InterlockedXor, lg_size)( \
217 &a->repr, (CX_ATOMIC_IL_REPR(lg_size))val); \
218}
219
220#define CX_EXTERN_INT_ATOMICS(type, short_type) \
221CX_EXTERN_ATOMICS(type, short_type) \
222 \
223extern inline type \
224atomicFetchAdd_##short_type(cx_atomic_##short_type *a, \
225 type val, AtmoicMemoryOrder mo); \
226 \
227extern inline type \
228atomicFetchSub_##short_type(cx_atomic_##short_type *a, \
229 type val, AtmoicMemoryOrder mo); \
230extern inline type \
231atomicFetchAnd_##short_type(cx_atomic_##short_type *a, \
232 type val, AtmoicMemoryOrder mo); \
233extern inline type \
234atomicFetchOr_##short_type(cx_atomic_##short_type *a, \
235 type val, AtmoicMemoryOrder mo); \
236extern inline type \
237atomicFetchXor_##short_type(cx_atomic_##short_type *a, \
238 type val, AtmoicMemoryOrder mo);