PyObject * slp_run_tasklet(void) { PyThreadState *ts = PyThreadState_GET(); PyObject *retval; if ( (ts->st.main == NULL) && initialize_main_and_current()) { ts->frame = NULL; return NULL; } retval = ts->st.current->tempval; Py_INCREF(retval); if (PyBomb_Check(retval)) retval = slp_bomb_explode(ts->st.current); while (ts->st.main != NULL) { /* XXX correct condition? or current? */ retval = slp_frame_dispatch_top(retval); retval = tasklet_end(retval); if (STACKLESS_UNWINDING(retval)) STACKLESS_UNPACK(retval); } return retval; }
static TASKLET_RAISE_EXCEPTION_HEAD(impl_tasklet_raise_exception) { STACKLESS_GETARG(); PyThreadState *ts = PyThreadState_GET(); PyObject *bomb; if (ts->st.main == NULL) return PyTasklet_RaiseException_M(self, klass, args); bomb = slp_make_bomb(klass, args, "tasklet.raise_exception"); if (bomb == NULL) return NULL; TASKLET_SETVAL_OWN(self, bomb); /* if the tasklet is dead, do not run it (no frame) but explode */ if (slp_get_frame(self) == NULL) { TASKLET_CLAIMVAL(self, &bomb); return slp_bomb_explode(bomb); } return slp_schedule_task(ts->st.current, self, stackless, 0); }
static PyObject * schedule_task_destruct(PyTaskletObject *prev, PyTaskletObject *next) { /* * The problem is to leave the dying tasklet alive * until we have done the switch. * This cannot easily be done by hard switching, since * the C stack we are leaving is never returned to, * and who should do the dereferencing? * Therefore, we enforce a soft-switch. */ PyThreadState *ts = PyThreadState_GET(); PyObject *retval; /* we should have no nesting level */ assert(ts->st.nesting_level == 0); /* even there is a (buggy) nesting, ensure soft switch */ if (ts->st.nesting_level != 0) { printf("XXX error, nesting_level = %d\n", ts->st.nesting_level); ts->st.nesting_level = 0; } /* update what's not yet updated */ assert(ts->recursion_depth == 0); prev->recursion_depth = 0; assert(ts->frame == NULL); prev->f.frame = NULL; /* do a soft switch */ if (prev != next) retval = slp_schedule_task(prev, next, 1); else { retval = prev->tempval; Py_INCREF(retval); if (PyBomb_Check(retval)) retval = slp_bomb_explode(prev); } prev->ob_type->tp_clear((PyObject *)prev); /* now it is safe to derefence prev */ Py_DECREF(prev); return retval; }
PyObject * slp_schedule_task(PyTaskletObject *prev, PyTaskletObject *next, int stackless) { PyThreadState *ts = PyThreadState_GET(); PyCStackObject **cstprev; PyObject *retval; int (*transfer)(PyCStackObject **, PyCStackObject *, PyTaskletObject *); if (next == NULL) { return schedule_task_block(prev, stackless); } #ifdef WITH_THREAD /* note that next->cstate is undefined if it is ourself */ if (next->cstate != NULL && next->cstate->tstate != ts) { return schedule_task_unblock(prev, next, stackless); } #endif if (next->flags.blocked) { /* unblock from channel */ slp_channel_remove_slow(next); slp_current_insert(next); } else if (next->next == NULL) { /* reactivate floating task */ Py_INCREF(next); slp_current_insert(next); } if (prev == next) { retval = prev->tempval; Py_INCREF(retval); if (PyBomb_Check(retval)) retval = slp_bomb_explode(prev); return retval; } NOTIFY_SCHEDULE(prev, next, NULL); ts->st.ticker = ts->st.interval; prev->recursion_depth = ts->recursion_depth; prev->f.frame = ts->frame; if (!stackless || ts->st.nesting_level != 0) goto hard_switching; /* start of soft switching code */ if (prev->cstate != ts->st.initial_stub) { Py_DECREF(prev->cstate); prev->cstate = ts->st.initial_stub; Py_INCREF(prev->cstate); } if (ts != slp_initial_tstate) { /* ensure to get all tasklets into the other thread's chain */ if (slp_ensure_linkage(prev) || slp_ensure_linkage(next)) return NULL; } /* handle exception */ if (ts->exc_type == Py_None) { Py_XDECREF(ts->exc_type); ts->exc_type = NULL; } if (ts->exc_type != NULL) { /* build a shadow frame */ PyCFrameObject *f = slp_cframe_new(restore_exception, 1); if (f == NULL) return NULL; f->ob1 = ts->exc_type; f->ob2 = ts->exc_value; f->ob3 = ts->exc_traceback; prev->f.frame = (PyFrameObject *) f; ts->exc_type = ts->exc_value = ts->exc_traceback = NULL; } if (ts->use_tracing || ts->tracing) { /* build a shadow frame */ PyCFrameObject *f = slp_cframe_new(restore_tracing, 1); if (f == NULL) return NULL; f->any1 = ts->c_tracefunc; f->any2 = ts->c_profilefunc; ts->c_tracefunc = ts->c_profilefunc = NULL; f->ob1 = ts->c_traceobj; f->ob2 = ts->c_profileobj; /* trace/profile does not add references */ Py_XINCREF(f->ob1); Py_XINCREF(f->ob2); ts->c_traceobj = ts->c_profileobj = NULL; f->i = ts->tracing; f->n = ts->use_tracing; ts->tracing = ts->use_tracing = 0; prev->f.frame = (PyFrameObject *) f; } ts->frame = next->f.frame; next->f.frame = NULL; ts->recursion_depth = next->recursion_depth; ts->st.current = next; retval = next->tempval; assert(next->cstate != NULL); if (next->cstate->nesting_level != 0) { /* create a helper frame to restore the target stack */ ts->frame = (PyFrameObject *) slp_cframe_new(jump_soft_to_hard, 1); if (ts->frame == NULL) { ts->frame = prev->f.frame; return NULL; } /* note that we don't explode the bomb now and don't incref! */ return STACKLESS_PACK(retval); } Py_INCREF(retval); if (PyBomb_Check(retval)) retval = slp_bomb_explode(next); return STACKLESS_PACK(retval); hard_switching: /* since we change the stack we must assure that the protocol was met */ STACKLESS_ASSERT(); /* note: nesting_level is handled in cstack_new */ cstprev = &prev->cstate; ts->st.current = next; if (ts->exc_type == Py_None) { Py_XDECREF(ts->exc_type); ts->exc_type = NULL; } ts->recursion_depth = next->recursion_depth; ts->frame = next->f.frame; next->f.frame = NULL; ++ts->st.nesting_level; if (ts->exc_type != NULL || ts->use_tracing || ts->tracing) transfer = transfer_with_exc; else transfer = slp_transfer; if (transfer(cstprev, next->cstate, prev) == 0) { --ts->st.nesting_level; retval = prev->tempval; Py_INCREF(retval); if (PyBomb_Check(retval)) retval = slp_bomb_explode(prev); return retval; } else { --ts->st.nesting_level; kill_wrap_bad_guy(prev, next); return NULL; } }