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

Reply via email to