diff -r 6298895a52de Include/pyatomic.h --- a/Include/pyatomic.h Wed Jul 23 12:06:47 2014 -0500 +++ b/Include/pyatomic.h Tue Jul 29 11:12:11 2014 -0300 @@ -1,12 +1,15 @@ #ifndef Py_LIMITED_API #ifndef Py_ATOMIC_H #define Py_ATOMIC_H -/* XXX: When compilers start offering a stdatomic.h with lock-free - atomic_int and atomic_address types, include that here and rewrite - the atomic operations in terms of it. */ #include "dynamic_annotations.h" +#include "pyconfig.h" + +#if defined(HAVE_STD_ATOMIC) +#include +#endif + #ifdef __cplusplus extern "C" { #endif @@ -20,6 +23,76 @@ * Beware, the implementations here are deep magic. */ +#if defined(HAVE_STD_ATOMIC) + +typedef enum _Py_memory_order { + _Py_memory_order_relaxed = memory_order_relaxed, + _Py_memory_order_acquire = memory_order_acquire, + _Py_memory_order_release = memory_order_release, + _Py_memory_order_acq_rel = memory_order_acq_rel, + _Py_memory_order_seq_cst = memory_order_seq_cst +} _Py_memory_order; + +typedef struct _Py_atomic_address { + _Atomic void *_value; +} _Py_atomic_address; + +typedef struct _Py_atomic_int { + atomic_int _value; +} _Py_atomic_int; + +#define _Py_atomic_signal_fence(/*memory_order*/ ORDER) \ + atomic_signal_fence(ORDER) + +#define _Py_atomic_thread_fence(/*memory_order*/ ORDER) \ + atomic_thread_fence(ORDER) + +#define _Py_atomic_store_explicit(ATOMIC_VAL, NEW_VAL, ORDER) \ + atomic_store_explicit(&(ATOMIC_VAL)->_value, NEW_VAL, ORDER) + +#define _Py_atomic_load_explicit(ATOMIC_VAL, ORDER) \ + atomic_load_explicit(&(ATOMIC_VAL)->_value, ORDER) + +/* Use builtin atomic operations in GCC >= 4.7 */ +#elif defined(HAVE_BUILTIN_ATOMIC) + +typedef enum _Py_memory_order { + _Py_memory_order_relaxed = __ATOMIC_RELAXED, + _Py_memory_order_acquire = __ATOMIC_ACQUIRE, + _Py_memory_order_release = __ATOMIC_RELEASE, + _Py_memory_order_acq_rel = __ATOMIC_ACQ_REL, + _Py_memory_order_seq_cst = __ATOMIC_SEQ_CST +} _Py_memory_order; + +typedef struct _Py_atomic_address { + void *_value; +} _Py_atomic_address; + +typedef struct _Py_atomic_int { + int _value; +} _Py_atomic_int; + +#define _Py_atomic_signal_fence(/*memory_order*/ ORDER) \ + __atomic_signal_fence(ORDER) + +#define _Py_atomic_thread_fence(/*memory_order*/ ORDER) \ + __atomic_thread_fence(ORDER) + +#define _Py_atomic_store_explicit(ATOMIC_VAL, NEW_VAL, ORDER) \ + (assert((ORDER) == __ATOMIC_RELAXED \ + || (ORDER) == __ATOMIC_SEQ_CST \ + || (ORDER) == __ATOMIC_RELEASE), \ + __atomic_store_n(&(ATOMIC_VAL)->_value, NEW_VAL, ORDER)) + +#define _Py_atomic_load_explicit(ATOMIC_VAL, ORDER) \ + (assert((ORDER) == __ATOMIC_RELAXED \ + || (ORDER) == __ATOMIC_SEQ_CST \ + || (ORDER) == __ATOMIC_ACQUIRE \ + || (ORDER) == __ATOMIC_CONSUME), \ + __atomic_load_n(&(ATOMIC_VAL)->_value, ORDER)) + +#else + typedef enum _Py_memory_order { _Py_memory_order_relaxed, _Py_memory_order_acquire, @@ -162,6 +235,7 @@ ((ATOMIC_VAL)->_value) #endif /* !gcc x86 */ +#endif /* Standardized shortcuts. */ #define _Py_atomic_store(ATOMIC_VAL, NEW_VAL) \ diff -r 6298895a52de configure --- a/configure Wed Jul 23 12:06:47 2014 -0500 +++ b/configure Tue Jul 29 11:12:11 2014 -0300 @@ -15492,6 +15492,72 @@ esac fi +# Check for stdatomic.h +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for stdatomic.h" >&5 +$as_echo_n "checking for stdatomic.h... " >&6; } +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + + #include + atomic_int value = ATOMIC_VAR_INIT(1); + _Atomic void *py_atomic_address = (void*) &value; + int main() { + int loaded_value = atomic_load(&value); + return 0; + } + + +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + have_stdatomic_h=yes +else + have_stdatomic_h=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $have_stdatomic_h" >&5 +$as_echo "$have_stdatomic_h" >&6; } + +if test "$have_stdatomic_h" = yes; then + +$as_echo "#define HAVE_STD_ATOMIC 1" >>confdefs.h + +fi + +# Check for GCC >= 4.7 __atomic builtins +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for GCC >= 4.7 __atomic builtins" >&5 +$as_echo_n "checking for GCC >= 4.7 __atomic builtins... " >&6; } +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + + volatile int val = 1; + int main() { + __atomic_load_n(&val, __ATOMIC_SEQ_CST); + return 0; + } + + +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + have_builtin_atomic=yes +else + have_builtin_atomic=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $have_builtin_atomic" >&5 +$as_echo "$have_builtin_atomic" >&6; } + +if test "$have_builtin_atomic" = yes; then + +$as_echo "#define HAVE_BUILTIN_ATOMIC 1" >>confdefs.h + +fi + # ensurepip option { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ensurepip" >&5 $as_echo_n "checking for ensurepip... " >&6; } diff -r 6298895a52de configure.ac --- a/configure.ac Wed Jul 23 12:06:47 2014 -0500 +++ b/configure.ac Tue Jul 29 11:12:11 2014 -0300 @@ -4826,6 +4826,46 @@ esac fi +# Check for stdatomic.h +AC_MSG_CHECKING(for stdatomic.h) +AC_LINK_IFELSE( +[ + AC_LANG_SOURCE([[ + #include + atomic_int value = ATOMIC_VAR_INIT(1); + _Atomic void *py_atomic_address = (void*) &value; + int main() { + int loaded_value = atomic_load(&value); + return 0; + } + ]]) +],[have_stdatomic_h=yes],[have_stdatomic_h=no]) + +AC_MSG_RESULT($have_stdatomic_h) + +if test "$have_stdatomic_h" = yes; then + AC_DEFINE(HAVE_STD_ATOMIC, 1, [Has stdatomic.h]) +fi + +# Check for GCC >= 4.7 __atomic builtins +AC_MSG_CHECKING(for GCC >= 4.7 __atomic builtins) +AC_LINK_IFELSE( +[ + AC_LANG_SOURCE([[ + volatile int val = 1; + int main() { + __atomic_load_n(&val, __ATOMIC_SEQ_CST); + return 0; + } + ]]) +],[have_builtin_atomic=yes],[have_builtin_atomic=no]) + +AC_MSG_RESULT($have_builtin_atomic) + +if test "$have_builtin_atomic" = yes; then + AC_DEFINE(HAVE_BUILTIN_ATOMIC, 1, [Has builtin atomics]) +fi + # ensurepip option AC_MSG_CHECKING(for ensurepip) AC_ARG_WITH(ensurepip, diff -r 6298895a52de pyconfig.h.in --- a/pyconfig.h.in Wed Jul 23 12:06:47 2014 -0500 +++ b/pyconfig.h.in Tue Jul 29 11:12:11 2014 -0300 @@ -101,6 +101,9 @@ /* Define if `unsetenv` does not return an int. */ #undef HAVE_BROKEN_UNSETENV +/* Has builtin atomics */ +#undef HAVE_BUILTIN_ATOMIC + /* Define this if you have the type _Bool. */ #undef HAVE_C99_BOOL @@ -868,6 +871,9 @@ /* Define to 1 if you have the header file. */ #undef HAVE_STDLIB_H +/* Has stdatomic.h */ +#undef HAVE_STD_ATOMIC + /* Define to 1 if you have the `strdup' function. */ #undef HAVE_STRDUP