Skip to content
This repository was archived by the owner on Feb 13, 2025. It is now read-only.

Commit 245a802

Browse files
author
Anselm Kruis
committed
Stackless issue #149: Move exc state from thread to tasklet
bpo-25612 (python#1773) moves the exception state information from frame object to coroutine (generator/thread) object where it belongs. As a consequence Stackless moves the exception state information for non-current tasklets from thread-state to the tasklet. This changes the pickle format of frame, tasklet and generator objects. The commit adds three test cases.
1 parent 87ee678 commit 245a802

13 files changed

+509
-340
lines changed

Include/frameobject.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ typedef struct _frame {
5252
char f_executing; /* whether the frame is still executing */
5353
PyTryBlock f_blockstack[CO_MAXBLOCKS]; /* for try and loop blocks */
5454
#ifdef STACKLESS
55-
PyCodeObject *f_code; /* code segment */
55+
PyCodeObject *f_code; /* code segment */
5656
#endif
5757
PyObject *f_localsplus[1]; /* locals+stack, dynamically sized */
5858
} PyFrameObject;

Objects/frameobject.c

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -363,14 +363,14 @@ frame_settrace(PyFrameObject *f, PyObject* v, void *closure)
363363
static PyObject *
364364
frame_getback(PyFrameObject *f, void *nope)
365365
{
366-
PyFrameObject *fb = f->f_back;
367-
PyObject *ret;
366+
PyFrameObject *fb = f->f_back;
367+
PyObject *ret;
368368
/* move over cframe objects but halt at NULL or None */
369-
while (fb != NULL && (PyObject*)fb != Py_None && !PyFrame_Check(fb))
370-
fb = fb->f_back;
371-
ret = (PyObject *) fb;
372-
if (ret == NULL)
373-
ret = Py_None;
369+
while (fb != NULL && (PyObject*)fb != Py_None && !PyFrame_Check(fb))
370+
fb = fb->f_back;
371+
ret = (PyObject *) fb;
372+
if (ret == NULL)
373+
ret = Py_None;
374374
Py_INCREF(ret);
375375
return ret;
376376
}
@@ -380,7 +380,7 @@ frame_getback(PyFrameObject *f, void *nope)
380380

381381
static PyGetSetDef frame_getsetlist[] = {
382382
#ifdef STACKLESS
383-
{"f_back", (getter)frame_getback, NULL, NULL},
383+
{"f_back", (getter)frame_getback, NULL, NULL},
384384
#endif
385385
{"f_locals", (getter)frame_getlocals, NULL, NULL},
386386
{"f_lineno", (getter)frame_getlineno,

Objects/genobject.c

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -274,6 +274,9 @@ gen_send_ex(PyGenObject *gen, PyObject *arg, int exc, int closing)
274274
f->f_back->f_back = stopframe;
275275

276276
gen->gi_running = 1;
277+
assert(gen->gi_exc_state.previous_item == NULL);
278+
gen->gi_exc_state.previous_item = tstate->exc_info;
279+
tstate->exc_info = &gen->gi_exc_state;
277280

278281
f->f_execute = PyEval_EvalFrameEx_slp;
279282

@@ -321,6 +324,10 @@ gen_iternext_callback(PyFrameObject *f, int exc, PyObject *result)
321324
/* Check, that this cframe belongs to gen */
322325
assert(f->f_back == (PyFrameObject *)cf);
323326

327+
assert(gen->gi_exc_state.previous_item != NULL);
328+
ts->exc_info = gen->gi_exc_state.previous_item;
329+
gen->gi_exc_state.previous_item = NULL;
330+
gen->gi_running = 0;
324331
#endif
325332
/* If the generator just returned (as opposed to yielding), signal
326333
* that the generator is exhausted. */
@@ -405,8 +412,6 @@ gen_iternext_callback(PyFrameObject *f, int exc, PyObject *result)
405412
}
406413

407414
#ifdef STACKLESS
408-
gen->gi_running = 0;
409-
410415
/* Don't keep the reference to f_back any longer than necessary. It
411416
* may keep a chain of frames alive or it could create a reference
412417
* cycle. */

Stackless/changelog.txt

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,13 @@ What's New in Stackless 3.X.X?
99

1010
*Release date: 20XX-XX-XX*
1111

12+
- https://github.com/stackless-dev/stackless/issues/149
13+
C-Python bpo-25612 (#1773) moves the exception state information from frame
14+
object to coroutine (generator/thread) object where it belongs. As a
15+
consequence Stackless moves the exception state information from thread
16+
to tasklet. This changes the pickle format of frame, tasklet and generator
17+
objects compared to previous major versions of Stackless.
18+
1219
- https://github.com/stackless-dev/stackless/issues/166
1320
Fix C-API functions PyEval_EvalFrameEx() and PyEval_EvalFrame().
1421
They are now compatible with C-Python.

Stackless/core/stackless_impl.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -402,7 +402,6 @@ PyObject * slp_eval_frame_iter(struct _frame *f, int throwflag, PyObject *retva
402402
PyObject * slp_eval_frame_setup_with(struct _frame *f, int throwflag, PyObject *retval);
403403
PyObject * slp_eval_frame_with_cleanup(struct _frame *f, int throwflag, PyObject *retval);
404404
/* other eval_frame functions from module/scheduling.c */
405-
PyObject * slp_restore_exception(PyFrameObject *f, int exc, PyObject *retval);
406405
PyObject * slp_restore_tracing(PyFrameObject *f, int exc, PyObject *retval);
407406
/* other eval_frame functions from Objects/typeobject.c */
408407
PyObject * slp_tp_init_callback(PyFrameObject *f, int exc, PyObject *retval);
@@ -748,6 +747,7 @@ PyObject * slp_curexc_to_bomb(void);
748747
PyObject * slp_nomemory_bomb(void);
749748
PyObject * slp_bomb_explode(PyObject *bomb);
750749
int slp_init_bombtype(void);
750+
PyObject * slp_get_obj_for_exc_state(_PyErr_StackItem *exc_info);
751751

752752
/* handy abbrevations */
753753

Stackless/core/stackless_structs.h

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -102,10 +102,6 @@ typedef struct _tasklet_tstate {
102102
Py_tracefunc c_tracefunc;
103103
PyObject *c_profileobj;
104104
PyObject *c_traceobj;
105-
106-
PyObject *exc_type;
107-
PyObject *exc_value;
108-
PyObject *exc_traceback;
109105
} PyTaskletTStateStruc;
110106

111107
typedef struct _tasklet {
@@ -117,10 +113,17 @@ typedef struct _tasklet {
117113
struct _cframe *cframe;
118114
} f;
119115
PyObject *tempval;
116+
struct _cstack *cstate;
117+
/* Pointer to the top of the stack of the exceptions currently
118+
* being handled */
119+
_PyErr_StackItem *exc_info;
120+
/* The exception currently being handled, if no coroutines/generators
121+
* are present. Always last element on the stack referred to be exc_info.
122+
*/
123+
_PyErr_StackItem exc_state;
120124
/* bits stuff */
121125
struct _tasklet_flags flags;
122126
int recursion_depth;
123-
struct _cstack *cstate;
124127
PyObject *def_globals;
125128
PyObject *tsk_weakreflist;
126129
} PyTaskletObject;

0 commit comments

Comments
 (0)