Author: Remi Meier <meier...@student.ethz.ch> Branch: implement-id Changeset: r219:589d41f3af88 Date: 2013-06-21 11:50 +0200 http://bitbucket.org/pypy/stmgc/changeset/589d41f3af88/
Log: intermediate backup before rewrite diff --git a/c4/demo_random.c b/c4/demo_random.c --- a/c4/demo_random.c +++ b/c4/demo_random.c @@ -27,6 +27,7 @@ struct node { struct stm_object_s hdr; long value; + revision_t id; struct node *next; }; typedef struct node * nodeptr; @@ -82,6 +83,7 @@ gcptr x = calloc(1, size); x->h_tid = PREBUILT_FLAGS | tid; x->h_revision = PREBUILT_REVISION; + x->h_original = 0; return x; } @@ -260,7 +262,7 @@ num = get_rand(SHARED_ROOTS); _sr = shared_roots[num]; - k = get_rand(15); + k = get_rand(16); switch (k) { case 0: // remove a root @@ -322,6 +324,17 @@ pop_roots(); p = NULL; break; + case 15: + w_r = (nodeptr)read_barrier(_r); + if (w_r->id) { + assert(w_r->id == stm_id((gcptr)w_r)); + assert(w_r->id == stm_id((gcptr)_r)); + } + else { + w_r = (nodeptr)write_barrier(_r); + w_r->id = stm_id((gcptr)w_r); + assert(w_r->id == stm_id((gcptr)_r)); + } } return p; } @@ -348,8 +361,8 @@ int interruptible_callback(gcptr arg1, int retry_counter) { td.num_roots = td.num_roots_outside_perform; - // done by the following pop_roots(): - //copy_roots(td.roots_outside_perform, td.roots, td.num_roots); + // done & overwritten by the following pop_roots(): + // copy_roots(td.roots_outside_perform, td.roots, td.num_roots); // refresh td.roots: arg1 = stm_pop_root(); diff --git a/c4/et.c b/c4/et.c --- a/c4/et.c +++ b/c4/et.c @@ -446,7 +446,9 @@ B = stmgc_duplicate_old(P); B->h_tid |= GCFLAG_BACKUP_COPY; - + if (P->h_tid & GCFLAG_OLD) + B->h_original = P; + P->h_tid |= GCFLAG_PRIVATE_FROM_PROTECTED; P->h_revision = (revision_t)B; @@ -473,6 +475,9 @@ /* note that stmgc_duplicate() usually returns a young object, but may return an old one if the nursery is full at this moment. */ gcptr L = stmgc_duplicate(R); + if (!(L->h_original)) + L->h_original = (revision_t)R; + assert(!(L->h_tid & GCFLAG_BACKUP_COPY)); assert(!(L->h_tid & GCFLAG_STUB)); assert(!(L->h_tid & GCFLAG_PRIVATE_FROM_PROTECTED)); @@ -1003,7 +1008,12 @@ stub->h_tid = (L->h_tid & STM_USER_TID_MASK) | GCFLAG_PUBLIC | GCFLAG_STUB | GCFLAG_OLD; + assert(!(L->h_tid & GCFLAG_HAS_ID)); stub->h_revision = ((revision_t)L) | 2; + if (L->h_original) + stub->h_original = L->h_original; + else + L->h_original = (revision_t)stub; item->val = stub; } G2L_LOOP_END; @@ -1069,6 +1079,8 @@ if (B->h_tid & GCFLAG_PUBLIC) { + assert(!(P->h_tid & GCFLAG_HAS_ID)); + /* B was stolen */ while (1) { @@ -1080,6 +1092,13 @@ break; } } + else if (P->h_tid & GCFLAG_HAS_ID) { + /* The backup is the "id object". */ + B->h_tid &= ~GCFLAG_BACKUP_COPY; + B->h_tid |= GCFLAG_PUBLIC; + P->h_tid &= ~GCFLAG_HAS_ID; + B->h_revision = (revision_t)P; + } else { stmgcpage_free(B); @@ -1111,6 +1130,7 @@ { assert(!(B->h_tid & GCFLAG_BACKUP_COPY)); P->h_tid |= GCFLAG_PUBLIC; + P->h_tid &= ~GCFLAG_HAS_ID; // just in case if (!(P->h_tid & GCFLAG_OLD)) P->h_tid |= GCFLAG_NURSERY_MOVED; /* P becomes a public outdated object. It may create an exception documented in doc-objects.txt: a public but young @@ -1119,10 +1139,20 @@ stealing will follow its h_revision (to B). */ } + else if (P->h_tid & GCFLAG_HAS_ID) { + /* The backup is the "id object". P becomes outdated. */ + P->h_tid |= GCFLAG_PUBLIC; + P->h_tid &= ~GCFLAG_HAS_ID; + B->h_tid |= GCFLAG_PUBLIC; + B->h_tid &= ~GCFLAG_BACKUP_COPY; + if (!(P->h_tid & GCFLAG_OLD)) P->h_tid |= GCFLAG_NURSERY_MOVED; + fprintf(stderr, "%p made outdated, %p is current\n", P, B); + } else { /* copy the backup copy B back over the now-protected object P, and then free B, which will not be used any more. */ + assert(B->h_original == P); size_t size = stmcb_size(B); assert(B->h_tid & GCFLAG_BACKUP_COPY); memcpy(((char *)P) + offsetof(struct stm_object_s, h_revision), diff --git a/c4/nursery.c b/c4/nursery.c --- a/c4/nursery.c +++ b/c4/nursery.c @@ -74,11 +74,6 @@ L->h_tid &= ~GCFLAG_OLD; L->h_tid &= ~GCFLAG_HAS_ID; - if (P->h_original) - L->h_original = P->h_original; - else - L->h_original = (revision_t)P; - return L; } @@ -88,12 +83,7 @@ gcptr L = (gcptr)stmgcpage_malloc(size); memcpy(L, P, size); L->h_tid |= GCFLAG_OLD; - L->h_tid &= ~GCFLAG_HAS_ID; - - if (P->h_original) - L->h_original = P->h_original; - else - L->h_original = (revision_t)P; + assert(!(L->h_tid & GCFLAG_HAS_ID)); return L; } @@ -108,28 +98,92 @@ revision_t stm_id(gcptr p) { + struct tx_descriptor *d = thread_descriptor; + revision_t result; + if (p->h_original) { + fprintf(stderr, "stm_id(%p) has original: %p\n", p, (gcptr)p->h_original); + return p->h_original; + } + + spinlock_acquire(d->public_descriptor->collection_lock, 'I'); + if (p->h_tid & GCFLAG_OLD) { + /* it must be this exact object */ + result = (revision_t)p; + } + else { + /* must create shadow original object */ + gcptr O = stmgc_duplicate_old(p); + p->h_original = (revision_t)O; + p->h_tid |= GCFLAG_HAS_ID; + O->h_tid |= GCFLAG_PUBLIC; + + result = (revision_t)O; + + fprintf(stderr, "stm_id(%p): is young, preallocate old id-copy %p\n", + p, O); + } + + + if (p->h_original) { + // maybe in the meantime? + fprintf(stderr, "stm_id(%p) has original NOW: %p\n", p, (gcptr)p->h_original); + spinlock_release(d->public_descriptor->collection_lock); return p->h_original; } //p->h_original == NULL - if (!(p->h_tid & GCFLAG_OLD)) {//(is_in_nursery(p)) { - struct tx_descriptor *d = thread_descriptor; - spinlock_acquire(d->public_descriptor->collection_lock, 'I'); + + if (p->h_tid & GCFLAG_PRIVATE_FROM_PROTECTED) { + gcptr B = (gcptr)p->h_revision; + if (p->h_tid & GCFLAG_OLD) { + /* may have become old after becoming priv_from_prot */ + if (B->h_tid & GCFLAG_BACKUP_COPY) { + B->h_original = p; + result = (revision_t)p; + fprintf(stderr, "stm_id(%p): is priv_from_prot and old. make "); + } + else { + /* someone stole and assumes the backup as the ID */ + p->h_original = B; + result = (revision_t)B; + } + } + else { + // use backup copy as ID object + p->h_tid |= GCFLAG_HAS_ID; // see AbortPrivateFromProtected + p->h_original = (revision_t)B; + // B->h_tid |= GCFLAG_PUBLIC; done by CommitPrivateFromProtected + + result = (revision_t)B; + fprintf(stderr, + "stm_id(%p): is private_from_protected, make the backup %p an id-copy\n", + p, B); + } + } + else if (!(p->h_tid & GCFLAG_OLD)) {//(is_in_nursery(p)) { // preallocate old "original" outside; // like stealing gcptr O = stmgc_duplicate_old(p); - p->h_revision = (revision_t)O; + //p->h_revision = (revision_t)O; p->h_original = (revision_t)O; p->h_tid |= GCFLAG_HAS_ID; + O->h_tid |= GCFLAG_PUBLIC; - spinlock_release(d->public_descriptor->collection_lock); - return (revision_t)O; + result = (revision_t)O; + + fprintf(stderr, "stm_id(%p): is young, preallocate old id-copy %p\n", + p, O); } - else { - // p is the original itself - return (revision_t)p; + else {// if (p->h_tid & GCFLAG_OLD) { + /* obj is old, possibly private or protected */ + /* last, because there are old private(_from_public) objects */ + result = (revision_t)p; + fprintf(stderr, "stm_id(%p): is itself\n", p); } + + spinlock_release(d->public_descriptor->collection_lock); + return result; } revision_t stm_pointer_equal(gcptr p1, gcptr p2) @@ -156,9 +210,14 @@ inline void copy_to_old_id_copy(gcptr obj, gcptr id) { + assert(!is_in_nursery(thread_descriptor, id)); + assert(id->h_tid & GCFLAG_OLD); + size_t size = stmcb_size(obj); memcpy(id, obj, size); id->h_tid &= ~GCFLAG_HAS_ID; + id->h_tid |= GCFLAG_OLD; + fprintf(stderr, "copy_to_old_id_copy(%p -> %p)\n", obj, id); } static void visit_if_young(gcptr *root) @@ -184,8 +243,16 @@ if (obj->h_tid & GCFLAG_HAS_ID) { /* already has a place to go to */ - copy_to_old_id_copy(obj, (gcptr)obj->h_original); - fresh_old_copy = (gcptr)obj->h_original; + gcptr id_obj = (gcptr)obj->h_original; + + /* assert(!(id_obj->h_tid & GCFLAG_BACKUP_COPY)); + well, if it is still a backup, then it wasn't + stolen. We can use it for our young obj. + */ + + copy_to_old_id_copy(obj, id_obj); + fresh_old_copy = id_obj; + obj->h_tid &= ~GCFLAG_HAS_ID; } else { /* make a copy of it outside */ diff --git a/c4/steal.c b/c4/steal.c --- a/c4/steal.c +++ b/c4/steal.c @@ -81,6 +81,10 @@ | GCFLAG_STUB | GCFLAG_OLD; stub->h_revision = ((revision_t)obj) | 2; + if (obj->h_original) + stub->h_original = obj->h_original; + else + obj->h_original = (revision_t)stub; g2l_insert(&sd->all_stubs, obj, stub); if (!(obj->h_tid & GCFLAG_OLD)) @@ -108,6 +112,20 @@ */ if (L->h_tid & GCFLAG_PRIVATE_FROM_PROTECTED) { gcptr B = (gcptr)L->h_revision; /* the backup copy */ + + if(L->h_tid & GCFLAG_HAS_ID) { + /* if L has ID, then the backup is the "original" */ + assert(L->h_original == (revision_t)B); + L->h_tid &= ~GCFLAG_HAS_ID; // now it's simply stolen + } + else if (L->h_tid & GCFLAG_OLD) { + /* became old after becoming priv_from_protected + make L the original + */ + B->h_original = (revision_t)L; + } + /* otherwise: L is the original */ + assert (!(B->h_tid & GCFLAG_HAS_ID)); /* B is now a backup copy, i.e. a protected object, and we own the foreign thread's collection_lock, so we can read/write the @@ -154,6 +172,7 @@ if (!(L->h_tid & GCFLAG_OLD)) { gcptr O; if (L->h_tid & GCFLAG_HAS_ID) { + /* use id-copy for us */ O = (gcptr)L->h_original; L->h_tid &= ~GCFLAG_HAS_ID; L->h_revision = (revision_t)O; _______________________________________________ pypy-commit mailing list pypy-commit@python.org http://mail.python.org/mailman/listinfo/pypy-commit