[pypy-commit] pypy reverse-debugger: Some fixes to weakrefs

arigo pypy.commits at gmail.com
Fri Jun 24 16:01:54 EDT 2016


Author: Armin Rigo <arigo at tunes.org>
Branch: reverse-debugger
Changeset: r85377:86a0d99713cd
Date: 2016-06-24 22:03 +0200
http://bitbucket.org/pypy/pypy/changeset/86a0d99713cd/

Log:	Some fixes to weakrefs

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
@@ -115,7 +115,7 @@
 
     if (filename && *filename) {
         putenv("PYPYRDB=");
-        rpy_rev_fileno = open(filename, O_WRONLY | O_CLOEXEC |
+        rpy_rev_fileno = open(filename, O_RDWR | O_CLOEXEC |
                               O_CREAT | O_NOCTTY | O_TRUNC, 0600);
         if (rpy_rev_fileno < 0) {
             fprintf(stderr, "Fatal error: can't create PYPYRDB file '%s'\n",
@@ -181,8 +181,8 @@
     off_t base_offset;
     ssize_t extra_size = rpy_revdb.buf_p - rpy_rev_buffer;
 
-    if (rpy_rev_buffer < 0)
-        return -1;
+    if (rpy_rev_fileno < 0)
+        return 1;
     base_offset = lseek(rpy_rev_fileno, 0, SEEK_CUR);
     if (base_offset < 0) {
         perror("lseek");
@@ -242,7 +242,11 @@
 {
     /* see comments in ../test/test_weak.py */
     struct pypy_REVDB_WEAKLINK0 *r;
-    r = malloc(sizeof(struct pypy_REVDB_WEAKLINK0));
+    if (!RPY_RDB_REPLAY)
+        r = GC_MALLOC_ATOMIC(sizeof(struct pypy_REVDB_WEAKLINK0));
+    else
+        r = GC_MALLOC(sizeof(struct pypy_REVDB_WEAKLINK0));
+
     if (!r) {
         fprintf(stderr, "out of memory for a weakref\n");
         exit(1);
@@ -261,10 +265,23 @@
         RPY_REVDB_EMIT(alive = WEAKREF_AFTERWARDS_DEAD;, char _e, alive);
 
         if (!RPY_RDB_REPLAY) {
-            OP_BOEHM_DISAPPEARING_LINK(r, target, /*nothing*/);
+            OP_BOEHM_DISAPPEARING_LINK(&r->re_addr, target, /*nothing*/);
         }
-        else if (alive == WEAKREF_AFTERWARDS_DEAD)
-            r->re_addr = NULL;
+        else {
+            /* replaying: we don't make the weakref actually weak at all,
+               but instead we always know if we're going to need the 
+               weakref value later or not */
+            switch (alive) {
+            case WEAKREF_AFTERWARDS_DEAD:
+                r->re_addr = NULL;
+                break;
+            case WEAKREF_AFTERWARDS_ALIVE:
+                break;
+            default:
+                fprintf(stderr, "bad weakref_create byte in log\n");
+                exit(1);
+            }
+        }
     }
     return r;
 }
@@ -288,8 +305,18 @@
         }
         RPY_REVDB_EMIT(alive = WEAKREF_AFTERWARDS_DEAD;, char _e, alive);
 
-        if (RPY_RDB_REPLAY && alive == WEAKREF_AFTERWARDS_DEAD)
-            r->re_addr = NULL;
+        if (RPY_RDB_REPLAY) {
+            switch (alive) {
+            case WEAKREF_AFTERWARDS_DEAD:
+                r->re_addr = NULL;
+                break;
+            case WEAKREF_AFTERWARDS_ALIVE:
+                break;
+            default:
+                fprintf(stderr, "bad weakref_deref byte in log\n");
+                exit(1);
+            }
+        }
     }
     return result;
 }
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
@@ -221,12 +221,14 @@
         s2.close()
         self.subproc = subproc
         child = ReplayProcess(subproc.pid, s1)
-        child.expect(ANSWER_INIT, INIT_VERSION_NUMBER, 3)
+        child.expect(ANSWER_INIT, INIT_VERSION_NUMBER,
+                     self.expected_stop_points)
         child.expect(ANSWER_READY, 1, Ellipsis)
         return child
 
 
 class TestSimpleInterpreter(InteractiveTests):
+    expected_stop_points = 3
 
     def setup_class(cls):
         def main(argv):
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
@@ -1,5 +1,10 @@
-import weakref
+import weakref, gc
+from rpython.rlib import revdb
+from rpython.rlib.debug import debug_print
+from rpython.rlib.objectmodel import keepalive_until_here
+from rpython.translator.revdb.message import *
 from rpython.translator.revdb.test.test_basic import BaseRecordingTests
+from rpython.translator.revdb.test.test_basic import InteractiveTests
 
 
 # Weakrefs: implemented so that the log file contains one byte
@@ -11,7 +16,7 @@
 # in the log, and patching that to "afterwards_alive" if later we find
 # a deref() where the weakref is still alive.  (If a deref() finds the
 # weakref dead, it doesn't do any recording or patching; it simply
-# leaves the previous "afterwards_dead" in place.)
+# leaves the previous already-written "afterwards_dead" byte.)
 
 
 WEAKREF_AFTERWARDS_DEAD  = chr(0xf2)
@@ -49,20 +54,77 @@
         glob = Glob()
         def main(argv):
             x1 = X(); x2 = X()
-            r1 = weakref.ref(x1)
-            r2 = weakref.ref(x2)
-            assert r1() is x1
-            assert r2() is x2
-            assert r1() is x1
+            r1 = weakref.ref(x1)     # (*)
+            r2 = weakref.ref(x2)     # (*)
+            for i in range(8500):
+                assert r1() is x1    # (*)
+                assert r2() is x2    # (*)
             return 9
         self.compile(main, [], backendopt=False)
         out = self.run('Xx')
         rdb = self.fetch_rdb([self.exename, 'Xx'])
-        # find the five WEAKREF_xxx
-        x = rdb.next('c'); assert x == WEAKREF_AFTERWARDS_ALIVE  # r1=ref(x1)
-        x = rdb.next('c'); assert x == WEAKREF_AFTERWARDS_ALIVE  # r2=ref(x2)
-        x = rdb.next('c'); assert x == WEAKREF_AFTERWARDS_ALIVE  # r1()
-        x = rdb.next('c'); assert x == WEAKREF_AFTERWARDS_DEAD   # r2()
-        x = rdb.next('c'); assert x == WEAKREF_AFTERWARDS_DEAD   # r1()
+        # find the 2 + 16998 first WEAKREF_xxx (all "(*)" but the last two)
+        for i in range(2 + 16998):
+            x = rdb.next('c'); assert x == WEAKREF_AFTERWARDS_ALIVE
+        for i in range(2):
+            x = rdb.next('c'); assert x == WEAKREF_AFTERWARDS_DEAD
         x = rdb.next('q'); assert x == 0      # number of stop points
         assert rdb.done()
+
+
+class TestReplayingWeakref(InteractiveTests):
+    expected_stop_points = 1
+
+    def setup_class(cls):
+        from rpython.translator.revdb.test.test_basic import compile, run
+
+        class X:
+            def __init__(self, s):
+                self.s = s
+        prebuilt = X('prebuilt')
+
+        def make(s):
+            lst = [prebuilt] + [X(c) for c in s]
+            keepalive = lst[-1]
+            return [weakref.ref(x) for x in lst], keepalive
+
+        def main(argv):
+            lst, keepalive = make(argv[0])
+            expected = ['prebuilt'] + [c for c in argv[0]]
+            dead = [False] * len(lst)
+            for j in range(17000):
+                outp = []
+                for i in range(len(lst)):
+                    v = lst[i]()
+                    debug_print(v)
+                    if dead[i]:
+                        assert v is None
+                    elif v is None:
+                        outp.append('<DEAD>')
+                        dead[i] = True
+                    else:
+                        outp.append(v.s)
+                        assert v.s == expected[i]
+                print ''.join(outp)
+                if (j % 1000) == 999:
+                    debug_print('============= COLLECT ===========')
+                    gc.collect()
+                debug_print('------ done', j, '.')
+            assert not dead[0]
+            assert not dead[-1]
+            keepalive_until_here(keepalive)
+            revdb.stop_point()
+            return 9
+        compile(cls, main, [], backendopt=False)
+        output = run(cls, '')
+        lines = output.splitlines()
+        assert lines[-1].startswith('prebuilt') and lines[-1].endswith(
+            str(cls.exename)[-1])
+        assert (len(lines[-1]) + output.count('<DEAD>') ==
+                len('prebuilt') + len(str(cls.exename)))
+
+    def test_replaying_weakref(self):
+        child = self.replay()
+        # the asserts are replayed; if we get here it means they passed again
+        child.send(Message(CMD_FORWARD, 1))
+        child.expect(ANSWER_AT_END)


More information about the pypy-commit mailing list