Index: Include/ceval.h =================================================================== --- Include/ceval.h (revision 83761) +++ Include/ceval.h (working copy) @@ -22,6 +22,8 @@ PyAPI_FUNC(void) PyEval_SetProfile(Py_tracefunc, PyObject *); PyAPI_FUNC(void) PyEval_SetTrace(Py_tracefunc, PyObject *); +PyAPI_FUNC(void) PyEval_SetGlobalProfile(Py_tracefunc, PyObject *); +PyAPI_FUNC(void) PyEval_SetGlobalTrace(Py_tracefunc, PyObject *); struct _frame; /* Avoid including frameobject.h */ Index: Modules/_lsprof.c =================================================================== --- Modules/_lsprof.c (revision 83761) +++ Modules/_lsprof.c (working copy) @@ -679,13 +679,14 @@ } PyDoc_STRVAR(enable_doc, "\ -enable(subcalls=True, builtins=True)\n\ +enable(subcalls=True, builtins=True, global=False)\n\ \n\ Start collecting profiling information.\n\ If 'subcalls' is True, also records for each function\n\ statistics separated according to its current caller.\n\ If 'builtins' is True, records the time spent in\n\ built-in functions separately from their caller.\n\ +If 'global' is True, profiling is started on all threads.\n\ "); static PyObject* @@ -693,13 +694,17 @@ { int subcalls = -1; int builtins = -1; - static char *kwlist[] = {"subcalls", "builtins", 0}; - if (!PyArg_ParseTupleAndKeywords(args, kwds, "|ii:enable", - kwlist, &subcalls, &builtins)) + int global = 0; + static char *kwlist[] = {"subcalls", "builtins", "global", 0}; + if (!PyArg_ParseTupleAndKeywords(args, kwds, "|iii:enable", + kwlist, &subcalls, &builtins, &global)) return NULL; if (setSubcalls(self, subcalls) < 0 || setBuiltins(self, builtins) < 0) return NULL; - PyEval_SetProfile(profiler_callback, (PyObject*)self); + if (global) + PyEval_SetGlobalProfile(profiler_callback, (PyObject*)self); + else + PyEval_SetProfile(profiler_callback, (PyObject*)self); self->flags |= POF_ENABLED; Py_INCREF(Py_None); return Py_None; Index: Python/ceval.c =================================================================== --- Python/ceval.c (revision 83761) +++ Python/ceval.c (working copy) @@ -3623,10 +3623,9 @@ return result; } -void -PyEval_SetProfile(Py_tracefunc func, PyObject *arg) +static void +_Py_SetProfile(PyThreadState *tstate, Py_tracefunc func, PyObject *arg) { - PyThreadState *tstate = PyThreadState_GET(); PyObject *temp = tstate->c_profileobj; Py_XINCREF(arg); tstate->c_profilefunc = NULL; @@ -3641,9 +3640,28 @@ } void -PyEval_SetTrace(Py_tracefunc func, PyObject *arg) +PyEval_SetProfile(Py_tracefunc func, PyObject *arg) { PyThreadState *tstate = PyThreadState_GET(); + _Py_SetProfile(tstate, func, arg); +} + +void +PyEval_SetGlobalProfile(Py_tracefunc func, PyObject *arg) +{ + PyThreadState *head = PyThreadState_GET(); + PyThreadState *tstate = head; + for(;;) { + _Py_SetProfile(tstate, func, arg); + tstate = tstate->next; + if (tstate == head) + break; + } +} + +static void +_Py_SetTrace(PyThreadState *tstate, Py_tracefunc func, PyObject *arg) +{ PyObject *temp = tstate->c_traceobj; _Py_TracingPossible += (func != NULL) - (tstate->c_tracefunc != NULL); Py_XINCREF(arg); @@ -3659,6 +3677,26 @@ || (tstate->c_profilefunc != NULL)); } +void +PyEval_SetTrace(Py_tracefunc func, PyObject *arg) +{ + PyThreadState *tstate = PyThreadState_GET(); + _Py_SetTrace(tstate, func, arg); +} + +void +PyEval_SetGlobalTrace(Py_tracefunc func, PyObject *arg) +{ + PyThreadState *head = PyThreadState_GET(); + PyThreadState *tstate = head; + for(;;) { + _Py_SetTrace(tstate, func, arg); + tstate = tstate->next; + if (tstate == head) + break; + } +} + PyObject * PyEval_GetBuiltins(void) { Index: Python/sysmodule.c =================================================================== --- Python/sysmodule.c (revision 83761) +++ Python/sysmodule.c (working copy) @@ -353,6 +353,7 @@ return 0; result = call_trampoline(tstate, callback, frame, what, arg); if (result == NULL) { + PyEval_SetGlobalTrace(NULL, NULL); PyEval_SetTrace(NULL, NULL); Py_XDECREF(frame->f_trace); frame->f_trace = NULL; @@ -371,23 +372,34 @@ } static PyObject * -sys_settrace(PyObject *self, PyObject *args) +sys_settrace(PyObject *self, PyObject *args, PyObject *kwds) { + PyObject *tracefunc, *global = Py_False; + char *kwlist[] = {"function", "global", NULL}; + if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|O:settrace", kwlist, + &tracefunc, &global)) + return NULL; if (trace_init() == -1) return NULL; - if (args == Py_None) + if (args == Py_None) { + PyEval_SetGlobalTrace(NULL, NULL); PyEval_SetTrace(NULL, NULL); - else - PyEval_SetTrace(trace_trampoline, args); + } else { + if (PyObject_IsTrue(global)) + PyEval_SetGlobalTrace(trace_trampoline, tracefunc); + else + PyEval_SetTrace(trace_trampoline, tracefunc); + } Py_INCREF(Py_None); return Py_None; } PyDoc_STRVAR(settrace_doc, -"settrace(function)\n\ +"settrace(function[, global])\n\ \n\ Set the global debug tracing function. It will be called on each\n\ -function call. See the debugger chapter in the library manual." +function call. See the debugger chapter in the library manual.\n\ +If 'global' is True, the call is effective for all threads." ); static PyObject * @@ -410,23 +422,34 @@ ); static PyObject * -sys_setprofile(PyObject *self, PyObject *args) +sys_setprofile(PyObject *self, PyObject *args, PyObject *kwds) { + PyObject *profilefunc, *global=Py_False; + char *kwlist[] = {"function", "global", NULL}; + if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|O:setprofile", kwlist, + &profilefunc, &global)) + return NULL; if (trace_init() == -1) return NULL; - if (args == Py_None) + if (args == Py_None) { + PyEval_SetGlobalProfile(NULL, NULL); PyEval_SetProfile(NULL, NULL); - else - PyEval_SetProfile(profile_trampoline, args); + } else { + if (PyObject_IsTrue(global)) + PyEval_SetGlobalProfile(profile_trampoline, args); + else + PyEval_SetProfile(profile_trampoline, args); + } Py_INCREF(Py_None); return Py_None; } PyDoc_STRVAR(setprofile_doc, -"setprofile(function)\n\ +"setprofile(function[, global])\n\ \n\ Set the profiling function. It will be called on each function call\n\ -and return. See the profiler chapter in the library manual." +and return. See the profiler chapter in the library manual.\n\ +If 'global' is True, the call is effective for all threads." ); static PyObject * @@ -1048,14 +1071,14 @@ {"setdlopenflags", sys_setdlopenflags, METH_VARARGS, setdlopenflags_doc}, #endif - {"setprofile", sys_setprofile, METH_O, setprofile_doc}, + {"setprofile", (PyCFunction)sys_setprofile, METH_KEYWORDS, setprofile_doc}, {"getprofile", sys_getprofile, METH_NOARGS, getprofile_doc}, {"setrecursionlimit", sys_setrecursionlimit, METH_VARARGS, setrecursionlimit_doc}, #ifdef WITH_TSC {"settscdump", sys_settscdump, METH_VARARGS, settscdump_doc}, #endif - {"settrace", sys_settrace, METH_O, settrace_doc}, + {"settrace", (PyCFunction)sys_settrace, METH_KEYWORDS, settrace_doc}, {"gettrace", sys_gettrace, METH_NOARGS, gettrace_doc}, {"call_tracing", sys_call_tracing, METH_VARARGS, call_tracing_doc}, {NULL, NULL} /* sentinel */