summaryrefslogtreecommitdiff
path: root/Python
diff options
context:
space:
mode:
authorTim Peters <tim.peters@gmail.com>2006-07-10 21:08:24 +0000
committerTim Peters <tim.peters@gmail.com>2006-07-10 21:08:24 +0000
commit32a8361f2da758c1de662b6d5a1b780466e18cf9 (patch)
tree8f60709d17ff6287fd3028944c799b94045c79da /Python
parent2b221ed6577809c4cc5cfd53963651af247cf546 (diff)
downloadcpython-git-32a8361f2da758c1de662b6d5a1b780466e18cf9.tar.gz
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 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},