summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlex Rønne Petersen <alexrp@xamarin.com>2013-09-25 19:59:37 +0200
committerJo Shields <directhex@apebox.org>2013-10-23 15:06:30 +0100
commitb37681e25ce03a65caca92ae299664c7c1621572 (patch)
treed44dbcaffc3b3bdc19f9b44087ab8e44fff47a34
parent70e8ca185b70e91d989ff6d24882c61181ae9540 (diff)
downloadmono-b37681e25ce03a65caca92ae299664c7c1621572.tar.gz
Add interlocked read/write functions to atomic.c/.h.
These are guaranteed to have sequential consistency regardless of the bitness of the machine they run on. (cherry picked from commit a92cfede81a7d91a699cab0ee325517c2415b6a7)
-rwxr-xr-xmono/utils/atomic.c82
-rwxr-xr-xmono/utils/atomic.h47
2 files changed, 129 insertions, 0 deletions
diff --git a/mono/utils/atomic.c b/mono/utils/atomic.c
index b0b3bf7de4..e8388b9d04 100755
--- a/mono/utils/atomic.c
+++ b/mono/utils/atomic.c
@@ -335,6 +335,88 @@ gint64 InterlockedExchangeAdd64(volatile gint64 *dest, gint64 add)
return(ret);
}
+gint32 InterlockedRead(volatile gint32 *src)
+{
+ 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= *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;
+
+ 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= *src;
+
+ thr_ret = pthread_mutex_unlock(&spin);
+ g_assert (thr_ret == 0);
+
+ pthread_cleanup_pop (0);
+
+ return(ret);
+}
+
+void InterlockedWrite(volatile gint32 *dst, gint32 val)
+{
+ 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);
+
+ *dst=val;
+
+ thr_ret = pthread_mutex_unlock(&spin);
+ g_assert (thr_ret == 0);
+
+ pthread_cleanup_pop (0);
+}
+
+void InterlockedWrite64(volatile gint64 *dst, gint64 val)
+{
+ 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);
+
+ *dst=val;
+
+ thr_ret = pthread_mutex_unlock(&spin);
+ g_assert (thr_ret == 0);
+
+ pthread_cleanup_pop (0);
+}
+
#define NEED_64BIT_CMPXCHG_FALLBACK
#endif
diff --git a/mono/utils/atomic.h b/mono/utils/atomic.h
index 7da7d5170c..95fd7717c1 100755
--- a/mono/utils/atomic.h
+++ b/mono/utils/atomic.h
@@ -31,6 +31,30 @@ static inline gint64 InterlockedCompareExchange64(volatile gint64 *dest, gint64
}
#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);
+}
+
+static inline gint64 InterlockedRead64(volatile gint64 *src)
+{
+ return InterlockedCompareExchange64 (src, 0, 0);
+}
+
+static inline void InterlockedWrite(volatile gint32 *dst, gint32 val)
+{
+ InterlockedExchange (dst, val);
+}
+
+static inline void InterlockedWrite64(volatile gint64 *dst, gint64 val)
+{
+ InterlockedExchange64 (dst, val);
+}
+
/* Prefer GCC atomic ops if the target supports it (see configure.in). */
#elif defined(USE_GCC_ATOMIC_OPS)
@@ -84,6 +108,19 @@ static inline gint32 InterlockedExchangeAdd(volatile gint32 *val, gint32 add)
return __sync_fetch_and_add (val, add);
}
+static inline gint32 InterlockedRead(volatile gint32 *src)
+{
+ /* Kind of a hack, but GCC doesn't give us anything better, and it's
+ certainly not as bad as using a CAS loop. */
+ return __sync_fetch_and_add (src, 0);
+}
+
+static inline void InterlockedWrite(volatile gint32 *dst, gint32 val)
+{
+ /* Nothing useful from GCC at all, so fall back to CAS. */
+ InterlockedExchange (dst, val);
+}
+
#if defined (TARGET_OSX)
#define BROKEN_64BIT_ATOMICS_INTRINSIC 1
#endif
@@ -115,6 +152,12 @@ static inline gint64 InterlockedExchangeAdd64(volatile gint64 *val, gint64 add)
return __sync_fetch_and_add (val, add);
}
+static inline gint64 InterlockedRead64(volatile gint64 *src)
+{
+ /* Kind of a hack, but GCC doesn't give us anything better. */
+ return __sync_fetch_and_add (src, 0);
+}
+
#else
/* Implement 64-bit cmpxchg by hand or emulate it. */
@@ -482,6 +525,10 @@ extern gint64 InterlockedExchange64(volatile gint64 *dest, gint64 exch);
extern gpointer InterlockedExchangePointer(volatile gpointer *dest, gpointer exch);
extern gint32 InterlockedExchangeAdd(volatile gint32 *dest, gint32 add);
extern gint64 InterlockedExchangeAdd64(volatile gint64 *dest, gint64 add);
+extern gint32 InterlockedRead(volatile gint32 *src);
+extern gint64 InterlockedRead64(volatile gint64 *src);
+extern void InterlockedWrite(volatile gint32 *dst, gint32 val);
+extern void InterlockedWrite64(volatile gint64 *dst, gint64 val);
#endif