Skip to content

Commit 08bc03f

Browse files
authored
gh-120321: Make gi_frame_state transitions atomic in FT build (gh-142599)
This makes generator frame state transitions atomic in the free threading build, which avoids segfaults when trying to execute a generator from multiple threads concurrently. There are still a few operations that aren't thread-safe and may crash if performed concurrently on the same generator/coroutine: * Accessing gi_yieldfrom/cr_await/ag_await * Accessing gi_frame/cr_frame/ag_frame * Async generator operations
1 parent e2a7db7 commit 08bc03f

File tree

16 files changed

+1097
-856
lines changed

16 files changed

+1097
-856
lines changed

Include/cpython/pyatomic.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -523,6 +523,9 @@ _Py_atomic_store_uintptr_release(uintptr_t *obj, uintptr_t value);
523523
static inline void
524524
_Py_atomic_store_ssize_release(Py_ssize_t *obj, Py_ssize_t value);
525525

526+
static inline void
527+
_Py_atomic_store_int8_release(int8_t *obj, int8_t value);
528+
526529
static inline void
527530
_Py_atomic_store_int_release(int *obj, int value);
528531

Include/cpython/pyatomic_gcc.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -572,6 +572,10 @@ static inline void
572572
_Py_atomic_store_int_release(int *obj, int value)
573573
{ __atomic_store_n(obj, value, __ATOMIC_RELEASE); }
574574

575+
static inline void
576+
_Py_atomic_store_int8_release(int8_t *obj, int8_t value)
577+
{ __atomic_store_n(obj, value, __ATOMIC_RELEASE); }
578+
575579
static inline void
576580
_Py_atomic_store_ssize_release(Py_ssize_t *obj, Py_ssize_t value)
577581
{ __atomic_store_n(obj, value, __ATOMIC_RELEASE); }

Include/cpython/pyatomic_msc.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1066,6 +1066,19 @@ _Py_atomic_store_int_release(int *obj, int value)
10661066
#endif
10671067
}
10681068

1069+
static inline void
1070+
_Py_atomic_store_int8_release(int8_t *obj, int8_t value)
1071+
{
1072+
#if defined(_M_X64) || defined(_M_IX86)
1073+
*(int8_t volatile *)obj = value;
1074+
#elif defined(_M_ARM64)
1075+
_Py_atomic_ASSERT_ARG_TYPE(unsigned __int8);
1076+
__stlr8((unsigned __int8 volatile *)obj, (unsigned __int8)value);
1077+
#else
1078+
# error "no implementation of _Py_atomic_store_int8_release"
1079+
#endif
1080+
}
1081+
10691082
static inline void
10701083
_Py_atomic_store_ssize_release(Py_ssize_t *obj, Py_ssize_t value)
10711084
{

Include/cpython/pyatomic_std.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1023,6 +1023,14 @@ _Py_atomic_store_int_release(int *obj, int value)
10231023
memory_order_release);
10241024
}
10251025

1026+
static inline void
1027+
_Py_atomic_store_int8_release(int8_t *obj, int8_t value)
1028+
{
1029+
_Py_USING_STD;
1030+
atomic_store_explicit((_Atomic(int8_t)*)obj, value,
1031+
memory_order_release);
1032+
}
1033+
10261034
static inline void
10271035
_Py_atomic_store_uint_release(unsigned int *obj, unsigned int value)
10281036
{

Include/internal/pycore_pyatomic_ft_wrappers.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,8 @@ extern "C" {
4141
_Py_atomic_load_uint8(&value)
4242
#define FT_ATOMIC_STORE_UINT8(value, new_value) \
4343
_Py_atomic_store_uint8(&value, new_value)
44+
#define FT_ATOMIC_LOAD_INT8_RELAXED(value) \
45+
_Py_atomic_load_int8_relaxed(&value)
4446
#define FT_ATOMIC_LOAD_UINT8_RELAXED(value) \
4547
_Py_atomic_load_uint8_relaxed(&value)
4648
#define FT_ATOMIC_LOAD_UINT16_RELAXED(value) \
@@ -55,6 +57,10 @@ extern "C" {
5557
_Py_atomic_store_ptr_release(&value, new_value)
5658
#define FT_ATOMIC_STORE_UINTPTR_RELEASE(value, new_value) \
5759
_Py_atomic_store_uintptr_release(&value, new_value)
60+
#define FT_ATOMIC_STORE_INT8_RELAXED(value, new_value) \
61+
_Py_atomic_store_int8_relaxed(&value, new_value)
62+
#define FT_ATOMIC_STORE_INT8_RELEASE(value, new_value) \
63+
_Py_atomic_store_int8_release(&value, new_value)
5864
#define FT_ATOMIC_STORE_SSIZE_RELAXED(value, new_value) \
5965
_Py_atomic_store_ssize_relaxed(&value, new_value)
6066
#define FT_ATOMIC_STORE_SSIZE_RELEASE(value, new_value) \
@@ -134,13 +140,16 @@ extern "C" {
134140
#define FT_ATOMIC_LOAD_PTR_RELAXED(value) value
135141
#define FT_ATOMIC_LOAD_UINT8(value) value
136142
#define FT_ATOMIC_STORE_UINT8(value, new_value) value = new_value
143+
#define FT_ATOMIC_LOAD_INT8_RELAXED(value) value
137144
#define FT_ATOMIC_LOAD_UINT8_RELAXED(value) value
138145
#define FT_ATOMIC_LOAD_UINT16_RELAXED(value) value
139146
#define FT_ATOMIC_LOAD_UINT32_RELAXED(value) value
140147
#define FT_ATOMIC_LOAD_ULONG_RELAXED(value) value
141148
#define FT_ATOMIC_STORE_PTR_RELAXED(value, new_value) value = new_value
142149
#define FT_ATOMIC_STORE_PTR_RELEASE(value, new_value) value = new_value
143150
#define FT_ATOMIC_STORE_UINTPTR_RELEASE(value, new_value) value = new_value
151+
#define FT_ATOMIC_STORE_INT8_RELAXED(value, new_value) value = new_value
152+
#define FT_ATOMIC_STORE_INT8_RELEASE(value, new_value) value = new_value
144153
#define FT_ATOMIC_STORE_SSIZE_RELAXED(value, new_value) value = new_value
145154
#define FT_ATOMIC_STORE_SSIZE_RELEASE(value, new_value) value = new_value
146155
#define FT_ATOMIC_STORE_UINT8_RELAXED(value, new_value) value = new_value

Include/internal/pycore_tstate.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,13 @@ typedef struct _PyThreadStateImpl {
8282
PyObject *asyncio_running_loop; // Strong reference
8383
PyObject *asyncio_running_task; // Strong reference
8484

85+
// Distinguishes between yield and return from PyEval_EvalFrame().
86+
// See gen_send_ex2() in Objects/genobject.c
87+
enum {
88+
GENERATOR_RETURN = 0,
89+
GENERATOR_YIELD = 1,
90+
} generator_return_kind;
91+
8592
/* Head of circular linked-list of all tasks which are instances of `asyncio.Task`
8693
or subclasses of it used in `asyncio.all_tasks`.
8794
*/

0 commit comments

Comments
 (0)