[pypy-commit] pypy reverse-debugger: Stop using setjmp/longjmp, and instead kill the subprocess. (Previously

arigo pypy.commits at gmail.com
Fri Aug 5 10:53:48 EDT 2016


Author: Armin Rigo <arigo at tunes.org>
Branch: reverse-debugger
Changeset: r86031:cf7c9337178d
Date: 2016-08-05 16:54 +0200
http://bitbucket.org/pypy/pypy/changeset/cf7c9337178d/

Log:	Stop using setjmp/longjmp, and instead kill the subprocess.
	(Previously the subprocess was in a half-zombie state.)

diff --git a/rpython/translator/revdb/message.py b/rpython/translator/revdb/message.py
--- a/rpython/translator/revdb/message.py
+++ b/rpython/translator/revdb/message.py
@@ -48,6 +48,10 @@
 # if breakpoint_mode=='i': ignored, never sent
 ANSWER_BREAKPOINT = -24
 
+# sent after an Attempted to do I/O or access raw memory, as the last message
+ANSWER_ATTEMPT_IO = -25
+
+
 # print one line of a file to the console, for CMD_PRINT
 #    Message(ANSWER_LINECACHE, linenum, extra=filename)
 ANSWER_LINECACHE  = 19
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
@@ -57,6 +57,10 @@
         return a
 
 
+class RecreateSubprocess(Exception):
+    pass
+
+
 class ReplayProcess(object):
     """Represent one replaying subprocess.
 
@@ -207,6 +211,8 @@
                     pgroup.all_printed_objects_lst.append(uid)
                 sys.stdout.write('$%d = ' % nid)
                 sys.stdout.flush()
+            elif msg.cmd == ANSWER_ATTEMPT_IO:
+                raise RecreateSubprocess
             else:
                 print >> sys.stderr, "unexpected %r" % (msg,)
 
@@ -441,7 +447,8 @@
 
     def _resume(self, from_time):
         clone_me = self.paused[from_time]
-        self.active.close()
+        if self.active is not None:
+            self.active.close()
         self.active = clone_me.clone()
 
     def jump_in_time(self, target_time):
@@ -534,6 +541,12 @@
             self.active.send(Message(CMD_ATTACHID, nid, uid, int(watch_env)))
             self.active.expect_ready()
 
+    def recreate_subprocess(self):
+        # recreate a subprocess at the current time
+        time = self.get_current_time()
+        self.active = None
+        self.jump_in_time(time)
+
     def print_cmd(self, expression, nids=[]):
         """Print an expression.
         """
@@ -545,7 +558,10 @@
         self.active.tainted = True
         self.attach_printed_objects(uids, watch_env=False)
         self.active.send(Message(CMD_PRINT, extra=expression))
-        self.active.print_text_answer(pgroup=self)
+        try:
+            self.active.print_text_answer(pgroup=self)
+        except RecreateSubprocess:
+            self.recreate_subprocess()
 
     def show_backtrace(self, complete=1):
         """Show the backtrace.
@@ -553,14 +569,20 @@
         if complete:
             self.active.tainted = True
         self.active.send(Message(CMD_BACKTRACE, complete))
-        self.active.print_text_answer()
+        try:
+            self.active.print_text_answer()
+        except RecreateSubprocess:
+            self.recreate_subprocess()
 
     def show_locals(self):
         """Show the locals.
         """
         self.active.tainted = True
         self.active.send(Message(CMD_LOCALS))
-        self.active.print_text_answer()
+        try:
+            self.active.print_text_answer()
+        except RecreateSubprocess:
+            self.recreate_subprocess()
 
     def edit_breakpoints(self):
         return self.all_breakpoints
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
@@ -9,7 +9,6 @@
 #include <fcntl.h>
 #include <unistd.h>
 #include <ctype.h>
-#include <setjmp.h>
 #include <signal.h>
 #include <search.h>
 
@@ -38,7 +37,7 @@
 
 #define FID_REGULAR_MODE           'R'
 #define FID_SAVED_STATE            'S'
-#define FID_JMPBUF_PROTECTED       'J'
+#define FID_POTENTIAL_IO           'I'
 
 
 typedef struct {
@@ -566,6 +565,7 @@
 #define ANSWER_FORKED     (-22)
 #define ANSWER_AT_END     (-23)
 #define ANSWER_BREAKPOINT (-24)
+#define ANSWER_ATTEMPT_IO (-25)
 
 #define RECORD_BKPT_NUM   50
 
@@ -575,7 +575,6 @@
 static const char *rpy_rev_filename;
 static uint64_t interactive_break = 1, finalizer_break = -1, uid_break = -1;
 static uint64_t total_stop_points;
-static jmp_buf jmp_buf_cancel_execution;
 static void (*pending_after_forward)(void);
 static RPyString *empty_string;
 static uint64_t last_recorded_breakpoint_loc;
@@ -858,13 +857,12 @@
         */
         fprintf(stderr, "%s:%d: Attempted to do I/O or access raw memory\n",
                 file, line);
-        if (flag_io_disabled == FID_JMPBUF_PROTECTED) {
-            longjmp(jmp_buf_cancel_execution, 1);
-        }
-        else {
+        if (flag_io_disabled != FID_POTENTIAL_IO) {
             fprintf(stderr, "but we are not in a jmpbuf_protected section\n");
             exit(1);
         }
+        write_answer(ANSWER_ATTEMPT_IO, 0, 0, 0);
+        exit(0);
     }
 }
 
@@ -916,23 +914,24 @@
     set_revdb_breakpoints();
 }
 
-static void protect_jmpbuf(void)
+static void protect_potential_io(void)
 {
-    change_flag_io_disabled(FID_SAVED_STATE, FID_JMPBUF_PROTECTED);
+    change_flag_io_disabled(FID_SAVED_STATE, FID_POTENTIAL_IO);
     saved_exc[0] = pypy_g_ExcData.ed_exc_type;
     saved_exc[1] = pypy_g_ExcData.ed_exc_value;
     pypy_g_ExcData.ed_exc_type = NULL;
     pypy_g_ExcData.ed_exc_value = NULL;
 }
 
-static void unprotect_jmpbuf(void)
+static void unprotect_potential_io(void)
 {
-    change_flag_io_disabled(FID_JMPBUF_PROTECTED, FID_SAVED_STATE);
+    change_flag_io_disabled(FID_POTENTIAL_IO, FID_SAVED_STATE);
     if (pypy_g_ExcData.ed_exc_type != NULL) {
         fprintf(stderr, "Command crashed with %.*s\n",
                 (int)(pypy_g_ExcData.ed_exc_type->ov_name->rs_chars.length),
                 pypy_g_ExcData.ed_exc_type->ov_name->rs_chars.items);
-        exit(1);
+        write_answer(ANSWER_ATTEMPT_IO, 1, 0, 0);
+        exit(0);
     }
     pypy_g_ExcData.ed_exc_type = saved_exc[0];
     pypy_g_ExcData.ed_exc_value = saved_exc[1];
@@ -942,10 +941,9 @@
                                  rpy_revdb_command_t *cmd,
                                  RPyString *extra)
 {
-    protect_jmpbuf();
-    if (setjmp(jmp_buf_cancel_execution) == 0)
-        func(cmd, extra);
-    unprotect_jmpbuf();
+    protect_potential_io();
+    func(cmd, extra);
+    unprotect_potential_io();
 }
 
 static void check_at_end(uint64_t stop_points)
@@ -1267,10 +1265,9 @@
 
     save_state();
     if (rpy_revdb_commands.rp_alloc) {
-        protect_jmpbuf();
-        if (setjmp(jmp_buf_cancel_execution) == 0)
-            rpy_revdb_commands.rp_alloc(uid, new_object);
-        unprotect_jmpbuf();
+        protect_potential_io();
+        rpy_revdb_commands.rp_alloc(uid, new_object);
+        unprotect_potential_io();
     }
     uid_break = *++future_next_id;
     restore_state();
diff --git a/rpython/translator/revdb/test/test_basic.py b/rpython/translator/revdb/test/test_basic.py
--- a/rpython/translator/revdb/test/test_basic.py
+++ b/rpython/translator/revdb/test/test_basic.py
@@ -395,6 +395,7 @@
     def test_io_not_permitted(self):
         child = self.replay(stderr=subprocess.PIPE)
         child.send(Message(1, extra='oops'))
+        child.expect(ANSWER_ATTEMPT_IO)
         child.close()
         err = self.subproc.stderr.read()
         assert err.endswith(': Attempted to do I/O or access raw memory\n')


More information about the pypy-commit mailing list