Esempio n. 1
0
static gr_param
g_switch(greenlet* target, gr_param data)
{
	/* _consumes_ a reference to the args tuple and kwargs dict,
	   and return a new tuple reference */

	/* check ts_current */
	if (!STATE_OK)
		return 0;


	/* find the real target by ignoring dead greenlets,
	   and if necessary starting a greenlet. */
	while (1) 
	{
		if (PyGreenlet_ACTIVE(target)) 
		{
			ts_target = target;
			ts_target->data = data;
			g_switchstack();
			break;
		}

		if (!PyGreenlet_STARTED(target)) 
		{
			void* dummymarker;
			ts_target = target;
			ts_target->data = data;
			g_initialstub(&dummymarker);
			break;
		}
		target = target->parent;
	}
    return ts_current->data;
}
Esempio n. 2
0
static int green_setparent(PyGreenlet* self, PyObject* nparent, void* c)
{
	PyGreenlet* p;
	PyObject* run_info = NULL;
	if (nparent == NULL) {
		PyErr_SetString(PyExc_AttributeError, "can't delete attribute");
		return -1;
	}
	if (!PyGreenlet_Check(nparent)) {
		PyErr_SetString(PyExc_TypeError, "parent must be a greenlet");
		return -1;
	}
	for (p=(PyGreenlet*) nparent; p; p=p->parent) {
		if (p == self) {
			PyErr_SetString(PyExc_ValueError, "cyclic parent chain");
			return -1;
		}
		run_info = PyGreenlet_ACTIVE(p) ? p->run_info : NULL;
	}
	if (run_info == NULL) {
		PyErr_SetString(PyExc_ValueError, "parent must not be garbage collected");
		return -1;
	}
	if (PyGreenlet_STARTED(self) && self->run_info != run_info) {
		PyErr_SetString(PyExc_ValueError, "parent cannot be on a different thread");
		return -1;
	}
	p = self->parent;
	self->parent = (PyGreenlet*) nparent;
	Py_INCREF(nparent);
	Py_XDECREF(p);
	return 0;
}
Esempio n. 3
0
static PyObject* green_getdead(PyGreenlet* self, void* c)
{
	if (PyGreenlet_ACTIVE(self) || !PyGreenlet_STARTED(self))
		Py_RETURN_FALSE;
	else
		Py_RETURN_TRUE;
}
Esempio n. 4
0
static int green_is_gc(PyGreenlet* self)
{
	/* Main greenlet can be garbage collected since it can only
	   become unreachable if the underlying thread exited.
	   Active greenlet cannot be garbage collected, however. */
	if (PyGreenlet_MAIN(self) || !PyGreenlet_ACTIVE(self))
		return 1;
	return 0;
}
Esempio n. 5
0
static PyObject* green_getdead(PyGreenlet* self, void* c)
{
	PyObject* res;
	if (PyGreenlet_ACTIVE(self) || !PyGreenlet_STARTED(self))
		res = Py_False;
	else
		res = Py_True;
	Py_INCREF(res);
	return res;
}
Esempio n. 6
0
static PyObject *
throw_greenlet(PyGreenlet *self, PyObject *typ, PyObject *val, PyObject *tb)
{
	/* Note: _consumes_ a reference to typ, val, tb */
	PyObject *result = NULL;
	PyErr_Restore(typ, val, tb);
	if (PyGreenlet_STARTED(self) && !PyGreenlet_ACTIVE(self))
	{
		/* dead greenlet: turn GreenletExit into a regular return */
		result = g_handle_exit(result);
	}
	return single_result(g_switch(self, result, NULL));
}
Esempio n. 7
0
static void green_dealloc(PyGreenlet* self)
{
	PyObject *error_type, *error_value, *error_traceback;

#ifdef GREENLET_USE_GC
	PyObject_GC_UnTrack((PyObject *)self);
	Py_TRASHCAN_SAFE_BEGIN(self);
#endif /* GREENLET_USE_GC */
	if (PyGreenlet_ACTIVE(self) && self->run_info != NULL && !PyGreenlet_MAIN(self)) {
		/* Hacks hacks hacks copied from instance_dealloc() */
		/* Temporarily resurrect the greenlet. */
		assert(Py_REFCNT(self) == 0);
		Py_REFCNT(self) = 1;
		/* Save the current exception, if any. */
		PyErr_Fetch(&error_type, &error_value, &error_traceback);
		if (kill_greenlet(self) < 0) {
			PyErr_WriteUnraisable((PyObject*) self);
			/* XXX what else should we do? */
		}
		/* Check for no resurrection must be done while we keep
		 * our internal reference, otherwise PyFile_WriteObject
		 * causes recursion if using Py_INCREF/Py_DECREF
		 */
		if (Py_REFCNT(self) == 1 && PyGreenlet_ACTIVE(self)) {
			/* Not resurrected, but still not dead!
			   XXX what else should we do? we complain. */
			PyObject* f = PySys_GetObject("stderr");
			Py_INCREF(self); /* leak! */
			if (f != NULL) {
				PyFile_WriteString("GreenletExit did not kill ",
						   f);
				PyFile_WriteObject((PyObject*) self, f, 0);
				PyFile_WriteString("\n", f);
			}
		}
		/* Restore the saved exception. */
		PyErr_Restore(error_type, error_value, error_traceback);
		/* Undo the temporary resurrection; can't use DECREF here,
		 * it would cause a recursive call.
		 */
		assert(Py_REFCNT(self) > 0);
		if (--Py_REFCNT(self) != 0) {
			/* Resurrected! */
			Py_ssize_t refcnt = Py_REFCNT(self);
			_Py_NewReference((PyObject*) self);
			Py_REFCNT(self) = refcnt;
#ifdef GREENLET_USE_GC
			PyObject_GC_Track((PyObject *)self);
#endif
			_Py_DEC_REFTOTAL;
#ifdef COUNT_ALLOCS
			--Py_TYPE(self)->tp_frees;
			--Py_TYPE(self)->tp_allocs;
#endif /* COUNT_ALLOCS */
			goto green_dealloc_end;
		}
	}
	if (self->weakreflist != NULL)
		PyObject_ClearWeakRefs((PyObject *) self);
	Py_CLEAR(self->parent);
	Py_CLEAR(self->run_info);
	Py_CLEAR(self->exc_type);
	Py_CLEAR(self->exc_value);
	Py_CLEAR(self->exc_traceback);
	Py_CLEAR(self->dict);
	Py_TYPE(self)->tp_free((PyObject*) self);
green_dealloc_end:
#ifdef GREENLET_USE_GC
	Py_TRASHCAN_SAFE_END(self);
#endif /* GREENLET_USE_GC */
	return;
}
Esempio n. 8
0
static PyObject *
g_switch(PyGreenlet* target, PyObject* args, PyObject* kwargs)
{
	/* _consumes_ a reference to the args tuple and kwargs dict,
	   and return a new tuple reference */
	PyObject* run_info;

	/* check ts_current */
	if (!STATE_OK) {
		Py_XDECREF(args);
		Py_XDECREF(kwargs);
		return NULL;
	}
	run_info = green_statedict(target);
	if (run_info == NULL || run_info != ts_current->run_info) {
		Py_XDECREF(args);
		Py_XDECREF(kwargs);
		PyErr_SetString(PyExc_GreenletError, run_info
				? "cannot switch to a different thread"
				: "cannot switch to a garbage collected greenlet");
		return NULL;
	}

	ts_passaround_args = args;
	ts_passaround_kwargs = kwargs;

	/* find the real target by ignoring dead greenlets,
	   and if necessary starting a greenlet. */
	while (target) {
		if (PyGreenlet_ACTIVE(target)) {
			ts_target = target;
			if (g_switchstack() < 0) {
				g_passaround_clear();
				return NULL;
			}
			break;
		}
		if (!PyGreenlet_STARTED(target)) {
			int err;
			void* dummymarker;
			ts_target = target;
			err = g_initialstub(&dummymarker);
			if (err == 1) {
				continue; /* retry the switch */
			}
			else if (err < 0) {
				g_passaround_clear();
				return NULL;
			}
			break;
		}
		target = target->parent;
	}

	/* We need to figure out what values to pass to the target greenlet
	   based on the arguments that have been passed to greenlet.switch(). If
	   switch() was just passed an arg tuple, then we'll just return that.
	   If only keyword arguments were passed, then we'll pass the keyword
	   argument dict. Otherwise, we'll create a tuple of (args, kwargs) and
	   return both. */
	if (ts_passaround_kwargs == NULL)
	{
		g_passaround_return_args();
	}
	else if (PyDict_Size(ts_passaround_kwargs) == 0)
	{
		g_passaround_return_args();
	}
	else if (PySequence_Length(ts_passaround_args) == 0)
	{
		g_passaround_return_kwargs();
	}
	else
	{
		PyObject *tuple = PyTuple_New(2);
		if (tuple == NULL) {
			g_passaround_clear();
			return NULL;
		}
		PyTuple_SET_ITEM(tuple, 0, ts_passaround_args);
		PyTuple_SET_ITEM(tuple, 1, ts_passaround_kwargs);
		ts_passaround_args = NULL;
		ts_passaround_kwargs = NULL;
		return tuple;
	}
}
Esempio n. 9
0
static int green_bool(PyGreenlet* self)
{
	return PyGreenlet_ACTIVE(self);
}
Esempio n. 10
0
int greenlet_isdead(greenlet* self)
{
	return (PyGreenlet_STARTED(self) && !PyGreenlet_ACTIVE(self));
}
Esempio n. 11
0
static PyObject *
g_switch(PyGreenlet* target, PyObject* args, PyObject* kwargs)
{
	/* _consumes_ a reference to the args tuple and kwargs dict,
	   and return a new tuple reference */
	int err = 0;
	PyObject* run_info;

	/* check ts_current */
	if (!STATE_OK) {
		Py_XDECREF(args);
		Py_XDECREF(kwargs);
		return NULL;
	}
	run_info = green_statedict(target);
	if (run_info == NULL || run_info != ts_current->run_info) {
		Py_XDECREF(args);
		Py_XDECREF(kwargs);
		PyErr_SetString(PyExc_GreenletError, run_info
		                ? "cannot switch to a different thread"
		                : "cannot switch to a garbage collected greenlet");
		return NULL;
	}

	ts_passaround_args = args;
	ts_passaround_kwargs = kwargs;

	/* find the real target by ignoring dead greenlets,
	   and if necessary starting a greenlet. */
	while (target) {
		if (PyGreenlet_ACTIVE(target)) {
			ts_target = target;
			err = g_switchstack();
			break;
		}
		if (!PyGreenlet_STARTED(target)) {
			void* dummymarker;
			ts_target = target;
			err = g_initialstub(&dummymarker);
			if (err == 1) {
				continue; /* retry the switch */
			}
			break;
		}
		target = target->parent;
	}

	/* For a very short time, immediately after the 'atomic'
	   g_switchstack() call, global variables are in a known state.
	   We need to save everything we need, before it is destroyed
	   by calls into arbitrary Python code. */
	args = ts_passaround_args;
	ts_passaround_args = NULL;
	kwargs = ts_passaround_kwargs;
	ts_passaround_kwargs = NULL;
	if (err < 0) {
		/* Turn switch errors into switch throws */
		assert(ts_origin == NULL);
		Py_CLEAR(kwargs);
		Py_CLEAR(args);
	} else {
		PyGreenlet *origin;
#if GREENLET_USE_TRACING
		PyGreenlet *current;
		PyObject *tracefunc;
#endif
		origin = ts_origin;
		ts_origin = NULL;
#if GREENLET_USE_TRACING
		current = ts_current;
		if ((tracefunc = PyDict_GetItem(current->run_info, ts_tracekey)) != NULL) {
			Py_INCREF(tracefunc);
			if (g_calltrace(tracefunc, args ? ts_event_switch : ts_event_throw, origin, current) < 0) {
				/* Turn trace errors into switch throws */
				Py_CLEAR(kwargs);
				Py_CLEAR(args);
			}
			Py_DECREF(tracefunc);
		}
#endif
		Py_DECREF(origin);
	}

	/* We need to figure out what values to pass to the target greenlet
	   based on the arguments that have been passed to greenlet.switch(). If
	   switch() was just passed an arg tuple, then we'll just return that.
	   If only keyword arguments were passed, then we'll pass the keyword
	   argument dict. Otherwise, we'll create a tuple of (args, kwargs) and
	   return both. */
	if (kwargs == NULL)
	{
		return args;
	}
	else if (PyDict_Size(kwargs) == 0)
	{
		Py_DECREF(kwargs);
		return args;
	}
	else if (PySequence_Length(args) == 0)
	{
		Py_DECREF(args);
		return kwargs;
	}
	else
	{
		PyObject *tuple = PyTuple_New(2);
		if (tuple == NULL) {
			Py_DECREF(args);
			Py_DECREF(kwargs);
			return NULL;
		}
		PyTuple_SET_ITEM(tuple, 0, args);
		PyTuple_SET_ITEM(tuple, 1, kwargs);
		return tuple;
	}
}