diff options
author | Alex Rønne Petersen <alexrp@xamarin.com> | 2013-09-25 19:59:37 +0200 |
---|---|---|
committer | Jo Shields <directhex@apebox.org> | 2013-10-23 15:06:30 +0100 |
commit | b37681e25ce03a65caca92ae299664c7c1621572 (patch) | |
tree | d44dbcaffc3b3bdc19f9b44087ab8e44fff47a34 | |
parent | 70e8ca185b70e91d989ff6d24882c61181ae9540 (diff) | |
download | mono-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-x | mono/utils/atomic.c | 82 | ||||
-rwxr-xr-x | mono/utils/atomic.h | 47 |
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 |