summaryrefslogtreecommitdiffstats
path: root/Python
diff options
context:
space:
mode:
authorTim Peters <tim.peters@gmail.com>2006-07-10 21:08:24 (GMT)
committerTim Peters <tim.peters@gmail.com>2006-07-10 21:08:24 (GMT)
commit32a8361f2da758c1de662b6d5a1b780466e18cf9 (patch)
tree8f60709d17ff6287fd3028944c799b94045c79da /Python
parent2b221ed6577809c4cc5cfd53963651af247cf546 (diff)
downloadcpython-32a8361f2da758c1de662b6d5a1b780466e18cf9.zip
cpython-32a8361f2da758c1de662b6d5a1b780466e18cf9.tar.gz
cpython-32a8361f2da758c1de662b6d5a1b780466e18cf9.tar.bz2
After approval from Anthony, merge the tim-current_frames
branch into the trunk. This adds a new sys._current_frames() function, which returns a dict mapping thread id to topmost thread stack frame.
Diffstat (limited to 'Python')
-rw-r--r--Python/pystate.c54
-rw-r--r--Python/sysmodule.c17
2 files changed, 68 insertions, 3 deletions
diff --git a/Python/pystate.c b/Python/pystate.c
index b8f460f..b872dc0 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 785653e..ea1388b 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},