Author: Armin Rigo <ar...@tunes.org> Branch: Changeset: r133:87748cb8c1c5 Date: 2013-06-15 11:28 +0200 http://bitbucket.org/pypy/stmgc/changeset/87748cb8c1c5/
Log: in-progress diff --git a/c4/et.c b/c4/et.c --- a/c4/et.c +++ b/c4/et.c @@ -82,12 +82,12 @@ restart_all: if (P->h_tid & GCFLAG_PRIVATE_FROM_PROTECTED) { - assert(!(P->h_revision & 1)); /* pointer to the backup copy */ + assert(IS_POINTER(P->h_revision)); /* pointer to the backup copy */ /* check P->h_revision->h_revision: if a pointer, then it means the backup copy has been stolen into a public object and then modified by some other thread. Abort. */ - if (!(((gcptr)P->h_revision)->h_revision & 1)) + if (IS_POINTER(((gcptr)P->h_revision)->h_revision)) AbortTransaction(ABRT_STOLEN_MODIFIED); goto add_in_recent_reads_cache; @@ -104,8 +104,8 @@ restart_all_public: assert(P->h_tid & GCFLAG_PUBLIC); v = ACCESS_ONCE(P->h_revision); - if (!(v & 1)) // "is a pointer", i.e. - { // "has a more recent revision" + if (IS_POINTER(v)) /* "is a pointer", "has a more recent revision" */ + { retry: if (v & 2) goto follow_stub; @@ -116,8 +116,8 @@ v = ACCESS_ONCE(P->h_revision); - if (!(v & 1)) // "is a pointer", i.e. - { // "has a more recent revision" + if (IS_POINTER(v)) + { if (v & 2) goto follow_stub; @@ -127,7 +127,7 @@ P_prev->h_revision = v; P = (gcptr)v; v = ACCESS_ONCE(P->h_revision); - if (!(v & 1)) // "is a pointer", i.e. "has a more recent rev" + if (IS_POINTER(v)) goto retry; } @@ -302,7 +302,7 @@ if (P->h_tid & GCFLAG_PRIVATE_FROM_PROTECTED) { /* private too, with a backup copy */ - assert(!(P->h_revision & 1)); + assert(IS_POINTER(P->h_revision)); fprintf(stderr, "private_from_protected\n"); return P; } @@ -311,7 +311,7 @@ { fprintf(stderr, "public "); - while (v = P->h_revision, !(v & 1)) + while (v = P->h_revision, IS_POINTER(v)) { if (v & 2) { @@ -553,8 +553,8 @@ revision_t v; retry: v = ACCESS_ONCE(R->h_revision); - if (!(v & 1)) // "is a pointer", i.e. - { // "has a more recent revision" + if (IS_POINTER(v)) /* "is a pointer", i.e. has a more recent revision */ + { if (R->h_tid & GCFLAG_PRIVATE_FROM_PROTECTED) { /* such an object R might be listed in list_of_read_objects @@ -815,8 +815,8 @@ retry: assert(R->h_tid & GCFLAG_PUBLIC); v = ACCESS_ONCE(R->h_revision); - if (!(v & 1)) // "is a pointer", i.e. - { // "has a more recent revision" + if (IS_POINTER(v)) /* "has a more recent revision" */ + { assert(v != 0); AbortTransaction(ABRT_COMMIT); } @@ -907,7 +907,7 @@ L->h_revision = new_revision; gcptr stub = stm_stub_malloc(d->public_descriptor); - stub->h_tid = GCFLAG_PUBLIC | GCFLAG_STUB; + stub->h_tid = GCFLAG_PUBLIC | GCFLAG_STUB | GCFLAG_OLD; stub->h_revision = ((revision_t)L) | 2; item->val = stub; @@ -962,7 +962,7 @@ assert(P->h_tid & GCFLAG_PRIVATE_FROM_PROTECTED); P->h_tid &= ~GCFLAG_PRIVATE_FROM_PROTECTED; - if (P->h_revision & 1) // "is not a pointer" + if (!IS_POINTER(P->h_revision)) { /* This case occurs when a GCFLAG_PRIVATE_FROM_PROTECTED object is stolen: it ends up as a value in 'public_to_private'. @@ -980,7 +980,7 @@ while (1) { revision_t v = ACCESS_ONCE(B->h_revision); - if (!(v & 1)) // "is a pointer", i.e. "was modified" + if (IS_POINTER(v)) /* "was modified" */ AbortTransaction(ABRT_STOLEN_MODIFIED); if (bool_cas(&B->h_revision, v, (revision_t)P)) @@ -1004,14 +1004,14 @@ { gcptr P = items[i]; assert(P->h_tid & GCFLAG_PRIVATE_FROM_PROTECTED); - assert(!(P->h_revision & 1)); // "is a pointer" + assert(IS_POINTER(P->h_revision)); gcptr B = (gcptr)P->h_revision; if (B->h_tid & GCFLAG_PUBLIC) { assert(!(B->h_tid & GCFLAG_BACKUP_COPY)); P->h_tid &= ~GCFLAG_PRIVATE_FROM_PROTECTED; - P->h_tid |= GCFLAG_PUBLIC; + P->h_tid |= GCFLAG_PUBLIC; abort(); /* P becomes a public outdated object */ } else diff --git a/c4/et.h b/c4/et.h --- a/c4/et.h +++ b/c4/et.h @@ -83,6 +83,8 @@ "PRIVATE_FROM_PROTECTED", \ NULL } +#define IS_POINTER(v) (!((v) & 1)) /* even-valued number */ + /************************************************************/ #define ABRT_MANUAL 0 diff --git a/c4/nursery.c b/c4/nursery.c --- a/c4/nursery.c +++ b/c4/nursery.c @@ -139,7 +139,7 @@ /* found P in 'public_to_private' */ - if (!(v & 1)) { // "is a pointer" + if (IS_POINTER(v)) { /* P is both a key in public_to_private and an outdated copy. We are in a case where we know the transaction will not be able to commit successfully. @@ -157,7 +157,7 @@ continue; not_in_public_to_private: - if (v & 1) { // "is not a pointer" + if (!IS_POINTER(v)) { /* P is neither a key in public_to_private nor outdated. It must come from an older transaction that aborted. Nothing to do now. diff --git a/c4/steal.c b/c4/steal.c --- a/c4/steal.c +++ b/c4/steal.c @@ -74,7 +74,8 @@ not_found: stub = stm_stub_malloc(sd->foreign_pd); stub->h_tid = (obj->h_tid & STM_USER_TID_MASK) | GCFLAG_PUBLIC - | GCFLAG_STUB; + | GCFLAG_STUB + | GCFLAG_OLD; stub->h_revision = ((revision_t)obj) | 2; g2l_insert(&sd->all_stubs, obj, stub); @@ -156,6 +157,17 @@ odd number that is also valid on a public up-to-date object. */ + /* Move the object out of the other thread's nursery, if needed */ + if (!(L->h_tid & GCFLAG_OLD)) { + size_t size = stmcb_size(L); + gcptr O = stm_malloc(size); + memcpy(O, L, size); + L->h_revision = (revision_t)O; + L->h_tid |= GCFLAG_NURSERY_MOVED; + O->h_tid |= GCFLAG_OLD; + L = O; + } + /* Fix the content of the object: we need to change all pointers that reference protected copies into pointers that reference stub copies. diff --git a/c4/test/support.py b/c4/test/support.py --- a/c4/test/support.py +++ b/c4/test/support.py @@ -188,8 +188,18 @@ int in_nursery(gcptr obj) { struct tx_descriptor *d = thread_descriptor; - return (d->nursery_base <= (char*)obj && - ((char*)obj) < d->nursery_end); + int result1 = (d->nursery_base <= (char*)obj && + ((char*)obj) < d->nursery_end); + if (obj->h_tid & GCFLAG_OLD) { + assert(result1 == 0); + } + else { + /* this assert() also fails if "obj" is in another nursery than + the one of the current thread. This is ok, because we + should not see such pointers. */ + assert(result1 == 1); + } + return result1; } gcptr pseudoprebuilt(size_t size, int tid) @@ -515,8 +525,15 @@ return "private" if public: if stub: + assert not lib.in_nursery(p) return "stub" - return "public" + else: + # public objects usually never live in the nursery, but + # if stealing makes one, it has GCFLAG_NURSERY_MOVED. + if lib.in_nursery(p): + assert p.h_tid & GCFLAG_NURSERY_MOVED + assert not (p.h_revision & 1) # "is a pointer" + return "public" if backup: return "backup" else: diff --git a/c4/test/test_et.py b/c4/test/test_et.py --- a/c4/test/test_et.py +++ b/c4/test/test_et.py @@ -198,7 +198,7 @@ assert p4 == p2 assert list_of_read_objects() == [p2] -def test_stealing(): +def test_stealing_old(): p = palloc(HDR + WORD) plist = [p] def f1(r): @@ -207,6 +207,10 @@ assert p1 != p assert classify(p) == "public" assert classify(p1) == "private" + minor_collect() + check_nursery_free(p1) + p1 = lib.stm_read_barrier(p) + assert p1.h_tid & GCFLAG_OLD assert p.h_tid & GCFLAG_PUBLIC_TO_PRIVATE lib.rawsetlong(p1, 0, 2782172) lib.stm_commit_transaction() @@ -235,6 +239,51 @@ r.set(3) run_parallel(f1, f2) +def test_stealing_young(): + p = palloc(HDR + WORD) + plist = [p] + def f1(r): + assert (p.h_tid & GCFLAG_PUBLIC_TO_PRIVATE) == 0 + p1 = lib.stm_write_barrier(p) # private copy + assert p1 != p + assert classify(p) == "public" + assert classify(p1) == "private" + assert p.h_tid & GCFLAG_PUBLIC_TO_PRIVATE + lib.rawsetlong(p1, 0, 2782172) + lib.stm_commit_transaction() + lib.stm_begin_inevitable_transaction() + assert classify(p) == "public" + assert classify(p1) == "protected" + plist.append(p1) # now p's most recent revision is protected + assert classify(follow_revision(p)) == "stub" + assert p1.h_revision & 1 + r.set(2) + r.wait(3) + assert classify(p1) == "public" + assert (p1.h_revision & 1) == 0 # outdated + p2 = ffi.cast("gcptr", p1.h_revision) + assert lib.in_nursery(p1) + assert not lib.in_nursery(p2) + assert lib.stm_read_barrier(p) == p2 + assert lib.stm_read_barrier(p1) == p2 + assert lib.stm_read_barrier(p2) == p2 + def f2(r): + r.wait(2) + p2 = lib.stm_read_barrier(p) # steals + assert classify(p2) == "public" + assert lib.rawgetlong(p2, 0) == 2782172 + assert p2 == lib.stm_read_barrier(p) # short-circuit h_revision + if SHORTCUT: + assert p.h_revision == int(ffi.cast("revision_t", p2)) + assert p2 == lib.stm_read_barrier(p) + assert p2 != plist[-1] # p2 is a public moved-out-of-nursery + assert plist[-1].h_tid & GCFLAG_PUBLIC + assert plist[-1].h_tid & GCFLAG_NURSERY_MOVED + assert plist[-1].h_revision == int(ffi.cast("revision_t", p2)) + assert classify(p2) == "public" + r.set(3) + run_parallel(f1, f2) + def test_stealing_while_modifying(aborting=False): p = palloc(HDR + WORD) diff --git a/c4/test/test_nursery.py b/c4/test/test_nursery.py --- a/c4/test/test_nursery.py +++ b/c4/test/test_nursery.py @@ -232,3 +232,32 @@ assert classify(p3) == "private" assert p3 == p2 != p1 assert not lib.in_nursery(p2) + +def _public_and_protected_in_nursery(): + p1 = palloc(HDR + WORD) + lib.rawsetlong(p1, 0, 1000000) + p2 = lib.stm_write_barrier(p1) + assert lib.in_nursery(p2) + lib.setlong(p1, 0, 2000000) + assert lib.rawgetlong(p2, 0) == 2000000 + lib.stm_commit_transaction() + lib.stm_begin_inevitable_transaction() + assert classify(p1) == "public" + assert classify(p2) == "protected" + check_not_free(p2) + return p1, p2 + +def test_public_not_in_nursery(): + p1, p2 = _public_and_protected_in_nursery() + plist = [] + def f1(_): + p3 = lib.stm_read_barrier(p1) + assert classify(p3) == "public" + assert not lib.in_nursery(p3) + assert p3 != p2 # not in-place, because p2 is in the nursery + plist.append(p3) + run_parallel(f1) + p3 = lib.stm_read_barrier(p1) + assert plist == [p3] + assert classify(p3) == "public" + assert not lib.in_nursery(p3) _______________________________________________ pypy-commit mailing list pypy-commit@python.org http://mail.python.org/mailman/listinfo/pypy-commit