2 * atomic.c: Workarounds for atomic operations for platforms that dont have
3 * really atomic asm functions in atomic.h
6 * Dick Porter (dick@ximian.com)
8 * (C) 2002 Ximian, Inc.
14 #include <mono/utils/atomic.h>
16 #if defined (WAPI_NO_ATOMIC_ASM) || defined (BROKEN_64BIT_ATOMICS_INTRINSIC)
20 static pthread_mutex_t spin G_GNUC_UNUSED = PTHREAD_MUTEX_INITIALIZER;
22 #define NEED_64BIT_CMPXCHG_FALLBACK
26 #ifdef WAPI_NO_ATOMIC_ASM
28 gint32 InterlockedCompareExchange(volatile gint32 *dest, gint32 exch,
34 pthread_cleanup_push ((void(*)(void *))pthread_mutex_unlock,
36 ret = pthread_mutex_lock(&spin);
44 ret = pthread_mutex_unlock(&spin);
47 pthread_cleanup_pop (0);
52 gpointer InterlockedCompareExchangePointer(volatile gpointer *dest,
53 gpointer exch, gpointer comp)
58 pthread_cleanup_push ((void(*)(void *))pthread_mutex_unlock,
60 ret = pthread_mutex_lock(&spin);
68 ret = pthread_mutex_unlock(&spin);
71 pthread_cleanup_pop (0);
76 gint32 InterlockedAdd(volatile gint32 *dest, gint32 add)
81 pthread_cleanup_push ((void(*)(void *))pthread_mutex_unlock,
83 thr_ret = pthread_mutex_lock(&spin);
84 g_assert (thr_ret == 0);
89 thr_ret = pthread_mutex_unlock(&spin);
90 g_assert (thr_ret == 0);
92 pthread_cleanup_pop (0);
97 gint64 InterlockedAdd64(volatile gint64 *dest, gint64 add)
102 pthread_cleanup_push ((void(*)(void *))pthread_mutex_unlock,
104 thr_ret = pthread_mutex_lock(&spin);
105 g_assert (thr_ret == 0);
110 thr_ret = pthread_mutex_unlock(&spin);
111 g_assert (thr_ret == 0);
113 pthread_cleanup_pop (0);
118 gint32 InterlockedIncrement(volatile gint32 *dest)
123 pthread_cleanup_push ((void(*)(void *))pthread_mutex_unlock,
125 thr_ret = pthread_mutex_lock(&spin);
126 g_assert (thr_ret == 0);
131 thr_ret = pthread_mutex_unlock(&spin);
132 g_assert (thr_ret == 0);
134 pthread_cleanup_pop (0);
139 gint64 InterlockedIncrement64(volatile gint64 *dest)
144 pthread_cleanup_push ((void(*)(void *))pthread_mutex_unlock,
146 thr_ret = pthread_mutex_lock(&spin);
147 g_assert (thr_ret == 0);
152 thr_ret = pthread_mutex_unlock(&spin);
153 g_assert (thr_ret == 0);
155 pthread_cleanup_pop (0);
160 gint32 InterlockedDecrement(volatile gint32 *dest)
165 pthread_cleanup_push ((void(*)(void *))pthread_mutex_unlock,
167 thr_ret = pthread_mutex_lock(&spin);
168 g_assert (thr_ret == 0);
173 thr_ret = pthread_mutex_unlock(&spin);
174 g_assert (thr_ret == 0);
176 pthread_cleanup_pop (0);
181 gint64 InterlockedDecrement64(volatile gint64 *dest)
186 pthread_cleanup_push ((void(*)(void *))pthread_mutex_unlock,
188 thr_ret = pthread_mutex_lock(&spin);
189 g_assert (thr_ret == 0);
194 thr_ret = pthread_mutex_unlock(&spin);
195 g_assert (thr_ret == 0);
197 pthread_cleanup_pop (0);
202 gint32 InterlockedExchange(volatile gint32 *dest, gint32 exch)
207 pthread_cleanup_push ((void(*)(void *))pthread_mutex_unlock,
209 thr_ret = pthread_mutex_lock(&spin);
210 g_assert (thr_ret == 0);
215 thr_ret = pthread_mutex_unlock(&spin);
216 g_assert (thr_ret == 0);
218 pthread_cleanup_pop (0);
223 gint64 InterlockedExchange64(volatile gint64 *dest, gint64 exch)
228 pthread_cleanup_push ((void(*)(void *))pthread_mutex_unlock,
230 thr_ret = pthread_mutex_lock(&spin);
231 g_assert (thr_ret == 0);
236 thr_ret = pthread_mutex_unlock(&spin);
237 g_assert (thr_ret == 0);
239 pthread_cleanup_pop (0);
244 gpointer InterlockedExchangePointer(volatile gpointer *dest, gpointer exch)
249 pthread_cleanup_push ((void(*)(void *))pthread_mutex_unlock,
251 thr_ret = pthread_mutex_lock(&spin);
252 g_assert (thr_ret == 0);
257 thr_ret = pthread_mutex_unlock(&spin);
258 g_assert (thr_ret == 0);
260 pthread_cleanup_pop (0);
265 gint32 InterlockedExchangeAdd(volatile gint32 *dest, gint32 add)
270 pthread_cleanup_push ((void(*)(void *))pthread_mutex_unlock,
272 thr_ret = pthread_mutex_lock(&spin);
273 g_assert (thr_ret == 0);
278 thr_ret = pthread_mutex_unlock(&spin);
279 g_assert (thr_ret == 0);
281 pthread_cleanup_pop (0);
286 gint64 InterlockedExchangeAdd64(volatile gint64 *dest, gint64 add)
291 pthread_cleanup_push ((void(*)(void *))pthread_mutex_unlock,
293 thr_ret = pthread_mutex_lock(&spin);
294 g_assert (thr_ret == 0);
299 thr_ret = pthread_mutex_unlock(&spin);
300 g_assert (thr_ret == 0);
302 pthread_cleanup_pop (0);
307 gint8 InterlockedRead8(volatile gint8 *src)
312 pthread_cleanup_push ((void(*)(void *))pthread_mutex_unlock,
314 thr_ret = pthread_mutex_lock(&spin);
315 g_assert (thr_ret == 0);
319 thr_ret = pthread_mutex_unlock(&spin);
320 g_assert (thr_ret == 0);
322 pthread_cleanup_pop (0);
327 gint16 InterlockedRead16(volatile gint16 *src)
332 pthread_cleanup_push ((void(*)(void *))pthread_mutex_unlock,
334 thr_ret = pthread_mutex_lock(&spin);
335 g_assert (thr_ret == 0);
339 thr_ret = pthread_mutex_unlock(&spin);
340 g_assert (thr_ret == 0);
342 pthread_cleanup_pop (0);
347 gint32 InterlockedRead(volatile gint32 *src)
352 pthread_cleanup_push ((void(*)(void *))pthread_mutex_unlock,
354 thr_ret = pthread_mutex_lock(&spin);
355 g_assert (thr_ret == 0);
359 thr_ret = pthread_mutex_unlock(&spin);
360 g_assert (thr_ret == 0);
362 pthread_cleanup_pop (0);
367 gint64 InterlockedRead64(volatile gint64 *src)
372 pthread_cleanup_push ((void(*)(void *))pthread_mutex_unlock,
374 thr_ret = pthread_mutex_lock(&spin);
375 g_assert (thr_ret == 0);
379 thr_ret = pthread_mutex_unlock(&spin);
380 g_assert (thr_ret == 0);
382 pthread_cleanup_pop (0);
387 gpointer InterlockedReadPointer(volatile gpointer *src)
392 pthread_cleanup_push ((void(*)(void *))pthread_mutex_unlock,
394 thr_ret = pthread_mutex_lock(&spin);
395 g_assert (thr_ret == 0);
399 thr_ret = pthread_mutex_unlock(&spin);
400 g_assert (thr_ret == 0);
402 pthread_cleanup_pop (0);
407 void InterlockedWrite(volatile gint8 *dst, gint8 val)
411 pthread_cleanup_push ((void(*)(void *))pthread_mutex_unlock,
413 thr_ret = pthread_mutex_lock(&spin);
414 g_assert (thr_ret == 0);
418 thr_ret = pthread_mutex_unlock(&spin);
419 g_assert (thr_ret == 0);
421 pthread_cleanup_pop (0);
424 void InterlockedWrite16(volatile gint16 *dst, gint16 val)
428 pthread_cleanup_push ((void(*)(void *))pthread_mutex_unlock,
430 thr_ret = pthread_mutex_lock(&spin);
431 g_assert (thr_ret == 0);
435 thr_ret = pthread_mutex_unlock(&spin);
436 g_assert (thr_ret == 0);
438 pthread_cleanup_pop (0);
441 void InterlockedWrite(volatile gint32 *dst, gint32 val)
445 pthread_cleanup_push ((void(*)(void *))pthread_mutex_unlock,
447 thr_ret = pthread_mutex_lock(&spin);
448 g_assert (thr_ret == 0);
452 thr_ret = pthread_mutex_unlock(&spin);
453 g_assert (thr_ret == 0);
455 pthread_cleanup_pop (0);
458 void InterlockedWrite64(volatile gint64 *dst, gint64 val)
462 pthread_cleanup_push ((void(*)(void *))pthread_mutex_unlock,
464 thr_ret = pthread_mutex_lock(&spin);
465 g_assert (thr_ret == 0);
469 thr_ret = pthread_mutex_unlock(&spin);
470 g_assert (thr_ret == 0);
472 pthread_cleanup_pop (0);
475 void InterlockedWritePointer(volatile gpointer *dst, gpointer val)
479 pthread_cleanup_push ((void(*)(void *))pthread_mutex_unlock,
481 thr_ret = pthread_mutex_lock(&spin);
482 g_assert (thr_ret == 0);
486 thr_ret = pthread_mutex_unlock(&spin);
487 g_assert (thr_ret == 0);
489 pthread_cleanup_pop (0);
494 #if defined (NEED_64BIT_CMPXCHG_FALLBACK)
496 #if defined (TARGET_OSX)
498 /* The compiler breaks if this code is in the header... */
501 InterlockedCompareExchange64(volatile gint64 *dest, gint64 exch, gint64 comp)
503 return __sync_val_compare_and_swap (dest, comp, exch);
506 #elif defined (__arm__) && defined (HAVE_ARMV7) && (defined(TARGET_IOS) || defined(TARGET_WATCHOS) || defined(TARGET_ANDROID))
508 #if defined (TARGET_IOS) || defined (TARGET_WATCHOS)
511 #error "Not supported."
515 InterlockedCompareExchange64(volatile gint64 *dest, gint64 exch, gint64 comp)
517 return __sync_val_compare_and_swap (dest, comp, exch);
520 #elif defined (TARGET_ANDROID)
522 /* Some Android systems can't find the 64-bit CAS intrinsic at runtime,
523 * so we have to roll our own...
526 gint64 InterlockedCompareExchange64(volatile gint64 *dest, gint64 exch, gint64 comp) __attribute__ ((naked));
529 InterlockedCompareExchange64(volatile gint64 *dest, gint64 exch, gint64 comp)
532 "push {r4, r5, r6, r7}\n"
533 "ldrd r4, [sp, #16]\n"
540 "strexd r1, r2, [r0]\n"
547 "pop {r4, r5, r6, r7}\n"
554 #error "Need a 64-bit CAS fallback!"
561 InterlockedCompareExchange64(volatile gint64 *dest, gint64 exch, gint64 comp)
566 pthread_cleanup_push ((void(*)(void *))pthread_mutex_unlock,
568 ret = pthread_mutex_lock(&spin);
576 ret = pthread_mutex_unlock(&spin);
579 pthread_cleanup_pop (0);