Example #1
0
static int
bind_tasklet_to_frame(PyTaskletObject *task, PyFrameObject *frame)
{
    PyThreadState *ts = task->cstate->tstate;

    if (task->f.frame != NULL)
        RUNTIME_ERROR("tasklet is already bound to a frame", -1);
    task->f.frame = frame;
    if (task->cstate != ts->st.initial_stub) {
        PyCStackObject *hold = task->cstate;
        task->cstate = ts->st.initial_stub;
        Py_INCREF(task->cstate);
        Py_DECREF(hold);
        if (ts != slp_initial_tstate)
            if (slp_ensure_linkage(task))
                return -1;
    }
    return 0;
    /* note: We expect that f_back is NULL, or will be adjusted immediately */
}
Example #2
0
PyTaskletObject *
PyTasklet_New(PyTypeObject *type, PyObject *func)
{
    PyThreadState *ts = PyThreadState_GET();
    PyTaskletObject *t;

    /* we always need a cstate, so be sure to initialize */
    if (ts->st.initial_stub == NULL) return PyTasklet_New_M(type, func);
    if (func != NULL && !PyCallable_Check(func))
        TYPE_ERROR("tasklet function must be a callable", NULL);
    if (type == NULL) type = &PyTasklet_Type;
    assert(PyType_IsSubtype(type, &PyTasklet_Type));
    t = (PyTaskletObject *) type->tp_alloc(type, 0);
    if (t != NULL) {
        *(int*)&t->flags = 0;
        t->next = NULL;
        t->prev = NULL;
        t->f.frame = NULL;
        if (func == NULL)
            func = Py_None;
        Py_INCREF(func);
        t->tempval = func;
        t->tsk_weakreflist = NULL;
        Py_INCREF(ts->st.initial_stub);
        t->cstate = ts->st.initial_stub;
        t->def_globals = PyEval_GetGlobals();
        Py_XINCREF(t->def_globals);
        if (ts != slp_initial_tstate) {
            /* make sure to kill tasklets with their thread */
            if (slp_ensure_linkage(t)) {
                Py_DECREF(t);
                return NULL;
            }
        }
    }
    return t;
}
Example #3
0
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;
	}
}