Add memory barriers to interlocked operations on ARM, since the runtime code depends...
[mono.git] / mono / io-layer / atomic.h
index 2a2f2975d37fa5a5927685c1fed17f5f352a26f3..d2b9d6394b850c1680c94bc2929f56ade1449f79 100644 (file)
@@ -744,11 +744,17 @@ static inline gint32 InterlockedExchangeAdd(volatile gint32 *dest, gint32 add)
 #elif defined(__arm__)
 #define WAPI_ATOMIC_ASM
 
+/*
+ * Atomic operations on ARM doesn't contain memory barriers, and the runtime code
+ * depends on this, so we add them explicitly.
+ */
+
 static inline gint32 InterlockedCompareExchange(volatile gint32 *dest, gint32 exch, gint32 comp)
 {
 #if defined(__ARM_ARCH_6__) || defined(__ARM_ARCH_7A__) || defined(__ARM_ARCH_7__)
        gint32 ret, tmp;
        __asm__ __volatile__ (  "1:\n"
+                               "dmb\n"
                                "mov    %0, #0\n"
                                "ldrex %1, [%2]\n"
                                "teq    %1, %3\n"
@@ -756,6 +762,7 @@ static inline gint32 InterlockedCompareExchange(volatile gint32 *dest, gint32 ex
                                "strexeq %0, %4, [%2]\n"
                                "teq %0, #0\n"
                                "bne 1b\n"
+                               "dmb\n"
                                : "=&r" (tmp), "=&r" (ret)
                                : "r" (dest), "r" (comp), "r" (exch)
                                : "memory", "cc");
@@ -786,7 +793,9 @@ static inline gpointer InterlockedCompareExchangePointer(volatile gpointer *dest
 {
 #if defined(__ARM_ARCH_6__) || defined(__ARM_ARCH_7A__) || defined(__ARM_ARCH_7__)
        gpointer ret, tmp;
-       __asm__ __volatile__ (  "1:\n"
+       __asm__ __volatile__ (
+                               "dmb\n"
+                               "1:\n"
                                "mov    %0, #0\n"
                                "ldrex %1, [%2]\n"
                                "teq    %1, %3\n"
@@ -794,6 +803,7 @@ static inline gpointer InterlockedCompareExchangePointer(volatile gpointer *dest
                                "strexeq %0, %4, [%2]\n"
                                "teq %0, #0\n"
                                "bne 1b\n"
+                               "dmb\n"
                                : "=&r" (tmp), "=&r" (ret)
                                : "r" (dest), "r" (comp), "r" (exch)
                                : "memory", "cc");
@@ -824,12 +834,15 @@ static inline gint32 InterlockedIncrement(volatile gint32 *dest)
 {
 #if defined(__ARM_ARCH_6__) || defined(__ARM_ARCH_7A__) || defined(__ARM_ARCH_7__)
        gint32 ret, flag;
-       __asm__ __volatile__ (  "1:\n"
+       __asm__ __volatile__ (
+                               "dmb\n"
+                               "1:\n"
                                "ldrex %0, [%2]\n"
                                "add %0, %0, %3\n"
                                "strex %1, %0, [%2]\n"
                                "teq %1, #0\n"
                                "bne 1b\n"
+                               "dmb\n"
                                : "=&r" (ret), "=&r" (flag)
                                : "r" (dest), "r" (1)
                                : "memory", "cc");
@@ -857,12 +870,15 @@ static inline gint32 InterlockedDecrement(volatile gint32 *dest)
 {
 #if defined(__ARM_ARCH_6__) || defined(__ARM_ARCH_7A__) || defined(__ARM_ARCH_7__)
        gint32 ret, flag;
-       __asm__ __volatile__ (  "1:\n"
+       __asm__ __volatile__ (
+                               "dmb\n"
+                               "1:\n"
                                "ldrex %0, [%2]\n"
                                "sub %0, %0, %3\n"
                                "strex %1, %0, [%2]\n"
                                "teq %1, #0\n"
                                "bne 1b\n"
+                               "dmb\n"
                                : "=&r" (ret), "=&r" (flag)
                                : "r" (dest), "r" (1)
                                : "memory", "cc");
@@ -891,11 +907,13 @@ static inline gint32 InterlockedExchange(volatile gint32 *dest, gint32 exch)
 #if defined(__ARM_ARCH_6__) || defined(__ARM_ARCH_7A__) || defined(__ARM_ARCH_7__)
        gint32 ret, flag;
        __asm__ __volatile__ (
+                                 "dmb\n"
                              "1:\n"
                              "ldrex %0, [%3]\n"
                              "strex %1, %2, [%3]\n"
                              "teq %1, #0\n"
                              "bne 1b\n"
+                                 "dmb\n"
                              : "=&r" (ret), "=&r" (flag)
                              : "r" (exch), "r" (dest)
                              : "memory", "cc");
@@ -916,11 +934,13 @@ static inline gpointer InterlockedExchangePointer(volatile gpointer *dest, gpoin
 #if defined(__ARM_ARCH_6__) || defined(__ARM_ARCH_7A__) || defined(__ARM_ARCH_7__)
        gpointer ret, flag;
        __asm__ __volatile__ (
+                                 "dmb\n"
                              "1:\n"
                              "ldrex %0, [%3]\n"
                              "strex %1, %2, [%3]\n"
                              "teq %1, #0\n"
                              "bne 1b\n"
+                                 "dmb\n"
                              : "=&r" (ret), "=&r" (flag)
                              : "r" (exch), "r" (dest)
                              : "memory", "cc");
@@ -940,12 +960,15 @@ static inline gint32 InterlockedExchangeAdd(volatile gint32 *dest, gint32 add)
 {
 #if defined(__ARM_ARCH_6__) || defined(__ARM_ARCH_7A__) || defined(__ARM_ARCH_7__)
        gint32 ret, tmp, flag;
-       __asm__ __volatile__ (  "1:\n"
+       __asm__ __volatile__ (
+                               "dmb\n"
+                               "1:\n"
                                "ldrex %0, [%3]\n"
                                "add %1, %0, %4\n"
                                "strex %2, %1, [%3]\n"
                                "teq %2, #0\n"
                                "bne 1b\n"
+                               "dmb\n"
                                : "=&r" (ret), "=&r" (tmp), "=&r" (flag)
                                : "r" (dest), "r" (add)
                                : "memory", "cc");