mirror of
https://github.com/python/cpython.git
synced 2025-12-23 09:19:18 +00:00
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
This commit is contained in:
parent
e2a7db7175
commit
08bc03ff2a
16 changed files with 1124 additions and 883 deletions
|
|
@ -523,6 +523,9 @@ _Py_atomic_store_uintptr_release(uintptr_t *obj, uintptr_t value);
|
|||
static inline void
|
||||
_Py_atomic_store_ssize_release(Py_ssize_t *obj, Py_ssize_t value);
|
||||
|
||||
static inline void
|
||||
_Py_atomic_store_int8_release(int8_t *obj, int8_t value);
|
||||
|
||||
static inline void
|
||||
_Py_atomic_store_int_release(int *obj, int value);
|
||||
|
||||
|
|
|
|||
|
|
@ -572,6 +572,10 @@ static inline void
|
|||
_Py_atomic_store_int_release(int *obj, int value)
|
||||
{ __atomic_store_n(obj, value, __ATOMIC_RELEASE); }
|
||||
|
||||
static inline void
|
||||
_Py_atomic_store_int8_release(int8_t *obj, int8_t value)
|
||||
{ __atomic_store_n(obj, value, __ATOMIC_RELEASE); }
|
||||
|
||||
static inline void
|
||||
_Py_atomic_store_ssize_release(Py_ssize_t *obj, Py_ssize_t value)
|
||||
{ __atomic_store_n(obj, value, __ATOMIC_RELEASE); }
|
||||
|
|
|
|||
|
|
@ -1066,6 +1066,19 @@ _Py_atomic_store_int_release(int *obj, int value)
|
|||
#endif
|
||||
}
|
||||
|
||||
static inline void
|
||||
_Py_atomic_store_int8_release(int8_t *obj, int8_t value)
|
||||
{
|
||||
#if defined(_M_X64) || defined(_M_IX86)
|
||||
*(int8_t volatile *)obj = value;
|
||||
#elif defined(_M_ARM64)
|
||||
_Py_atomic_ASSERT_ARG_TYPE(unsigned __int8);
|
||||
__stlr8((unsigned __int8 volatile *)obj, (unsigned __int8)value);
|
||||
#else
|
||||
# error "no implementation of _Py_atomic_store_int8_release"
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void
|
||||
_Py_atomic_store_ssize_release(Py_ssize_t *obj, Py_ssize_t value)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1023,6 +1023,14 @@ _Py_atomic_store_int_release(int *obj, int value)
|
|||
memory_order_release);
|
||||
}
|
||||
|
||||
static inline void
|
||||
_Py_atomic_store_int8_release(int8_t *obj, int8_t value)
|
||||
{
|
||||
_Py_USING_STD;
|
||||
atomic_store_explicit((_Atomic(int8_t)*)obj, value,
|
||||
memory_order_release);
|
||||
}
|
||||
|
||||
static inline void
|
||||
_Py_atomic_store_uint_release(unsigned int *obj, unsigned int value)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -41,6 +41,8 @@ extern "C" {
|
|||
_Py_atomic_load_uint8(&value)
|
||||
#define FT_ATOMIC_STORE_UINT8(value, new_value) \
|
||||
_Py_atomic_store_uint8(&value, new_value)
|
||||
#define FT_ATOMIC_LOAD_INT8_RELAXED(value) \
|
||||
_Py_atomic_load_int8_relaxed(&value)
|
||||
#define FT_ATOMIC_LOAD_UINT8_RELAXED(value) \
|
||||
_Py_atomic_load_uint8_relaxed(&value)
|
||||
#define FT_ATOMIC_LOAD_UINT16_RELAXED(value) \
|
||||
|
|
@ -55,6 +57,10 @@ extern "C" {
|
|||
_Py_atomic_store_ptr_release(&value, new_value)
|
||||
#define FT_ATOMIC_STORE_UINTPTR_RELEASE(value, new_value) \
|
||||
_Py_atomic_store_uintptr_release(&value, new_value)
|
||||
#define FT_ATOMIC_STORE_INT8_RELAXED(value, new_value) \
|
||||
_Py_atomic_store_int8_relaxed(&value, new_value)
|
||||
#define FT_ATOMIC_STORE_INT8_RELEASE(value, new_value) \
|
||||
_Py_atomic_store_int8_release(&value, new_value)
|
||||
#define FT_ATOMIC_STORE_SSIZE_RELAXED(value, new_value) \
|
||||
_Py_atomic_store_ssize_relaxed(&value, new_value)
|
||||
#define FT_ATOMIC_STORE_SSIZE_RELEASE(value, new_value) \
|
||||
|
|
@ -134,6 +140,7 @@ extern "C" {
|
|||
#define FT_ATOMIC_LOAD_PTR_RELAXED(value) value
|
||||
#define FT_ATOMIC_LOAD_UINT8(value) value
|
||||
#define FT_ATOMIC_STORE_UINT8(value, new_value) value = new_value
|
||||
#define FT_ATOMIC_LOAD_INT8_RELAXED(value) value
|
||||
#define FT_ATOMIC_LOAD_UINT8_RELAXED(value) value
|
||||
#define FT_ATOMIC_LOAD_UINT16_RELAXED(value) value
|
||||
#define FT_ATOMIC_LOAD_UINT32_RELAXED(value) value
|
||||
|
|
@ -141,6 +148,8 @@ extern "C" {
|
|||
#define FT_ATOMIC_STORE_PTR_RELAXED(value, new_value) value = new_value
|
||||
#define FT_ATOMIC_STORE_PTR_RELEASE(value, new_value) value = new_value
|
||||
#define FT_ATOMIC_STORE_UINTPTR_RELEASE(value, new_value) value = new_value
|
||||
#define FT_ATOMIC_STORE_INT8_RELAXED(value, new_value) value = new_value
|
||||
#define FT_ATOMIC_STORE_INT8_RELEASE(value, new_value) value = new_value
|
||||
#define FT_ATOMIC_STORE_SSIZE_RELAXED(value, new_value) value = new_value
|
||||
#define FT_ATOMIC_STORE_SSIZE_RELEASE(value, new_value) value = new_value
|
||||
#define FT_ATOMIC_STORE_UINT8_RELAXED(value, new_value) value = new_value
|
||||
|
|
|
|||
|
|
@ -82,6 +82,13 @@ typedef struct _PyThreadStateImpl {
|
|||
PyObject *asyncio_running_loop; // Strong reference
|
||||
PyObject *asyncio_running_task; // Strong reference
|
||||
|
||||
// Distinguishes between yield and return from PyEval_EvalFrame().
|
||||
// See gen_send_ex2() in Objects/genobject.c
|
||||
enum {
|
||||
GENERATOR_RETURN = 0,
|
||||
GENERATOR_YIELD = 1,
|
||||
} generator_return_kind;
|
||||
|
||||
/* Head of circular linked-list of all tasks which are instances of `asyncio.Task`
|
||||
or subclasses of it used in `asyncio.all_tasks`.
|
||||
*/
|
||||
|
|
|
|||
1134
Include/internal/pycore_uop_ids.h
generated
1134
Include/internal/pycore_uop_ids.h
generated
File diff suppressed because it is too large
Load diff
10
Include/internal/pycore_uop_metadata.h
generated
10
Include/internal/pycore_uop_metadata.h
generated
|
|
@ -2131,10 +2131,10 @@ const _PyUopCachingInfo _PyUop_Caching[MAX_UOP_ID+1] = {
|
|||
},
|
||||
},
|
||||
[_FOR_ITER_GEN_FRAME] = {
|
||||
.best = { 2, 2, 2, 2 },
|
||||
.best = { 0, 1, 2, 2 },
|
||||
.entries = {
|
||||
{ -1, -1, -1 },
|
||||
{ -1, -1, -1 },
|
||||
{ 3, 0, _FOR_ITER_GEN_FRAME_r03 },
|
||||
{ 3, 1, _FOR_ITER_GEN_FRAME_r13 },
|
||||
{ 3, 2, _FOR_ITER_GEN_FRAME_r23 },
|
||||
{ -1, -1, -1 },
|
||||
},
|
||||
|
|
@ -3620,6 +3620,8 @@ const uint16_t _PyUop_Uncached[MAX_UOP_REGS_ID+1] = {
|
|||
[_ITER_NEXT_RANGE_r03] = _ITER_NEXT_RANGE,
|
||||
[_ITER_NEXT_RANGE_r13] = _ITER_NEXT_RANGE,
|
||||
[_ITER_NEXT_RANGE_r23] = _ITER_NEXT_RANGE,
|
||||
[_FOR_ITER_GEN_FRAME_r03] = _FOR_ITER_GEN_FRAME,
|
||||
[_FOR_ITER_GEN_FRAME_r13] = _FOR_ITER_GEN_FRAME,
|
||||
[_FOR_ITER_GEN_FRAME_r23] = _FOR_ITER_GEN_FRAME,
|
||||
[_INSERT_NULL_r10] = _INSERT_NULL,
|
||||
[_LOAD_SPECIAL_r00] = _LOAD_SPECIAL,
|
||||
|
|
@ -4182,6 +4184,8 @@ const char *const _PyOpcode_uop_name[MAX_UOP_REGS_ID+1] = {
|
|||
[_FORMAT_WITH_SPEC] = "_FORMAT_WITH_SPEC",
|
||||
[_FORMAT_WITH_SPEC_r21] = "_FORMAT_WITH_SPEC_r21",
|
||||
[_FOR_ITER_GEN_FRAME] = "_FOR_ITER_GEN_FRAME",
|
||||
[_FOR_ITER_GEN_FRAME_r03] = "_FOR_ITER_GEN_FRAME_r03",
|
||||
[_FOR_ITER_GEN_FRAME_r13] = "_FOR_ITER_GEN_FRAME_r13",
|
||||
[_FOR_ITER_GEN_FRAME_r23] = "_FOR_ITER_GEN_FRAME_r23",
|
||||
[_FOR_ITER_TIER_TWO] = "_FOR_ITER_TIER_TWO",
|
||||
[_FOR_ITER_TIER_TWO_r23] = "_FOR_ITER_TIER_TWO_r23",
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue