aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Chisnall <dchisnall@pathscale.com>2014-05-09 01:35:36 +0000
committerAndroid Git Automerger <android-git-automerger@android.com>2014-05-09 01:35:36 +0000
commit16f40b036e8854aa076cef56c06aad5b7e89abd1 (patch)
tree647c5d01545708898247f1b9ea5ee949914236df
parent964952e95678174c4f36ea45f487132c7fd0344f (diff)
parentc61efa043b14378efbd69c9a2686d44ed46ae179 (diff)
downloadlibcxxrt-16f40b036e8854aa076cef56c06aad5b7e89abd1.tar.gz
am c61efa04: Refactor the guards so that we use the same code on ARM as everywhere else, just with different types.
* commit 'c61efa043b14378efbd69c9a2686d44ed46ae179': Refactor the guards so that we use the same code on ARM as everywhere else, just with different types.
-rw-r--r--src/atomic.h10
-rw-r--r--src/guard.cc110
2 files changed, 33 insertions, 87 deletions
diff --git a/src/atomic.h b/src/atomic.h
index a3d2710..cfaff3f 100644
--- a/src/atomic.h
+++ b/src/atomic.h
@@ -28,13 +28,3 @@
(__sync_synchronize(), *addr)
#endif
-#if __has_builtin(__c11_atomic_store)
-#define ATOMIC_STORE(addr, value)\
- __c11_atomic_store((_Atomic(__typeof__(*addr))*)addr, value, __ATOMIC_RELEASE)
-#else
-#define ATOMIC_STORE(addr, value)\
- do {\
- *addr = value;\
- (__sync_synchronize(), *addr);\
- } while (0)
-#endif
diff --git a/src/guard.cc b/src/guard.cc
index 72a53e5..f0c26ab 100644
--- a/src/guard.cc
+++ b/src/guard.cc
@@ -47,22 +47,48 @@
#include <assert.h>
#include "atomic.h"
-#ifdef __arm__
-// ARM ABI - 32-bit guards.
+// Older GCC doesn't define __LITTLE_ENDIAN__
+#ifndef __LITTLE_ENDIAN__
+ // If __BYTE_ORDER__ is defined, use that instead
+# ifdef __BYTE_ORDER__
+# if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
+# define __LITTLE_ENDIAN__
+# endif
+ // x86 and ARM are the most common little-endian CPUs, so let's have a
+ // special case for them (ARM is already special cased). Assume everything
+ // else is big endian.
+# elif defined(__x86_64) || defined(__i386)
+# define __LITTLE_ENDIAN__
+# endif
+#endif
+
/*
* The least significant bit of the guard variable indicates that the object
* has been initialised, the most significant bit is used for a spinlock.
*/
-static const uint32_t LOCKED = ((uint32_t)1) << 31;
+#ifdef __arm__
+// ARM ABI - 32-bit guards.
+typedef uint32_t guard_t;
+static const uint32_t LOCKED = ((guard_t)1) << 31;
static const uint32_t INITIALISED = 1;
+#else
+typedef uint64_t guard_t;
+# if defined(__LITTLE_ENDIAN__)
+static const guard_t LOCKED = ((guard_t)1) << 63;
+static const guard_t INITIALISED = 1;
+# else
+static const guard_t LOCKED = 1;
+static const guard_t INITIALISED = ((guard_t)1) << 56;
+# endif
+#endif
/**
* Acquires a lock on a guard, returning 0 if the object has already been
* initialised, and 1 if it has not. If the object is already constructed then
* this function just needs to read a byte from memory and return.
*/
-extern "C" int __cxa_guard_acquire(volatile uint32_t *guard_object)
+extern "C" int __cxa_guard_acquire(volatile guard_t *guard_object)
{
// Not an atomic read, doesn't establish a happens-before relationship, but
// if one is already established and we end up seeing an initialised state
@@ -88,6 +114,7 @@ extern "C" int __cxa_guard_acquire(volatile uint32_t *guard_object)
// If it is locked by another thread, relinquish the CPU and try
// again later.
case LOCKED:
+ case LOCKED | INITIALISED:
sched_yield();
break;
// If it is some other value, then something has gone badly wrong.
@@ -105,7 +132,7 @@ extern "C" int __cxa_guard_acquire(volatile uint32_t *guard_object)
* Releases the lock without marking the object as initialised. This function
* is called if initialising a static causes an exception to be thrown.
*/
-extern "C" void __cxa_guard_abort(uint32_t *guard_object)
+extern "C" void __cxa_guard_abort(volatile guard_t *guard_object)
{
__attribute__((unused))
bool reset = __sync_bool_compare_and_swap(guard_object, LOCKED, 0);
@@ -115,7 +142,7 @@ extern "C" void __cxa_guard_abort(uint32_t *guard_object)
* Releases the guard and marks the object as initialised. This function is
* called after successful initialisation of a static.
*/
-extern "C" void __cxa_guard_release(uint32_t *guard_object)
+extern "C" void __cxa_guard_release(volatile guard_t *guard_object)
{
__attribute__((unused))
bool reset = __sync_bool_compare_and_swap(guard_object, LOCKED, INITIALISED);
@@ -123,74 +150,3 @@ extern "C" void __cxa_guard_release(uint32_t *guard_object)
}
-#else
-// Itanium ABI: 64-bit guards
-
-/**
- * Returns a pointer to the low 32 bits in a 64-bit value, respecting the
- * platform's byte order.
- */
-static int32_t *low_32_bits(volatile int64_t *ptr)
-{
- int32_t *low= (int32_t*)ptr;
- // Test if the machine is big endian - constant propagation at compile
- // time should eliminate this completely.
- int one = 1;
- if (*(char*)&one != 1)
- {
- low++;
- }
- return low;
-}
-
-/**
- * Acquires a lock on a guard, returning 0 if the object has already been
- * initialised, and 1 if it has not. If the object is already constructed then
- * this function just needs to read a byte from memory and return.
- */
-extern "C" int __cxa_guard_acquire(volatile int64_t *guard_object)
-{
- char first_byte = (*guard_object) >> 56;
- if (1 == first_byte) { return 0; }
- int32_t *lock = low_32_bits(guard_object);
- // Simple spin lock using the low 32 bits. We assume that concurrent
- // attempts to initialize statics are very rare, so we don't need to
- // optimise for the case where we have lots of threads trying to acquire
- // the lock at the same time.
- while (!__sync_bool_compare_and_swap_4(lock, 0, 1))
- {
- if (1 == ((*guard_object) >> 56))
- {
- break;
- }
- sched_yield();
- }
- // We have to test the guard again, in case another thread has performed
- // the initialisation while we were trying to acquire the lock.
- first_byte = (*guard_object) >> 56;
- return (1 != first_byte);
-}
-
-/**
- * Releases the lock without marking the object as initialised. This function
- * is called if initialising a static causes an exception to be thrown.
- */
-extern "C" void __cxa_guard_abort(int64_t *guard_object)
-{
- int32_t *lock = low_32_bits(guard_object);
- ATOMIC_STORE(lock, 0);
-}
-/**
- * Releases the guard and marks the object as initialised. This function is
- * called after successful initialisation of a static.
- */
-extern "C" void __cxa_guard_release(int64_t *guard_object)
-{
- // Set the first byte to 1
- // Note: We don't do an atomic load here because getting a stale value
- // is not a problem in the current implementation.
- ATOMIC_STORE(guard_object, (*guard_object | ((int64_t)1) << 56));
- __cxa_guard_abort(guard_object);
-}
-
-#endif