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

Reply via email to