static PyObject * wrapper_call(wrapperobject *wp, PyObject *args, PyObject *kwds) { STACKLESS_GETARG(); wrapperfunc wrapper = wp->descr->d_base->wrapper; PyObject *self = wp->self; PyObject *ret; if (wp->descr->d_base->flags & PyWrapperFlag_KEYWORDS) { wrapperfunc_kwds wk = (wrapperfunc_kwds)wrapper; STACKLESS_PROMOTE_WRAPPER(wp); ret = (*wk)(self, args, wp->descr->d_wrapped, kwds); STACKLESS_ASSERT(); return ret; } if (kwds != NULL && (!PyDict_Check(kwds) || PyDict_Size(kwds) != 0)) { PyErr_Format(PyExc_TypeError, "wrapper %s doesn't take keyword arguments", wp->descr->d_base->name); return NULL; } STACKLESS_PROMOTE_WRAPPER(wp); ret = (*wrapper)(self, args, wp->descr->d_wrapped); STACKLESS_ASSERT(); return ret; }
static TASKLET_KILL_HEAD(impl_tasklet_kill) { STACKLESS_GETARG(); PyObject *noargs; PyObject *ret; /* * silently do nothing if the tasklet is dead. * simple raising would kill ourself in this case. */ if (slp_get_frame(task) == NULL) Py_RETURN_NONE; /* we might be called after exceptions are gone */ if (PyExc_TaskletExit == NULL) { PyExc_TaskletExit = PyString_FromString("zombie"); if (PyExc_TaskletExit == NULL) return NULL; /* give up */ } noargs = PyTuple_New(0); STACKLESS_PROMOTE_ALL(); ret = impl_tasklet_raise_exception(task, PyExc_TaskletExit, noargs); STACKLESS_ASSERT(); Py_DECREF(noargs); return ret; }
static PyObject * channel_send_exception(PyObject *myself, PyObject *args) { STACKLESS_GETARG(); PyObject *retval = NULL; PyObject *klass = PySequence_GetItem(args, 0); if (klass == NULL) VALUE_ERROR("channel.send_exception(e, v...)", NULL); args = PySequence_GetSlice(args, 1, PySequence_Size(args)); if (!args) { goto err_exit; } STACKLESS_PROMOTE_ALL(); retval = impl_channel_send_exception((PyChannelObject*)myself, klass, args); STACKLESS_ASSERT(); if (retval == NULL || STACKLESS_UNWINDING(retval)) { goto err_exit; } Py_INCREF(Py_None); retval = Py_None; err_exit: Py_DECREF(klass); Py_XDECREF(args); return retval; }
PyObject * PyChannel_Receive(PyChannelObject *self) { PyObject *ret = impl_channel_receive(self); STACKLESS_ASSERT(); assert(!STACKLESS_UNWINDING(self)); return ret; }
PyObject * PyChannel_Receive_nr(PyChannelObject *self) { PyObject *ret; STACKLESS_PROPOSE_ALL(); ret = impl_channel_receive(self); STACKLESS_ASSERT(); return ret; }
PyObject * PyChannel_Receive_nr(PyChannelObject *self) { PyChannel_HeapType *t = (PyChannel_HeapType *) Py_TYPE(self); PyObject *ret; slp_try_stackless = 1; ret = t->receive(self); STACKLESS_ASSERT(); return ret; }
static PyObject * run_mod(mod_ty mod, const char *filename, PyObject *globals, PyObject *locals, PyCompilerFlags *flags, PyArena *arena) { STACKLESS_GETARG(); PyCodeObject *co; PyObject *v; co = PyAST_Compile(mod, filename, flags, arena); if (co == NULL) return NULL; STACKLESS_PROMOTE_ALL(); v = PyEval_EvalCode(co, globals, locals); STACKLESS_ASSERT(); Py_DECREF(co); return v; }
static PyObject * classmethoddescr_call(PyMethodDescrObject *descr, PyObject *args, PyObject *kwds) { STACKLESS_GETARG(); PyObject *func, *result; func = PyCFunction_New(descr->d_method, (PyObject *)descr->d_type); if (func == NULL) return NULL; STACKLESS_PROMOTE_ALL(); result = PyEval_CallObjectWithKeywords(func, args, kwds); STACKLESS_ASSERT(); Py_DECREF(func); return result; }
static PyObject * wrapperdescr_call(PyWrapperDescrObject *descr, PyObject *args, PyObject *kwds) { STACKLESS_GETARG(); Py_ssize_t argc; PyObject *self, *func, *result; /* Make sure that the first argument is acceptable as 'self' */ assert(PyTuple_Check(args)); argc = PyTuple_GET_SIZE(args); if (argc < 1) { PyErr_Format(PyExc_TypeError, "descriptor '%.300s' of '%.100s' " "object needs an argument", descr_name((PyDescrObject *)descr), descr->d_type->tp_name); return NULL; } self = PyTuple_GET_ITEM(args, 0); if (!PyObject_IsInstance(self, (PyObject *)(descr->d_type))) { PyErr_Format(PyExc_TypeError, "descriptor '%.200s' " "requires a '%.100s' object " "but received a '%.100s'", descr_name((PyDescrObject *)descr), descr->d_type->tp_name, self->ob_type->tp_name); return NULL; } func = PyWrapper_New((PyObject *)descr, self); if (func == NULL) return NULL; args = PyTuple_GetSlice(args, 1, argc); if (args == NULL) { Py_DECREF(func); return NULL; } STACKLESS_PROMOTE_ALL(); result = PyEval_CallObjectWithKeywords(func, args, kwds); STACKLESS_ASSERT(); Py_DECREF(args); Py_DECREF(func); return result; }
static PyObject * tasklet_raise_exception(PyObject *myself, PyObject *args) { STACKLESS_GETARG(); PyObject *result = NULL; PyObject *klass = PySequence_GetItem(args, 0); if (klass == NULL) VALUE_ERROR("tasklet.raise_exception(e, v...)", NULL); args = PySequence_GetSlice(args, 1, PySequence_Size(args)); if (!args) goto err_exit; STACKLESS_PROMOTE_ALL(); result = impl_tasklet_raise_exception( (PyTaskletObject*)myself, klass, args); STACKLESS_ASSERT(); err_exit: Py_DECREF(klass); Py_XDECREF(args); return result; }
int slp_transfer(PyCStackObject **cstprev, PyCStackObject *cst, PyTaskletObject *prev) { PyThreadState *ts = PyThreadState_GET(); /* since we change the stack we must assure that the protocol was met */ STACKLESS_ASSERT(); if ((intptr_t *) &ts > ts->st.cstack_base) return climb_stack_and_transfer(cstprev, cst, prev); if (cst == NULL || cst->ob_size == 0) cst = ts->st.initial_stub; if (cst != NULL) { if (cst->tstate != ts) { PyErr_SetString(PyExc_SystemError, "bad thread state in transfer"); return -1; } if (ts->st.cstack_base != cst->startaddr) { PyErr_SetString(PyExc_SystemError, "bad stack reference in transfer"); return -1; } /* record the context of the target stack */ ts->st.serial_last_jump = cst->serial; /* * if stacks are same and refcount==1, it must be the same * task. In this case, we would destroy the target before * switching. Therefore, we simply don't switch, just save. */ if (cstprev && *cstprev == cst && cst->ob_refcnt == 1) cst = NULL; } _cstprev = cstprev; _cst = cst; _prev = prev; return slp_switch(); }
static PyObject * channel_send_throw(PyObject *myself, PyObject *args) { STACKLESS_GETARG(); PyObject *typ; PyObject *tb = Py_None; PyObject *val = Py_None; PyObject *retval; if (!PyArg_UnpackTuple(args, "send_throw", 1, 3, &typ, &val, &tb)) return NULL; STACKLESS_PROMOTE_ALL(); retval = impl_channel_send_throw((PyChannelObject*)myself, typ, val, tb); STACKLESS_ASSERT(); if (retval == NULL || STACKLESS_UNWINDING(retval)) { goto err_exit; } Py_INCREF(Py_None); retval = Py_None; err_exit: return retval; }
static PyObject * run_cframe(PyFrameObject *f, int exc, PyObject *retval) { PyThreadState *ts = PyThreadState_GET(); PyCFrameObject *cf = (PyCFrameObject*) f; PyTaskletObject *task = ts->st.current; int done = cf->i; ts->frame = f; if (retval == NULL || done) goto exit_run_cframe; if (cf->ob2 == NULL) cf->ob2 = PyTuple_New(0); Py_DECREF(retval); STACKLESS_PROPOSE_ALL(); retval = PyObject_Call(cf->ob1, cf->ob2, cf->ob3); STACKLESS_ASSERT(); cf->i = 1; /* mark ourself as done */ if (STACKLESS_UNWINDING(retval)) { /* try to shortcut */ if (ts->st.current == task && ts->frame != NULL && ts->frame->f_back == (PyFrameObject *) cf) { Py_DECREF(ts->frame->f_back); ts->frame->f_back = cf->f_back; Py_DECREF(cf); /* the exec reference */ } return retval; } /* pop frame */ exit_run_cframe: ts->frame = cf->f_back; Py_DECREF(cf); 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; } }