Author: Armin Rigo <ar...@tunes.org> 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 pypy-commit@python.org https://mail.python.org/mailman/listinfo/pypy-commit