Author: Armin Rigo <[email protected]>
Branch: reverse-debugger
Changeset: r86162:9b771a2cb860
Date: 2016-08-11 22:15 +0200
http://bitbucket.org/pypy/pypy/changeset/9b771a2cb860/
Log: Add commands 'nthread' and 'bthread' to navigate thread switches.
diff --git a/pypy/interpreter/reverse_debugging.py
b/pypy/interpreter/reverse_debugging.py
--- a/pypy/interpreter/reverse_debugging.py
+++ b/pypy/interpreter/reverse_debugging.py
@@ -479,6 +479,7 @@
def command_breakpoints(cmd, extra):
space = dbstate.space
dbstate.breakpoint_stack_id = cmd.c_arg1
+ revdb.set_thread_breakpoint(cmd.c_arg2)
funcnames = None
watch_progs = []
with non_standard_code:
diff --git a/rpython/rlib/revdb.py b/rpython/rlib/revdb.py
--- a/rpython/rlib/revdb.py
+++ b/rpython/rlib/revdb.py
@@ -92,6 +92,9 @@
def breakpoint(num):
llop.revdb_breakpoint(lltype.Void, num)
+def set_thread_breakpoint(tnum):
+ llop.revdb_set_thread_breakpoint(lltype.Void, tnum)
+
@specialize.argtype(0)
def get_unique_id(x):
"""Returns the creation number of the object 'x'. For objects created
diff --git a/rpython/rtyper/lltypesystem/lloperation.py
b/rpython/rtyper/lltypesystem/lloperation.py
--- a/rpython/rtyper/lltypesystem/lloperation.py
+++ b/rpython/rtyper/lltypesystem/lloperation.py
@@ -583,6 +583,7 @@
'revdb_weakref_create': LLOp(),
'revdb_weakref_deref': LLOp(),
'revdb_call_destructor': LLOp(),
+ 'revdb_set_thread_breakpoint': LLOp(),
}
# ***** Run test_lloperation after changes. *****
diff --git a/rpython/translator/revdb/interact.py
b/rpython/translator/revdb/interact.py
--- a/rpython/translator/revdb/interact.py
+++ b/rpython/translator/revdb/interact.py
@@ -45,7 +45,7 @@
if self.pgroup.get_current_thread() != previous_thread:
previous_thread = self.pgroup.get_current_thread()
if previous_thread == 0:
- print ('-------------------- in the main thread '
+ print ('-------------------- in main thread #0 '
'--------------------')
else:
print ('-------------------- in non-main thread '
@@ -147,6 +147,9 @@
elif num == -3:
kind = 'stoppoint'
name = 'explicit stop'
+ elif num == -4:
+ kind = 'switchpoint'
+ name = 'thread switch'
else:
kind = '?????point'
name = repr(break_at)
@@ -245,6 +248,17 @@
finally:
b.stack_id = 0
+ @contextmanager
+ def _thread_num_break(self, thread_num):
+ # add temporarily a breakpoint that hits when we enter/leave
+ # the given thread
+ b = self.pgroup.edit_breakpoints()
+ b.thread_num = thread_num
+ try:
+ yield
+ finally:
+ b.thread_num = -1
+
def command_next(self, argument):
"""Run forward for one step, skipping calls"""
while True:
@@ -308,7 +322,7 @@
"""Run forward until the current function finishes"""
stack_id = self.pgroup.get_stack_id(is_parent=True)
if stack_id == 0:
- print 'No stack.'
+ print 'No caller.'
else:
with self._stack_id_break(stack_id):
self.command_continue('')
@@ -317,7 +331,7 @@
"""Run backward until the current function is called"""
stack_id = self.pgroup.get_stack_id(is_parent=True)
if stack_id == 0:
- print 'No stack.'
+ print 'No caller.'
else:
with self._stack_id_break(stack_id):
self.command_bcontinue('')
@@ -333,6 +347,31 @@
self.move_backward(self.pgroup.get_current_time() - 1)
command_bc = command_bcontinue
+ def _cmd_thread(self, argument, cmd_continue):
+ argument = argument.lstrip('#')
+ if argument:
+ arg = int(argument)
+ if arg == self.pgroup.get_current_thread():
+ print 'Thread #%d is already the current one.' % (arg,)
+ return
+ else:
+ # use the current thread number to detect switches to any
+ # other thread (this works because revdb.c issues a
+ # breakpoint whenever there is a switch FROM or TO the
+ # thread '#arg').
+ arg = self.pgroup.get_current_thread()
+ #
+ with self._thread_num_break(arg):
+ cmd_continue('')
+
+ def command_nthread(self, argument):
+ """Run forward until thread switch (optionally to #ARG)"""
+ self._cmd_thread(argument, self.command_continue)
+
+ def command_bthread(self, argument):
+ """Run backward until thread switch (optionally to #ARG)"""
+ self._cmd_thread(argument, self.command_bcontinue)
+
def command_print(self, argument):
"""Print an expression or execute a line of code"""
# locate which $NUM appear used in the expression
diff --git a/rpython/translator/revdb/process.py
b/rpython/translator/revdb/process.py
--- a/rpython/translator/revdb/process.py
+++ b/rpython/translator/revdb/process.py
@@ -31,15 +31,17 @@
self.watchuids = {} # {small number: [uid...]}
self.stack_id = 0 # breaks when leaving/entering a frame from/to
# the frame identified by 'stack_id'
+ self.thread_num = -1 # breaks when leaving/entering the thread_num
def __repr__(self):
- return 'AllBreakpoints(%r, %r, %r, %r)' % (
+ return 'AllBreakpoints(%r, %r, %r, %r, %r)' % (
self.num2break, self.watchvalues, self.watchuids,
- self.stack_id)
+ self.stack_id, self.thread_num)
def compare(self, other):
if (self.num2break == other.num2break and
- self.stack_id == other.stack_id):
+ self.stack_id == other.stack_id and
+ self.thread_num == other.thread_num):
if self.watchvalues == other.watchvalues:
return 2 # completely equal
else:
@@ -48,12 +50,14 @@
return 0 # different
def is_empty(self):
- return len(self.num2break) == 0 and self.stack_id == 0
+ return (len(self.num2break) == 0 and self.stack_id == 0
+ and self.thread_num == -1)
def duplicate(self):
a = AllBreakpoints()
a.num2break.update(self.num2break)
a.stack_id = self.stack_id
+ a.thread_num = self.thread_num
return a
@@ -392,8 +396,9 @@
if cmp == 0:
flat = [num2break.get(n, '\x00') for n in range(N)]
arg1 = self.all_breakpoints.stack_id
+ arg2 = self.all_breakpoints.thread_num
extra = ''.join(flat)
- self.active.send(Message(CMD_BREAKPOINTS, arg1, extra=extra))
+ self.active.send(Message(CMD_BREAKPOINTS, arg1, arg2, extra=extra))
self.active.expect_ready()
else:
assert cmp == 1
diff --git a/rpython/translator/revdb/src-revdb/revdb.c
b/rpython/translator/revdb/src-revdb/revdb.c
--- a/rpython/translator/revdb/src-revdb/revdb.c
+++ b/rpython/translator/revdb/src-revdb/revdb.c
@@ -663,7 +663,7 @@
static stacklet_thread_handle st_thread;
static stacklet_handle st_outer_controller_h;
static uint64_t current_thread_id, target_thread_id;
-static uint64_t current_thread_num, next_thread_num;
+static uint64_t current_thread_num, next_thread_num, break_thread_num;
static void *thread_tree_root;
@@ -726,6 +726,13 @@
return 1;
}
+static void set_current_thread_num(uint64_t tnum)
+{
+ if (break_thread_num == current_thread_num || break_thread_num == tnum)
+ rpy_reverse_db_breakpoint(-4);
+ current_thread_num = tnum;
+}
+
RPY_EXTERN
int rpy_reverse_db_main(Signed entry_point(Signed, char**),
int argc, char **argv)
@@ -797,7 +804,7 @@
item = tfind(&dummy, &thread_tree_root, compare_replay_thread);
if (item == NULL) {
/* it's a new thread, start it now */
- current_thread_num = next_thread_num++;
+ set_current_thread_num(next_thread_num++);
if (real_tloc != NULL)
memset(((char *)real_tloc) + RPY_TLOFSFIRST, 0,
sizeof(struct pypy_threadlocal_s) - RPY_TLOFSFIRST);
@@ -806,7 +813,7 @@
else {
node = *item;
assert(node->tid == target_thread_id);
- current_thread_num = node->tnum;
+ set_current_thread_num(node->tnum);
h = node->h;
tdelete(node, &thread_tree_root, compare_replay_thread);
if (real_tloc != NULL)
@@ -965,6 +972,7 @@
current_thread_id = h.main_thread_id;
current_thread_num = 0;
next_thread_num = 1;
+ break_thread_num = (uint64_t)-1;
if (h.ptr1 != &rpy_reverse_db_stop_point ||
h.ptr2 != &rpy_revdb) {
fprintf(stderr,
@@ -1713,6 +1721,12 @@
exit(1);
}
+RPY_EXTERN
+void rpy_reverse_db_set_thread_breakpoint(int64_t tnum)
+{
+ break_thread_num = (uint64_t)tnum;
+}
+
/* ------------------------------------------------------------ */
diff --git a/rpython/translator/revdb/src-revdb/revdb_include.h
b/rpython/translator/revdb/src-revdb/revdb_include.h
--- a/rpython/translator/revdb/src-revdb/revdb_include.h
+++ b/rpython/translator/revdb/src-revdb/revdb_include.h
@@ -227,6 +227,9 @@
we'll just return the UID. */
#define RPY_REVDB_CAST_PTR_TO_INT(obj) (((struct pypy_header0 *)obj)->h_uid)
+#define OP_REVDB_SET_THREAD_BREAKPOINT(tnum, r) \
+ rpy_reverse_db_set_thread_breakpoint(tnum)
+
RPY_EXTERN void rpy_reverse_db_flush(void); /* must be called with the lock */
RPY_EXTERN void rpy_reverse_db_fetch(const char *file, int line);
@@ -249,5 +252,6 @@
RPY_EXTERN void rpy_reverse_db_callback_loc(int);
RPY_EXTERN void rpy_reverse_db_lock_acquire(bool_t lock_contention);
RPY_EXTERN void rpy_reverse_db_bad_acquire_gil(void);
+RPY_EXTERN void rpy_reverse_db_set_thread_breakpoint(int64_t tnum);
/* ------------------------------------------------------------ */
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit