First set of licensing changes
[mono.git] / mono / utils / atomic.h
index 79455ad9c435c889e9e2fb5289b365324b2ea29a..78ab036a22b9f2b013fb61bb946113306110f29a 100755 (executable)
@@ -6,6 +6,7 @@
  *
  * (C) 2002 Ximian, Inc.
  * Copyright 2012 Xamarin Inc
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
  */
 
 #ifndef _WAPI_ATOMIC_H_
 #include "config.h"
 #include <glib.h>
 
-#ifdef ENABLE_EXTENSION_MODULE
-#include "../../../mono-extensions/mono/utils/atomic.h"
+/*
+The current Nexus 7 arm-v7a fails with:
+F/MonoDroid( 1568): shared runtime initialization error: Cannot load library: reloc_library[1285]:    37 cannot locate '__sync_val_compare_and_swap_8'
+
+Apple targets have historically being problematic, xcode 4.6 would miscompile the intrinsic.
+*/
+
+#if defined (__arm__) && defined (HAVE_ARMV7)
+#define HAVE_64BIT_CMPXCHG_FALLBACK /* See atomic.c in this directory. */
 #endif
 
 /* On Windows, we always use the functions provided by the Windows API. */
@@ -79,13 +87,48 @@ static inline gint64 InterlockedAdd64(volatile gint64 *dest, gint64 add)
 }
 #endif
 
+#if defined(_MSC_VER) && !defined(InterlockedAdd)
+/* MSVC before 2013 only defines InterlockedAdd* for the Itanium architecture */
+static inline gint32 InterlockedAdd(volatile gint32 *dest, gint32 add)
+{
+       return InterlockedExchangeAdd (dest, add) + add;
+}
+#endif
+
+#if defined(_MSC_VER) && !defined(InterlockedAdd64)
+#if defined(InterlockedExchangeAdd64)
+/* This may be defined only on amd64 */
+static inline gint64 InterlockedAdd64(volatile gint64 *dest, gint64 add)
+{
+       return InterlockedExchangeAdd64 (dest, add) + add;
+}
+#else
+static inline gint64 InterlockedAdd64(volatile gint64 *dest, gint64 add)
+{
+       gint64 prev_value;
+
+       do {
+               prev_value = *dest;
+       } while (prev_value != InterlockedCompareExchange64(dest, prev_value + add, prev_value));
+
+       return prev_value + add;
+}
+#endif
+#endif
+
+#ifdef HOST_WIN32
+#define TO_INTERLOCKED_ARGP(ptr) ((volatile LONG*)(ptr))
+#else
+#define TO_INTERLOCKED_ARGP(ptr) (ptr)
+#endif
+
 /* And now for some dirty hacks... The Windows API doesn't
  * provide any useful primitives for this (other than getting
  * into architecture-specific madness), so use CAS. */
 
 static inline gint32 InterlockedRead(volatile gint32 *src)
 {
-       return InterlockedCompareExchange (src, 0, 0);
+       return InterlockedCompareExchange (TO_INTERLOCKED_ARGP (src), 0, 0);
 }
 
 static inline gint64 InterlockedRead64(volatile gint64 *src)
@@ -100,7 +143,7 @@ static inline gpointer InterlockedReadPointer(volatile gpointer *src)
 
 static inline void InterlockedWrite(volatile gint32 *dst, gint32 val)
 {
-       InterlockedExchange (dst, val);
+       InterlockedExchange (TO_INTERLOCKED_ARGP (dst), val);
 }
 
 static inline void InterlockedWrite64(volatile gint64 *dst, gint64 val)
@@ -138,7 +181,7 @@ static inline void InterlockedWrite16(volatile gint16 *dst, gint16 val)
        mono_memory_barrier ();
 }
 
-/* Prefer GCC atomic ops if the target supports it (see configure.in). */
+/* Prefer GCC atomic ops if the target supports it (see configure.ac). */
 #elif defined(USE_GCC_ATOMIC_OPS)
 
 static inline gint32 InterlockedCompareExchange(volatile gint32 *dest,