@@ -190,9 +190,12 @@ gen_send_ex2(PyGenObject *gen, PyObject *arg, PyObject **presult,
190190{
191191 PyThreadState * tstate = _PyThreadState_GET ();
192192 _PyInterpreterFrame * frame = & gen -> gi_iframe ;
193+ int8_t frame_state ;
193194
194195 * presult = NULL ;
195- if (gen -> gi_frame_state == FRAME_CREATED && arg && arg != Py_None ) {
196+ retry :
197+ frame_state = FT_ATOMIC_LOAD_INT8_RELAXED (gen -> gi_frame_state );
198+ if (frame_state == FRAME_CREATED && arg && arg != Py_None ) {
196199 const char * msg = "can't send non-None value to a "
197200 "just-started generator" ;
198201 if (PyCoro_CheckExact (gen )) {
@@ -205,7 +208,7 @@ gen_send_ex2(PyGenObject *gen, PyObject *arg, PyObject **presult,
205208 PyErr_SetString (PyExc_TypeError , msg );
206209 return PYGEN_ERROR ;
207210 }
208- if (gen -> gi_frame_state == FRAME_EXECUTING ) {
211+ if (frame_state == FRAME_EXECUTING ) {
209212 const char * msg = "generator already executing" ;
210213 if (PyCoro_CheckExact (gen )) {
211214 msg = "coroutine already executing" ;
@@ -216,7 +219,7 @@ gen_send_ex2(PyGenObject *gen, PyObject *arg, PyObject **presult,
216219 PyErr_SetString (PyExc_ValueError , msg );
217220 return PYGEN_ERROR ;
218221 }
219- if (FRAME_STATE_FINISHED (gen -> gi_frame_state )) {
222+ if (FRAME_STATE_FINISHED (frame_state )) {
220223 if (PyCoro_CheckExact (gen ) && !closing ) {
221224 /* `gen` is an exhausted coroutine: raise an error,
222225 except when called from gen_close(), which should
@@ -234,8 +237,12 @@ gen_send_ex2(PyGenObject *gen, PyObject *arg, PyObject **presult,
234237 return PYGEN_ERROR ;
235238 }
236239
237- assert ((gen -> gi_frame_state == FRAME_CREATED ) ||
238- FRAME_STATE_SUSPENDED (gen -> gi_frame_state ));
240+ assert ((frame_state == FRAME_CREATED ) ||
241+ FRAME_STATE_SUSPENDED (frame_state ));
242+
243+ if (!_PyGen_TransitionFrameState (gen , & frame_state , FRAME_EXECUTING )) {
244+ goto retry ;
245+ }
239246
240247 /* Push arg onto the frame's value stack */
241248 PyObject * arg_obj = arg ? arg : Py_None ;
@@ -245,23 +252,36 @@ gen_send_ex2(PyGenObject *gen, PyObject *arg, PyObject **presult,
245252 gen -> gi_exc_state .previous_item = prev_exc_info ;
246253 tstate -> exc_info = & gen -> gi_exc_state ;
247254
255+ #ifdef Py_GIL_DISABLED
256+ /* Store the resulting frame_state in frame_state */
257+ assert (gen -> gi_out_frame_state == NULL );
258+ gen -> gi_out_frame_state = & frame_state ;
259+ #endif
260+
248261 if (exc ) {
249262 assert (_PyErr_Occurred (tstate ));
250263 _PyErr_ChainStackItem ();
251264 }
252265
253- gen -> gi_frame_state = FRAME_EXECUTING ;
254266 EVAL_CALL_STAT_INC (EVAL_CALL_GENERATOR );
255267 PyObject * result = _PyEval_EvalFrame (tstate , frame , exc );
256- assert (tstate -> exc_info == prev_exc_info );
257- assert (gen -> gi_exc_state .previous_item == NULL );
258- assert (gen -> gi_frame_state != FRAME_EXECUTING );
268+
269+ #ifndef Py_GIL_DISABLED
270+ frame_state = gen -> gi_frame_state ;
271+
272+ // These asserts are not thread-safe in the free threaded build. Some
273+ // other thread can immediately start executing the generator here.
259274 assert (frame -> previous == NULL );
275+ assert (gen -> gi_exc_state .previous_item == NULL );
276+ #endif
277+
278+ assert (tstate -> exc_info == prev_exc_info );
279+ assert (frame_state != FRAME_EXECUTING );
260280
261281 /* If the generator just returned (as opposed to yielding), signal
262282 * that the generator is exhausted. */
263283 if (result ) {
264- if (FRAME_STATE_SUSPENDED (gen -> gi_frame_state )) {
284+ if (FRAME_STATE_SUSPENDED (frame_state )) {
265285 * presult = result ;
266286 return PYGEN_NEXT ;
267287 }
@@ -277,8 +297,10 @@ gen_send_ex2(PyGenObject *gen, PyObject *arg, PyObject **presult,
277297 !PyErr_ExceptionMatches (PyExc_StopAsyncIteration ));
278298 }
279299
300+ #ifndef Py_GIL_DISABLED
280301 assert (gen -> gi_exc_state .exc_value == NULL );
281- assert (gen -> gi_frame_state == FRAME_CLEARED );
302+ #endif
303+ assert (frame_state == FRAME_CLEARED );
282304 * presult = result ;
283305 return result ? PYGEN_RETURN : PYGEN_ERROR ;
284306}
@@ -918,6 +940,9 @@ make_gen(PyTypeObject *type, PyFunctionObject *func)
918940 gen -> gi_weakreflist = NULL ;
919941 gen -> gi_exc_state .exc_value = NULL ;
920942 gen -> gi_exc_state .previous_item = NULL ;
943+ #ifdef Py_GIL_DISABLED
944+ gen -> gi_out_frame_state = NULL ;
945+ #endif
921946 assert (func -> func_name != NULL );
922947 gen -> gi_name = Py_NewRef (func -> func_name );
923948 assert (func -> func_qualname != NULL );
@@ -1001,6 +1026,9 @@ gen_new_with_qualname(PyTypeObject *type, PyFrameObject *f,
10011026 gen -> gi_weakreflist = NULL ;
10021027 gen -> gi_exc_state .exc_value = NULL ;
10031028 gen -> gi_exc_state .previous_item = NULL ;
1029+ #ifdef Py_GIL_DISABLED
1030+ gen -> gi_out_frame_state = NULL ;
1031+ #endif
10041032 if (name != NULL )
10051033 gen -> gi_name = Py_NewRef (name );
10061034 else
0 commit comments