From d7b6df5808e7bef5930b61a82e880699a9f9e208 Mon Sep 17 00:00:00 2001 From: Khem Raj Date: Thu, 29 Jun 2017 15:39:19 -0700 Subject: [PATCH] implement 64bit atomic for mips GCC does not provide 64bit atomics for mips32 Signed-off-by: Khem Raj --- src/Makefile.am | 1 + src/atomic64.c | 228 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 229 insertions(+) create mode 100644 src/atomic64.c diff --git a/src/Makefile.am b/src/Makefile.am index 99aaace0..cbbbbee9 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -27,6 +27,7 @@ libtorrent_la_LIBADD = \ utils/libsub_utils.la libtorrent_la_SOURCES = \ + atomic64.c \ globals.cc \ globals.h \ manager.cc \ diff --git a/src/atomic64.c b/src/atomic64.c new file mode 100644 index 00000000..f841b39b --- /dev/null +++ b/src/atomic64.c @@ -0,0 +1,228 @@ +/*===----- atomic64.c - Support functions for 64-bit atomic operations.-----=== + * + * The LLVM Compiler Infrastructure + * + * This file is dual licensed under the MIT and the University of Illinois Open + * Source Licenses. See LICENSE.TXT for details. + * + *===-----------------------------------------------------------------------=== + * + * atomic64.c defines a set of functions for performing atomic accesses on + * 64-bit memory locations. It also implements spinlock synchronization + * operations. + * + *===-----------------------------------------------------------------------=== + */ + +#include +#include + +/* + * only need these on MIPS, since it lacks hardware 64-bit atomics, + * unlike x86 and ARM. + */ +#if defined(__mips__) || defined(__mipsel__) + +static void __spin_lock(volatile int *lock) { + while (__sync_lock_test_and_set(lock, 1)) + while (*lock) {} +} + +static void __spin_unlock(volatile int *lock) { + __sync_lock_release(lock); +} + +/* + * Make sure the lock is on its own cache line to prevent false sharing. + * Put it inside a struct that is aligned and padded to the typical MIPS + * cacheline which is 32 bytes. + */ +static struct { + int lock; + char pad[32 - sizeof(int)]; +} __attribute__((aligned (32))) lock = { 0 }; + + +uint64_t __sync_fetch_and_add_8(volatile uint64_t *ptr, uint64_t val) { + uint64_t ret; + + __spin_lock(&lock.lock); + + ret = *ptr; + *ptr = ret + val; + + __spin_unlock(&lock.lock); + + return ret; +} + +uint64_t __sync_fetch_and_sub_8(volatile uint64_t *ptr, uint64_t val) { + uint64_t ret; + + __spin_lock(&lock.lock); + + ret = *ptr; + *ptr = ret - val; + + __spin_unlock(&lock.lock); + + return ret; +} + +uint64_t __sync_fetch_and_and_8(volatile uint64_t *ptr, uint64_t val) { + uint64_t ret; + + __spin_lock(&lock.lock); + + ret = *ptr; + *ptr = ret & val; + + __spin_unlock(&lock.lock); + + return ret; +} + +uint64_t __sync_fetch_and_or_8(volatile uint64_t *ptr, uint64_t val) { + uint64_t ret; + + __spin_lock(&lock.lock); + + ret = *ptr; + *ptr = ret | val; + + __spin_unlock(&lock.lock); + + return ret; +} + +uint64_t __sync_fetch_and_xor_8(volatile uint64_t *ptr, uint64_t val) { + uint64_t ret; + + __spin_lock(&lock.lock); + + ret = *ptr; + *ptr = ret ^ val; + + __spin_unlock(&lock.lock); + + return ret; +} + +uint64_t __sync_add_and_fetch_8(volatile uint64_t *ptr, uint64_t val) { + uint64_t ret; + + __spin_lock(&lock.lock); + + ret = *ptr + val; + *ptr = ret; + + __spin_unlock(&lock.lock); + + return ret; +} + +uint64_t __sync_sub_and_fetch_8(volatile uint64_t *ptr, uint64_t val) { + uint64_t ret; + + __spin_lock(&lock.lock); + + ret = *ptr - val; + *ptr = ret; + + __spin_unlock(&lock.lock); + + return ret; +} + +uint64_t __sync_and_and_fetch_8(volatile uint64_t *ptr, uint64_t val) { + uint64_t ret; + + __spin_lock(&lock.lock); + + ret = *ptr & val; + *ptr = ret; + + __spin_unlock(&lock.lock); + + return ret; +} + +uint64_t __sync_or_and_fetch_8(volatile uint64_t *ptr, uint64_t val) { + uint64_t ret; + + __spin_lock(&lock.lock); + + ret = *ptr | val; + *ptr = ret; + + __spin_unlock(&lock.lock); + + return ret; +} + +uint64_t __sync_xor_and_fetch_8(volatile uint64_t *ptr, uint64_t val) { + uint64_t ret; + + __spin_lock(&lock.lock); + + ret = *ptr ^ val; + *ptr = ret; + + __spin_unlock(&lock.lock); + + return ret; +} + +bool __sync_bool_compare_and_swap_8(volatile uint64_t *ptr, + uint64_t oldval, uint64_t newval) { + bool ret = false; + + __spin_lock(&lock.lock); + + if (*ptr == oldval) { + *ptr = newval; + ret = true; + } + + __spin_unlock(&lock.lock); + + return ret; +} + +uint64_t __sync_val_compare_and_swap_8(volatile uint64_t *ptr, + uint64_t oldval, uint64_t newval) { + uint64_t ret; + + __spin_lock(&lock.lock); + + ret = *ptr; + if (ret == oldval) + *ptr = newval; + + __spin_unlock(&lock.lock); + + return ret; +} + +uint64_t __sync_lock_test_and_set_8(volatile uint64_t *ptr, uint64_t val) { + uint64_t ret; + + __spin_lock(&lock.lock); + + ret = *ptr; + *ptr = val; + + __spin_unlock(&lock.lock); + + return ret; +} + +void __sync_lock_release_8(volatile uint64_t *ptr) { + __spin_lock(&lock.lock); + + *ptr = 0; + + __spin_unlock(&lock.lock); +} + +#endif -- 2.13.2