Skip to content

Commit 86559dd

Browse files
authored
gh-109693: Update _gil_runtime_state.locked to use pyatomic.h (gh-110836)
1 parent 06f844e commit 86559dd

File tree

8 files changed

+86
-18
lines changed

8 files changed

+86
-18
lines changed

Include/cpython/pyatomic.h

+6
Original file line numberDiff line numberDiff line change
@@ -463,6 +463,12 @@ _Py_atomic_load_ptr_acquire(const void *obj);
463463
static inline void
464464
_Py_atomic_store_ptr_release(void *obj, void *value);
465465

466+
static inline void
467+
_Py_atomic_store_int_release(int *obj, int value);
468+
469+
static inline int
470+
_Py_atomic_load_int_acquire(const int *obj);
471+
466472

467473
// --- _Py_atomic_fence ------------------------------------------------------
468474

Include/cpython/pyatomic_gcc.h

+8
Original file line numberDiff line numberDiff line change
@@ -487,6 +487,14 @@ static inline void
487487
_Py_atomic_store_ptr_release(void *obj, void *value)
488488
{ __atomic_store_n((void **)obj, value, __ATOMIC_RELEASE); }
489489

490+
static inline void
491+
_Py_atomic_store_int_release(int *obj, int value)
492+
{ __atomic_store_n(obj, value, __ATOMIC_RELEASE); }
493+
494+
static inline int
495+
_Py_atomic_load_int_acquire(const int *obj)
496+
{ return __atomic_load_n(obj, __ATOMIC_ACQUIRE); }
497+
490498

491499
// --- _Py_atomic_fence ------------------------------------------------------
492500

Include/cpython/pyatomic_msc.h

+26
Original file line numberDiff line numberDiff line change
@@ -912,6 +912,32 @@ _Py_atomic_store_ptr_release(void *obj, void *value)
912912
#endif
913913
}
914914

915+
static inline void
916+
_Py_atomic_store_int_release(int *obj, int value)
917+
{
918+
#if defined(_M_X64) || defined(_M_IX86)
919+
*(int volatile *)obj = value;
920+
#elif defined(_M_ARM64)
921+
_Py_atomic_ASSERT_ARG_TYPE(unsigned __int32);
922+
__stlr32((unsigned __int32 volatile *)obj, (unsigned __int32)value);
923+
#else
924+
# error "no implementation of _Py_atomic_store_int_release"
925+
#endif
926+
}
927+
928+
static inline int
929+
_Py_atomic_load_int_acquire(const int *obj)
930+
{
931+
#if defined(_M_X64) || defined(_M_IX86)
932+
return *(int volatile *)obj;
933+
#elif defined(_M_ARM64)
934+
_Py_atomic_ASSERT_ARG_TYPE(unsigned __int32);
935+
return (int)__ldar32((unsigned __int32 volatile *)obj);
936+
#else
937+
# error "no implementation of _Py_atomic_load_int_acquire"
938+
#endif
939+
}
940+
915941

916942
// --- _Py_atomic_fence ------------------------------------------------------
917943

Include/cpython/pyatomic_std.h

+17
Original file line numberDiff line numberDiff line change
@@ -854,6 +854,23 @@ _Py_atomic_store_ptr_release(void *obj, void *value)
854854
memory_order_release);
855855
}
856856

857+
static inline void
858+
_Py_atomic_store_int_release(int *obj, int value)
859+
{
860+
_Py_USING_STD;
861+
atomic_store_explicit((_Atomic(int)*)obj, value,
862+
memory_order_release);
863+
}
864+
865+
static inline int
866+
_Py_atomic_load_int_acquire(const int *obj)
867+
{
868+
_Py_USING_STD;
869+
return atomic_load_explicit((const _Atomic(int)*)obj,
870+
memory_order_acquire);
871+
}
872+
873+
857874

858875
// --- _Py_atomic_fence ------------------------------------------------------
859876

Include/internal/pycore_gil.h

+1-2
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ extern "C" {
88
# error "this header requires Py_BUILD_CORE define"
99
#endif
1010

11-
#include "pycore_atomic.h" // _Py_atomic_int
1211
#include "pycore_condvar.h" // PyCOND_T
1312

1413
#ifndef Py_HAVE_CONDVAR
@@ -28,7 +27,7 @@ struct _gil_runtime_state {
2827
PyThreadState* last_holder;
2928
/* Whether the GIL is already taken (-1 if uninitialized). This is
3029
atomic because it can be read without any lock taken in ceval.c. */
31-
_Py_atomic_int locked;
30+
int locked;
3231
/* Number of GIL switches since the beginning. */
3332
unsigned long switch_number;
3433
/* This condition variable allows one or several threads to wait

Modules/_testcapi/pyatomic.c

+16
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,21 @@ test_atomic_release_acquire(PyObject *self, PyObject *obj) {
140140
Py_RETURN_NONE;
141141
}
142142

143+
static PyObject *
144+
test_atomic_load_store_int_release_acquire(PyObject *self, PyObject *obj) { \
145+
int x = 0;
146+
int y = 1;
147+
int z = 2;
148+
assert(_Py_atomic_load_int_acquire(&x) == 0);
149+
_Py_atomic_store_int_release(&x, y);
150+
assert(x == y);
151+
assert(_Py_atomic_load_int_acquire(&x) == y);
152+
_Py_atomic_store_int_release(&x, z);
153+
assert(x == z);
154+
assert(_Py_atomic_load_int_acquire(&x) == z);
155+
Py_RETURN_NONE;
156+
}
157+
143158
// NOTE: all tests should start with "test_atomic_" to be included
144159
// in test_pyatomic.py
145160

@@ -162,6 +177,7 @@ static PyMethodDef test_methods[] = {
162177
FOR_BITWISE_TYPES(BIND_TEST_AND_OR)
163178
{"test_atomic_fences", test_atomic_fences, METH_NOARGS},
164179
{"test_atomic_release_acquire", test_atomic_release_acquire, METH_NOARGS},
180+
{"test_atomic_load_store_int_release_acquire", test_atomic_load_store_int_release_acquire, METH_NOARGS},
165181
{NULL, NULL} /* sentinel */
166182
};
167183

Python/ceval_gil.c

+11-16
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11

22
#include "Python.h"
3-
#include "pycore_atomic.h" // _Py_atomic_int
3+
#include "pycore_atomic.h" // _Py_ANNOTATE_RWLOCK_CREATE
44
#include "pycore_ceval.h" // _PyEval_SignalReceived()
55
#include "pycore_initconfig.h" // _PyStatus_OK()
66
#include "pycore_interp.h" // _Py_RunGC()
@@ -120,9 +120,6 @@ UNSIGNAL_PENDING_CALLS(PyInterpreterState *interp)
120120
#include <stdlib.h>
121121
#include <errno.h>
122122

123-
#include "pycore_atomic.h"
124-
125-
126123
#include "condvar.h"
127124

128125
#define MUTEX_INIT(mut) \
@@ -166,8 +163,7 @@ UNSIGNAL_PENDING_CALLS(PyInterpreterState *interp)
166163

167164
static void _gil_initialize(struct _gil_runtime_state *gil)
168165
{
169-
_Py_atomic_int uninitialized = {-1};
170-
gil->locked = uninitialized;
166+
gil->locked = -1;
171167
gil->interval = DEFAULT_INTERVAL;
172168
}
173169

@@ -176,7 +172,7 @@ static int gil_created(struct _gil_runtime_state *gil)
176172
if (gil == NULL) {
177173
return 0;
178174
}
179-
return (_Py_atomic_load_explicit(&gil->locked, _Py_memory_order_acquire) >= 0);
175+
return (_Py_atomic_load_int_acquire(&gil->locked) >= 0);
180176
}
181177

182178
static void create_gil(struct _gil_runtime_state *gil)
@@ -191,7 +187,7 @@ static void create_gil(struct _gil_runtime_state *gil)
191187
#endif
192188
_Py_atomic_store_ptr_relaxed(&gil->last_holder, 0);
193189
_Py_ANNOTATE_RWLOCK_CREATE(&gil->locked);
194-
_Py_atomic_store_explicit(&gil->locked, 0, _Py_memory_order_release);
190+
_Py_atomic_store_int_release(&gil->locked, 0);
195191
}
196192

197193
static void destroy_gil(struct _gil_runtime_state *gil)
@@ -205,8 +201,7 @@ static void destroy_gil(struct _gil_runtime_state *gil)
205201
COND_FINI(gil->switch_cond);
206202
MUTEX_FINI(gil->switch_mutex);
207203
#endif
208-
_Py_atomic_store_explicit(&gil->locked, -1,
209-
_Py_memory_order_release);
204+
_Py_atomic_store_int_release(&gil->locked, -1);
210205
_Py_ANNOTATE_RWLOCK_DESTROY(&gil->locked);
211206
}
212207

@@ -247,7 +242,7 @@ drop_gil(PyInterpreterState *interp, PyThreadState *tstate)
247242

248243
MUTEX_LOCK(gil->mutex);
249244
_Py_ANNOTATE_RWLOCK_RELEASED(&gil->locked, /*is_write=*/1);
250-
_Py_atomic_store_relaxed(&gil->locked, 0);
245+
_Py_atomic_store_int_relaxed(&gil->locked, 0);
251246
COND_SIGNAL(gil->cond);
252247
MUTEX_UNLOCK(gil->mutex);
253248

@@ -313,12 +308,12 @@ take_gil(PyThreadState *tstate)
313308

314309
MUTEX_LOCK(gil->mutex);
315310

316-
if (!_Py_atomic_load_relaxed(&gil->locked)) {
311+
if (!_Py_atomic_load_int_relaxed(&gil->locked)) {
317312
goto _ready;
318313
}
319314

320315
int drop_requested = 0;
321-
while (_Py_atomic_load_relaxed(&gil->locked)) {
316+
while (_Py_atomic_load_int_relaxed(&gil->locked)) {
322317
unsigned long saved_switchnum = gil->switch_number;
323318

324319
unsigned long interval = (gil->interval >= 1 ? gil->interval : 1);
@@ -328,7 +323,7 @@ take_gil(PyThreadState *tstate)
328323
/* If we timed out and no switch occurred in the meantime, it is time
329324
to ask the GIL-holding thread to drop it. */
330325
if (timed_out &&
331-
_Py_atomic_load_relaxed(&gil->locked) &&
326+
_Py_atomic_load_int_relaxed(&gil->locked) &&
332327
gil->switch_number == saved_switchnum)
333328
{
334329
if (_PyThreadState_MustExit(tstate)) {
@@ -358,7 +353,7 @@ take_gil(PyThreadState *tstate)
358353
MUTEX_LOCK(gil->switch_mutex);
359354
#endif
360355
/* We now hold the GIL */
361-
_Py_atomic_store_relaxed(&gil->locked, 1);
356+
_Py_atomic_store_int_relaxed(&gil->locked, 1);
362357
_Py_ANNOTATE_RWLOCK_ACQUIRED(&gil->locked, /*is_write=*/1);
363358

364359
if (tstate != (PyThreadState*)_Py_atomic_load_ptr_relaxed(&gil->last_holder)) {
@@ -437,7 +432,7 @@ current_thread_holds_gil(struct _gil_runtime_state *gil, PyThreadState *tstate)
437432
if (((PyThreadState*)_Py_atomic_load_ptr_relaxed(&gil->last_holder)) != tstate) {
438433
return 0;
439434
}
440-
return _Py_atomic_load_relaxed(&gil->locked);
435+
return _Py_atomic_load_int_relaxed(&gil->locked);
441436
}
442437

443438
static void

Python/thread_pthread.h

+1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
#include "pycore_interp.h" // _PyInterpreterState.threads.stacksize
22
#include "pycore_pythread.h" // _POSIX_SEMAPHORES
3+
#include "pycore_atomic.h" // _Py_ANNOTATE_PURE_HAPPENS_BEFORE_MUTEX
34

45
/* Posix threads interface */
56

0 commit comments

Comments
 (0)