@@ -25,7 +25,281 @@ F/MonoDroid( 1568): shared runtime initialization error: Cannot load library: re
25
25
Apple targets have historically being problematic, xcode 4.6 would miscompile the intrinsic.
26
26
*/
27
27
28
- #if defined(HOST_WIN32 )
28
+ /* For each platform, decide what atomic implementation to use.
29
+ *
30
+ * Generally, we can enable C11 atomics if the header is available and if all the primitive types we
31
+ * care about (int, long, void*, long long) are lock-free.
32
+ *
33
+ * Note that we generally don't want the compiler's locking implementation because it may take a
34
+ * global lock, in which case if the atomic is used by both the GC implementation and runtime
35
+ * internals we may have deadlocks during GC suspend.
36
+ *
37
+ * It might be possible to use some Mono specific implementation for specific types (e.g. long long)
38
+ * on some platforms if the standard atomics for some type are not lock-free (for example: long
39
+ * long). We might be able to use a GC-aware lock, for example.
40
+ *
41
+ */
42
+ #undef MONO_USE_C11_ATOMIC
43
+ #undef MONO_USE_WIN32_ATOMIC
44
+ #undef MONO_USE_GCC_ATOMIC
45
+ #undef MONO_USE_EMULATED_ATOMIC
46
+
47
+ #if defined(MONO_GENERATING_OFFSETS )
48
+ /*
49
+ * Hack: for the offsets tool, define MONO_USE_EMULATED_ATOMIC since it doesn't actually need to see
50
+ * the impementation, and the stdatomic ones cause problems on some Linux configurations where
51
+ * libclang sees the platform header, not the clang one.
52
+ */
53
+ # define MONO_USE_EMULATED_ATOMIC 1
54
+ #elif defined(_MSC_VER ) || defined(HOST_WIN32 )
55
+ /*
56
+ * we need two things to switch to C11 atomics on Windows:
57
+ *
58
+ * 1. MSVC atomics support is not experimental, or we pass /experimental:c11atomics
59
+ *
60
+ * 2. We build our C++ code with C++23 or later (otherwise MSVC will complain about including
61
+ * stdatomic.h)
62
+ *
63
+ */
64
+ # define MONO_USE_WIN32_ATOMIC 1
65
+ #elif defined(HOST_IOS ) || defined(HOST_OSX ) || defined(HOST_WATCHOS ) || defined(HOST_TVOS )
66
+ # define MONO_USE_C11_ATOMIC 1
67
+ #elif defined(HOST_ANDROID )
68
+ /* on Android-x86 ATOMIC_LONG_LONG_LOCK_FREE == 1, not 2 like we want. */
69
+ /* on Andriod-x64 ATOMIC_LONG_LOCK_FREE == 1, not 2 */
70
+ /* on Android-armv7 ATOMIC_INT_LOCK_FREE == 1, not 2 */
71
+ # if defined(HOST_ARM64 )
72
+ # define MONO_USE_C11_ATOMIC 1
73
+ # elif defined(USE_GCC_ATOMIC_OPS )
74
+ # define MONO_USE_GCC_ATOMIC 1
75
+ # else
76
+ # define MONO_USE_EMULATED_ATOMIC 1
77
+ # endif
78
+ #elif defined(HOST_LINUX )
79
+ /* FIXME: probably need arch checks */
80
+ # define MONO_USE_C11_ATOMIC 1
81
+ #elif defined(HOST_WASI ) || defined(HOST_BROWSER )
82
+ # define MONO_USE_C11_ATOMIC 1
83
+ #elif defined(USE_GCC_ATOMIC_OPS )
84
+ /* Prefer GCC atomic ops if the target supports it (see configure.ac). */
85
+ # define MONO_USE_GCC_ATOMIC 1
86
+ #else
87
+ # define MONO_USE_EMULATED_ATOMIC 1
88
+ #endif
89
+
90
+ #if defined(MONO_USE_C11_ATOMIC )
91
+
92
+ #include <stdatomic.h>
93
+
94
+ static inline gint32
95
+ mono_atomic_cas_i32 (volatile gint32 * dest , gint32 exch , gint32 comp )
96
+ {
97
+ g_static_assert (sizeof (atomic_int ) == sizeof (* dest ) && ATOMIC_INT_LOCK_FREE == 2 );
98
+ (void )atomic_compare_exchange_strong ((volatile atomic_int * )dest , & comp , exch );
99
+ return comp ;
100
+ }
101
+
102
+ static inline gint64
103
+ mono_atomic_cas_i64 (volatile gint64 * dest , gint64 exch , gint64 comp )
104
+ {
105
+ #if SIZEOF_LONG == 8
106
+ g_static_assert (sizeof (atomic_long ) == sizeof (* dest ) && ATOMIC_LONG_LOCK_FREE == 2 );
107
+ (void )atomic_compare_exchange_strong ((volatile atomic_long * )dest , (long * )& comp , exch );
108
+ return comp ;
109
+ #elif SIZEOF_LONG_LONG == 8
110
+ g_static_assert (sizeof (atomic_llong ) == sizeof (* dest ) && ATOMIC_LLONG_LOCK_FREE == 2 );
111
+ (void )atomic_compare_exchange_strong ((volatile atomic_llong * )dest , (long long * )& comp , exch );
112
+ return comp ;
113
+ #else
114
+ #error gint64 not same size atomic_llong or atomic_long, don't define MONO_USE_STDATOMIC
115
+ #endif
116
+ }
117
+
118
+ static inline gpointer
119
+ mono_atomic_cas_ptr (volatile gpointer * dest , gpointer exch , gpointer comp )
120
+ {
121
+ g_static_assert (ATOMIC_POINTER_LOCK_FREE == 2 );
122
+ (void )atomic_compare_exchange_strong ((volatile _Atomic (gpointer ) * )dest , & comp , exch );
123
+ return comp ;
124
+ }
125
+
126
+ static inline gint32
127
+ mono_atomic_fetch_add_i32 (volatile gint32 * dest , gint32 add );
128
+ static inline gint64
129
+ mono_atomic_fetch_add_i64 (volatile gint64 * dest , gint64 add );
130
+
131
+ static inline gint32
132
+ mono_atomic_add_i32 (volatile gint32 * dest , gint32 add )
133
+ {
134
+ // mono_atomic_add_ is supposed to return the value that is stored.
135
+ // the atomic_add intrinsic returns the previous value instead.
136
+ // so we return prev+add which should be the new value
137
+ return mono_atomic_fetch_add_i32 (dest , add ) + add ;
138
+ }
139
+
140
+ static inline gint64
141
+ mono_atomic_add_i64 (volatile gint64 * dest , gint64 add )
142
+ {
143
+ return mono_atomic_fetch_add_i64 (dest , add ) + add ;
144
+ }
145
+
146
+ static inline gint32
147
+ mono_atomic_inc_i32 (volatile gint32 * dest )
148
+ {
149
+ return mono_atomic_add_i32 (dest , 1 );
150
+ }
151
+
152
+ static inline gint64
153
+ mono_atomic_inc_i64 (volatile gint64 * dest )
154
+ {
155
+ return mono_atomic_add_i64 (dest , 1 );
156
+ }
157
+
158
+ static inline gint32
159
+ mono_atomic_dec_i32 (volatile gint32 * dest )
160
+ {
161
+ return mono_atomic_add_i32 (dest , -1 );
162
+ }
163
+
164
+ static inline gint64
165
+ mono_atomic_dec_i64 (volatile gint64 * dest )
166
+ {
167
+ return mono_atomic_add_i64 (dest , -1 );
168
+ }
169
+
170
+ static inline gint32
171
+ mono_atomic_xchg_i32 (volatile gint32 * dest , gint32 exch )
172
+ {
173
+ g_static_assert (sizeof (atomic_int ) == sizeof (* dest ) && ATOMIC_INT_LOCK_FREE == 2 );
174
+ return atomic_exchange ((volatile atomic_int * )dest , exch );
175
+ }
176
+
177
+ static inline gint64
178
+ mono_atomic_xchg_i64 (volatile gint64 * dest , gint64 exch )
179
+ {
180
+ #if SIZEOF_LONG == 8
181
+ g_static_assert (sizeof (atomic_long ) == sizeof (* dest ) && ATOMIC_LONG_LOCK_FREE == 2 );
182
+ return atomic_exchange ((volatile atomic_long * )dest , exch );
183
+ #elif SIZEOF_LONG_LONG == 8
184
+ g_static_assert (sizeof (atomic_llong ) == sizeof (* dest ) && ATOMIC_LLONG_LOCK_FREE == 2 );
185
+ return atomic_exchange ((volatile atomic_llong * )dest , exch );
186
+ #else
187
+ #error gint64 not same size atomic_llong or atomic_long, don't define MONO_USE_STDATOMIC
188
+ #endif
189
+ }
190
+
191
+ static inline gpointer
192
+ mono_atomic_xchg_ptr (volatile gpointer * dest , gpointer exch )
193
+ {
194
+ g_static_assert (ATOMIC_POINTER_LOCK_FREE == 2 );
195
+ return atomic_exchange ((volatile _Atomic (gpointer ) * )dest , exch );
196
+ }
197
+
198
+ static inline gint32
199
+ mono_atomic_fetch_add_i32 (volatile gint32 * dest , gint32 add )
200
+ {
201
+ g_static_assert (sizeof (atomic_int ) == sizeof (* dest ) && ATOMIC_INT_LOCK_FREE == 2 );
202
+ return atomic_fetch_add ((volatile atomic_int * )dest , add );
203
+ }
204
+
205
+ static inline gint64
206
+ mono_atomic_fetch_add_i64 (volatile gint64 * dest , gint64 add )
207
+ {
208
+ #if SIZEOF_LONG == 8
209
+ g_static_assert (sizeof (atomic_long ) == sizeof (* dest ) && ATOMIC_LONG_LOCK_FREE == 2 );
210
+ return atomic_fetch_add ((volatile atomic_long * )dest , add );
211
+ #elif SIZEOF_LONG_LONG == 8
212
+ g_static_assert (sizeof (atomic_llong ) == sizeof (* dest ) && ATOMIC_LLONG_LOCK_FREE == 2 );
213
+ return atomic_fetch_add ((volatile atomic_llong * )dest , add );
214
+ #else
215
+ #error gint64 not same size atomic_llong or atomic_long, don't define MONO_USE_STDATOMIC
216
+ #endif
217
+ }
218
+
219
+ static inline gint8
220
+ mono_atomic_load_i8 (volatile gint8 * src )
221
+ {
222
+ g_static_assert (sizeof (atomic_char ) == sizeof (* src ) && ATOMIC_CHAR_LOCK_FREE == 2 );
223
+ return atomic_load ((volatile atomic_char * )src );
224
+ }
225
+
226
+ static inline gint16
227
+ mono_atomic_load_i16 (volatile gint16 * src )
228
+ {
229
+ g_static_assert (sizeof (atomic_short ) == sizeof (* src ) && ATOMIC_SHORT_LOCK_FREE == 2 );
230
+ return atomic_load ((volatile atomic_short * )src );
231
+ }
232
+
233
+ static inline gint32 mono_atomic_load_i32 (volatile gint32 * src )
234
+ {
235
+ g_static_assert (sizeof (atomic_int ) == sizeof (* src ) && ATOMIC_INT_LOCK_FREE == 2 );
236
+ return atomic_load ((volatile atomic_int * )src );
237
+ }
238
+
239
+ static inline gint64
240
+ mono_atomic_load_i64 (volatile gint64 * src )
241
+ {
242
+ #if SIZEOF_LONG == 8
243
+ g_static_assert (sizeof (atomic_long ) == sizeof (* src ) && ATOMIC_LONG_LOCK_FREE == 2 );
244
+ return atomic_load ((volatile atomic_long * )src );
245
+ #elif SIZEOF_LONG_LONG == 8
246
+ g_static_assert (sizeof (atomic_llong ) == sizeof (* src ) && ATOMIC_LLONG_LOCK_FREE == 2 );
247
+ return atomic_load ((volatile atomic_llong * )src );
248
+ #else
249
+ #error gint64 not same size atomic_llong or atomic_long, don't define MONO_USE_STDATOMIC
250
+ #endif
251
+ }
252
+
253
+ static inline gpointer
254
+ mono_atomic_load_ptr (volatile gpointer * src )
255
+ {
256
+ g_static_assert (ATOMIC_POINTER_LOCK_FREE == 2 );
257
+ return atomic_load ((volatile _Atomic (gpointer ) * )src );
258
+ }
259
+
260
+ static inline void
261
+ mono_atomic_store_i8 (volatile gint8 * dst , gint8 val )
262
+ {
263
+ g_static_assert (sizeof (atomic_char ) == sizeof (* dst ) && ATOMIC_CHAR_LOCK_FREE == 2 );
264
+ atomic_store ((volatile atomic_char * )dst , val );
265
+ }
266
+
267
+ static inline void
268
+ mono_atomic_store_i16 (volatile gint16 * dst , gint16 val )
269
+ {
270
+ g_static_assert (sizeof (atomic_short ) == sizeof (* dst ) && ATOMIC_SHORT_LOCK_FREE == 2 );
271
+ atomic_store ((volatile atomic_short * )dst , val );
272
+ }
273
+
274
+ static inline void
275
+ mono_atomic_store_i32 (volatile gint32 * dst , gint32 val )
276
+ {
277
+ g_static_assert (sizeof (atomic_int ) == sizeof (* dst ) && ATOMIC_INT_LOCK_FREE == 2 );
278
+ atomic_store ((atomic_int * )dst , val );
279
+ }
280
+
281
+ static inline void
282
+ mono_atomic_store_i64 (volatile gint64 * dst , gint64 val )
283
+ {
284
+ #if SIZEOF_LONG == 8
285
+ g_static_assert (sizeof (atomic_long ) == sizeof (* dst ) && ATOMIC_LONG_LOCK_FREE == 2 );
286
+ atomic_store ((volatile atomic_long * )dst , val );
287
+ #elif SIZEOF_LONG_LONG == 8
288
+ g_static_assert (sizeof (atomic_llong ) == sizeof (* dst ) && ATOMIC_LLONG_LOCK_FREE == 2 );
289
+ atomic_store ((volatile atomic_llong * )dst , val );
290
+ #else
291
+ #error gint64 not same size atomic_llong or atomic_long, don't define MONO_USE_STDATOMIC
292
+ #endif
293
+ }
294
+
295
+ static inline void
296
+ mono_atomic_store_ptr (volatile gpointer * dst , gpointer val )
297
+ {
298
+ g_static_assert (ATOMIC_POINTER_LOCK_FREE == 2 );
299
+ atomic_store ((volatile _Atomic (gpointer ) * )dst , val );
300
+ }
301
+
302
+ #elif defined(MONO_USE_WIN32_ATOMIC )
29
303
30
304
#ifndef WIN32_LEAN_AND_MEAN
31
305
#define WIN32_LEAN_AND_MEAN
@@ -204,8 +478,8 @@ mono_atomic_store_ptr (volatile gpointer *dst, gpointer val)
204
478
InterlockedExchangePointer ((PVOID volatile * )dst , (PVOID )val );
205
479
}
206
480
207
- /* Prefer GCC atomic ops if the target supports it (see configure.ac). */
208
- #elif defined(USE_GCC_ATOMIC_OPS )
481
+
482
+ #elif defined(MONO_USE_GCC_ATOMIC )
209
483
210
484
/*
211
485
* As of this comment (August 2016), all current Clang versions get atomic
@@ -453,7 +727,7 @@ static inline void mono_atomic_store_i64(volatile gint64 *dst, gint64 val)
453
727
mono_atomic_xchg_i64 (dst , val );
454
728
}
455
729
456
- #else
730
+ #elif defined( MONO_USE_EMULATED_ATOMIC )
457
731
458
732
#define WAPI_NO_ATOMIC_ASM
459
733
@@ -482,6 +756,8 @@ extern void mono_atomic_store_i32(volatile gint32 *dst, gint32 val);
482
756
extern void mono_atomic_store_i64 (volatile gint64 * dst , gint64 val );
483
757
extern void mono_atomic_store_ptr (volatile gpointer * dst , gpointer val );
484
758
759
+ #else
760
+ #error one of MONO_USE_C11_ATOMIC, MONO_USE_WIN32_ATOMIC, MONO_USE_GCC_ATOMIC or MONO_USE_EMULATED_ATOMIC must be defined
485
761
#endif
486
762
487
763
#if SIZEOF_VOID_P == 4
0 commit comments