Index: core/stackless_tstate.h =================================================================== --- core/stackless_tstate.h (revision 60407) +++ core/stackless_tstate.h (working copy) @@ -36,6 +36,7 @@ #endif /* number of nested interpreters (1.0/2.0 merge) */ int nesting_level; + int globaltrace; /* tracing is global for thread */ } PyStacklessState; @@ -53,7 +54,8 @@ tstate->st.main = NULL; \ tstate->st.current = NULL; \ tstate->st.runcount = 0; \ - tstate->st.nesting_level = 0; + tstate->st.nesting_level = 0; \ + tstate->st.globaltrace = 0; /* note that the scheduler knows how to zap. It checks if it is in charge for this tstate and then clears everything. This will not work if Index: core/stacklesseval.c =================================================================== --- core/stacklesseval.c (revision 60407) +++ core/stacklesseval.c (working copy) @@ -367,8 +367,14 @@ { PyThreadState *ts = PyThreadState_Get(); - if (ts->st.main == NULL) - initialize_main_and_current(); + if (ts->st.main == NULL) { + if (initialize_main_and_current()) { + PyObject *s = PyString_FromString("tasklet cleanup"); + PyErr_WriteUnraisable(s); + Py_XDECREF(s); + return; + } + } slp_kill_tasks_with_stacks(allthreads ? NULL : ts); } Index: module/scheduling.c =================================================================== --- module/scheduling.c (revision 60407) +++ module/scheduling.c (working copy) @@ -321,25 +321,30 @@ int ret; ts->exc_type = ts->exc_value = ts->exc_traceback = NULL; - ts->c_profilefunc = ts->c_tracefunc = NULL; - ts->c_profileobj = ts->c_traceobj = NULL; - ts->use_tracing = ts->tracing = 0; - /* note that trace/profile are set without ref */ - Py_XINCREF(c_profileobj); - Py_XINCREF(c_traceobj); + if (!ts->st.globaltrace) { + ts->c_profilefunc = ts->c_tracefunc = NULL; + ts->c_profileobj = ts->c_traceobj = NULL; + ts->use_tracing = ts->tracing = 0; + /* note that trace/profile are set without ref */ + Py_XINCREF(c_profileobj); + Py_XINCREF(c_traceobj); + } + ret = slp_transfer(cstprev, cst, prev); - ts->tracing = tracing; - ts->use_tracing = use_tracing; + if (!ts->st.globaltrace) { + ts->tracing = tracing; + ts->use_tracing = use_tracing; - ts->c_profilefunc = c_profilefunc; - ts->c_tracefunc = c_tracefunc; - ts->c_profileobj = c_profileobj; - ts->c_traceobj = c_traceobj; - Py_XDECREF(c_profileobj); - Py_XDECREF(c_traceobj); + ts->c_profilefunc = c_profilefunc; + ts->c_tracefunc = c_tracefunc; + ts->c_profileobj = c_profileobj; + ts->c_traceobj = c_traceobj; + Py_XDECREF(c_profileobj); + Py_XDECREF(c_traceobj); + } ts->exc_type = exc_type; ts->exc_value = exc_value; @@ -850,7 +855,7 @@ ts->exc_type = ts->exc_value = ts->exc_traceback = NULL; } - if (ts->use_tracing || ts->tracing) { + if (!ts->st.globaltrace && (ts->use_tracing || ts->tracing)) { /* build a shadow frame */ PyCFrameObject *f = slp_cframe_new(restore_tracing, 1); if (f == NULL) Index: module/stacklessmodule.c =================================================================== --- module/stacklessmodule.c (revision 60407) +++ module/stacklessmodule.c (working copy) @@ -853,6 +853,26 @@ } static PyObject * +slpmodule_get_globaltrace(PySlpModuleObject *mod, void *context) +{ + PyThreadState *ts = PyThreadState_GET(); + PyObject *result = ts->st.globaltrace ? Py_True : Py_False; + Py_INCREF(result); + return result; +} + +static int +slpmodule_set_globaltrace(PySlpModuleObject *mod, PyObject *val, void *context) +{ + PyThreadState *ts = PyThreadState_GET(); + int r = PyObject_IsTrue(val); + if (r == -1) + return r; + ts->st.globaltrace = r; + return 0; +} + +static PyObject * slpmodule_getdebug(PySlpModuleObject *mod) { #ifdef _DEBUG @@ -932,6 +952,9 @@ uncollectables__doc__}, {"threads", (getter)slpmodule_getthreads, NULL, "a list of all thread ids, starting with main."}, + {"globaltrace", (getter)slpmodule_get_globaltrace, + (setter)slpmodule_set_globaltrace, + "is tracing or profiling global for the thread"}, {0}, };