Author: Armin Rigo <[email protected]>
Branch: 
Changeset: r135:450808530645
Date: 2013-06-15 18:52 +0200
http://bitbucket.org/pypy/stmgc/changeset/450808530645/

Log:    Tweaks tweaks.

diff --git a/c4/doc-objects.txt b/c4/doc-objects.txt
--- a/c4/doc-objects.txt
+++ b/c4/doc-objects.txt
@@ -270,3 +270,26 @@
 - public copies: must be changed carefully: `h_tid` is only modified to
 add GCFLAG_PUBLIC_TO_PRIVATE; and `h_revision` changes are done with
 bool_cas() in a thread-controlled way.
+
+
+
+Nursery and minor collections
+-----------------------------
+
+Every thread has its own nursery.  When it's full, the thread does a
+minor collection and proceed.
+
+Most object copies are allocated "young", i.e. from the nursery of its
+thread, with the following exceptions.
+
+Any public object (GCFLAG_PUBLIC) must be old.  This is a consequence of
+the fact that public objects may be accessed concurrently by any thead,
+but young objects are moved during a minor collection.  The rule admits
+one exception: a young object may be turned GCFLAG_PUBLIC during its
+existence (together with GCFLAG_NURSERY_MOVED) in order to get the
+behavior of public objects, but only if we know that no other thread
+will access it anyway.
+
+The backup copy of a GCFLAG_PRIVATE_FROM_PROTECTED copy is allocated
+old, and explicitly freed when the thread commits (unless it was
+stolen).
diff --git a/c4/et.c b/c4/et.c
--- a/c4/et.c
+++ b/c4/et.c
@@ -1007,12 +1007,20 @@
       assert(IS_POINTER(P->h_revision));
 
       gcptr B = (gcptr)P->h_revision;
+      assert(B->h_tid & GCFLAG_OLD);
+
       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 becomes a public (possibly young) outdated object */
+          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
+             object.  It's still fine because it should only be seen by
+             other threads during stealing, and as it's outdated,
+             stealing will follow its h_revision (to B).
+          */
         }
       else
         {
diff --git a/c4/nursery.c b/c4/nursery.c
--- a/c4/nursery.c
+++ b/c4/nursery.c
@@ -81,10 +81,7 @@
     assert(!(obj->h_tid & GCFLAG_PREBUILT_ORIGINAL));
     assert(!(obj->h_tid & GCFLAG_OLD));
 
-    size_t size = stmcb_size(obj);
-    gcptr fresh_old_copy = stm_malloc(size);
-    memcpy(fresh_old_copy, obj, size);
-    fresh_old_copy->h_tid |= GCFLAG_OLD;
+    gcptr fresh_old_copy = stmgc_duplicate_old(obj);
 
     fprintf(stderr, "minor: %p is copied to %p\n", obj, fresh_old_copy);
     return fresh_old_copy;
diff --git a/c4/steal.c b/c4/steal.c
--- a/c4/steal.c
+++ b/c4/steal.c
@@ -104,8 +104,9 @@
 
         /* 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
-           flags
+           flags.  B is old, like all backup copies.
         */
+        assert(B->h_tid & GCFLAG_OLD);
         B->h_tid &= ~GCFLAG_BACKUP_COPY;
 
         if (B->h_tid & GCFLAG_PUBLIC_TO_PRIVATE) {
@@ -129,11 +130,27 @@
         if (L->h_tid & GCFLAG_PUBLIC) {
             /* already stolen */
             fprintf(stderr, "already stolen: %p -> %p\n", P, L);
+
+            /* note that we should follow h_revision at least one more
+               step: it is necessary if L is public but young (and then
+               has GCFLAG_NURSERY_MOVED), but it is fine to do it more
+               generally. */
+            v = ACCESS_ONCE(L->h_revision);
+            if (IS_POINTER(v))
+                L = (gcptr)v;
             goto already_stolen;
         }
         else {
             fprintf(stderr, "stolen: %p -> %p\n", P, L);
         }
+
+        /* Copy the object out of the other thread's nursery, if needed */
+        if (!(L->h_tid & GCFLAG_OLD)) {
+            gcptr O = stmgc_duplicate_old(L);
+            L->h_revision = (revision_t)O;
+            L->h_tid |= GCFLAG_PUBLIC | GCFLAG_NURSERY_MOVED;
+            L = O;
+        }
     }
 
     /* Here L is a protected (or backup) copy, and we own the foreign
@@ -157,17 +174,6 @@
        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.
@@ -188,6 +194,8 @@
     smp_wmb();
 
  already_stolen:
+    assert(L->h_tid & GCFLAG_OLD);
+
     /* update the original P->h_revision to point directly to L */
     P->h_revision = (revision_t)L;
 
_______________________________________________
pypy-commit mailing list
[email protected]
http://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to