Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 52a327c

Browse files
authored
bpo-39465: Add pycore_atomic_funcs.h header (GH-20766)
Add pycore_atomic_funcs.h internal header file: similar to pycore_atomic.h but don't require to declare variables as atomic. Add _Py_atomic_size_get() and _Py_atomic_size_set() functions.
1 parent 46b5c6b commit 52a327c

9 files changed

+132
-17
lines changed

Include/internal/pycore_atomic.h

+3-3
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,8 @@ extern "C" {
1111
#include "dynamic_annotations.h" /* _Py_ANNOTATE_MEMORY_ORDER */
1212
#include "pyconfig.h"
1313

14-
#if defined(HAVE_STD_ATOMIC)
15-
#include <stdatomic.h>
14+
#ifdef HAVE_STD_ATOMIC
15+
# include <stdatomic.h>
1616
#endif
1717

1818

@@ -62,7 +62,7 @@ typedef struct _Py_atomic_int {
6262
#define _Py_atomic_load_explicit(ATOMIC_VAL, ORDER) \
6363
atomic_load_explicit(&((ATOMIC_VAL)->_value), ORDER)
6464

65-
/* Use builtin atomic operations in GCC >= 4.7 */
65+
// Use builtin atomic operations in GCC >= 4.7 and clang
6666
#elif defined(HAVE_BUILTIN_ATOMIC)
6767

6868
typedef enum _Py_memory_order {
+94
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
/* Atomic functions: similar to pycore_atomic.h, but don't need
2+
to declare variables as atomic.
3+
4+
Py_ssize_t type:
5+
6+
* value = _Py_atomic_size_get(&var)
7+
* _Py_atomic_size_set(&var, value)
8+
9+
Use sequentially-consistent ordering (__ATOMIC_SEQ_CST memory order):
10+
enforce total ordering with all other atomic functions.
11+
*/
12+
#ifndef Py_ATOMIC_FUNC_H
13+
#define Py_ATOMIC_FUNC_H
14+
#ifdef __cplusplus
15+
extern "C" {
16+
#endif
17+
18+
#ifndef Py_BUILD_CORE
19+
# error "this header requires Py_BUILD_CORE define"
20+
#endif
21+
22+
#if defined(_MSC_VER)
23+
# include <intrin.h> // _InterlockedExchange()
24+
#endif
25+
26+
27+
// Use builtin atomic operations in GCC >= 4.7 and clang
28+
#ifdef HAVE_BUILTIN_ATOMIC
29+
30+
static inline Py_ssize_t _Py_atomic_size_get(Py_ssize_t *var)
31+
{
32+
return __atomic_load_n(var, __ATOMIC_SEQ_CST);
33+
}
34+
35+
static inline void _Py_atomic_size_set(Py_ssize_t *var, Py_ssize_t value)
36+
{
37+
__atomic_store_n(var, value, __ATOMIC_SEQ_CST);
38+
}
39+
40+
#elif defined(_MSC_VER)
41+
42+
static inline Py_ssize_t _Py_atomic_size_get(Py_ssize_t *var)
43+
{
44+
#if SIZEOF_VOID_P == 8
45+
Py_BUILD_ASSERT(sizeof(__int64) == sizeof(*var));
46+
volatile __int64 *volatile_var = (volatile __int64 *)var;
47+
__int64 old;
48+
do {
49+
old = *volatile_var;
50+
} while(_InterlockedCompareExchange64(volatile_var, old, old) != old);
51+
#else
52+
Py_BUILD_ASSERT(sizeof(long) == sizeof(*var));
53+
volatile long *volatile_var = (volatile long *)var;
54+
long old;
55+
do {
56+
old = *volatile_var;
57+
} while(_InterlockedCompareExchange(volatile_var, old, old) != old);
58+
#endif
59+
return old;
60+
}
61+
62+
static inline void _Py_atomic_size_set(Py_ssize_t *var, Py_ssize_t value)
63+
{
64+
#if SIZEOF_VOID_P == 8
65+
Py_BUILD_ASSERT(sizeof(__int64) == sizeof(*var));
66+
volatile __int64 *volatile_var = (volatile __int64 *)var;
67+
_InterlockedExchange64(volatile_var, value);
68+
#else
69+
Py_BUILD_ASSERT(sizeof(long) == sizeof(*var));
70+
volatile long *volatile_var = (volatile long *)var;
71+
_InterlockedExchange(volatile_var, value);
72+
#endif
73+
}
74+
75+
#else
76+
// Fallback implementation using volatile
77+
78+
static inline Py_ssize_t _Py_atomic_size_get(Py_ssize_t *var)
79+
{
80+
volatile Py_ssize_t *volatile_var = (volatile Py_ssize_t *)var;
81+
return *volatile_var;
82+
}
83+
84+
static inline void _Py_atomic_size_set(Py_ssize_t *var, Py_ssize_t value)
85+
{
86+
volatile Py_ssize_t *volatile_var = (volatile Py_ssize_t *)var;
87+
*volatile_var = value;
88+
}
89+
#endif
90+
91+
#ifdef __cplusplus
92+
}
93+
#endif
94+
#endif /* Py_ATOMIC_FUNC_H */

Makefile.pre.in

+1
Original file line numberDiff line numberDiff line change
@@ -1111,6 +1111,7 @@ PYTHON_HEADERS= \
11111111
$(srcdir)/Include/internal/pycore_abstract.h \
11121112
$(srcdir)/Include/internal/pycore_accu.h \
11131113
$(srcdir)/Include/internal/pycore_atomic.h \
1114+
$(srcdir)/Include/internal/pycore_atomic_funcs.h \
11141115
$(srcdir)/Include/internal/pycore_bitutils.h \
11151116
$(srcdir)/Include/internal/pycore_bytes_methods.h \
11161117
$(srcdir)/Include/internal/pycore_call.h \

Modules/_testinternalcapi.c

+13
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
#define PY_SSIZE_T_CLEAN
1313

1414
#include "Python.h"
15+
#include "pycore_atomic_funcs.h" // _Py_atomic_int_get()
1516
#include "pycore_bitutils.h" // _Py_bswap32()
1617
#include "pycore_gc.h" // PyGC_Head
1718
#include "pycore_hashtable.h" // _Py_hashtable_new()
@@ -267,6 +268,17 @@ test_set_config(PyObject *Py_UNUSED(self), PyObject *dict)
267268
}
268269

269270

271+
static PyObject*
272+
test_atomic_funcs(PyObject *self, PyObject *Py_UNUSED(args))
273+
{
274+
// Test _Py_atomic_size_get() and _Py_atomic_size_set()
275+
Py_ssize_t var = 1;
276+
_Py_atomic_size_set(&var, 2);
277+
assert(_Py_atomic_size_get(&var) == 2);
278+
Py_RETURN_NONE;
279+
}
280+
281+
270282
static PyMethodDef TestMethods[] = {
271283
{"get_configs", get_configs, METH_NOARGS},
272284
{"get_recursion_depth", get_recursion_depth, METH_NOARGS},
@@ -276,6 +288,7 @@ static PyMethodDef TestMethods[] = {
276288
{"test_hashtable", test_hashtable, METH_NOARGS},
277289
{"get_config", test_get_config, METH_NOARGS},
278290
{"set_config", test_set_config, METH_O},
291+
{"test_atomic_funcs", test_atomic_funcs, METH_NOARGS},
279292
{NULL, NULL} /* sentinel */
280293
};
281294

PCbuild/pythoncore.vcxproj

+1
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,7 @@
168168
<ClInclude Include="..\Include\internal\pycore_abstract.h" />
169169
<ClInclude Include="..\Include\internal\pycore_accu.h" />
170170
<ClInclude Include="..\Include\internal\pycore_atomic.h" />
171+
<ClInclude Include="..\Include\internal\pycore_atomic_funcs.h" />
171172
<ClInclude Include="..\Include\internal\pycore_bitutils.h" />
172173
<ClInclude Include="..\Include\internal\pycore_bytes_methods.h" />
173174
<ClInclude Include="..\Include\internal\pycore_call.h" />

PCbuild/pythoncore.vcxproj.filters

+3
Original file line numberDiff line numberDiff line change
@@ -486,6 +486,9 @@
486486
<ClInclude Include="..\Include\internal\pycore_atomic.h">
487487
<Filter>Include\internal</Filter>
488488
</ClInclude>
489+
<ClInclude Include="..\Include\internal\pycore_atomic_funcs.h">
490+
<Filter>Include</Filter>
491+
</ClInclude>
489492
<ClInclude Include="..\Include\internal\pycore_bitutils.h">
490493
<Filter>Include\internal</Filter>
491494
</ClInclude>

configure

+7-5
Original file line numberDiff line numberDiff line change
@@ -15429,6 +15429,7 @@ _ACEOF
1542915429

1543015430
fi
1543115431

15432+
1543215433
EXT_SUFFIX=.${SOABI}${SHLIB_SUFFIX}
1543315434

1543415435
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking LDVERSION" >&5
@@ -17095,16 +17096,17 @@ $as_echo "#define HAVE_STD_ATOMIC 1" >>confdefs.h
1709517096

1709617097
fi
1709717098

17098-
# Check for GCC >= 4.7 __atomic builtins
17099-
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for GCC >= 4.7 __atomic builtins" >&5
17100-
$as_echo_n "checking for GCC >= 4.7 __atomic builtins... " >&6; }
17099+
# Check for GCC >= 4.7 and clang __atomic builtin functions
17100+
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for builtin __atomic_load_n and __atomic_store_n functions" >&5
17101+
$as_echo_n "checking for builtin __atomic_load_n and __atomic_store_n functions... " >&6; }
1710117102
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
1710217103
/* end confdefs.h. */
1710317104

1710417105

17105-
volatile int val = 1;
17106+
int val;
1710617107
int main() {
17107-
__atomic_load_n(&val, __ATOMIC_SEQ_CST);
17108+
__atomic_store_n(&val, 1, __ATOMIC_SEQ_CST);
17109+
(void)__atomic_load_n(&val, __ATOMIC_SEQ_CST);
1710817110
return 0;
1710917111
}
1711017112

configure.ac

+6-5
Original file line numberDiff line numberDiff line change
@@ -5586,14 +5586,15 @@ if test "$have_stdatomic_h" = yes; then
55865586
[Has stdatomic.h with atomic_int and atomic_uintptr_t])
55875587
fi
55885588

5589-
# Check for GCC >= 4.7 __atomic builtins
5590-
AC_MSG_CHECKING(for GCC >= 4.7 __atomic builtins)
5589+
# Check for GCC >= 4.7 and clang __atomic builtin functions
5590+
AC_MSG_CHECKING(for builtin __atomic_load_n and __atomic_store_n functions)
55915591
AC_LINK_IFELSE(
55925592
[
55935593
AC_LANG_SOURCE([[
5594-
volatile int val = 1;
5594+
int val;
55955595
int main() {
5596-
__atomic_load_n(&val, __ATOMIC_SEQ_CST);
5596+
__atomic_store_n(&val, 1, __ATOMIC_SEQ_CST);
5597+
(void)__atomic_load_n(&val, __ATOMIC_SEQ_CST);
55975598
return 0;
55985599
}
55995600
]])
@@ -5602,7 +5603,7 @@ AC_LINK_IFELSE(
56025603
AC_MSG_RESULT($have_builtin_atomic)
56035604

56045605
if test "$have_builtin_atomic" = yes; then
5605-
AC_DEFINE(HAVE_BUILTIN_ATOMIC, 1, [Has builtin atomics])
5606+
AC_DEFINE(HAVE_BUILTIN_ATOMIC, 1, [Has builtin __atomic_load_n() and __atomic_store_n() functions])
56065607
fi
56075608

56085609
# ensurepip option

pyconfig.h.in

+4-4
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,7 @@
115115
/* Define if `unsetenv` does not return an int. */
116116
#undef HAVE_BROKEN_UNSETENV
117117

118-
/* Has builtin atomics */
118+
/* Has builtin __atomic_load_n() and __atomic_store_n() functions */
119119
#undef HAVE_BUILTIN_ATOMIC
120120

121121
/* Define to 1 if you have the 'chflags' function. */
@@ -287,6 +287,9 @@
287287
/* Define to 1 if you have the `dup3' function. */
288288
#undef HAVE_DUP3
289289

290+
/* Define if you have the '_dyld_shared_cache_contains_path' function. */
291+
#undef HAVE_DYLD_SHARED_CACHE_CONTAINS_PATH
292+
290293
/* Defined when any dynamic module loading is enabled. */
291294
#undef HAVE_DYNAMIC_LOADING
292295

@@ -787,9 +790,6 @@
787790
/* Define if you have the 'prlimit' functions. */
788791
#undef HAVE_PRLIMIT
789792

790-
/* Define if you have the '_dyld_shared_cache_contains_path' function. */
791-
#undef HAVE_DYLD_SHARED_CACHE_CONTAINS_PATH
792-
793793
/* Define to 1 if you have the <process.h> header file. */
794794
#undef HAVE_PROCESS_H
795795

0 commit comments

Comments
 (0)