static int GREENLET_NOINLINE(g_initialstub)(void* mark)
{
int err;
PyObject *o, *run;
PyObject *exc, *val, *tb;
PyObject *run_info;
PyGreenlet* self = ts_target;
PyObject* args = ts_passaround_args;
PyObject* kwargs = ts_passaround_kwargs;
/* save exception in case getattr clears it */
PyErr_Fetch(&exc, &val, &tb);
/* self.run is the object to call in the new greenlet */
run = PyObject_GetAttrString((PyObject*) self, "run");
if (run == NULL) {
Py_XDECREF(exc);
Py_XDECREF(val);
Py_XDECREF(tb);
return -1;
}
/* restore saved exception */
PyErr_Restore(exc, val, tb);
/* recheck the state in case getattr caused thread switches */
if (!STATE_OK) {
Py_DECREF(run);
return -1;
}
/* recheck run_info in case greenlet reparented anywhere above */
run_info = green_statedict(self);
if (run_info == NULL || run_info != ts_current->run_info) {
Py_DECREF(run);
PyErr_SetString(PyExc_GreenletError, run_info
? "cannot switch to a different thread"
: "cannot switch to a garbage collected greenlet");
return -1;
}
/* by the time we got here another start could happen elsewhere,
* that means it should now be a regular switch
*/
if (PyGreenlet_STARTED(self)) {
Py_DECREF(run);
ts_passaround_args = args;
ts_passaround_kwargs = kwargs;
return 1;
}
/* start the greenlet */
self->stack_start = NULL;
self->stack_stop = (char*) mark;
if (ts_current->stack_start == NULL) {
/* ts_current is dying */
self->stack_prev = ts_current->stack_prev;
}
else {
self->stack_prev = ts_current;
}
self->top_frame = NULL;
self->exc_type = NULL;
self->exc_value = NULL;
self->exc_traceback = NULL;
self->recursion_depth = PyThreadState_GET()->recursion_depth;
/* restore arguments in case they are clobbered */
ts_target = self;
ts_passaround_args = args;
ts_passaround_kwargs = kwargs;
/* perform the initial switch */
err = g_switchstack();
/* returns twice!
The 1st time with err=1: we are in the new greenlet
The 2nd time with err=0: back in the caller's greenlet
*/
if (err == 1) {
/* in the new greenlet */
PyGreenlet* origin;
#if GREENLET_USE_TRACING
PyObject* tracefunc;
#endif
PyObject* result;
PyGreenlet* parent;
self->stack_start = (char*) 1; /* running */
/* grab origin while we still can */
origin = ts_origin;
ts_origin = NULL;
/* now use run_info to store the statedict */
o = self->run_info;
self->run_info = green_statedict(self->parent);
Py_INCREF(self->run_info);
Py_XDECREF(o);
#if GREENLET_USE_TRACING
if ((tracefunc = PyDict_GetItem(self->run_info, ts_tracekey)) != NULL) {
Py_INCREF(tracefunc);
//.........这里部分代码省略.........
// Call a single slot and return the result.
PyObject *PyQtSlot::call(PyObject *callable, PyObject *args) const
{
PyObject *sa, *oxtype, *oxvalue, *oxtb;
// Keep some compilers quiet.
oxtype = oxvalue = oxtb = 0;
// We make repeated attempts to call a slot. If we work out that it failed
// because of an immediate type error we try again with one less argument.
// We keep going until we run out of arguments to drop. This emulates the
// Qt ability of the slot to accept fewer arguments than a signal provides.
sa = args;
Py_INCREF(sa);
for (;;)
{
PyObject *nsa, *xtype, *xvalue, *xtb, *res;
if ((res = PyEval_CallObject(callable, sa)) != NULL)
{
// Remove any previous exception.
if (sa != args)
{
Py_XDECREF(oxtype);
Py_XDECREF(oxvalue);
Py_XDECREF(oxtb);
PyErr_Clear();
}
Py_DECREF(sa);
return res;
}
// Get the exception.
PyErr_Fetch(&xtype, &xvalue, &xtb);
// See if it is unacceptable. An acceptable failure is a type error
// with no traceback - so long as we can still reduce the number of
// arguments and try again.
if (!PyErr_GivenExceptionMatches(xtype, PyExc_TypeError) || xtb ||
PyTuple_Size(sa) == 0)
{
// If there is a traceback then we must have called the slot and
// the exception was later on - so report the exception as is.
if (xtb)
{
if (sa != args)
{
Py_XDECREF(oxtype);
Py_XDECREF(oxvalue);
Py_XDECREF(oxtb);
}
PyErr_Restore(xtype,xvalue,xtb);
}
else if (sa == args)
{
PyErr_Restore(xtype, xvalue, xtb);
}
else
{
// Discard the latest exception and restore the original one.
Py_XDECREF(xtype);
Py_XDECREF(xvalue);
Py_XDECREF(xtb);
PyErr_Restore(oxtype, oxvalue, oxtb);
}
break;
}
// If this is the first attempt, save the exception.
if (sa == args)
{
oxtype = xtype;
oxvalue = xvalue;
oxtb = xtb;
}
else
{
Py_XDECREF(xtype);
Py_XDECREF(xvalue);
Py_XDECREF(xtb);
}
// Create the new argument tuple.
if ((nsa = PyTuple_GetSlice(sa, 0, PyTuple_Size(sa) - 1)) == NULL)
{
// Tidy up.
Py_XDECREF(oxtype);
Py_XDECREF(oxvalue);
Py_XDECREF(oxtb);
break;
}
//.........这里部分代码省略.........
static int
profiler_callback(PyObject *self, PyFrameObject *frame, int what,
PyObject *arg)
{
ProfilerObject *pObj = (ProfilerObject*)self;
{
/* keep error state, see ptrace_enter_call above.
* We could keep this more focused, only really needed
* when calling a user time function, and initializing
* a user object
*/
PyObject *et, *ev, *tb;
PyErr_Fetch(&et, &ev, &tb);
pObj->currentTime = CALL_TIMER(pObj);
SelectStack(pObj);
PyErr_Restore(et, ev, tb);
}
if (pObj->currentProfilerStack == NULL)
return 0;
switch (what) {
/* the 'frame' of a called function is about to start its execution */
case PyTrace_CALL:
ptrace_enter_call(self, (void *)frame->f_code,
(PyObject *)frame->f_code);
break;
/* the 'frame' of a called function is about to finish
(either normally or with an exception) */
case PyTrace_RETURN:
ptrace_leave_call(self, (void *)frame->f_code);
break;
/* case PyTrace_EXCEPTION:
If the exception results in the function exiting, a
PyTrace_RETURN event will be generated, so we don't need to
handle it. */
#ifdef PyTrace_C_CALL /* not defined in Python <= 2.3 */
/* the Python function 'frame' is issuing a call to the built-in
function 'arg' */
case PyTrace_C_CALL:
if ((((ProfilerObject *)self)->flags & POF_BUILTINS)
&& PyCFunction_Check(arg)) {
ptrace_enter_call(self,
((PyCFunctionObject *)arg)->m_ml,
arg);
}
break;
/* the call to the built-in function 'arg' is returning into its
caller 'frame' */
case PyTrace_C_RETURN: /* ...normally */
case PyTrace_C_EXCEPTION: /* ...with an exception set */
if ((((ProfilerObject *)self)->flags & POF_BUILTINS)
&& PyCFunction_Check(arg)) {
ptrace_leave_call(self,
((PyCFunctionObject *)arg)->m_ml);
}
break;
#endif
default:
break;
}
return 0;
}
// Format the current Python exception as a string.
// Let Python do the work for us; call traceback.format_exception()
std::string formatPythonException() {
if (!PyErr_Occurred()) {
return "<no error?>";
}
// Retrieve Python exception and "normalize" (the docs are unclear but
// they say you should do it :) )
PyObject* exceptionObj;
PyObject* valueObj;
PyObject* tracebackObj;
PyErr_Fetch(&exceptionObj, &valueObj, &tracebackObj);
DCHECK(exceptionObj);
PyErr_NormalizeException(&exceptionObj, &valueObj, &tracebackObj);
PyObjectHandle exception(exceptionObj);
PyObjectHandle value(valueObj);
PyObjectHandle traceback(tracebackObj);
// value and traceback may be null
if (!value) {
value.reset(PyObjectHandle::INCREF, Py_None);
}
if (!traceback) {
traceback.reset(PyObjectHandle::INCREF, Py_None);
}
PyObjectHandle tbModule(PyImport_ImportModule("traceback"));
if (!tbModule) {
return "<import traceback failed>";
}
PyObject* tbDict = PyModule_GetDict(tbModule.get()); // borrowed
if (!tbDict) {
return "<no dict in traceback module>";
}
// borrowed
PyObject* formatFunc = PyDict_GetItemString(tbDict, "format_exception");
if (!formatFunc) {
return "<no format_exception in traceback module>";
}
PyObjectHandle formatted(PyObject_CallFunction(
formatFunc, const_cast<char*>("OOO"), exception.get(), value.get(),
traceback.get()));
if (!formatted) {
return "<traceback.format_exception error>";
}
// format_exception returns a list of strings that should be concatenated.
// Well then, let's do that.
if (!PyList_Check(formatted.get())) {
return "<traceback.format_exception didn't return a list>";
}
std::string out;
for (Py_ssize_t i = 0; i < PyList_GET_SIZE(formatted.get()); ++i) {
PyObject* obj = PyList_GET_ITEM(formatted.get(), i); // borrowed
char* data;
Py_ssize_t len;
if (PyString_AsStringAndSize(obj, &data, &len) == -1) {
return "<traceback.format_exception member not a string>";
}
out.append(data, len);
}
return out;
}
static PyObject *
gen_send_ex(PyGenObject *gen, PyObject *arg, int exc, int closing)
{
PyThreadState *tstate = PyThreadState_GET();
PyFrameObject *f = gen->gi_frame;
PyObject *result;
if (gen->gi_running) {
char *msg = "generator already executing";
if (PyCoro_CheckExact(gen))
msg = "coroutine already executing";
PyErr_SetString(PyExc_ValueError, msg);
return NULL;
}
if (f == NULL || f->f_stacktop == NULL) {
if (PyCoro_CheckExact(gen) && !closing) {
/* `gen` is an exhausted coroutine: raise an error,
except when called from gen_close(), which should
always be a silent method. */
PyErr_SetString(
PyExc_RuntimeError,
"cannot reuse already awaited coroutine");
} else if (arg && !exc) {
/* `gen` is an exhausted generator:
only set exception if called from send(). */
PyErr_SetNone(PyExc_StopIteration);
}
return NULL;
}
if (f->f_lasti == -1) {
if (arg && arg != Py_None) {
char *msg = "can't send non-None value to a "
"just-started generator";
if (PyCoro_CheckExact(gen))
msg = "can't send non-None value to a "
"just-started coroutine";
PyErr_SetString(PyExc_TypeError, msg);
return NULL;
}
} else {
/* Push arg onto the frame's value stack */
result = arg ? arg : Py_None;
Py_INCREF(result);
*(f->f_stacktop++) = result;
}
/* Generators always return to their most recent caller, not
* necessarily their creator. */
Py_XINCREF(tstate->frame);
assert(f->f_back == NULL);
f->f_back = tstate->frame;
gen->gi_running = 1;
result = PyEval_EvalFrameEx(f, exc);
gen->gi_running = 0;
/* Don't keep the reference to f_back any longer than necessary. It
* may keep a chain of frames alive or it could create a reference
* cycle. */
assert(f->f_back == tstate->frame);
Py_CLEAR(f->f_back);
/* If the generator just returned (as opposed to yielding), signal
* that the generator is exhausted. */
if (result && f->f_stacktop == NULL) {
if (result == Py_None) {
/* Delay exception instantiation if we can */
PyErr_SetNone(PyExc_StopIteration);
} else {
PyObject *e = PyObject_CallFunctionObjArgs(
PyExc_StopIteration, result, NULL);
if (e != NULL) {
PyErr_SetObject(PyExc_StopIteration, e);
Py_DECREF(e);
}
}
Py_CLEAR(result);
}
else if (!result && PyErr_ExceptionMatches(PyExc_StopIteration)) {
/* Check for __future__ generator_stop and conditionally turn
* a leaking StopIteration into RuntimeError (with its cause
* set appropriately). */
if (((PyCodeObject *)gen->gi_code)->co_flags &
(CO_FUTURE_GENERATOR_STOP | CO_COROUTINE | CO_ITERABLE_COROUTINE))
{
PyObject *exc, *val, *val2, *tb;
char *msg = "generator raised StopIteration";
if (PyCoro_CheckExact(gen))
msg = "coroutine raised StopIteration";
PyErr_Fetch(&exc, &val, &tb);
PyErr_NormalizeException(&exc, &val, &tb);
if (tb != NULL)
PyException_SetTraceback(val, tb);
Py_DECREF(exc);
Py_XDECREF(tb);
PyErr_SetString(PyExc_RuntimeError, msg);
PyErr_Fetch(&exc, &val2, &tb);
PyErr_NormalizeException(&exc, &val2, &tb);
Py_INCREF(val);
//.........这里部分代码省略.........
int
_PyIOBase_finalize(PyObject *self)
{
PyObject *res;
PyObject *tp, *v, *tb;
int closed = 1;
int is_zombie;
/* If _PyIOBase_finalize() is called from a destructor, we need to
resurrect the object as calling close() can invoke arbitrary code. */
is_zombie = (Py_REFCNT(self) == 0);
if (is_zombie) {
++Py_REFCNT(self);
}
PyErr_Fetch(&tp, &v, &tb);
/* If `closed` doesn't exist or can't be evaluated as bool, then the
object is probably in an unusable state, so ignore. */
res = PyObject_GetAttr(self, _PyIO_str_closed);
if (res == NULL)
PyErr_Clear();
else {
closed = PyObject_IsTrue(res);
Py_DECREF(res);
if (closed == -1)
PyErr_Clear();
}
if (closed == 0) {
res = PyObject_CallMethodObjArgs((PyObject *) self, _PyIO_str_close,
NULL);
/* Silencing I/O errors is bad, but printing spurious tracebacks is
equally as bad, and potentially more frequent (because of
shutdown issues). */
if (res == NULL)
PyErr_Clear();
else
Py_DECREF(res);
}
PyErr_Restore(tp, v, tb);
if (is_zombie) {
if (--Py_REFCNT(self) != 0) {
/* The object lives again. The following code is taken from
slot_tp_del in typeobject.c. */
Py_ssize_t refcnt = Py_REFCNT(self);
_Py_NewReference(self);
Py_REFCNT(self) = refcnt;
/* If Py_REF_DEBUG, _Py_NewReference bumped _Py_RefTotal, so
* we need to undo that. */
_Py_DEC_REFTOTAL;
/* If Py_TRACE_REFS, _Py_NewReference re-added self to the object
* chain, so no more to do there.
* If COUNT_ALLOCS, the original decref bumped tp_frees, and
* _Py_NewReference bumped tp_allocs: both of those need to be
* undone.
*/
#ifdef COUNT_ALLOCS
--Py_TYPE(self)->tp_frees;
--Py_TYPE(self)->tp_allocs;
#endif
return -1;
}
}
return 0;
}
请发表评论