@@ -47,7 +47,7 @@ _PyGen_Finalize(PyObject *self)
47
47
PyObject * res = NULL ;
48
48
PyObject * error_type , * error_value , * error_traceback ;
49
49
50
- if (gen -> gi_frame == NULL || gen -> gi_frame -> f_stacktop == NULL ) {
50
+ if (gen -> gi_frame == NULL || _PyFrameHasCompleted ( gen -> gi_frame ) ) {
51
51
/* Generator isn't paused, so no need to close */
52
52
return ;
53
53
}
@@ -143,7 +143,7 @@ gen_send_ex(PyGenObject *gen, PyObject *arg, int exc, int closing)
143
143
PyFrameObject * f = gen -> gi_frame ;
144
144
PyObject * result ;
145
145
146
- if (gen -> gi_running ) {
146
+ if (f != NULL && _PyFrameIsExecuting ( f ) ) {
147
147
const char * msg = "generator already executing" ;
148
148
if (PyCoro_CheckExact (gen )) {
149
149
msg = "coroutine already executing" ;
@@ -154,7 +154,7 @@ gen_send_ex(PyGenObject *gen, PyObject *arg, int exc, int closing)
154
154
PyErr_SetString (PyExc_ValueError , msg );
155
155
return NULL ;
156
156
}
157
- if (f == NULL || f -> f_stacktop == NULL ) {
157
+ if (f == NULL || _PyFrameHasCompleted ( f ) ) {
158
158
if (PyCoro_CheckExact (gen ) && !closing ) {
159
159
/* `gen` is an exhausted coroutine: raise an error,
160
160
except when called from gen_close(), which should
@@ -176,6 +176,7 @@ gen_send_ex(PyGenObject *gen, PyObject *arg, int exc, int closing)
176
176
return NULL ;
177
177
}
178
178
179
+ assert (_PyFrameIsRunnable (f ));
179
180
if (f -> f_lasti == -1 ) {
180
181
if (arg && arg != Py_None ) {
181
182
const char * msg = "can't send non-None value to a "
@@ -203,7 +204,6 @@ gen_send_ex(PyGenObject *gen, PyObject *arg, int exc, int closing)
203
204
assert (f -> f_back == NULL );
204
205
f -> f_back = tstate -> frame ;
205
206
206
- gen -> gi_running = 1 ;
207
207
gen -> gi_exc_state .previous_item = tstate -> exc_info ;
208
208
tstate -> exc_info = & gen -> gi_exc_state ;
209
209
@@ -215,7 +215,6 @@ gen_send_ex(PyGenObject *gen, PyObject *arg, int exc, int closing)
215
215
result = _PyEval_EvalFrame (tstate , f , exc );
216
216
tstate -> exc_info = gen -> gi_exc_state .previous_item ;
217
217
gen -> gi_exc_state .previous_item = NULL ;
218
- gen -> gi_running = 0 ;
219
218
220
219
/* Don't keep the reference to f_back any longer than necessary. It
221
220
* may keep a chain of frames alive or it could create a reference
@@ -225,7 +224,7 @@ gen_send_ex(PyGenObject *gen, PyObject *arg, int exc, int closing)
225
224
226
225
/* If the generator just returned (as opposed to yielding), signal
227
226
* that the generator is exhausted. */
228
- if (result && f -> f_stacktop == NULL ) {
227
+ if (result && _PyFrameHasCompleted ( f ) ) {
229
228
if (result == Py_None ) {
230
229
/* Delay exception instantiation if we can */
231
230
if (PyAsyncGen_CheckExact (gen )) {
@@ -264,7 +263,7 @@ gen_send_ex(PyGenObject *gen, PyObject *arg, int exc, int closing)
264
263
_PyErr_FormatFromCause (PyExc_RuntimeError , "%s" , msg );
265
264
}
266
265
267
- if (!result || f -> f_stacktop == NULL ) {
266
+ if (!result || _PyFrameHasCompleted ( f ) ) {
268
267
/* generator can't be rerun, so release the frame */
269
268
/* first clean reference cycle through stored exception traceback */
270
269
_PyErr_ClearExcState (& gen -> gi_exc_state );
@@ -356,9 +355,10 @@ gen_close(PyGenObject *gen, PyObject *args)
356
355
int err = 0 ;
357
356
358
357
if (yf ) {
359
- gen -> gi_running = 1 ;
358
+ PyFrameState state = gen -> gi_frame -> f_state ;
359
+ gen -> gi_frame -> f_state = FRAME_EXECUTING ;
360
360
err = gen_close_iter (yf );
361
- gen -> gi_running = 0 ;
361
+ gen -> gi_frame -> f_state = state ;
362
362
Py_DECREF (yf );
363
363
}
364
364
if (err == 0 )
@@ -405,9 +405,10 @@ _gen_throw(PyGenObject *gen, int close_on_genexit,
405
405
We have to allow some awaits to work it through, hence the
406
406
`close_on_genexit` parameter here.
407
407
*/
408
- gen -> gi_running = 1 ;
408
+ PyFrameState state = gen -> gi_frame -> f_state ;
409
+ gen -> gi_frame -> f_state = FRAME_EXECUTING ;
409
410
err = gen_close_iter (yf );
410
- gen -> gi_running = 0 ;
411
+ gen -> gi_frame -> f_state = state ;
411
412
Py_DECREF (yf );
412
413
if (err < 0 )
413
414
return gen_send_ex (gen , Py_None , 1 , 0 );
@@ -418,7 +419,6 @@ _gen_throw(PyGenObject *gen, int close_on_genexit,
418
419
PyThreadState * tstate = _PyThreadState_GET ();
419
420
PyFrameObject * f = tstate -> frame ;
420
421
421
- gen -> gi_running = 1 ;
422
422
/* Since we are fast-tracking things by skipping the eval loop,
423
423
we need to update the current frame so the stack trace
424
424
will be reported correctly to the user. */
@@ -427,10 +427,12 @@ _gen_throw(PyGenObject *gen, int close_on_genexit,
427
427
tstate -> frame = gen -> gi_frame ;
428
428
/* Close the generator that we are currently iterating with
429
429
'yield from' or awaiting on with 'await'. */
430
+ PyFrameState state = gen -> gi_frame -> f_state ;
431
+ gen -> gi_frame -> f_state = FRAME_EXECUTING ;
430
432
ret = _gen_throw ((PyGenObject * )yf , close_on_genexit ,
431
433
typ , val , tb );
432
434
tstate -> frame = f ;
433
- gen -> gi_running = 0 ;
435
+ gen -> gi_frame -> f_state = state ;
434
436
} else {
435
437
/* `yf` is an iterator or a coroutine-like object. */
436
438
PyObject * meth ;
@@ -442,9 +444,10 @@ _gen_throw(PyGenObject *gen, int close_on_genexit,
442
444
Py_DECREF (yf );
443
445
goto throw_here ;
444
446
}
445
- gen -> gi_running = 1 ;
447
+ PyFrameState state = gen -> gi_frame -> f_state ;
448
+ gen -> gi_frame -> f_state = FRAME_EXECUTING ;
446
449
ret = PyObject_CallFunctionObjArgs (meth , typ , val , tb , NULL );
447
- gen -> gi_running = 0 ;
450
+ gen -> gi_frame -> f_state = state ;
448
451
Py_DECREF (meth );
449
452
}
450
453
Py_DECREF (yf );
@@ -701,19 +704,30 @@ gen_getyieldfrom(PyGenObject *gen, void *Py_UNUSED(ignored))
701
704
return yf ;
702
705
}
703
706
707
+
708
+ static PyObject *
709
+ gen_getrunning (PyGenObject * gen , void * Py_UNUSED (ignored ))
710
+ {
711
+ if (gen -> gi_frame == NULL ) {
712
+ Py_INCREF (Py_False );
713
+ return Py_False ;
714
+ }
715
+ return PyBool_FromLong (_PyFrameIsExecuting (gen -> gi_frame ));
716
+ }
717
+
704
718
static PyGetSetDef gen_getsetlist [] = {
705
719
{"__name__" , (getter )gen_get_name , (setter )gen_set_name ,
706
720
PyDoc_STR ("name of the generator" )},
707
721
{"__qualname__" , (getter )gen_get_qualname , (setter )gen_set_qualname ,
708
722
PyDoc_STR ("qualified name of the generator" )},
709
723
{"gi_yieldfrom" , (getter )gen_getyieldfrom , NULL ,
710
724
PyDoc_STR ("object being iterated by yield from, or None" )},
725
+ {"gi_running" , (getter )gen_getrunning , NULL , NULL },
711
726
{NULL } /* Sentinel */
712
727
};
713
728
714
729
static PyMemberDef gen_memberlist [] = {
715
730
{"gi_frame" , T_OBJECT , offsetof(PyGenObject , gi_frame ), READONLY },
716
- {"gi_running" , T_BOOL , offsetof(PyGenObject , gi_running ), READONLY },
717
731
{"gi_code" , T_OBJECT , offsetof(PyGenObject , gi_code ), READONLY },
718
732
{NULL } /* Sentinel */
719
733
};
@@ -791,7 +805,6 @@ gen_new_with_qualname(PyTypeObject *type, PyFrameObject *f,
791
805
f -> f_gen = (PyObject * ) gen ;
792
806
Py_INCREF (f -> f_code );
793
807
gen -> gi_code = (PyObject * )(f -> f_code );
794
- gen -> gi_running = 0 ;
795
808
gen -> gi_weakreflist = NULL ;
796
809
gen -> gi_exc_state .exc_type = NULL ;
797
810
gen -> gi_exc_state .exc_value = NULL ;
@@ -921,19 +934,29 @@ coro_get_cr_await(PyCoroObject *coro, void *Py_UNUSED(ignored))
921
934
return yf ;
922
935
}
923
936
937
+ static PyObject *
938
+ cr_getrunning (PyCoroObject * coro , void * Py_UNUSED (ignored ))
939
+ {
940
+ if (coro -> cr_frame == NULL ) {
941
+ Py_INCREF (Py_False );
942
+ return Py_False ;
943
+ }
944
+ return PyBool_FromLong (_PyFrameIsExecuting (coro -> cr_frame ));
945
+ }
946
+
924
947
static PyGetSetDef coro_getsetlist [] = {
925
948
{"__name__" , (getter )gen_get_name , (setter )gen_set_name ,
926
949
PyDoc_STR ("name of the coroutine" )},
927
950
{"__qualname__" , (getter )gen_get_qualname , (setter )gen_set_qualname ,
928
951
PyDoc_STR ("qualified name of the coroutine" )},
929
952
{"cr_await" , (getter )coro_get_cr_await , NULL ,
930
953
PyDoc_STR ("object being awaited on, or None" )},
954
+ {"cr_running" , (getter )cr_getrunning , NULL , NULL },
931
955
{NULL } /* Sentinel */
932
956
};
933
957
934
958
static PyMemberDef coro_memberlist [] = {
935
959
{"cr_frame" , T_OBJECT , offsetof(PyCoroObject , cr_frame ), READONLY },
936
- {"cr_running" , T_BOOL , offsetof(PyCoroObject , cr_running ), READONLY },
937
960
{"cr_code" , T_OBJECT , offsetof(PyCoroObject , cr_code ), READONLY },
938
961
{"cr_origin" , T_OBJECT , offsetof(PyCoroObject , cr_origin ), READONLY },
939
962
{NULL } /* Sentinel */
@@ -1828,7 +1851,7 @@ async_gen_athrow_send(PyAsyncGenAThrow *o, PyObject *arg)
1828
1851
return NULL ;
1829
1852
}
1830
1853
1831
- if (f == NULL || f -> f_stacktop == NULL ) {
1854
+ if (f == NULL || _PyFrameHasCompleted ( f ) ) {
1832
1855
o -> agt_state = AWAITABLE_STATE_CLOSED ;
1833
1856
PyErr_SetNone (PyExc_StopIteration );
1834
1857
return NULL ;
0 commit comments