Sane C++ Libraries
C++ Platform Abstraction Libraries
Atomic.h
1// Copyright (c) Stefano Cristiano
2// SPDX-License-Identifier: MIT
3#pragma once
4#include "../Foundation/PrimitiveTypes.h"
5
6#if _MSC_VER
7extern "C"
8{
9 long _InterlockedExchangeAdd(long volatile* Addend, long Value);
10 char _InterlockedExchange8(char volatile* Target, char Value);
11 void __dmb(unsigned int _Type);
12 void __iso_volatile_store8(volatile __int8*, __int8);
13 __int8 __iso_volatile_load8(const volatile __int8*);
14 __int32 __iso_volatile_load32(const volatile __int32*);
15 void _ReadWriteBarrier(void);
16
17#ifdef __clang__
18#define SC_COMPILER_MSVC_DISABLE_DEPRECATED_WARNING \
19 _Pragma("clang diagnostic push") _Pragma("clang diagnostic ignored \"-Wdeprecated-declarations\"")
20#elif defined(__CUDACC__) || defined(__INTEL_COMPILER)
21#define SC_COMPILER_MSVC_DISABLE_DEPRECATED_WARNING \
22 __pragma(warning(push)) __pragma(warning(disable : 4996)) // was declared deprecated
23#else // vvv MSVC vvv
24#define SC_COMPILER_MSVC_DISABLE_DEPRECATED_WARNING \
25 _Pragma("warning(push)") _Pragma("warning(disable : 4996)") // was declared deprecated
26#endif // ^^^ MSVC ^^^
27
28#ifdef __clang__
29#define SC_COMPILER_MSVC_RESTORE_DEPRECATED_WARNING _Pragma("clang diagnostic pop")
30#elif defined(__CUDACC__) || defined(__INTEL_COMPILER)
31#define SC_COMPILER_MSVC_RESTORE_DEPRECATED_WARNING __pragma(warning(pop))
32#else
33#define SC_COMPILER_MSVC_RESTORE_DEPRECATED_WARNING _Pragma("warning(pop)")
34#endif
35
36#define SC_COMPILER_MSVC_COMPILER_BARRIER() \
37 SC_COMPILER_MSVC_DISABLE_DEPRECATED_WARNING _ReadWriteBarrier() SC_COMPILER_MSVC_RESTORE_DEPRECATED_WARNING
38
39#if defined(_M_ARM) || defined(_M_ARM64) || defined(_M_ARM64EC)
40#define SC_COMPILER_MSVC_MEMORY_BARRIER() __dmb(0xB)
41#define SC_COMPILER_MSVC_COMPILER_MEMORY_BARRIER() SC_COMPILER_MSVC_MEMORY_BARRIER()
42#elif defined(_M_IX86) || defined(_M_X64)
43#define SC_COMPILER_MSVC_COMPILER_MEMORY_BARRIER() SC_COMPILER_MSVC_COMPILER_BARRIER()
44#else
45#error Unsupported hardware
46#endif
47
48#define SC_COMPILER_MSVC_ATOMIC_LOAD_VERIFY_MEMORY_ORDER(_Order_var) \
49 switch (_Order_var) \
50 { \
51 case memory_order_relaxed: break; \
52 case memory_order_consume: \
53 case memory_order_acquire: \
54 case memory_order_seq_cst: SC_COMPILER_MSVC_COMPILER_MEMORY_BARRIER(); break; \
55 case memory_order_release: \
56 case memory_order_acq_rel: \
57 default: break; \
58 }
59}
60#endif
61
62namespace SC
63{
64#if _MSC_VER
65typedef enum memory_order
66{
67 memory_order_relaxed,
68 memory_order_consume,
69 memory_order_acquire,
70 memory_order_release,
71 memory_order_acq_rel,
72 memory_order_seq_cst
73} memory_order;
74#else
75typedef enum memory_order
76{
77 memory_order_relaxed = __ATOMIC_RELAXED,
78 memory_order_consume = __ATOMIC_CONSUME,
79 memory_order_acquire = __ATOMIC_ACQUIRE,
80 memory_order_release = __ATOMIC_RELEASE,
81 memory_order_acq_rel = __ATOMIC_ACQ_REL,
82 memory_order_seq_cst = __ATOMIC_SEQ_CST
83} memory_order;
84
85#endif
96template <typename T>
97struct Atomic;
98
99template <>
100struct Atomic<int32_t>
101{
102 Atomic(int32_t value) : value(value) {}
103
104 int32_t fetch_add(int32_t val)
105 {
106#if _MSC_VER
107 int32_t res;
108 res = _InterlockedExchangeAdd(reinterpret_cast<volatile long*>(&value), val);
109 return res;
110#else
111 return __atomic_fetch_add(&value, val, __ATOMIC_SEQ_CST);
112#endif
113 }
114
115 int32_t load() const
116 {
117 int32_t res;
118#if _MSC_VER
119 res = __iso_volatile_load32(reinterpret_cast<volatile const int*>(&value));
120 SC_COMPILER_MSVC_COMPILER_MEMORY_BARRIER();
121#else
122 __atomic_load(&value, &res, __ATOMIC_SEQ_CST);
123#endif
124 return res;
125 }
126
127 int32_t load(memory_order mem) const
128 {
129 int32_t res;
130#if _MSC_VER
131 res = __iso_volatile_load32(reinterpret_cast<volatile const int*>(&value));
132 SC_COMPILER_MSVC_ATOMIC_LOAD_VERIFY_MEMORY_ORDER(mem);
133#else
134 __atomic_load(&value, &res, mem);
135#endif
136 return res;
137 }
138
139 private:
140 volatile int32_t value;
141};
142
143template <>
144struct Atomic<bool>
145{
146 Atomic(bool value) : value(value) {}
147
148 bool exchange(bool desired)
149 {
150#if _MSC_VER
151 return static_cast<bool>(_InterlockedExchange8(reinterpret_cast<volatile char*>(&value), desired));
152#else
153 bool res;
154 __atomic_exchange(&value, &desired, &res, __ATOMIC_SEQ_CST);
155 return res;
156#endif
157 }
158
159 bool load() const
160 {
161#if _MSC_VER
162 char res = __iso_volatile_load8(reinterpret_cast<volatile const char*>(&value));
163 SC_COMPILER_MSVC_COMPILER_MEMORY_BARRIER();
164 return reinterpret_cast<bool&>(res);
165#else
166 bool res;
167 __atomic_load(&value, &res, __ATOMIC_SEQ_CST);
168 return res;
169#endif
170 }
171
172 bool load(memory_order mem) const
173 {
174#if _MSC_VER
175 char res = __iso_volatile_load8(reinterpret_cast<volatile const char*>(&value));
176 SC_COMPILER_MSVC_ATOMIC_LOAD_VERIFY_MEMORY_ORDER(mem);
177 return reinterpret_cast<bool&>(res);
178#else
179 bool res;
180 __atomic_load(&value, &res, mem);
181 return res;
182#endif
183 }
184
185 private:
186 volatile bool value;
187};
188
189} // namespace SC
190
191#undef SC_COMPILER_MSVC_ATOMIC_LOAD_VERIFY_MEMORY_ORDER
192#undef SC_COMPILER_MSVC_DISABLE_DEPRECATED_WARNING
193#undef SC_COMPILER_MSVC_RESTORE_DEPRECATED_WARNING
194#undef SC_COMPILER_MSVC_COMPILER_BARRIER
195#undef SC_COMPILER_MSVC_MEMORY_BARRIER
196#undef SC_COMPILER_MSVC_COMPILER_MEMORY_BARRIER
int int32_t
Platform independent (4) bytes signed int.
Definition: PrimitiveTypes.h:46
Atomic variables (only for int and bool for now).
Definition: Atomic.h:97