[runtime] When attaching a tools thread, spin-wait for thread system init. Fixes...
[mono.git] / mono / utils / atomic.c
old mode 100755 (executable)
new mode 100644 (file)
index 0f4ae57..9ab8746
 #include <glib.h>
 
 #include <mono/utils/atomic.h>
+#include <mono/utils/mono-mutex.h>
 
-#if defined (WAPI_NO_ATOMIC_ASM) || !defined (HAS_64BITS_ATOMICS)
+#if defined (WAPI_NO_ATOMIC_ASM) || defined (BROKEN_64BIT_ATOMICS_INTRINSIC)
 
 #include <pthread.h>
 
-static pthread_mutex_t spin = PTHREAD_MUTEX_INITIALIZER;
+static pthread_mutex_t spin G_GNUC_UNUSED = PTHREAD_MUTEX_INITIALIZER;
+
+#define NEED_64BIT_CMPXCHG_FALLBACK
 
 #endif
 
 #ifdef WAPI_NO_ATOMIC_ASM
 
-static mono_once_t spin_once=MONO_ONCE_INIT;
-
-static void spin_init(void)
-{
-       g_warning("Using non-atomic functions!  Expect race conditions when using process-shared handles!");
-}
-
 gint32 InterlockedCompareExchange(volatile gint32 *dest, gint32 exch,
                                  gint32 comp)
 {
        gint32 old;
        int ret;
        
-       mono_once(&spin_once, spin_init);
-       
        pthread_cleanup_push ((void(*)(void *))pthread_mutex_unlock,
                              (void *)&spin);
        ret = pthread_mutex_lock(&spin);
@@ -62,8 +56,6 @@ gpointer InterlockedCompareExchangePointer(volatile gpointer *dest,
        gpointer old;
        int ret;
        
-       mono_once(&spin_once, spin_init);
-       
        pthread_cleanup_push ((void(*)(void *))pthread_mutex_unlock,
                              (void *)&spin);
        ret = pthread_mutex_lock(&spin);
@@ -82,13 +74,53 @@ gpointer InterlockedCompareExchangePointer(volatile gpointer *dest,
        return(old);
 }
 
+gint32 InterlockedAdd(volatile gint32 *dest, gint32 add)
+{
+       gint32 ret;
+       int thr_ret;
+
+       pthread_cleanup_push ((void(*)(void *))pthread_mutex_unlock,
+                             (void *)&spin);
+       thr_ret = pthread_mutex_lock(&spin);
+       g_assert (thr_ret == 0);
+
+       *dest += add;
+       ret= *dest;
+
+       thr_ret = pthread_mutex_unlock(&spin);
+       g_assert (thr_ret == 0);
+
+       pthread_cleanup_pop (0);
+
+       return(ret);
+}
+
+gint64 InterlockedAdd64(volatile gint64 *dest, gint64 add)
+{
+       gint64 ret;
+       int thr_ret;
+
+       pthread_cleanup_push ((void(*)(void *))pthread_mutex_unlock,
+                             (void *)&spin);
+       thr_ret = pthread_mutex_lock(&spin);
+       g_assert (thr_ret == 0);
+
+       *dest += add;
+       ret= *dest;
+
+       thr_ret = pthread_mutex_unlock(&spin);
+       g_assert (thr_ret == 0);
+
+       pthread_cleanup_pop (0);
+
+       return(ret);
+}
+
 gint32 InterlockedIncrement(volatile gint32 *dest)
 {
        gint32 ret;
        int thr_ret;
        
-       mono_once(&spin_once, spin_init);
-       
        pthread_cleanup_push ((void(*)(void *))pthread_mutex_unlock,
                              (void *)&spin);
        thr_ret = pthread_mutex_lock(&spin);
@@ -105,13 +137,32 @@ gint32 InterlockedIncrement(volatile gint32 *dest)
        return(ret);
 }
 
+gint64 InterlockedIncrement64(volatile gint64 *dest)
+{
+       gint64 ret;
+       int thr_ret;
+
+       pthread_cleanup_push ((void(*)(void *))pthread_mutex_unlock,
+                             (void *)&spin);
+       thr_ret = pthread_mutex_lock(&spin);
+       g_assert (thr_ret == 0);
+
+       (*dest)++;
+       ret= *dest;
+
+       thr_ret = pthread_mutex_unlock(&spin);
+       g_assert (thr_ret == 0);
+
+       pthread_cleanup_pop (0);
+
+       return(ret);
+}
+
 gint32 InterlockedDecrement(volatile gint32 *dest)
 {
        gint32 ret;
        int thr_ret;
        
-       mono_once(&spin_once, spin_init);
-       
        pthread_cleanup_push ((void(*)(void *))pthread_mutex_unlock,
                              (void *)&spin);
        thr_ret = pthread_mutex_lock(&spin);
@@ -128,13 +179,32 @@ gint32 InterlockedDecrement(volatile gint32 *dest)
        return(ret);
 }
 
+gint64 InterlockedDecrement64(volatile gint64 *dest)
+{
+       gint64 ret;
+       int thr_ret;
+
+       pthread_cleanup_push ((void(*)(void *))pthread_mutex_unlock,
+                             (void *)&spin);
+       thr_ret = pthread_mutex_lock(&spin);
+       g_assert (thr_ret == 0);
+
+       (*dest)--;
+       ret= *dest;
+
+       thr_ret = pthread_mutex_unlock(&spin);
+       g_assert (thr_ret == 0);
+
+       pthread_cleanup_pop (0);
+
+       return(ret);
+}
+
 gint32 InterlockedExchange(volatile gint32 *dest, gint32 exch)
 {
        gint32 ret;
        int thr_ret;
        
-       mono_once(&spin_once, spin_init);
-       
        pthread_cleanup_push ((void(*)(void *))pthread_mutex_unlock,
                              (void *)&spin);
        thr_ret = pthread_mutex_lock(&spin);
@@ -151,13 +221,32 @@ gint32 InterlockedExchange(volatile gint32 *dest, gint32 exch)
        return(ret);
 }
 
+gint64 InterlockedExchange64(volatile gint64 *dest, gint64 exch)
+{
+       gint64 ret;
+       int thr_ret;
+
+       pthread_cleanup_push ((void(*)(void *))pthread_mutex_unlock,
+                             (void *)&spin);
+       thr_ret = pthread_mutex_lock(&spin);
+       g_assert (thr_ret == 0);
+
+       ret=*dest;
+       *dest=exch;
+
+       thr_ret = pthread_mutex_unlock(&spin);
+       g_assert (thr_ret == 0);
+
+       pthread_cleanup_pop (0);
+
+       return(ret);
+}
+
 gpointer InterlockedExchangePointer(volatile gpointer *dest, gpointer exch)
 {
        gpointer ret;
        int thr_ret;
        
-       mono_once(&spin_once, spin_init);
-       
        pthread_cleanup_push ((void(*)(void *))pthread_mutex_unlock,
                              (void *)&spin);
        thr_ret = pthread_mutex_lock(&spin);
@@ -179,7 +268,26 @@ gint32 InterlockedExchangeAdd(volatile gint32 *dest, gint32 add)
        gint32 ret;
        int thr_ret;
        
-       mono_once(&spin_once, spin_init);
+       pthread_cleanup_push ((void(*)(void *))pthread_mutex_unlock,
+                             (void *)&spin);
+       thr_ret = pthread_mutex_lock(&spin);
+       g_assert (thr_ret == 0);
+
+       ret= *dest;
+       *dest+=add;
+       
+       thr_ret = pthread_mutex_unlock(&spin);
+       g_assert (thr_ret == 0);
+
+       pthread_cleanup_pop (0);
+
+       return(ret);
+}
+
+gint64 InterlockedExchangeAdd64(volatile gint64 *dest, gint64 add)
+{
+       gint64 ret;
+       int thr_ret;
        
        pthread_cleanup_push ((void(*)(void *))pthread_mutex_unlock,
                              (void *)&spin);
@@ -197,40 +305,198 @@ gint32 InterlockedExchangeAdd(volatile gint32 *dest, gint32 add)
        return(ret);
 }
 
-#endif
+gint8 InterlockedRead8(volatile gint8 *src)
+{
+       gint8 ret;
+       int thr_ret;
+       
+       pthread_cleanup_push ((void(*)(void *))pthread_mutex_unlock,
+                             (void *)&spin);
+       thr_ret = pthread_mutex_lock(&spin);
+       g_assert (thr_ret == 0);
+
+       ret= *src;
+       
+       thr_ret = pthread_mutex_unlock(&spin);
+       g_assert (thr_ret == 0);
 
-#ifndef HAS_64BITS_ATOMICS
+       pthread_cleanup_pop (0);
 
-#if defined (TARGET_MACH) && defined (TARGET_ARM) && (defined(__ARM_ARCH_7__) || defined(__ARM_ARCH_7A__) || defined(__ARM_ARCH_7S__))
+       return(ret);
+}
 
-gint64 InterlockedCompareExchange64(volatile gint64 *dest, gint64 exch, gint64 comp)  __attribute__ ((naked));
+gint16 InterlockedRead16(volatile gint16 *src)
+{
+       gint16 ret;
+       int thr_ret;
+       
+       pthread_cleanup_push ((void(*)(void *))pthread_mutex_unlock,
+                             (void *)&spin);
+       thr_ret = pthread_mutex_lock(&spin);
+       g_assert (thr_ret == 0);
 
-gint64
-InterlockedCompareExchange64(volatile gint64 *dest, gint64 exch, gint64 comp)
+       ret= *src;
+       
+       thr_ret = pthread_mutex_unlock(&spin);
+       g_assert (thr_ret == 0);
+
+       pthread_cleanup_pop (0);
+
+       return(ret);
+}
+
+gint32 InterlockedRead(volatile gint32 *src)
+{
+       gint32 ret;
+       int thr_ret;
+       
+       pthread_cleanup_push ((void(*)(void *))pthread_mutex_unlock,
+                             (void *)&spin);
+       thr_ret = pthread_mutex_lock(&spin);
+       g_assert (thr_ret == 0);
+
+       ret= *src;
+       
+       thr_ret = pthread_mutex_unlock(&spin);
+       g_assert (thr_ret == 0);
+
+       pthread_cleanup_pop (0);
+
+       return(ret);
+}
+
+gint64 InterlockedRead64(volatile gint64 *src)
+{
+       gint64 ret;
+       int thr_ret;
+       
+       pthread_cleanup_push ((void(*)(void *))pthread_mutex_unlock,
+                             (void *)&spin);
+       thr_ret = pthread_mutex_lock(&spin);
+       g_assert (thr_ret == 0);
+
+       ret= *src;
+       
+       thr_ret = pthread_mutex_unlock(&spin);
+       g_assert (thr_ret == 0);
+
+       pthread_cleanup_pop (0);
+
+       return(ret);
+}
+
+gpointer InterlockedReadPointer(volatile gpointer *src)
+{
+       gpointer ret;
+       int thr_ret;
+       
+       pthread_cleanup_push ((void(*)(void *))pthread_mutex_unlock,
+                             (void *)&spin);
+       thr_ret = pthread_mutex_lock(&spin);
+       g_assert (thr_ret == 0);
+
+       ret= *src;
+       
+       thr_ret = pthread_mutex_unlock(&spin);
+       g_assert (thr_ret == 0);
+
+       pthread_cleanup_pop (0);
+
+       return(ret);
+}
+
+void InterlockedWrite(volatile gint8 *dst, gint8 val)
+{
+       int thr_ret;
+       
+       pthread_cleanup_push ((void(*)(void *))pthread_mutex_unlock,
+                             (void *)&spin);
+       thr_ret = pthread_mutex_lock(&spin);
+       g_assert (thr_ret == 0);
+
+       *dst=val;
+       
+       thr_ret = pthread_mutex_unlock(&spin);
+       g_assert (thr_ret == 0);
+       
+       pthread_cleanup_pop (0);
+}
+
+void InterlockedWrite16(volatile gint16 *dst, gint16 val)
+{
+       int thr_ret;
+       
+       pthread_cleanup_push ((void(*)(void *))pthread_mutex_unlock,
+                             (void *)&spin);
+       thr_ret = pthread_mutex_lock(&spin);
+       g_assert (thr_ret == 0);
+
+       *dst=val;
+       
+       thr_ret = pthread_mutex_unlock(&spin);
+       g_assert (thr_ret == 0);
+       
+       pthread_cleanup_pop (0);
+}
+
+void InterlockedWrite(volatile gint32 *dst, gint32 val)
 {
-       __asm__ (
-       "push {r4, r5, r6, r7}\n"
-       "ldr r4, [sp, #16]\n"
-       "dmb\n"
-"1:\n"
-       "ldrexd r6, r7, [r0]\n"
-       "cmp    r7, r4\n"
-       "bne 2f\n"
-       "cmp    r6, r3\n"
-       "bne    2f\n"
-       "strexd r5, r1, r2, [r0]\n"
-       "cmp    r5, #0\n"
-       "bne    1b\n"
-"2:\n"
-       "dmb\n"
-       "mov    r0, r6\n"
-       "mov    r1, r7\n"
-       "pop {r4, r5, r6, r7}\n"
-       "bx     lr\n"
-       );
+       int thr_ret;
+       
+       pthread_cleanup_push ((void(*)(void *))pthread_mutex_unlock,
+                             (void *)&spin);
+       thr_ret = pthread_mutex_lock(&spin);
+       g_assert (thr_ret == 0);
+
+       *dst=val;
+       
+       thr_ret = pthread_mutex_unlock(&spin);
+       g_assert (thr_ret == 0);
+       
+       pthread_cleanup_pop (0);
 }
 
-#elif defined (TARGET_MACH) && (defined (TARGET_X86) || defined (TARGET_AMD64))
+void InterlockedWrite64(volatile gint64 *dst, gint64 val)
+{
+       int thr_ret;
+       
+       pthread_cleanup_push ((void(*)(void *))pthread_mutex_unlock,
+                             (void *)&spin);
+       thr_ret = pthread_mutex_lock(&spin);
+       g_assert (thr_ret == 0);
+
+       *dst=val;
+       
+       thr_ret = pthread_mutex_unlock(&spin);
+       g_assert (thr_ret == 0);
+       
+       pthread_cleanup_pop (0);
+}
+
+void InterlockedWritePointer(volatile gpointer *dst, gpointer val)
+{
+       int thr_ret;
+       
+       pthread_cleanup_push ((void(*)(void *))pthread_mutex_unlock,
+                             (void *)&spin);
+       thr_ret = pthread_mutex_lock(&spin);
+       g_assert (thr_ret == 0);
+
+       *dst=val;
+       
+       thr_ret = pthread_mutex_unlock(&spin);
+       g_assert (thr_ret == 0);
+       
+       pthread_cleanup_pop (0);
+}
+
+#endif
+
+#if defined (NEED_64BIT_CMPXCHG_FALLBACK)
+
+#if defined (TARGET_OSX)
+
+/* The compiler breaks if this code is in the header... */
 
 gint64
 InterlockedCompareExchange64(volatile gint64 *dest, gint64 exch, gint64 comp)
@@ -238,22 +504,38 @@ InterlockedCompareExchange64(volatile gint64 *dest, gint64 exch, gint64 comp)
        return __sync_val_compare_and_swap (dest, comp, exch);
 }
 
+#elif defined (HAVE_64BIT_CMPXCHG_FALLBACK)
+
+#ifdef ENABLE_EXTENSION_MODULE
+#include "../../../mono-extensions/mono/utils/atomic.c"
+#endif
+
 #else
 
 gint64
 InterlockedCompareExchange64(volatile gint64 *dest, gint64 exch, gint64 comp)
 {
        gint64 old;
+       int ret;
+       
+       pthread_cleanup_push ((void(*)(void *))pthread_mutex_unlock,
+                             (void *)&spin);
+       ret = pthread_mutex_lock(&spin);
+       g_assert (ret == 0);
+       
+       old= *dest;
+       if(old==comp) {
+               *dest=exch;
+       }
+       
+       ret = pthread_mutex_unlock(&spin);
+       g_assert (ret == 0);
+       
+       pthread_cleanup_pop (0);
 
-       pthread_mutex_lock (&spin);
-
-       old = *dest;
-       if(old == comp)
-               *dest = exch;
-
-       pthread_mutex_unlock (&spin);
-       return old;
+       return(old);
 }
 
 #endif
+
 #endif