Author: Armin Rigo <[email protected]>
Branch: 
Changeset: r87:391c68e20cf5
Date: 2013-06-09 21:05 +0200
http://bitbucket.org/pypy/stmgc/changeset/391c68e20cf5/

Log:    Implement most of the document, found a few issues to work on

diff --git a/README.txt b/README.txt
--- a/README.txt
+++ b/README.txt
@@ -7,13 +7,13 @@
 This is a C library that combines a GC with STM capabilities.
 It is meant to be a general library that can be used in C programs.
 
-The library interface is in "c3/stmgc.h".
+The library interface is in "c4/stmgc.h".
 
-The file "c3/doc-stmgc.txt" contains a high-level overview followed by
-more detailled explanations.
+The file "c4/doc-objects.txt" contains some low-level explanations.
 
-A demo program can be found in "c3/demo1.c", but the code so far is
-outdated (it doesn't follow what c3/doc-stmgc describes).
+Run tests with "py.test".
+
+A demo program will be found in "c4/demo1.c" (not there yet).
 It can be built with "make debug-demo1" or "make build-demo1".
 
 The plan is to use this C code directly with PyPy, and not write
diff --git a/c4/doc-objects.txt b/c4/doc-objects.txt
--- a/c4/doc-objects.txt
+++ b/c4/doc-objects.txt
@@ -219,13 +219,6 @@
 
 (This occurs during commit, when we have got the collection_lock.)
 
-public_to_private:
-
-    write GT into the private object
-
-    make a stub with h_revision = private object | 2
-
-    after a CPU write barrier, make the public h_revision to point to the stub
 
 private_from_protected:
 
@@ -233,6 +226,8 @@
 
     set P->h_revision to GT
 
+    remove GCFLAG_PRIVATE_FROM_PROTECTED from P
+
     if B has GCFLAG_PUBLIC: it has been stolen
 
         if it has been modified: conflict, abort transaction
@@ -242,3 +237,11 @@
     else:
         possibly free B now, it's not used any more
 
+
+public_to_private:
+
+    write GT into the private object
+
+    make a stub with h_revision = private object | 2
+
+    after a CPU write barrier, make the public h_revision to point to the stub
diff --git a/c4/et.c b/c4/et.c
--- a/c4/et.c
+++ b/c4/et.c
@@ -66,11 +66,16 @@
   gcptr P = G;
   revision_t v;
 
-  if (UNLIKELY(d->public_descriptor->stolen_objects.size > 0))
+  if (P->h_tid & GCFLAG_PRIVATE_FROM_PROTECTED)
     {
-      spinlock_acquire(d->public_descriptor->collection_lock, 'N');
-      stm_normalize_stolen_objects(d->public_descriptor);
-      spinlock_release(d->public_descriptor->collection_lock);
+    private_from_protected:
+      /* 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))
+        AbortTransaction(ABRT_STOLEN_MODIFIED);
+
+      goto add_in_recent_reads_cache;
     }
 
   if (P->h_tid & GCFLAG_PUBLIC)
@@ -142,8 +147,10 @@
     }
 
  register_in_list_of_read_objects:
+  gcptrlist_insert(&d->list_of_read_objects, P);
+
+ add_in_recent_reads_cache:
   fxcache_add(&d->recent_reads_cache, P);
-  gcptrlist_insert(&d->list_of_read_objects, P);
   return P;
 
  follow_stub:;
@@ -159,6 +166,12 @@
                   "private\n", G, P);
           return P;
         }
+      else if (P->h_tid & GCFLAG_PRIVATE_FROM_PROTECTED)
+        {
+          fprintf(stderr, "read_barrier: %p -> %p handle "
+                  "private_from_protected\n", G, P);
+          goto private_from_protected;
+        }
       else if (FXCACHE_AT(P) == P)
         {
           fprintf(stderr, "read_barrier: %p -> %p handle "
@@ -307,24 +320,15 @@
   assert(!(P->h_tid & GCFLAG_PUBLIC_TO_PRIVATE));
   assert(!(P->h_tid & GCFLAG_BACKUP_COPY));
   assert(!(P->h_tid & GCFLAG_STUB));
+  assert(!(P->h_tid & GCFLAG_PRIVATE_FROM_PROTECTED));
 
-  if (P->h_revision & 1)
-    {
-      /* does not have a backup yet */
-      B = stmgc_duplicate(P);
-      B->h_tid |= GCFLAG_BACKUP_COPY;
-    }
-  else
-    {
-      B = (gcptr)P->h_revision;
-      assert(B->h_tid & GCFLAG_BACKUP_COPY);
-      size_t size = stmcb_size(P);
-      memcpy(B + 1, P + 1, size - sizeof(*B));
-    }
-  assert(B->h_tid & GCFLAG_BACKUP_COPY);
+  B = stmgc_duplicate(P);
+  B->h_tid |= GCFLAG_BACKUP_COPY;
 
-  gcptrlist_insert2(&d->public_descriptor->active_backup_copies, P, B);
-  P->h_revision = stm_private_rev_num;
+  P->h_tid |= GCFLAG_PRIVATE_FROM_PROTECTED;
+  P->h_revision = (revision_t)B;
+
+  gcptrlist_insert(&d->private_from_protected, P);
 
   spinlock_release(d->public_descriptor->collection_lock);
   return P;
@@ -333,21 +337,20 @@
 static gcptr LocalizePublic(struct tx_descriptor *d, gcptr R)
 {
   assert(R->h_tid & GCFLAG_PUBLIC);
-  if (R->h_tid & GCFLAG_PUBLIC_TO_PRIVATE)
-    {
-      wlog_t *entry;
-      gcptr L;
-      G2L_FIND(d->public_to_private, R, entry, goto not_found);
-      L = entry->val;
-      assert(L->h_revision == stm_private_rev_num);   /* private object */
-      return L;
-    }
+
+#ifdef _GC_DEBUG
+  wlog_t *entry;
+  G2L_FIND(d->public_to_private, R, entry, goto not_found);
+  assert(!"R is already in public_to_private");
+ not_found:
+#endif
+
   R->h_tid |= GCFLAG_PUBLIC_TO_PRIVATE;
 
- not_found:;
   gcptr L = stmgc_duplicate(R);
   assert(!(L->h_tid & GCFLAG_BACKUP_COPY));
   assert(!(L->h_tid & GCFLAG_STUB));
+  assert(!(L->h_tid & GCFLAG_PRIVATE_FROM_PROTECTED));
   L->h_tid &= ~(GCFLAG_OLD               |
                 GCFLAG_VISITED           |
                 GCFLAG_PUBLIC            |
@@ -369,36 +372,31 @@
 
 gcptr stm_WriteBarrier(gcptr P)
 {
-  gcptr W;
+  gcptr R, W;
   struct tx_descriptor *d = thread_descriptor;
   assert(d->active >= 1);
 
- retry:
-  P = stm_read_barrier(P);
+  R = stm_read_barrier(P);
 
-  if (P->h_tid & GCFLAG_PUBLIC)
-    W = LocalizePublic(d, P);
+  if (R->h_revision == stm_private_rev_num ||
+      (R->h_tid & GCFLAG_PRIVATE_FROM_PROTECTED))
+    return R;
+
+  if (R->h_tid & GCFLAG_PUBLIC)
+    W = LocalizePublic(d, R);
   else
-    W = LocalizeProtected(d, P);
+    W = LocalizeProtected(d, R);
 
-  fprintf(stderr, "write_barrier: %p -> %p\n", P, W);
+  fprintf(stderr, "write_barrier: %p -> %p -> %p\n", P, R, W);
 
   return W;
 }
 
-gcptr stm_get_backup_copy(long index)
+gcptr stm_get_private_from_protected(long index)
 {
-  struct tx_public_descriptor *pd = thread_descriptor->public_descriptor;
-  if (index < gcptrlist_size(&pd->active_backup_copies))
-    return pd->active_backup_copies.items[index];
-  return NULL;
-}
-
-gcptr stm_get_stolen_obj(long index)
-{
-  struct tx_public_descriptor *pd = thread_descriptor->public_descriptor;
-  if (index < gcptrlist_size(&pd->stolen_objects))
-    return pd->stolen_objects.items[index];
+  struct tx_descriptor *d = thread_descriptor;
+  if (index < gcptrlist_size(&d->private_from_protected))
+    return d->private_from_protected.items[index];
   return NULL;
 }
 
@@ -570,9 +568,9 @@
   }
 
   gcptrlist_clear(&d->list_of_read_objects);
-  gcptrlist_clear(&d->public_descriptor->active_backup_copies);
   abort();
-  d->public_descriptor->stolen_objects;//XXX clean up
+  gcptrlist_clear(&d->private_from_protected);  //XXX clean up
+  abort();
   //stmgc_abort_transaction(d);
 
   fprintf(stderr,
@@ -636,14 +634,15 @@
     d->start_real_time.tv_nsec = -1;
   }
   assert(d->list_of_read_objects.size == 0);
+  assert(d->private_from_protected.size == 0);
   assert(!g2l_any_entry(&d->public_to_private));
 
   d->count_reads = 1;
   fxcache_clear(&d->recent_reads_cache);
 #if 0
   gcptrlist_clear(&d->undolog);
+  gcptrlist_clear(&d->abortinfo);
 #endif
-  gcptrlist_clear(&d->abortinfo);
 }
 
 void BeginTransaction(jmp_buf* buf)
@@ -819,24 +818,41 @@
 }
 #endif
 
-void TurnPrivateWithBackupToProtected(struct tx_descriptor *d,
-                                      revision_t cur_time)
+void CommitPrivateFromProtected(struct tx_descriptor *d, revision_t cur_time)
 {
-  struct tx_public_descriptor *pd = d->public_descriptor;
-  long i, size = pd->active_backup_copies.size;
-  gcptr *items = pd->active_backup_copies.items;
+  long i, size = d->private_from_protected.size;
+  gcptr *items = d->private_from_protected.items;
 
-  for (i = 0; i < size; i += 2)
+  for (i = 0; i < size; i++)
     {
       gcptr P = items[i];
-      gcptr B = items[i + 1];
-      assert(B->h_tid & GCFLAG_BACKUP_COPY);
-      assert(!(B->h_tid & GCFLAG_PUBLIC));
-      assert(P->h_revision == stm_private_rev_num);
-      B->h_revision = cur_time;
-      P->h_revision = (revision_t)B;
+
+      assert(!(P->h_revision & 1));   // "is a pointer"
+      gcptr B = (gcptr)P->h_revision;
+
+      assert(P->h_tid & GCFLAG_PRIVATE_FROM_PROTECTED);
+      P->h_tid &= ~GCFLAG_PRIVATE_FROM_PROTECTED;
+      P->h_revision = cur_time;
+
+      if (B->h_tid & GCFLAG_PUBLIC)
+        {
+          /* B was stolen */
+          while (1)
+            {
+              revision_t v = ACCESS_ONCE(B->h_revision);
+              if (!(v & 1))    // "is a pointer", i.e. "was modified"
+                AbortTransaction(ABRT_STOLEN_MODIFIED);
+
+              if (bool_cas(&B->h_revision, v, (revision_t)P))
+                break;
+            }
+        }
+      else
+        {
+          //stm_free(B);
+        }
     };
-  gcptrlist_clear(&pd->active_backup_copies);
+  gcptrlist_clear(&d->private_from_protected);
 }
 
 void CommitTransaction(void)
@@ -846,9 +862,6 @@
   assert(d->active >= 1);
 
   spinlock_acquire(d->public_descriptor->collection_lock, 'C');  /*committing*/
-  if (d->public_descriptor->stolen_objects.size)
-    stm_normalize_stolen_objects(d->public_descriptor);
-
   AcquireLocks(d);
 
   if (is_inevitable(d))
@@ -885,6 +898,8 @@
         if (!ValidateDuringTransaction(d, 1))
           AbortTransaction(ABRT_VALIDATE_COMMIT);
     }
+  CommitPrivateFromProtected(d, cur_time);
+
   /* we cannot abort any more from here */
   d->setjmp_buf = NULL;
   gcptrlist_clear(&d->list_of_read_objects);
@@ -895,8 +910,6 @@
           "*************************************\n",
           (long)cur_time);
 
-  TurnPrivateWithBackupToProtected(d, cur_time);
-
   revision_t localrev = stm_private_rev_num;
   //UpdateProtectedChainHeads(d, cur_time, localrev);
   //smp_wmb();
@@ -1159,12 +1172,12 @@
     thread_descriptor = NULL;
 
     g2l_delete(&d->public_to_private);
-    assert(d->public_descriptor->active_backup_copies.size == 0);
-    gcptrlist_delete(&d->public_descriptor->active_backup_copies);
+    assert(d->private_from_protected.size == 0);
+    gcptrlist_delete(&d->private_from_protected);
     gcptrlist_delete(&d->list_of_read_objects);
+#if 0
     gcptrlist_delete(&d->abortinfo);
     free(d->longest_abort_info);
-#if 0
     gcptrlist_delete(&d->undolog);
 #endif
 
diff --git a/c4/et.h b/c4/et.h
--- a/c4/et.h
+++ b/c4/et.h
@@ -62,6 +62,7 @@
 #define GCFLAG_NURSERY_MOVED     (STM_FIRST_GCFLAG << 6)
 #define GCFLAG_BACKUP_COPY       (STM_FIRST_GCFLAG << 7)   /* debugging */
 #define GCFLAG_STUB              (STM_FIRST_GCFLAG << 8)   /* debugging */
+#define GCFLAG_PRIVATE_FROM_PROTECTED (STM_FIRST_GCFLAG << 9)
 
 /* this value must be reflected in PREBUILT_FLAGS in stmgc.h */
 #define GCFLAG_PREBUILT  (GCFLAG_VISITED           | \
@@ -73,24 +74,25 @@
                          "VISITED",           \
                          "PUBLIC",            \
                          "PREBUILT_ORIGINAL", \
-                         "BACKUP_COPY",       \
                          "PUBLIC_TO_PRIVATE", \
                          "WRITE_BARRIER",     \
                          "NURSERY_MOVED",     \
-                         "STOLEN",            \
+                         "BACKUP_COPY",       \
                          "STUB",              \
+                         "PRIVATE_FROM_PROTECTED", \
                          NULL }
 
 /************************************************************/
 
 #define ABRT_MANUAL               0
 #define ABRT_COMMIT               1
-#define ABRT_VALIDATE_INFLIGHT    2
-#define ABRT_VALIDATE_COMMIT      3
-#define ABRT_VALIDATE_INEV        4
-#define ABRT_COLLECT_MINOR        5
-#define ABRT_COLLECT_MAJOR        6
-#define ABORT_REASONS         7
+#define ABRT_STOLEN_MODIFIED      2
+#define ABRT_VALIDATE_INFLIGHT    3
+#define ABRT_VALIDATE_COMMIT      4
+#define ABRT_VALIDATE_INEV        5
+#define ABRT_COLLECT_MINOR        6
+#define ABRT_COLLECT_MAJOR        7
+#define ABORT_REASONS         8
 
 #define SPLP_ABORT                0
 #define SPLP_LOCKED_INFLIGHT      1
@@ -105,8 +107,6 @@
   revision_t collection_lock;
   struct stub_block_s *stub_blocks;
   gcptr stub_free_list;
-  struct GcPtrList active_backup_copies;  /* (P,B) where P=private, B=backup */
-  struct GcPtrList stolen_objects;      /* (P,Q) where P=priv/prot, Q=public */
   revision_t *private_revision_ref;
   revision_t free_list_next;
   /* xxx gcpage data here */
@@ -135,7 +135,8 @@
   unsigned int num_aborts[ABORT_REASONS];
   unsigned int num_spinloops[SPINLOOP_REASONS];
   struct GcPtrList list_of_read_objects;
-  struct GcPtrList abortinfo;
+  //struct GcPtrList abortinfo;
+  struct GcPtrList private_from_protected;
   struct G2L public_to_private;
   char *longest_abort_info;
   long long longest_abort_info_time;
@@ -162,8 +163,7 @@
 gcptr stm_RepeatReadBarrier(gcptr);
 gcptr stm_WriteBarrier(gcptr);
 gcptr _stm_nonrecord_barrier(gcptr, int *);
-gcptr stm_get_backup_copy(long);  /* debugging */
-gcptr stm_get_stolen_obj(long);  /* debugging */
+gcptr stm_get_private_from_protected(long);  /* debugging */
 gcptr stm_get_read_obj(long);  /* debugging */
 gcptr stmgc_duplicate(gcptr);
 
diff --git a/c4/steal.c b/c4/steal.c
--- a/c4/steal.c
+++ b/c4/steal.c
@@ -54,54 +54,21 @@
         goto done;     /* un-stubbed while we waited for the lock */
 
     gcptr L = (gcptr)(v - 2);
-    revision_t w = L->h_revision;
 
-    if (w == *foreign_pd->private_revision_ref) {
-        /* The stub points to a private object L.  Because it cannot point
-           to "really private" objects, it must mean that L used to be
-           a protected object, and it has an attached backed copy.
-           XXX find a way to optimize this search, maybe */
-        long i, size = foreign_pd->active_backup_copies.size;
-        gcptr *items = foreign_pd->active_backup_copies.items;
-        for (i = size - 2; ; i -= 2) {
-            assert(i >= 0);
-            if (items[i] == L)
-                break;
-        }
-        L = items[i + 1];
-        assert(L->h_tid & GCFLAG_BACKUP_COPY);
+    if (L->h_tid & GCFLAG_PRIVATE_FROM_PROTECTED) {
+        L = (gcptr)L->h_revision;     /* the backup copy */
         L->h_tid &= ~GCFLAG_BACKUP_COPY;
     }
-    else if (L->h_tid & GCFLAG_PUBLIC) {
-        /* The stub already points to a public object */
-        goto unstub;
-    }
-    else if (!(w & 1)) {
-        /* The stub points to a protected object L which has a backup
-           copy attached.  Forget the backup copy. */
-        w = ((gcptr)w)->h_revision;
-        assert(w & 1);
-        L->h_revision = w;
-    }
-    /* turn L into a public object */
+
+    /* change L from protected to public */
     L->h_tid |= GCFLAG_PUBLIC;
 
- unstub:
+    smp_wmb();      /* the following update must occur "after" the flag
+                       GCFLAG_PUBLIC was added, for other threads */
+
+    /* update the original P->h_revision to point directly to L */
     P->h_revision = (revision_t)L;
 
  done:
     spinlock_release(foreign_pd->collection_lock);
 }
-
-void stm_normalize_stolen_objects(struct tx_public_descriptor *pd)
-{
-    long i, size = pd->stolen_objects.size;
-    gcptr *items = pd->stolen_objects.items;
-    for (i = 0; i < size; i += 2) {
-        gcptr L = items[i];
-        gcptr Q = items[i + 1];
-        if (L->h_revision == stm_private_rev_num) {
-            
-        }
-    }
-}
diff --git a/c4/stmsync.c b/c4/stmsync.c
--- a/c4/stmsync.c
+++ b/c4/stmsync.c
@@ -87,8 +87,8 @@
 gcptr stm_write_barrier(gcptr obj)
 {
     /* XXX inline in the caller */
-    if (UNLIKELY(((obj->h_tid & GCFLAG_WRITE_BARRIER) != 0) |
-                 (obj->h_revision != stm_private_rev_num)))
+    if (UNLIKELY((obj->h_revision != stm_private_rev_num) &
+                 ((obj->h_tid & GCFLAG_PRIVATE_FROM_PROTECTED) == 0)))
         obj = stm_WriteBarrier(obj);
     return obj;
 }
diff --git a/c4/test/support.py b/c4/test/support.py
--- a/c4/test/support.py
+++ b/c4/test/support.py
@@ -68,8 +68,7 @@
     void stm_start_sharedlock(void);
     void stm_stop_sharedlock(void);
     void AbortTransaction(int);
-    gcptr stm_get_backup_copy(long index);
-    gcptr stm_get_stolen_obj(long index);
+    gcptr stm_get_private_from_protected(long index);
     gcptr stm_get_read_obj(long index);
     void *STUB_THREAD(gcptr);
 
@@ -105,6 +104,7 @@
     #define GCFLAG_WRITE_BARRIER     ...
     #define GCFLAG_NURSERY_MOVED     ...
     #define GCFLAG_STUB              ...
+    #define GCFLAG_PRIVATE_FROM_PROTECTED  ...
     #define ABRT_MANUAL              ...
     //typedef struct { ...; } page_header_t;
 ''')
@@ -524,7 +524,8 @@
     lib.AbortTransaction(lib.ABRT_MANUAL)
 
 def classify(p):
-    private = p.h_revision == lib.get_private_rev_num()
+    private = (p.h_revision == lib.get_private_rev_num() or
+               (p.h_tid & GCFLAG_PRIVATE_FROM_PROTECTED) != 0)
     public  = (p.h_tid & GCFLAG_PUBLIC) != 0
     backup  = (p.h_tid & GCFLAG_BACKUP_COPY) != 0
     stub    = (p.h_tid & GCFLAG_STUB) != 0
@@ -541,34 +542,26 @@
     else:
         return "protected"
 
-def list_of_read_objects():
+def _get_full_list(getter):
     result = []
     index = 0
     while 1:
-        p = lib.stm_get_read_obj(index)
+        p = getter(index)
         if p == ffi.NULL:
             break
         result.append(p)
         index += 1
     return result
 
-def _list2dict(getter):
-    result = {}
-    index = 0
-    while 1:
-        p = getter(index)
-        if p == ffi.NULL:
-            break
-        q = getter(index + 1)
-        assert q != ffi.NULL
-        result[p] = q
-        index += 2
-    return result
+def list_of_read_objects():
+    return _get_full_list(lib.stm_get_read_obj)
 
-def backup_copies():
-    return _list2dict(lib.stm_get_backup_copy)
-
-def stolen_objs():
-    return _list2dict(lib.stm_get_stolen_obj)
+def list_of_private_from_protected():
+    return _get_full_list(lib.stm_get_private_from_protected)
 
 stub_thread = lib.STUB_THREAD
+
+def follow_revision(p):
+    r = p.h_revision
+    assert (r % 4) == 0
+    return ffi.cast("gcptr", r)
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
@@ -49,8 +49,10 @@
     assert classify(p) == "protected"
     p2 = lib.stm_write_barrier(p)
     assert p2 == p       # does not move
-    assert p.h_revision == r2
     assert classify(p) == "private"
+    pback = follow_revision(p)
+    assert classify(pback) == "backup"
+    assert list_of_private_from_protected() == [p]
 
 def test_get_backup_copy():
     p = nalloc(HDR + WORD)
@@ -58,52 +60,19 @@
     lib.stm_commit_transaction()
     lib.stm_begin_inevitable_transaction()
     org_r = p.h_revision
+    assert classify(p) == "protected"
     lib.setlong(p, 0, 927122)
-    assert p.h_revision == lib.get_private_rev_num()
-    pback = backup_copies()[p]
+    assert classify(p) == "private"
+    pback = follow_revision(p)
     assert pback and pback != p
     assert pback.h_revision == org_r
-    assert pback.h_tid == p.h_tid | GCFLAG_BACKUP_COPY
+    assert pback.h_tid == ((p.h_tid & ~GCFLAG_PRIVATE_FROM_PROTECTED) |
+                           GCFLAG_BACKUP_COPY)
     assert lib.rawgetlong(pback, 0) == 78927812
     assert lib.rawgetlong(p, 0) == 927122
     assert classify(p) == "private"
     assert classify(pback) == "backup"
 
-def test_protected_with_backup():
-    p = nalloc(HDR + WORD)
-    lib.setlong(p, 0, 78927812)
-    lib.stm_commit_transaction()
-    lib.stm_begin_inevitable_transaction()
-    lib.setlong(p, 0, 927122)
-    pback = backup_copies()[p]
-    assert pback != p
-    assert p.h_revision == lib.get_private_rev_num()
-    lib.stm_commit_transaction()
-    lib.stm_begin_inevitable_transaction()
-    assert classify(p) == "protected"
-    assert classify(pback) == "backup"
-    assert ffi.cast("gcptr", p.h_revision) == pback
-
-def test_protected_backup_reused():
-    p = nalloc(HDR + WORD)
-    lib.setlong(p, 0, 78927812)
-    lib.stm_commit_transaction()
-    lib.stm_begin_inevitable_transaction()
-    lib.setlong(p, 0, 927122)
-    pback = backup_copies()[p]
-    assert pback != p
-    lib.stm_commit_transaction()
-    lib.stm_begin_inevitable_transaction()
-    assert classify(p) == "protected"
-    assert classify(pback) == "backup"
-    assert lib.rawgetlong(p, 0) == 927122
-    assert lib.rawgetlong(pback, 0) == 78927812    # but should not be used
-    lib.setlong(p, 0, 43891)
-    assert p.h_revision == lib.get_private_rev_num()
-    assert pback == backup_copies()[p]
-    assert lib.rawgetlong(p, 0) == 43891
-    assert lib.rawgetlong(pback, 0) == 927122
-
 def test_prebuilt_is_public():
     p = palloc(HDR)
     assert p.h_revision == 1
@@ -240,15 +209,13 @@
         assert classify(p) == "public"
         assert classify(p1) == "protected"
         plist.append(p1)     # now p's most recent revision is protected
-        assert classify(ffi.cast("gcptr", p.h_revision)) == "stub"
+        assert classify(follow_revision(p)) == "stub"
+        assert p1.h_revision & 1
         r.set(2)
         r.wait(3)
-        d = stolen_objs()
-        assert len(d) == 1
-        assert d.keys() == [p1]
-        [p2] = d.values()
-        assert lib.stm_read_barrier(p) == p2
-        assert lib.stm_read_barrier(p1) == p2
+        assert classify(p1) == "public"
+        assert lib.stm_read_barrier(p) == p1
+        assert lib.stm_read_barrier(p1) == p1
     def f2(r):
         r.wait(2)
         p2 = lib.stm_read_barrier(p)    # steals
@@ -256,8 +223,61 @@
         assert p2 == lib.stm_read_barrier(p)    # short-circuit h_revision
         assert p.h_revision == int(ffi.cast("revision_t", p2))
         assert p2 == lib.stm_read_barrier(p)
-        assert p2 not in plist
+        assert p2 == plist[-1]
         assert classify(p2) == "public"
-        plist.append(p2)
         r.set(3)
     run_parallel(f1, f2)
+
+def test_stealing_while_modifying():
+    py.test.skip("in-progress")
+    p = palloc(HDR + WORD)
+
+    def f1(r):
+        p1 = lib.stm_write_barrier(p)   # private copy
+        assert classify(p) == "public"
+        assert classify(p1) == "private"
+        lib.rawsetlong(p1, 0, 2782172)
+
+        def cb(c):
+            assert c == 0
+            assert classify(p) == "public"
+            assert classify(p1) == "protected"
+            assert classify(follow_revision(p)) == "stub"
+            p2 = lib.stm_write_barrier(p)
+            assert p2 == p1
+            lib.rawsetlong(p2, 0, -451112)
+            pback = follow_revision(p1)
+            assert classify(p1) == "private"
+            assert classify(pback) == "backup"
+            assert lib.stm_read_barrier(p) == p1
+            assert lib.stm_read_barrier(p1) == p1
+            assert pback.h_revision & 1
+            r.wait_while_in_parallel()
+            assert classify(p1) == "private"
+            assert classify(pback) == "public"
+            assert pback.h_tid & GCFLAG_PUBLIC_TO_PRIVATE
+            assert lib.stm_read_barrier(p) == p1
+            assert lib.stm_read_barrier(p1) == p1
+            assert pback.h_revision & 1
+        perform_transaction(cb)
+
+        lib.stm_commit_transaction()
+        lib.stm_begin_inevitable_transaction()
+        assert classify(p1) == "protected"
+        assert classify(pback) == "public"
+        assert classify(follow_revision(pback)) == "stub"
+        assert follow_revision(pback).h_revision == (
+            ffi.cast("revision_t", p1) | 2)
+
+    def f2(r):
+        def cb(c):
+            assert c == 0
+            r.enter_in_parallel()
+            p2 = lib.stm_read_barrier(p)    # steals
+            assert lib.rawgetlong(p2, 0) == 2782172
+            assert p2 == lib.stm_read_barrier(p)
+            assert classify(p2) == "public"
+            r.leave_in_parallel()
+        perform_transaction(cb)
+
+    run_parallel(f1, f2)
_______________________________________________
pypy-commit mailing list
[email protected]
http://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to