diff options
author | Hans Boehm <hboehm@google.com> | 2014-08-28 15:21:32 -0700 |
---|---|---|
committer | Hans Boehm <hboehm@google.com> | 2014-08-29 17:03:26 -0700 |
commit | 32429606bf696d3b2ca555f132a0d60c566d0bd0 (patch) | |
tree | a78cacfc6e28d35fdd41b0b4d6682b22b49939f2 | |
parent | bbe06e0da1742e9bdc52d3246ffa9f2ab3ce999a (diff) | |
download | android_bionic-32429606bf696d3b2ca555f132a0d60c566d0bd0.tar.gz android_bionic-32429606bf696d3b2ca555f132a0d60c566d0bd0.tar.bz2 android_bionic-32429606bf696d3b2ca555f132a0d60c566d0bd0.zip |
Make stdatomic.h work with gcc4.6 host compiler
This is needed to make L work correctly, and bionic tests pass
again, after applying the equivalent of
commit 00aaea364501b3b0abe58dae461136159df1e356 there.
It makes the preexisting code that uses __sync implementations
much more useful, although we should no longer be exercising that
code in AOSP.
Specifically fixes:
We were invoking __has_extension and __has_builtin for GCC compilations.
They're clang specific. Restructured the tests.
The __sync implementation was not defining the LOCK_FREE macros.
ATOMIC_VAR_INIT was using named field initializations. These are a
C, not C++, feature, that is not supported by g++ 4.6.
The stdatomic bionic test still failed with 4.6 and glibc with our
questionable LOCK_FREE macro implementation. Don't run that piece
with 4.6.
In L, this is a prerequisite for fixing:
Bug:16880454
Bug:16513433
Change-Id: I9b61e42307f96a114dce7552b6ead4ad1c544eab
-rw-r--r-- | libc/include/stdatomic.h | 69 | ||||
-rw-r--r-- | tests/stdatomic_test.cpp | 5 |
2 files changed, 62 insertions, 12 deletions
diff --git a/libc/include/stdatomic.h b/libc/include/stdatomic.h index 47b333cf1..3db25a78e 100644 --- a/libc/include/stdatomic.h +++ b/libc/include/stdatomic.h @@ -32,8 +32,20 @@ #include <sys/cdefs.h> -#if defined(__cplusplus) && defined(_USING_LIBCXX) && \ - (__has_feature(cxx_atomic) || _GNUC_VER >= 407) + +#if defined(__cplusplus) && defined(_USING_LIBCXX) +# ifdef __clang__ +# if __has_feature(cxx_atomic) +# define _STDATOMIC_HAVE_ATOMIC +# endif +# else /* gcc */ +# if __GNUC_PREREQ(4, 7) +# define _STDATOMIC_HAVE_ATOMIC +# endif +# endif +#endif + +#ifdef _STDATOMIC_HAVE_ATOMIC /* We have a usable C++ <atomic>; use it instead. */ @@ -46,6 +58,7 @@ /* included. The definitions in <atomic> themselves see */ /* the old definition, as they should. */ /* Client code sees the following definition. */ + #define _Atomic(t) std::atomic<t> using std::atomic_is_lock_free; @@ -136,14 +149,24 @@ using std::atomic_uintmax_t; # include <uchar.h> /* For char16_t and char32_t. */ #endif -#if __has_extension(c_atomic) || __has_extension(cxx_atomic) -#define __CLANG_ATOMICS -#elif __GNUC_PREREQ(4, 7) -#define __GNUC_ATOMICS -#elif defined(__GNUC__) -#define __SYNC_ATOMICS +#ifdef __clang__ +# if __has_extension(c_atomic) || __has_extension(cxx_atomic) +# define __CLANG_ATOMICS +# else +# error "stdatomic.h does not support your compiler" +# endif +# if __has_builtin(__sync_swap) +# define __HAS_BUILTIN_SYNC_SWAP +# endif #else -#error "stdatomic.h does not support your compiler" +# if __GNUC_PREREQ(4, 7) +# define __GNUC_ATOMICS +# else +# define __SYNC_ATOMICS +# ifdef __cplusplus +# define __ATOMICS_AVOID_DOT_INIT +# endif +# endif #endif /* @@ -152,33 +175,53 @@ using std::atomic_uintmax_t; #ifdef __GCC_ATOMIC_BOOL_LOCK_FREE #define ATOMIC_BOOL_LOCK_FREE __GCC_ATOMIC_BOOL_LOCK_FREE +#elif defined(__SYNC_ATOMICS) +#define ATOMIC_BOOL_LOCK_FREE 2 /* For all modern platforms */ #endif #ifdef __GCC_ATOMIC_CHAR_LOCK_FREE #define ATOMIC_CHAR_LOCK_FREE __GCC_ATOMIC_CHAR_LOCK_FREE +#elif defined(__SYNC_ATOMICS) +#define ATOMIC_CHAR_LOCK_FREE 2 #endif #ifdef __GCC_ATOMIC_CHAR16_T_LOCK_FREE #define ATOMIC_CHAR16_T_LOCK_FREE __GCC_ATOMIC_CHAR16_T_LOCK_FREE +#elif defined(__SYNC_ATOMICS) +#define ATOMIC_CHAR16_T_LOCK_FREE 2 #endif #ifdef __GCC_ATOMIC_CHAR32_T_LOCK_FREE #define ATOMIC_CHAR32_T_LOCK_FREE __GCC_ATOMIC_CHAR32_T_LOCK_FREE +#elif defined(__SYNC_ATOMICS) +#define ATOMIC_CHAR32_T_LOCK_FREE 2 #endif #ifdef __GCC_ATOMIC_WCHAR_T_LOCK_FREE #define ATOMIC_WCHAR_T_LOCK_FREE __GCC_ATOMIC_WCHAR_T_LOCK_FREE +#elif defined(__SYNC_ATOMICS) +#define ATOMIC_WCHAR_T_LOCK_FREE 2 #endif #ifdef __GCC_ATOMIC_SHORT_LOCK_FREE #define ATOMIC_SHORT_LOCK_FREE __GCC_ATOMIC_SHORT_LOCK_FREE +#elif defined(__SYNC_ATOMICS) +#define ATOMIC_SHORT_LOCK_FREE 2 #endif #ifdef __GCC_ATOMIC_INT_LOCK_FREE #define ATOMIC_INT_LOCK_FREE __GCC_ATOMIC_INT_LOCK_FREE +#elif defined(__SYNC_ATOMICS) +#define ATOMIC_INT_LOCK_FREE 2 #endif #ifdef __GCC_ATOMIC_LONG_LOCK_FREE #define ATOMIC_LONG_LOCK_FREE __GCC_ATOMIC_LONG_LOCK_FREE +#elif defined(__SYNC_ATOMICS) +#define ATOMIC_LONG_LOCK_FREE 2 #endif #ifdef __GCC_ATOMIC_LLONG_LOCK_FREE #define ATOMIC_LLONG_LOCK_FREE __GCC_ATOMIC_LLONG_LOCK_FREE +#elif defined(__SYNC_ATOMICS) +#define ATOMIC_LLONG_LOCK_FREE 1 /* maybe */ #endif #ifdef __GCC_ATOMIC_POINTER_LOCK_FREE #define ATOMIC_POINTER_LOCK_FREE __GCC_ATOMIC_POINTER_LOCK_FREE +#elif defined(__SYNC_ATOMICS) +#define ATOMIC_POINTER_LOCK_FREE 2 #endif /* @@ -189,7 +232,11 @@ using std::atomic_uintmax_t; #define ATOMIC_VAR_INIT(value) (value) #define atomic_init(obj, value) __c11_atomic_init(obj, value) #else +#ifdef __ATOMICS_AVOID_DOT_INIT +#define ATOMIC_VAR_INIT(value) { value } +#else #define ATOMIC_VAR_INIT(value) { .__val = (value) } +#endif #define atomic_init(obj, value) ((void)((obj)->__val = (value))) #endif @@ -289,7 +336,7 @@ atomic_signal_fence(memory_order __order __attribute__((unused))) * 7.17.6 Atomic integer types. */ -#if !__has_extension(c_atomic) && !__has_extension(cxx_atomic) +#ifndef __CLANG_ATOMICS /* * No native support for _Atomic(). Place object in structure to prevent * most forms of direct non-atomic access. @@ -410,7 +457,7 @@ typedef _Atomic(uintmax_t) atomic_uintmax_t; desired, success, failure) \ atomic_compare_exchange_strong_explicit(object, expected, \ desired, success, failure) -#if __has_builtin(__sync_swap) +#ifdef __HAS_BUILTIN_SYNC_SWAP /* Clang provides a full-barrier atomic exchange - use it if available. */ #define atomic_exchange_explicit(object, desired, order) \ ((void)(order), __sync_swap(&(object)->__val, desired)) diff --git a/tests/stdatomic_test.cpp b/tests/stdatomic_test.cpp index 222bd9c80..b7fb19b0d 100644 --- a/tests/stdatomic_test.cpp +++ b/tests/stdatomic_test.cpp @@ -63,14 +63,17 @@ TEST(stdatomic, atomic_signal_fence) { TEST(stdatomic, atomic_is_lock_free) { atomic_char small; - atomic_intmax_t big; ASSERT_TRUE(atomic_is_lock_free(&small)); +#if defined(__clang__) || __GNUC_PREREQ(4, 7) + // Otherwise stdatomic.h doesn't handle this. + atomic_intmax_t big; // atomic_intmax_t(size = 64) is not lock free on mips32. #if defined(__mips__) && !defined(__LP64__) ASSERT_FALSE(atomic_is_lock_free(&big)); #else ASSERT_TRUE(atomic_is_lock_free(&big)); #endif +#endif } TEST(stdatomic, atomic_flag) { |