diff options
author | Alex Rønne Petersen <alexrp@xamarin.com> | 2013-09-25 19:26:24 +0200 |
---|---|---|
committer | Jo Shields <directhex@apebox.org> | 2013-10-23 15:05:57 +0100 |
commit | 70e8ca185b70e91d989ff6d24882c61181ae9540 (patch) | |
tree | 1d95473c2d99175d00fa89167448437ff7f2856b | |
parent | 73ec43769736026857d726ef6ea23536e0e086ee (diff) | |
download | mono-70e8ca185b70e91d989ff6d24882c61181ae9540.tar.gz |
Add implementations of various interlocked functions to atomic.c/.h.
Mainly 64-bit variants, but also InterlockedAdd ().
(cherry picked from commit ec96b2dc2289e00a9c30a8b39b14c3f62ab484ed)
-rwxr-xr-x | mono/utils/atomic.c | 138 | ||||
-rwxr-xr-x | mono/utils/atomic.h | 109 |
2 files changed, 241 insertions, 6 deletions
diff --git a/mono/utils/atomic.c b/mono/utils/atomic.c index c902c21fca..b0b3bf7de4 100755 --- a/mono/utils/atomic.c +++ b/mono/utils/atomic.c @@ -82,6 +82,52 @@ gpointer InterlockedCompareExchangePointer(volatile gpointer *dest, return(old); } +gint32 InterlockedAdd(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); + + *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; + + 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); + + *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; @@ -105,6 +151,29 @@ gint32 InterlockedIncrement(volatile gint32 *dest) return(ret); } +gint64 InterlockedIncrement64(volatile gint64 *dest) +{ + 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); + + (*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; @@ -128,6 +197,29 @@ gint32 InterlockedDecrement(volatile gint32 *dest) return(ret); } +gint64 InterlockedDecrement64(volatile gint64 *dest) +{ + 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); + + (*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; @@ -151,6 +243,29 @@ gint32 InterlockedExchange(volatile gint32 *dest, gint32 exch) return(ret); } +gint64 InterlockedExchange64(volatile gint64 *dest, gint64 exch) +{ + 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=*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; @@ -197,6 +312,29 @@ gint32 InterlockedExchangeAdd(volatile gint32 *dest, gint32 add) return(ret); } +gint64 InterlockedExchangeAdd64(volatile gint64 *dest, gint64 add) +{ + 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= *dest; + *dest+=add; + + thr_ret = pthread_mutex_unlock(&spin); + g_assert (thr_ret == 0); + + pthread_cleanup_pop (0); + + return(ret); +} + #define NEED_64BIT_CMPXCHG_FALLBACK #endif diff --git a/mono/utils/atomic.h b/mono/utils/atomic.h index 727582c5b9..7da7d5170c 100755 --- a/mono/utils/atomic.h +++ b/mono/utils/atomic.h @@ -45,6 +45,11 @@ static inline gpointer InterlockedCompareExchangePointer(volatile gpointer *dest return __sync_val_compare_and_swap (dest, comp, exch); } +static inline gint32 InterlockedAdd(volatile gint32 *dest, gint32 add) +{ + return __sync_add_and_fetch (dest, add); +} + static inline gint32 InterlockedIncrement(volatile gint32 *val) { return __sync_add_and_fetch (val, 1); @@ -90,8 +95,99 @@ static inline gint64 InterlockedCompareExchange64(volatile gint64 *dest, gint64 return __sync_val_compare_and_swap (dest, comp, exch); } +static inline gint64 InterlockedAdd64(volatile gint64 *dest, gint64 add) +{ + return __sync_add_and_fetch (dest, add); +} + +static inline gint64 InterlockedIncrement64(volatile gint64 *val) +{ + return __sync_add_and_fetch (val, 1); +} + +static inline gint64 InterlockedDecrement64(volatile gint64 *val) +{ + return __sync_sub_and_fetch (val, 1); +} + +static inline gint64 InterlockedExchangeAdd64(volatile gint64 *val, gint64 add) +{ + return __sync_fetch_and_add (val, add); +} + +#else + +/* Implement 64-bit cmpxchg by hand or emulate it. */ +extern gint64 InterlockedCompareExchange64(volatile gint64 *dest, gint64 exch, gint64 comp); + +/* Implement all other 64-bit atomics in terms of a specialized CAS + * in this case, since chances are that the other 64-bit atomic + * intrinsics are broken too. + */ + +static inline gint64 InterlockedExchangeAdd64(volatile gint64 *dest, gint64 add) +{ + gint64 old_val; + do { + old_val = *dest; + } while (InterlockedCompareExchange64 (dest, old_val + add, old_val) != old_val); + return old_val; +} + +static inline gint64 InterlockedIncrement64(volatile gint64 *val) +{ + gint64 get, set; + do { + get = *val; + set = get + 1; + } while (InterlockedCompareExchange64 (val, set, get) != set); + return set; +} + +static inline gint64 InterlockedDecrement64(volatile gint64 *val) +{ + gint64 get, set; + do { + get = *val; + set = get - 1; + } while (InterlockedCompareExchange64 (val, set, get) != set); + return set; +} + +static inline gint64 InterlockedAdd64(volatile gint64 *dest, gint64 add) +{ + gint64 get, set; + do { + get = *dest; + set = get + add; + } while (InterlockedCompareExchange64 (dest, set, get) != set); + return set; +} + +static inline gint64 InterlockedRead64(volatile gint64 *src) +{ + return InterlockedCompareExchange64 (src, 0, 0); +} + #endif +/* We always implement this in terms of a 64-bit cmpxchg since + * GCC doesn't have an intrisic to model it anyway. */ +static inline gint64 InterlockedExchange64(volatile gint64 *val, gint64 new_val) +{ + gint64 old_val; + do { + old_val = *val; + } while (InterlockedCompareExchange64 (val, new_val, old_val) != old_val); + return old_val; +} + +static inline void InterlockedWrite64(volatile gint64 *dst, gint64 val) +{ + /* Nothing useful from GCC at all, so fall back to CAS. */ + InterlockedExchange64 (dst, val); +} + #elif (defined(sparc) || defined (__sparc__)) && defined(__GNUC__) G_GNUC_UNUSED @@ -373,18 +469,19 @@ static inline gint32 InterlockedExchangeAdd(gint32 volatile *val, gint32 add) #define WAPI_NO_ATOMIC_ASM extern gint32 InterlockedCompareExchange(volatile gint32 *dest, gint32 exch, gint32 comp); +extern gint64 InterlockedCompareExchange64(volatile gint64 *dest, gint64 exch, gint64 comp); extern gpointer InterlockedCompareExchangePointer(volatile gpointer *dest, gpointer exch, gpointer comp); +extern gint32 InterlockedAdd(volatile gint32 *dest, gint32 add); +extern gint64 InterlockedAdd64(volatile gint64 *dest, gint64 add); extern gint32 InterlockedIncrement(volatile gint32 *dest); +extern gint64 InterlockedIncrement64(volatile gint64 *dest); extern gint32 InterlockedDecrement(volatile gint32 *dest); +extern gint64 InterlockedDecrement64(volatile gint64 *dest); extern gint32 InterlockedExchange(volatile gint32 *dest, gint32 exch); +extern gint64 InterlockedExchange64(volatile gint64 *dest, gint64 exch); extern gpointer InterlockedExchangePointer(volatile gpointer *dest, gpointer exch); extern gint32 InterlockedExchangeAdd(volatile gint32 *dest, gint32 add); - -#endif - -#if defined (WAPI_NO_ATOMIC_ASM) || defined (BROKEN_64BIT_ATOMICS_INTRINSIC) - -extern gint64 InterlockedCompareExchange64(volatile gint64 *dest, gint64 exch, gint64 comp); +extern gint64 InterlockedExchangeAdd64(volatile gint64 *dest, gint64 add); #endif |