Ejemplo n.º 1
0
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;
}
Ejemplo n.º 2
0
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);
}
Ejemplo n.º 3
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;
}
Ejemplo n.º 4
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;
	}
}