diff options
Diffstat (limited to 'Python')
-rw-r--r-- | Python/pystate.c | 54 | ||||
-rw-r--r-- | Python/sysmodule.c | 17 |
2 files changed, 68 insertions, 3 deletions
diff --git a/Python/pystate.c b/Python/pystate.c index b8f460ff8a..b872dc0752 100644 --- a/Python/pystate.c +++ b/Python/pystate.c @@ -444,15 +444,15 @@ _PyGILState_NoteThreadState(PyThreadState* tstate) /* If autoTLSkey is 0, this must be the very first threadstate created in Py_Initialize(). Don't do anything for now (we'll be back here when _PyGILState_Init is called). */ - if (!autoTLSkey) + if (!autoTLSkey) return; - + /* Stick the thread state for this thread in thread local storage. The only situation where you can legitimately have more than one thread state for an OS level thread is when there are multiple interpreters, when: - + a) You shouldn't really be using the PyGILState_ APIs anyway, and: @@ -550,6 +550,54 @@ PyGILState_Release(PyGILState_STATE oldstate) PyEval_SaveThread(); } +/* The implementation of sys._current_frames(). This is intended to be + called with the GIL held, as it will be when called via + sys._current_frames(). It's possible it would work fine even without + the GIL held, but haven't thought enough about that. +*/ +PyObject * +_PyThread_CurrentFrames(void) +{ + PyObject *result; + PyInterpreterState *i; + + result = PyDict_New(); + if (result == NULL) + return NULL; + + /* for i in all interpreters: + * for t in all of i's thread states: + * if t's frame isn't NULL, map t's id to its frame + * Because these lists can mutute even when the GIL is held, we + * need to grab head_mutex for the duration. + */ + HEAD_LOCK(); + for (i = interp_head; i != NULL; i = i->next) { + PyThreadState *t; + for (t = i->tstate_head; t != NULL; t = t->next) { + PyObject *id; + int stat; + struct _frame *frame = t->frame; + if (frame == NULL) + continue; + id = PyInt_FromLong(t->thread_id); + if (id == NULL) + goto Fail; + stat = PyDict_SetItem(result, id, (PyObject *)frame); + Py_DECREF(id); + if (stat < 0) + goto Fail; + } + } + HEAD_UNLOCK(); + return result; + + Fail: + HEAD_UNLOCK(); + Py_DECREF(result); + return NULL; +} + #ifdef __cplusplus } #endif diff --git a/Python/sysmodule.c b/Python/sysmodule.c index 785653ede0..ea1388b641 100644 --- a/Python/sysmodule.c +++ b/Python/sysmodule.c @@ -660,6 +660,21 @@ sys_getframe(PyObject *self, PyObject *args) return (PyObject*)f; } +PyDoc_STRVAR(current_frames_doc, +"_current_frames() -> dictionary\n\ +\n\ +Return a dictionary mapping each current thread T's thread id to T's\n\ +current stack frame.\n\ +\n\ +This function should be used for specialized purposes only." +); + +static PyObject * +sys_current_frames(PyObject *self, PyObject *noargs) +{ + return _PyThread_CurrentFrames(); +} + PyDoc_STRVAR(call_tracing_doc, "call_tracing(func, args) -> object\n\ \n\ @@ -722,6 +737,8 @@ static PyMethodDef sys_methods[] = { /* Might as well keep this in alphabetic order */ {"callstats", (PyCFunction)PyEval_GetCallStats, METH_NOARGS, callstats_doc}, + {"_current_frames", sys_current_frames, METH_NOARGS, + current_frames_doc}, {"displayhook", sys_displayhook, METH_O, displayhook_doc}, {"exc_info", sys_exc_info, METH_NOARGS, exc_info_doc}, {"exc_clear", sys_exc_clear, METH_NOARGS, exc_clear_doc}, |