Commit 71221ac7 authored by Marius Wachtler's avatar Marius Wachtler

add sys._current_frames

parent 3099a9c1
......@@ -30,6 +30,7 @@
#include "core/thread_utils.h"
#include "core/util.h"
#include "runtime/objmodel.h" // _printStacktrace
#include "runtime/types.h"
namespace pyston {
namespace threading {
......@@ -737,5 +738,23 @@ extern "C" void PyThread_delete_key_value(int key) noexcept {
Py_FatalError("unimplemented");
}
extern "C" PyObject *_PyThread_CurrentFrames(void) noexcept {
try {
LOCK_REGION(&threading_lock);
BoxedDict* result = new BoxedDict;
for (auto& pair : current_threads) {
FrameInfo* frame_info = (FrameInfo*)pair.second->public_thread_state->frame_info;
Box* frame = getFrame(frame_info);
assert(frame);
result->d[boxInt(pair.first)] = frame;
}
return result;
} catch (ExcInfo) {
RELEASE_ASSERT(0, "not implemented");
}
}
} // namespace threading
} // namespace pyston
......@@ -121,6 +121,13 @@ Box* sysGetFrame(Box* val) {
return frame;
}
Box* sysCurrentFrames() {
Box* rtn = _PyThread_CurrentFrames();
if (!rtn)
throwCAPIException();
return rtn;
}
Box* sysGetDefaultEncoding() {
return boxString(PyUnicode_GetDefaultEncoding());
}
......@@ -674,6 +681,8 @@ void setupSys() {
sys_module->giveAttr(
"_getframe",
new BoxedFunction(FunctionMetadata::create((void*)sysGetFrame, UNKNOWN, 1, false, false), { NULL }));
sys_module->giveAttr("_current_frames",
new BoxedFunction(FunctionMetadata::create((void*)sysCurrentFrames, UNKNOWN, 0)));
sys_module->giveAttr("getdefaultencoding", new BoxedBuiltinFunctionOrMethod(
FunctionMetadata::create((void*)sysGetDefaultEncoding, STR, 0),
"getdefaultencoding", getdefaultencoding_doc));
......
# this is copied out of cpythons test_sys.py and adopted to use assert stmts
import sys
import thread
import threading, thread
import traceback
# Spawn a thread that blocks at a known place. Then the main
# thread does sys._current_frames(), and verifies that the frames
# returned make sense.
entered_g = threading.Event()
leave_g = threading.Event()
thread_info = [] # the thread's id
def f123():
g456()
def g456():
thread_info.append(thread.get_ident())
entered_g.set()
leave_g.wait()
t = threading.Thread(target=f123)
t.start()
entered_g.wait()
# At this point, t has finished its entered_g.set(), although it's
# impossible to guess whether it's still on that line or has moved on
# to its leave_g.wait().
assert len(thread_info) == 1
thread_id = thread_info[0]
d = sys._current_frames()
main_id = thread.get_ident()
assert main_id in d
assert thread_id in d
# Verify that the captured main-thread frame is _this_ frame.
frame = d.pop(main_id)
assert frame is sys._getframe()
# Verify that the captured thread frame is blocked in g456, called
# from f123. This is a litte tricky, since various bits of
# threading.py are also in the thread's call stack.
frame = d.pop(thread_id)
stack = traceback.extract_stack(frame)
for i, (filename, lineno, funcname, sourceline) in enumerate(stack):
if funcname == "f123":
break
else:
self.fail("didn't find f123() on thread's call stack")
assert sourceline == "g456()"
# And the next record must be for g456().
filename, lineno, funcname, sourceline = stack[i+1]
assert funcname == "g456"
assert sourceline in ["leave_g.wait()", "entered_g.set()"]
# Reap the spawned thread.
leave_g.set()
t.join()
print "finished"
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment