[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