Issue #22038: pyatomic.h now uses stdatomic.h or GCC built-in functions for

atomic memory access if available. Patch written by Vitor de Lima and Gustavo
Temple.
This commit is contained in:
Victor Stinner 2015-01-09 02:13:19 +01:00
parent b551fac136
commit 4f5366e65a
6 changed files with 193 additions and 3 deletions

View File

@ -1,12 +1,15 @@
#ifndef Py_LIMITED_API #ifndef Py_LIMITED_API
#ifndef Py_ATOMIC_H #ifndef Py_ATOMIC_H
#define 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 "dynamic_annotations.h"
#include "pyconfig.h"
#if defined(HAVE_STD_ATOMIC)
#include <stdatomic.h>
#endif
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif #endif
@ -20,6 +23,76 @@ extern "C" {
* Beware, the implementations here are deep magic. * 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 { typedef enum _Py_memory_order {
_Py_memory_order_relaxed, _Py_memory_order_relaxed,
_Py_memory_order_acquire, _Py_memory_order_acquire,
@ -162,6 +235,7 @@ _Py_ANNOTATE_MEMORY_ORDER(const volatile void *address, _Py_memory_order order)
((ATOMIC_VAL)->_value) ((ATOMIC_VAL)->_value)
#endif /* !gcc x86 */ #endif /* !gcc x86 */
#endif
/* Standardized shortcuts. */ /* Standardized shortcuts. */
#define _Py_atomic_store(ATOMIC_VAL, NEW_VAL) \ #define _Py_atomic_store(ATOMIC_VAL, NEW_VAL) \

View File

@ -821,6 +821,7 @@ Ross Light
Shawn Ligocki Shawn Ligocki
Martin Ligr Martin Ligr
Gediminas Liktaras Gediminas Liktaras
Vitor de Lima
Grant Limberg Grant Limberg
Christopher Lindblad Christopher Lindblad
Ulf A. Lindgren Ulf A. Lindgren
@ -1355,6 +1356,7 @@ Steven Taschuk
Amy Taylor Amy Taylor
Monty Taylor Monty Taylor
Anatoly Techtonik Anatoly Techtonik
Gustavo Temple
Mikhail Terekhov Mikhail Terekhov
Victor Terrón Victor Terrón
Richard M. Tew Richard M. Tew

View File

@ -10,6 +10,10 @@ Release date: TBA
Core and Builtins Core and Builtins
----------------- -----------------
- Issue #22038: pyatomic.h now uses stdatomic.h or GCC built-in functions for
atomic memory access if available. Patch written by Vitor de Lima and Gustavo
Temple.
- Issue #23048: Fix jumping out of an infinite while loop in the pdb. - Issue #23048: Fix jumping out of an infinite while loop in the pdb.
- Issue #20335: bytes constructor now raises TypeError when encoding or errors - Issue #20335: bytes constructor now raises TypeError when encoding or errors

65
configure vendored
View File

@ -15703,6 +15703,71 @@ $as_echo "#define HAVE_IPA_PURE_CONST_BUG 1" >>confdefs.h
esac esac
fi 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 <stdatomic.h>
_Atomic int value = ATOMIC_VAR_INIT(1);
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 # ensurepip option
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ensurepip" >&5 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ensurepip" >&5
$as_echo_n "checking for ensurepip... " >&6; } $as_echo_n "checking for ensurepip... " >&6; }

View File

@ -4884,6 +4884,45 @@ if test "$have_gcc_asm_for_x87" = yes; then
esac esac
fi fi
# Check for stdatomic.h
AC_MSG_CHECKING(for stdatomic.h)
AC_LINK_IFELSE(
[
AC_LANG_SOURCE([[
#include <stdatomic.h>
_Atomic int value = ATOMIC_VAR_INIT(1);
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 # ensurepip option
AC_MSG_CHECKING(for ensurepip) AC_MSG_CHECKING(for ensurepip)
AC_ARG_WITH(ensurepip, AC_ARG_WITH(ensurepip,

View File

@ -101,6 +101,9 @@
/* Define if `unsetenv` does not return an int. */ /* Define if `unsetenv` does not return an int. */
#undef HAVE_BROKEN_UNSETENV #undef HAVE_BROKEN_UNSETENV
/* Has builtin atomics */
#undef HAVE_BUILTIN_ATOMIC
/* Define this if you have the type _Bool. */ /* Define this if you have the type _Bool. */
#undef HAVE_C99_BOOL #undef HAVE_C99_BOOL
@ -877,6 +880,9 @@
/* Define to 1 if you have the <stdlib.h> header file. */ /* Define to 1 if you have the <stdlib.h> header file. */
#undef HAVE_STDLIB_H #undef HAVE_STDLIB_H
/* Has stdatomic.h */
#undef HAVE_STD_ATOMIC
/* Define to 1 if you have the `strdup' function. */ /* Define to 1 if you have the `strdup' function. */
#undef HAVE_STRDUP #undef HAVE_STRDUP