@@ -153,6 +153,7 @@ _PyGen_Finalize(PyObject *self)
153153static void
154154gen_clear_frame (PyGenObject * gen )
155155{
156+ assert (gen -> gi_frame_state == FRAME_CLEARED );
156157 _PyInterpreterFrame * frame = & gen -> gi_iframe ;
157158 frame -> previous = NULL ;
158159 _PyFrame_ClearExceptCode (frame );
@@ -285,48 +286,45 @@ gen_send_ex(PyGenObject *gen, PyObject *arg, PyObject **presult)
285286{
286287 * presult = NULL ;
287288 int8_t frame_state = FT_ATOMIC_LOAD_INT8_RELAXED (gen -> gi_frame_state );
288- retry :
289- if (frame_state == FRAME_CREATED && arg && arg != Py_None ) {
290- const char * msg = "can't send non-None value to a "
291- "just-started generator" ;
292- if (PyCoro_CheckExact (gen )) {
293- msg = NON_INIT_CORO_MSG ;
294- }
295- else if (PyAsyncGen_CheckExact (gen )) {
296- msg = "can't send non-None value to a "
297- "just-started async generator" ;
289+ do {
290+ if (frame_state == FRAME_CREATED && arg && arg != Py_None ) {
291+ const char * msg = "can't send non-None value to a "
292+ "just-started generator" ;
293+ if (PyCoro_CheckExact (gen )) {
294+ msg = NON_INIT_CORO_MSG ;
295+ }
296+ else if (PyAsyncGen_CheckExact (gen )) {
297+ msg = "can't send non-None value to a "
298+ "just-started async generator" ;
299+ }
300+ PyErr_SetString (PyExc_TypeError , msg );
301+ return PYGEN_ERROR ;
298302 }
299- PyErr_SetString (PyExc_TypeError , msg );
300- return PYGEN_ERROR ;
301- }
302- if (frame_state == FRAME_EXECUTING ) {
303- gen_raise_already_executing_error (gen );
304- return PYGEN_ERROR ;
305- }
306- if (FRAME_STATE_FINISHED (frame_state )) {
307- if (PyCoro_CheckExact (gen )) {
308- /* `gen` is an exhausted coroutine: raise an error,
309- except when called from gen_close(), which should
310- always be a silent method. */
311- PyErr_SetString (
312- PyExc_RuntimeError ,
313- "cannot reuse already awaited coroutine" );
303+ if (frame_state == FRAME_EXECUTING ) {
304+ gen_raise_already_executing_error (gen );
305+ return PYGEN_ERROR ;
314306 }
315- else if (arg ) {
316- /* `gen` is an exhausted generator:
317- only return value if called from send(). */
318- * presult = Py_NewRef (Py_None );
319- return PYGEN_RETURN ;
307+ if (FRAME_STATE_FINISHED (frame_state )) {
308+ if (PyCoro_CheckExact (gen )) {
309+ /* `gen` is an exhausted coroutine: raise an error,
310+ except when called from gen_close(), which should
311+ always be a silent method. */
312+ PyErr_SetString (
313+ PyExc_RuntimeError ,
314+ "cannot reuse already awaited coroutine" );
315+ }
316+ else if (arg ) {
317+ /* `gen` is an exhausted generator:
318+ only return value if called from send(). */
319+ * presult = Py_NewRef (Py_None );
320+ return PYGEN_RETURN ;
321+ }
322+ return PYGEN_ERROR ;
320323 }
321- return PYGEN_ERROR ;
322- }
323324
324- assert ((frame_state == FRAME_CREATED ) ||
325- FRAME_STATE_SUSPENDED (frame_state ));
326-
327- if (!_Py_GEN_TRY_SET_FRAME_STATE (gen , frame_state , FRAME_EXECUTING )) {
328- goto retry ;
329- }
325+ assert ((frame_state == FRAME_CREATED ) ||
326+ FRAME_STATE_SUSPENDED (frame_state ));
327+ } while (!_Py_GEN_TRY_SET_FRAME_STATE (gen , frame_state , FRAME_EXECUTING ));
330328
331329 return gen_send_ex2 (gen , arg , presult , 0 );
332330}
@@ -422,29 +420,27 @@ gen_close(PyObject *self, PyObject *args)
422420 PyGenObject * gen = _PyGen_CAST (self );
423421
424422 int8_t frame_state = FT_ATOMIC_LOAD_INT8_RELAXED (gen -> gi_frame_state );
425- retry :
426- if (frame_state == FRAME_CREATED ) {
427- if (!_Py_GEN_TRY_SET_FRAME_STATE (gen , frame_state , FRAME_COMPLETED )) {
428- goto retry ;
423+ do {
424+ if (frame_state == FRAME_CREATED ) {
425+ if (!_Py_GEN_TRY_SET_FRAME_STATE (gen , frame_state , FRAME_COMPLETED )) {
426+ continue ;
427+ }
428+ Py_RETURN_NONE ;
429429 }
430- Py_RETURN_NONE ;
431- }
432430
433- if (FRAME_STATE_FINISHED (frame_state )) {
434- Py_RETURN_NONE ;
435- }
431+ if (FRAME_STATE_FINISHED (frame_state )) {
432+ Py_RETURN_NONE ;
433+ }
436434
437- if (frame_state == FRAME_EXECUTING ) {
438- gen_raise_already_executing_error (gen );
439- return NULL ;
440- }
435+ if (frame_state == FRAME_EXECUTING ) {
436+ gen_raise_already_executing_error (gen );
437+ return NULL ;
438+ }
441439
442- assert (frame_state == FRAME_SUSPENDED_YIELD_FROM ||
443- frame_state == FRAME_SUSPENDED );
440+ assert (frame_state == FRAME_SUSPENDED_YIELD_FROM ||
441+ frame_state == FRAME_SUSPENDED );
444442
445- if (!_Py_GEN_TRY_SET_FRAME_STATE (gen , frame_state , FRAME_EXECUTING )) {
446- goto retry ;
447- }
443+ } while (!_Py_GEN_TRY_SET_FRAME_STATE (gen , frame_state , FRAME_EXECUTING ));
448444
449445 int err = 0 ;
450446 _PyInterpreterFrame * frame = & gen -> gi_iframe ;
@@ -584,27 +580,27 @@ _gen_throw(PyGenObject *gen, int close_on_genexit,
584580 PyObject * typ , PyObject * val , PyObject * tb )
585581{
586582 int8_t frame_state = FT_ATOMIC_LOAD_INT8_RELAXED (gen -> gi_frame_state );
587- retry :
588- if (frame_state == FRAME_EXECUTING ) {
589- gen_raise_already_executing_error (gen );
590- return NULL ;
591- }
583+ do {
584+ if (frame_state == FRAME_EXECUTING ) {
585+ gen_raise_already_executing_error (gen );
586+ return NULL ;
587+ }
592588
593- if (FRAME_STATE_FINISHED (frame_state )) {
594- if (PyCoro_CheckExact (gen )) {
595- /* `gen` is an exhausted coroutine: raise an error */
596- PyErr_SetString (
597- PyExc_RuntimeError ,
598- "cannot reuse already awaited coroutine" );
589+ if (FRAME_STATE_FINISHED (frame_state )) {
590+ if (PyCoro_CheckExact (gen )) {
591+ /* `gen` is an exhausted coroutine: raise an error */
592+ PyErr_SetString (
593+ PyExc_RuntimeError ,
594+ "cannot reuse already awaited coroutine" );
595+ return NULL ;
596+ }
597+ gen_set_exception (typ , val , tb );
599598 return NULL ;
600599 }
601- gen_set_exception (typ , val , tb );
602- return NULL ;
603- }
604600
605- if (! _Py_GEN_TRY_SET_FRAME_STATE ( gen , frame_state , FRAME_EXECUTING )) {
606- goto retry ;
607- }
601+ assert (( frame_state == FRAME_CREATED ) ||
602+ FRAME_STATE_SUSPENDED ( frame_state )) ;
603+ } while (! _Py_GEN_TRY_SET_FRAME_STATE ( gen , frame_state , FRAME_EXECUTING ));
608604
609605 if (frame_state == FRAME_SUSPENDED_YIELD_FROM ) {
610606 _PyInterpreterFrame * frame = & gen -> gi_iframe ;
0 commit comments