Skip to content

Commit 4f5366e

Browse files
committed
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.
1 parent b551fac commit 4f5366e

6 files changed

Lines changed: 193 additions & 3 deletions

File tree

Include/pyatomic.h

Lines changed: 77 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,15 @@
11
#ifndef Py_LIMITED_API
22
#ifndef Py_ATOMIC_H
33
#define Py_ATOMIC_H
4-
/* XXX: When compilers start offering a stdatomic.h with lock-free
5-
atomic_int and atomic_address types, include that here and rewrite
6-
the atomic operations in terms of it. */
74

85
#include "dynamic_annotations.h"
96

7+
#include "pyconfig.h"
8+
9+
#if defined(HAVE_STD_ATOMIC)
10+
#include <stdatomic.h>
11+
#endif
12+
1013
#ifdef __cplusplus
1114
extern "C" {
1215
#endif
@@ -20,6 +23,76 @@ extern "C" {
2023
* Beware, the implementations here are deep magic.
2124
*/
2225

26+
#if defined(HAVE_STD_ATOMIC)
27+
28+
typedef enum _Py_memory_order {
29+
_Py_memory_order_relaxed = memory_order_relaxed,
30+
_Py_memory_order_acquire = memory_order_acquire,
31+
_Py_memory_order_release = memory_order_release,
32+
_Py_memory_order_acq_rel = memory_order_acq_rel,
33+
_Py_memory_order_seq_cst = memory_order_seq_cst
34+
} _Py_memory_order;
35+
36+
typedef struct _Py_atomic_address {
37+
_Atomic void *_value;
38+
} _Py_atomic_address;
39+
40+
typedef struct _Py_atomic_int {
41+
atomic_int _value;
42+
} _Py_atomic_int;
43+
44+
#define _Py_atomic_signal_fence(/*memory_order*/ ORDER) \
45+
atomic_signal_fence(ORDER)
46+
47+
#define _Py_atomic_thread_fence(/*memory_order*/ ORDER) \
48+
atomic_thread_fence(ORDER)
49+
50+
#define _Py_atomic_store_explicit(ATOMIC_VAL, NEW_VAL, ORDER) \
51+
atomic_store_explicit(&(ATOMIC_VAL)->_value, NEW_VAL, ORDER)
52+
53+
#define _Py_atomic_load_explicit(ATOMIC_VAL, ORDER) \
54+
atomic_load_explicit(&(ATOMIC_VAL)->_value, ORDER)
55+
56+
/* Use builtin atomic operations in GCC >= 4.7 */
57+
#elif defined(HAVE_BUILTIN_ATOMIC)
58+
59+
typedef enum _Py_memory_order {
60+
_Py_memory_order_relaxed = __ATOMIC_RELAXED,
61+
_Py_memory_order_acquire = __ATOMIC_ACQUIRE,
62+
_Py_memory_order_release = __ATOMIC_RELEASE,
63+
_Py_memory_order_acq_rel = __ATOMIC_ACQ_REL,
64+
_Py_memory_order_seq_cst = __ATOMIC_SEQ_CST
65+
} _Py_memory_order;
66+
67+
typedef struct _Py_atomic_address {
68+
void *_value;
69+
} _Py_atomic_address;
70+
71+
typedef struct _Py_atomic_int {
72+
int _value;
73+
} _Py_atomic_int;
74+
75+
#define _Py_atomic_signal_fence(/*memory_order*/ ORDER) \
76+
__atomic_signal_fence(ORDER)
77+
78+
#define _Py_atomic_thread_fence(/*memory_order*/ ORDER) \
79+
__atomic_thread_fence(ORDER)
80+
81+
#define _Py_atomic_store_explicit(ATOMIC_VAL, NEW_VAL, ORDER) \
82+
(assert((ORDER) == __ATOMIC_RELAXED \
83+
|| (ORDER) == __ATOMIC_SEQ_CST \
84+
|| (ORDER) == __ATOMIC_RELEASE), \
85+
__atomic_store_n(&(ATOMIC_VAL)->_value, NEW_VAL, ORDER))
86+
87+
#define _Py_atomic_load_explicit(ATOMIC_VAL, ORDER) \
88+
(assert((ORDER) == __ATOMIC_RELAXED \
89+
|| (ORDER) == __ATOMIC_SEQ_CST \
90+
|| (ORDER) == __ATOMIC_ACQUIRE \
91+
|| (ORDER) == __ATOMIC_CONSUME), \
92+
__atomic_load_n(&(ATOMIC_VAL)->_value, ORDER))
93+
94+
#else
95+
2396
typedef enum _Py_memory_order {
2497
_Py_memory_order_relaxed,
2598
_Py_memory_order_acquire,
@@ -162,6 +235,7 @@ _Py_ANNOTATE_MEMORY_ORDER(const volatile void *address, _Py_memory_order order)
162235
((ATOMIC_VAL)->_value)
163236

164237
#endif /* !gcc x86 */
238+
#endif
165239

166240
/* Standardized shortcuts. */
167241
#define _Py_atomic_store(ATOMIC_VAL, NEW_VAL) \

Misc/ACKS

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -821,6 +821,7 @@ Ross Light
821821
Shawn Ligocki
822822
Martin Ligr
823823
Gediminas Liktaras
824+
Vitor de Lima
824825
Grant Limberg
825826
Christopher Lindblad
826827
Ulf A. Lindgren
@@ -1355,6 +1356,7 @@ Steven Taschuk
13551356
Amy Taylor
13561357
Monty Taylor
13571358
Anatoly Techtonik
1359+
Gustavo Temple
13581360
Mikhail Terekhov
13591361
Victor Terrón
13601362
Richard M. Tew

Misc/NEWS

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,10 @@ Release date: TBA
1010
Core and Builtins
1111
-----------------
1212

13+
- Issue #22038: pyatomic.h now uses stdatomic.h or GCC built-in functions for
14+
atomic memory access if available. Patch written by Vitor de Lima and Gustavo
15+
Temple.
16+
1317
- Issue #23048: Fix jumping out of an infinite while loop in the pdb.
1418

1519
- Issue #20335: bytes constructor now raises TypeError when encoding or errors

configure

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15703,6 +15703,71 @@ $as_echo "#define HAVE_IPA_PURE_CONST_BUG 1" >>confdefs.h
1570315703
esac
1570415704
fi
1570515705

15706+
# Check for stdatomic.h
15707+
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for stdatomic.h" >&5
15708+
$as_echo_n "checking for stdatomic.h... " >&6; }
15709+
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
15710+
/* end confdefs.h. */
15711+
15712+
15713+
#include <stdatomic.h>
15714+
_Atomic int value = ATOMIC_VAR_INIT(1);
15715+
int main() {
15716+
int loaded_value = atomic_load(&value);
15717+
return 0;
15718+
}
15719+
15720+
15721+
_ACEOF
15722+
if ac_fn_c_try_link "$LINENO"; then :
15723+
have_stdatomic_h=yes
15724+
else
15725+
have_stdatomic_h=no
15726+
fi
15727+
rm -f core conftest.err conftest.$ac_objext \
15728+
conftest$ac_exeext conftest.$ac_ext
15729+
15730+
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $have_stdatomic_h" >&5
15731+
$as_echo "$have_stdatomic_h" >&6; }
15732+
15733+
if test "$have_stdatomic_h" = yes; then
15734+
15735+
$as_echo "#define HAVE_STD_ATOMIC 1" >>confdefs.h
15736+
15737+
fi
15738+
15739+
# Check for GCC >= 4.7 __atomic builtins
15740+
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for GCC >= 4.7 __atomic builtins" >&5
15741+
$as_echo_n "checking for GCC >= 4.7 __atomic builtins... " >&6; }
15742+
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
15743+
/* end confdefs.h. */
15744+
15745+
15746+
volatile int val = 1;
15747+
int main() {
15748+
__atomic_load_n(&val, __ATOMIC_SEQ_CST);
15749+
return 0;
15750+
}
15751+
15752+
15753+
_ACEOF
15754+
if ac_fn_c_try_link "$LINENO"; then :
15755+
have_builtin_atomic=yes
15756+
else
15757+
have_builtin_atomic=no
15758+
fi
15759+
rm -f core conftest.err conftest.$ac_objext \
15760+
conftest$ac_exeext conftest.$ac_ext
15761+
15762+
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $have_builtin_atomic" >&5
15763+
$as_echo "$have_builtin_atomic" >&6; }
15764+
15765+
if test "$have_builtin_atomic" = yes; then
15766+
15767+
$as_echo "#define HAVE_BUILTIN_ATOMIC 1" >>confdefs.h
15768+
15769+
fi
15770+
1570615771
# ensurepip option
1570715772
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ensurepip" >&5
1570815773
$as_echo_n "checking for ensurepip... " >&6; }

configure.ac

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4884,6 +4884,45 @@ if test "$have_gcc_asm_for_x87" = yes; then
48844884
esac
48854885
fi
48864886

4887+
# Check for stdatomic.h
4888+
AC_MSG_CHECKING(for stdatomic.h)
4889+
AC_LINK_IFELSE(
4890+
[
4891+
AC_LANG_SOURCE([[
4892+
#include <stdatomic.h>
4893+
_Atomic int value = ATOMIC_VAR_INIT(1);
4894+
int main() {
4895+
int loaded_value = atomic_load(&value);
4896+
return 0;
4897+
}
4898+
]])
4899+
],[have_stdatomic_h=yes],[have_stdatomic_h=no])
4900+
4901+
AC_MSG_RESULT($have_stdatomic_h)
4902+
4903+
if test "$have_stdatomic_h" = yes; then
4904+
AC_DEFINE(HAVE_STD_ATOMIC, 1, [Has stdatomic.h])
4905+
fi
4906+
4907+
# Check for GCC >= 4.7 __atomic builtins
4908+
AC_MSG_CHECKING(for GCC >= 4.7 __atomic builtins)
4909+
AC_LINK_IFELSE(
4910+
[
4911+
AC_LANG_SOURCE([[
4912+
volatile int val = 1;
4913+
int main() {
4914+
__atomic_load_n(&val, __ATOMIC_SEQ_CST);
4915+
return 0;
4916+
}
4917+
]])
4918+
],[have_builtin_atomic=yes],[have_builtin_atomic=no])
4919+
4920+
AC_MSG_RESULT($have_builtin_atomic)
4921+
4922+
if test "$have_builtin_atomic" = yes; then
4923+
AC_DEFINE(HAVE_BUILTIN_ATOMIC, 1, [Has builtin atomics])
4924+
fi
4925+
48874926
# ensurepip option
48884927
AC_MSG_CHECKING(for ensurepip)
48894928
AC_ARG_WITH(ensurepip,

pyconfig.h.in

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,9 @@
101101
/* Define if `unsetenv` does not return an int. */
102102
#undef HAVE_BROKEN_UNSETENV
103103

104+
/* Has builtin atomics */
105+
#undef HAVE_BUILTIN_ATOMIC
106+
104107
/* Define this if you have the type _Bool. */
105108
#undef HAVE_C99_BOOL
106109

@@ -877,6 +880,9 @@
877880
/* Define to 1 if you have the <stdlib.h> header file. */
878881
#undef HAVE_STDLIB_H
879882

883+
/* Has stdatomic.h */
884+
#undef HAVE_STD_ATOMIC
885+
880886
/* Define to 1 if you have the `strdup' function. */
881887
#undef HAVE_STRDUP
882888

0 commit comments

Comments
 (0)