|
10 | 10 | #ifndef UMF_UTILS_CONCURRENCY_H
|
11 | 11 | #define UMF_UTILS_CONCURRENCY_H 1
|
12 | 12 |
|
| 13 | +#include <stdbool.h> |
| 14 | +#include <stdint.h> |
13 | 15 | #include <stdio.h>
|
14 | 16 | #include <stdlib.h>
|
15 | 17 |
|
|
19 | 21 | #include "utils_windows_intrin.h"
|
20 | 22 |
|
21 | 23 | #pragma intrinsic(_BitScanForward64)
|
22 |
| -#else |
| 24 | +#else /* !_WIN32 */ |
23 | 25 | #include <pthread.h>
|
24 | 26 |
|
25 | 27 | #ifndef __cplusplus
|
26 | 28 | #include <stdatomic.h>
|
27 | 29 | #else /* __cplusplus */
|
28 | 30 | #include <atomic>
|
29 | 31 | #define _Atomic(X) std::atomic<X>
|
| 32 | + |
| 33 | +using std::memory_order_acq_rel; |
| 34 | +using std::memory_order_acquire; |
| 35 | +using std::memory_order_relaxed; |
| 36 | +using std::memory_order_release; |
| 37 | + |
30 | 38 | #endif /* __cplusplus */
|
31 | 39 |
|
32 |
| -#endif /* _WIN32 */ |
| 40 | +#endif /* !_WIN32 */ |
33 | 41 |
|
| 42 | +#include "utils_common.h" |
34 | 43 | #include "utils_sanitizers.h"
|
35 | 44 |
|
36 | 45 | #ifdef __cplusplus
|
@@ -92,57 +101,123 @@ static __inline unsigned char utils_mssb_index(long long value) {
|
92 | 101 | }
|
93 | 102 |
|
94 | 103 | // There is no good way to do atomic_load on windows...
|
95 |
| -#define utils_atomic_load_acquire(object, dest) \ |
96 |
| - do { \ |
97 |
| - *(LONG64 *)dest = \ |
98 |
| - InterlockedOr64Acquire((LONG64 volatile *)object, 0); \ |
99 |
| - } while (0) |
| 104 | +static __inline void utils_atomic_load_acquire_u64(uint64_t *ptr, |
| 105 | + uint64_t *out) { |
| 106 | + // NOTE: Windows cl complains about direct accessing 'ptr' which is next |
| 107 | + // accessed using Interlocked* functions (warning 28112 - disabled) |
| 108 | + ASSERT_IS_ALIGNED((uintptr_t)ptr, 8); |
| 109 | + |
| 110 | + // On Windows, there is no equivalent to __atomic_load, so we use cmpxchg |
| 111 | + // with 0, 0 here. This will always return the value under the pointer |
| 112 | + // without writing anything. |
| 113 | + LONG64 ret = InterlockedCompareExchange64((LONG64 volatile *)ptr, 0, 0); |
| 114 | + *out = *(uint64_t *)&ret; |
| 115 | +} |
| 116 | + |
| 117 | +static __inline void utils_atomic_load_acquire_ptr(void **ptr, void **out) { |
| 118 | + ASSERT_IS_ALIGNED((uintptr_t)ptr, 8); |
| 119 | + uintptr_t ret = (uintptr_t)InterlockedCompareExchangePointer(ptr, 0, 0); |
| 120 | + *(uintptr_t *)out = ret; |
| 121 | +} |
100 | 122 |
|
101 |
| -#define utils_atomic_store_release(object, desired) \ |
102 |
| - InterlockedExchange64((LONG64 volatile *)object, (LONG64)desired) |
| 123 | +static __inline void utils_atomic_store_release_ptr(void **ptr, void *val) { |
| 124 | + ASSERT_IS_ALIGNED((uintptr_t)ptr, 8); |
| 125 | + InterlockedExchangePointer(ptr, val); |
| 126 | +} |
103 | 127 |
|
104 |
| -#define utils_atomic_increment(object) \ |
105 |
| - InterlockedIncrement64((LONG64 volatile *)object) |
| 128 | +static __inline uint64_t utils_atomic_increment_u64(uint64_t *ptr) { |
| 129 | + ASSERT_IS_ALIGNED((uintptr_t)ptr, 8); |
| 130 | + // return incremented value |
| 131 | + return InterlockedIncrement64((LONG64 volatile *)ptr); |
| 132 | +} |
106 | 133 |
|
107 |
| -#define utils_atomic_decrement(object) \ |
108 |
| - InterlockedDecrement64((LONG64 volatile *)object) |
| 134 | +static __inline uint64_t utils_atomic_decrement_u64(uint64_t *ptr) { |
| 135 | + ASSERT_IS_ALIGNED((uintptr_t)ptr, 8); |
| 136 | + // return decremented value |
| 137 | + return InterlockedDecrement64((LONG64 volatile *)ptr); |
| 138 | +} |
109 | 139 |
|
110 |
| -#define utils_fetch_and_add64(ptr, value) \ |
111 |
| - InterlockedExchangeAdd64((LONG64 *)(ptr), value) |
| 140 | +static __inline uint64_t utils_fetch_and_add_u64(uint64_t *ptr, uint64_t val) { |
| 141 | + ASSERT_IS_ALIGNED((uintptr_t)ptr, 8); |
| 142 | + // return the value that had previously been in *ptr |
| 143 | + return InterlockedExchangeAdd64((LONG64 volatile *)(ptr), val); |
| 144 | +} |
112 | 145 |
|
113 |
| -// NOTE: windows version have different order of args |
114 |
| -#define utils_compare_exchange(object, desired, expected) \ |
115 |
| - InterlockedCompareExchange64((LONG64 volatile *)object, *expected, *desired) |
| 146 | +static __inline uint64_t utils_fetch_and_sub_u64(uint64_t *ptr, uint64_t val) { |
| 147 | + ASSERT_IS_ALIGNED((uintptr_t)ptr, 8); |
| 148 | + // return the value that had previously been in *ptr |
| 149 | + // NOTE: on Windows there is no *Sub* version of InterlockedExchange |
| 150 | + return InterlockedExchangeAdd64((LONG64 volatile *)(ptr), -(LONG64)val); |
| 151 | +} |
| 152 | + |
| 153 | +static __inline bool utils_compare_exchange_u64(uint64_t *ptr, |
| 154 | + uint64_t *expected, |
| 155 | + uint64_t *desired) { |
| 156 | + ASSERT_IS_ALIGNED((uintptr_t)ptr, 8); |
| 157 | + LONG64 out = InterlockedCompareExchange64( |
| 158 | + (LONG64 volatile *)ptr, *(LONG64 *)desired, *(LONG64 *)expected); |
| 159 | + if (out == *(LONG64 *)expected) { |
| 160 | + return true; |
| 161 | + } |
| 162 | + |
| 163 | + // else |
| 164 | + *expected = out; |
| 165 | + return false; |
| 166 | +} |
116 | 167 |
|
117 | 168 | #else // !defined(_WIN32)
|
118 | 169 |
|
119 | 170 | #define utils_lssb_index(x) ((unsigned char)__builtin_ctzll(x))
|
120 | 171 | #define utils_mssb_index(x) ((unsigned char)(63 - __builtin_clzll(x)))
|
121 | 172 |
|
122 |
| -#define utils_atomic_load_acquire(object, dest) \ |
123 |
| - do { \ |
124 |
| - utils_annotate_acquire((void *)object); \ |
125 |
| - __atomic_load(object, dest, memory_order_acquire); \ |
126 |
| - } while (0) |
| 173 | +static inline void utils_atomic_load_acquire_u64(uint64_t *ptr, uint64_t *out) { |
| 174 | + ASSERT_IS_ALIGNED((uintptr_t)ptr, 8); |
| 175 | + ASSERT_IS_ALIGNED((uintptr_t)out, 8); |
| 176 | + __atomic_load(ptr, out, memory_order_acquire); |
| 177 | +} |
127 | 178 |
|
128 |
| -#define utils_atomic_store_release(object, desired) \ |
129 |
| - do { \ |
130 |
| - __atomic_store_n(object, desired, memory_order_release); \ |
131 |
| - utils_annotate_release((void *)object); \ |
132 |
| - } while (0) |
| 179 | +static inline void utils_atomic_load_acquire_ptr(void **ptr, void **out) { |
| 180 | + ASSERT_IS_ALIGNED((uintptr_t)ptr, 8); |
| 181 | + ASSERT_IS_ALIGNED((uintptr_t)out, 8); |
| 182 | + __atomic_load((uintptr_t *)ptr, (uintptr_t *)out, memory_order_acquire); |
| 183 | +} |
133 | 184 |
|
134 |
| -#define utils_atomic_increment(object) \ |
135 |
| - __atomic_add_fetch(object, 1, memory_order_acq_rel) |
| 185 | +static inline void utils_atomic_store_release_ptr(void **ptr, void *val) { |
| 186 | + ASSERT_IS_ALIGNED((uintptr_t)ptr, 8); |
| 187 | + __atomic_store_n((uintptr_t *)ptr, (uintptr_t)val, memory_order_release); |
| 188 | +} |
136 | 189 |
|
137 |
| -#define utils_atomic_decrement(object) \ |
138 |
| - __atomic_sub_fetch(object, 1, memory_order_acq_rel) |
| 190 | +static inline uint64_t utils_atomic_increment_u64(uint64_t *val) { |
| 191 | + ASSERT_IS_ALIGNED((uintptr_t)val, 8); |
| 192 | + // return incremented value |
| 193 | + return __atomic_add_fetch(val, 1, memory_order_acq_rel); |
| 194 | +} |
139 | 195 |
|
140 |
| -#define utils_fetch_and_add64(object, value) \ |
141 |
| - __atomic_fetch_add(object, value, memory_order_acq_rel) |
| 196 | +static inline uint64_t utils_atomic_decrement_u64(uint64_t *val) { |
| 197 | + ASSERT_IS_ALIGNED((uintptr_t)val, 8); |
| 198 | + // return decremented value |
| 199 | + return __atomic_sub_fetch(val, 1, memory_order_acq_rel); |
| 200 | +} |
142 | 201 |
|
143 |
| -#define utils_compare_exchange(object, expected, desired) \ |
144 |
| - __atomic_compare_exchange(object, expected, desired, 0 /* strong */, \ |
145 |
| - memory_order_acq_rel, memory_order_relaxed) |
| 202 | +static inline uint64_t utils_fetch_and_add_u64(uint64_t *ptr, uint64_t val) { |
| 203 | + ASSERT_IS_ALIGNED((uintptr_t)ptr, 8); |
| 204 | + // return the value that had previously been in *ptr |
| 205 | + return __atomic_fetch_add(ptr, val, memory_order_acq_rel); |
| 206 | +} |
| 207 | + |
| 208 | +static inline uint64_t utils_fetch_and_sub_u64(uint64_t *ptr, uint64_t val) { |
| 209 | + // return the value that had previously been in *ptr |
| 210 | + ASSERT_IS_ALIGNED((uintptr_t)ptr, 8); |
| 211 | + return __atomic_fetch_sub(ptr, val, memory_order_acq_rel); |
| 212 | +} |
| 213 | + |
| 214 | +static inline bool utils_compare_exchange_u64(uint64_t *ptr, uint64_t *expected, |
| 215 | + uint64_t *desired) { |
| 216 | + ASSERT_IS_ALIGNED((uintptr_t)ptr, 8); |
| 217 | + return __atomic_compare_exchange(ptr, expected, desired, 0 /* strong */, |
| 218 | + memory_order_acq_rel, |
| 219 | + memory_order_relaxed); |
| 220 | +} |
146 | 221 |
|
147 | 222 | #endif // !defined(_WIN32)
|
148 | 223 |
|
|
0 commit comments