Author: Armin Rigo <[email protected]>
Branch: reverse-debugger
Changeset: r86137:8ac394503ebe
Date: 2016-08-11 10:45 +0200
http://bitbucket.org/pypy/pypy/changeset/8ac394503ebe/

Log:    Careful, we need the gil_acquire byte as well: otherwise effects
        like writing to GC objects might occur at the wrong time

diff --git a/rpython/translator/revdb/gencsupp.py 
b/rpython/translator/revdb/gencsupp.py
--- a/rpython/translator/revdb/gencsupp.py
+++ b/rpython/translator/revdb/gencsupp.py
@@ -83,18 +83,19 @@
         return call_code   # a hack for ll_call_destructor() to mean
                            # that the calls should really be done
     #
-    # hack: we don't need the flag for at least this common function
-    if call_code == 'RPyGilAcquire();':
-        return 'RPY_REVDB_CALL_GILCTRL(%s);' % (call_code,)
-    if call_code == 'RPyGilRelease();':
+    if call_code in ('RPyGilAcquire();', 'RPyGilRelease();'):
         # Could also work with a regular RPY_REVDB_CALL_VOID, but we
-        # use a different byte (0xFD instead of 0xFC) to detect more
-        # sync misses.  In a single-threaded environment this 0xFD
+        # use a different byte (0xFD, 0xFE instead of 0xFC) to detect more
+        # sync misses.  In a single-threaded environment this 0xFD or 0xFE
         # byte is not needed at all, but in a multi-threaded
         # environment it ensures that during replaying, just after
-        # reading the 0xFD, we switch to a different thread if needed
+        # reading the 0xFD or 0xFE, we switch to a different thread if needed
         # (actually implemented with stacklets).
-        return 'RPY_REVDB_CALL_GIL(%s);' % (call_code,)
+        if call_code == 'RPyGilAcquire();':
+            byte = '0xFD'
+        else:
+            byte = '0xFE'
+        return 'RPY_REVDB_CALL_GIL(%s, %s);' % (call_code, byte)
     #
     tp = funcgen.lltypename(v_result)
     if tp == 'void @':
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
@@ -57,8 +57,8 @@
 static char rpy_rev_buffer[16384];    /* max. 32768 */
 int rpy_rev_fileno = -1;
 static char flag_io_disabled = FID_REGULAR_MODE;
-__thread bool_t rpy_active_thread;
-static bool_t *rpy_active_thread_ptr;
+__thread int rpy_active_thread;
+static int *rpy_active_thread_ptr;
 
 
 static void setup_record_mode(int argc, char *argv[]);
@@ -1680,7 +1680,8 @@
 RPY_EXTERN
 void rpy_reverse_db_bad_acquire_gil(void)
 {
-    fprintf(stderr, "out of sync: unexpected byte in log (at acquire_gil)\n");
+    fprintf(stderr, "out of sync: unexpected byte in log "
+                    " (at acquire_gil or release_gil)\n");
     exit(1);
 }
 
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
@@ -15,7 +15,7 @@
 # error "explicit RPY_RDB_REPLAY: not really supported"
 #endif
     bool_t watch_enabled;
-    long lock;
+    int lock;
     char *buf_p, *buf_limit, *buf_readend;
     uint64_t stop_point_seen, stop_point_break;
     uint64_t unique_id_seen, unique_id_break;
@@ -23,7 +23,7 @@
 
 RPY_EXTERN rpy_revdb_t rpy_revdb;
 RPY_EXTERN int rpy_rev_fileno;
-RPY_EXTERN __thread bool_t rpy_active_thread;
+RPY_EXTERN __thread int rpy_active_thread;
 
 
 /* ------------------------------------------------------------ */
@@ -66,11 +66,15 @@
 /* Acquire/release the lock around EMIT_RECORD, because it may be
    called without holding the GIL.  Note that we're always
    single-threaded during replaying: the lock is only useful during
-   recording. */
+   recording.  
+
+   Implementation trick: use 'a >= b' to mean 'a || !b' (the two
+   variables can only take the values 0 or 1).
+*/
 #define _RPY_REVDB_LOCK()                                               \
     {                                                                   \
-        bool_t _lock_contention = pypy_lock_test_and_set(&rpy_revdb.lock, 1); \
-        if (_lock_contention || !rpy_active_thread)                     \
+        int _lock_contention = pypy_lock_test_and_set(&rpy_revdb.lock, 1); \
+        if (_lock_contention >= rpy_active_thread)                      \
             rpy_reverse_db_lock_acquire(_lock_contention);              \
     }
 #define _RPY_REVDB_UNLOCK()                                             \
@@ -143,17 +147,17 @@
             rpy_reverse_db_invoke_callback(_re);                        \
     }
 
-#define RPY_REVDB_CALL_GIL(call_code)                                   \
+#define RPY_REVDB_CALL_GIL(call_code, byte)                             \
     if (!RPY_RDB_REPLAY) {                                              \
         call_code                                                       \
         _RPY_REVDB_LOCK();                                              \
-        _RPY_REVDB_EMIT_RECORD_L(unsigned char _e, 0xFD)                \
+        _RPY_REVDB_EMIT_RECORD_L(unsigned char _e, byte)                \
         _RPY_REVDB_UNLOCK();                                            \
     }                                                                   \
     else {                                                              \
         unsigned char _re;                                              \
         _RPY_REVDB_EMIT_REPLAY(unsigned char _e, _re)                   \
-        if (_re != 0xFD)                                                \
+        if (_re != byte)                                                \
             rpy_reverse_db_bad_acquire_gil();                           \
     }
 
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
@@ -95,12 +95,16 @@
         x = self.next(); assert x == len(expected_string)
         self.same_stack()   # errno
         x = self.next('i'); assert x == 0      # errno
+        self.gil_acquire()
 
     def same_stack(self):
         x = self.next('c'); assert x == '\xFC'
 
+    def gil_acquire(self):
+        x = self.next('c'); assert x == '\xFD'
+
     def gil_release(self):
-        x = self.next('c'); assert x == '\xFD'
+        x = self.next('c'); assert x == '\xFE'
 
     def switch_thread(self, expected=None):
         th, = self.special_packet(ASYNC_THREAD_SWITCH, 'q')
diff --git a/rpython/translator/revdb/test/test_callback.py 
b/rpython/translator/revdb/test/test_callback.py
--- a/rpython/translator/revdb/test/test_callback.py
+++ b/rpython/translator/revdb/test/test_callback.py
@@ -66,16 +66,20 @@
         rdb.gil_release()
         rdb.same_stack()                        # callmesimple()
         x = rdb.next('i'); assert x == 55555
+        rdb.gil_acquire()
         rdb.write_call('55555\n')
         rdb.gil_release()
         b = rdb.next('!h'); assert 300 <= b < 310  # -> callback
         x = rdb.next('i'); assert x == 40       # arg n
+        rdb.gil_acquire()
         rdb.gil_release()
         x = rdb.next('!h'); assert x == b       # -> callback
         x = rdb.next('i'); assert x == 3        # arg n
+        rdb.gil_acquire()
         rdb.gil_release()
         rdb.same_stack()                        # <- return in main thread
         x = rdb.next('i'); assert x == 4000 * 300   # return from callme()
+        rdb.gil_acquire()
         rdb.write_call('%s\n' % (4000 * 300,))
         x = rdb.next('q'); assert x == 0      # number of stop points
         assert rdb.done()
@@ -88,14 +92,17 @@
         rdb.gil_release()
         b = rdb.next('!h'); assert 300 <= b < 310  # -> callback
         x = rdb.next('i'); assert x == 40       # arg n
+        rdb.gil_acquire()
         rdb.write_call('40\n')
         rdb.gil_release()
         x = rdb.next('!h'); assert x == b       # -> callback again
         x = rdb.next('i'); assert x == 3        # arg n
+        rdb.gil_acquire()
         rdb.write_call('3\n')
         rdb.gil_release()
         rdb.same_stack()                        # -> return in main thread
         x = rdb.next('i'); assert x == 120      # <- return from callme()
+        rdb.gil_acquire()
         rdb.write_call('120\n')
         x = rdb.next('q'); assert x == 2        # number of stop points
         assert rdb.done()
diff --git a/rpython/translator/revdb/test/test_thread.py 
b/rpython/translator/revdb/test/test_thread.py
--- a/rpython/translator/revdb/test/test_thread.py
+++ b/rpython/translator/revdb/test/test_thread.py
@@ -41,34 +41,40 @@
         th_B = rdb.switch_thread()
         assert th_B != th_A
         b = rdb.next('!h'); assert 300 <= b < 310   # "callback": start thread
+        rdb.gil_acquire()
         rdb.gil_release()
 
         rdb.switch_thread(th_A)
         rdb.same_stack()      # start_new_thread returns
         x = rdb.next(); assert x == th_B    # result is the 'th_B' id
+        rdb.gil_acquire()
         rdb.gil_release()
 
         rdb.switch_thread(th_B)
-        rdb.same_stack()      # sleep()
+        rdb.same_stack()      # sleep() (finishes here)
         rdb.next('i')         # sleep()
+        rdb.gil_acquire()
         rdb.write_call("BB\n")
         rdb.gil_release()
 
         rdb.switch_thread(th_A)
         rdb.same_stack()      # sleep()
         rdb.next('i')         # sleep()
+        rdb.gil_acquire()
         rdb.write_call("AAAA\n")
         rdb.gil_release()
 
         rdb.switch_thread(th_B)
         rdb.same_stack()      # sleep()
         rdb.next('i')         # sleep()
+        rdb.gil_acquire()
         rdb.write_call("BBB\n")
         rdb.gil_release()
 
         rdb.switch_thread(th_A)
         rdb.same_stack()      # sleep()
         rdb.next('i')         # sleep()
+        rdb.gil_acquire()
         rdb.write_call("AAAA\n")
         rdb.done()
 
diff --git a/rpython/translator/revdb/test/test_weak.py 
b/rpython/translator/revdb/test/test_weak.py
--- a/rpython/translator/revdb/test/test_weak.py
+++ b/rpython/translator/revdb/test/test_weak.py
@@ -204,8 +204,9 @@
                 y = intmask(rdb.next('q')); assert y == -1
                 triggered = True
             rdb.gil_release()
-            rdb.same_stack()
-            j = rdb.next()
+            rdb.same_stack()  #
+            j = rdb.next()    # call to foobar()
+            rdb.gil_acquire()
             assert j == i + 1000000 * triggered
             if triggered:
                 lst = []
@@ -217,8 +218,9 @@
                     uid_seen.add(uid)
                     lst.append(uid)
                 rdb.gil_release()
-                rdb.same_stack()
-                totals.append((lst, intmask(rdb.next())))
+                rdb.same_stack()                           #
+                totals.append((lst, intmask(rdb.next())))  # call to foobar()
+                rdb.gil_acquire()
         x = rdb.next('q'); assert x == 3000    # number of stop points
         #
         assert 1500 <= len(uid_seen) <= 3000
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to