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