Author: Armin Rigo <ar...@tunes.org>
Branch: 
Changeset: r80:1456f52e680d
Date: 2013-06-08 22:49 +0200
http://bitbucket.org/pypy/stmgc/changeset/1456f52e680d/

Log:    in-progress

diff --git a/c4/et.c b/c4/et.c
--- a/c4/et.c
+++ b/c4/et.c
@@ -60,38 +60,6 @@
 
 /************************************************************/
 
-#if 0
-static inline gcptr AddInReadSet(struct tx_descriptor *d, gcptr R)
-{
-  fprintf(stderr, "AddInReadSet(%p)\n", R);
-  d->count_reads++;
-  if (!fxcache_add(&d->recent_reads_cache, R)) {
-      /* not in the cache: it may be the first time we see it,
-       * so insert it into the list */
-      gcptrlist_insert(&d->list_of_read_objects, R);
-  }
-      //      break;
-
-      //  case 2:
-      /* already in the cache, and FX_THRESHOLD reached */
-      //      return Localize(d, R);
-      //  }
-  return R;
-}
-#endif
-
-static void steal(gcptr P)
-{
-  struct tx_public_descriptor *foreign_pd;
-  revision_t target_descriptor_index;
-  revision_t v = ACCESS_ONCE(P->h_revision);
-  if ((v & 3) != 2)
-    return;
-  target_descriptor_index = *(revision_t *)(v & ~(HANDLE_BLOCK_SIZE-1));
-  //foreign_pd = ACCESS_ONCE(stm_descriptor_array[target_descriptor_index]);
-  abort();
-}
-
 gcptr stm_DirectReadBarrier(gcptr G)
 {
   struct tx_descriptor *d = thread_descriptor;
@@ -106,26 +74,26 @@
       v = ACCESS_ONCE(P->h_revision);
       if (!(v & 1))  // "is a pointer", i.e.
         {            //      "has a more recent revision"
-          if (v & 2)
-            goto old_to_young;
-          assert(P->h_tid & GCFLAG_PUBLIC);
+          /* if we land on a P in read_barrier_cache: just return it */
+          gcptr P_next = (gcptr)v;
+          if (FXCACHE_AT(P_next) == P_next)
+            {
+              fprintf(stderr, "read_barrier: %p -> %p fxcache\n", G, P_next);
+              return P_next;
+            }
+
+          if (P->h_tid & GCFLAG_STUB)
+            goto follow_stub;
 
           gcptr P_prev = P;
-          P = (gcptr)v;
-
-          /* if we land on a P in read_barrier_cache: just return it */
-          if (FXCACHE_AT(P) == P)
-            {
-              fprintf(stderr, "read_barrier: %p -> %p fxcache\n", G, P);
-              return P;
-            }
+          P = P_next;
+          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 (v & 2)
-                goto old_to_young;
-              assert(P->h_tid & GCFLAG_PUBLIC);
+              if (P->h_tid & GCFLAG_STUB)
+                goto follow_stub;
 
               /* we update P_prev->h_revision as a shortcut */
               /* XXX check if this really gives a worse performance than only
@@ -171,12 +139,12 @@
   gcptrlist_insert(&d->list_of_read_objects, P);
   return P;
 
- old_to_young:;
-  revision_t target_descriptor_index;
-  target_descriptor_index = *(revision_t *)(v & ~(HANDLE_BLOCK_SIZE-1));
-  if (target_descriptor_index == d->public_descriptor_index)
+ follow_stub:;
+  struct tx_public_descriptor *foreign_pd = STUB_THREAD(P);
+  if (foreign_pd == d->public_descriptor)
     {
-      P = (gcptr)(*(revision_t *)(v - 2));
+      /* same thread */
+      P = (gcptr)P->h_revision;
       assert(!(P->h_tid & GCFLAG_PUBLIC));
       if (P->h_revision == stm_private_rev_num)
         {
@@ -200,8 +168,8 @@
   else
     {
       /* stealing */
-      fprintf(stderr, "read_barrier: %p -> stealing %p...", G, (gcptr)v);
-      steal(P);
+      fprintf(stderr, "read_barrier: %p -> stealing %p...", G, P);
+      stm_steal_stub(P);
       goto retry;
     }
 }
@@ -401,6 +369,8 @@
 
 gcptr stm_get_backup_copy(gcptr P)
 {
+  assert(P->h_revision == stm_private_rev_num);
+
   struct tx_public_descriptor *pd = thread_descriptor->public_descriptor;
   long i, size = pd->active_backup_copies.size;
   gcptr *items = pd->active_backup_copies.items;
@@ -735,7 +705,7 @@
 #endif
 }
 
-static pthread_mutex_t mutex_prebuilt_gcroots = PTHREAD_MUTEX_INITIALIZER;
+//static pthread_mutex_t mutex_prebuilt_gcroots = PTHREAD_MUTEX_INITIALIZER;
 
 static void UpdateChainHeads(struct tx_descriptor *d, revision_t cur_time,
                              revision_t localrev)
@@ -763,6 +733,11 @@
 #endif
       L->h_revision = new_revision;
 
+      gcptr stub = stm_stub_malloc(d->public_descriptor);
+      stub->h_tid = GCFLAG_PUBLIC | GCFLAG_STUB;
+      stub->h_revision = (revision_t)L;
+      item->val = stub;
+
     } G2L_LOOP_END;
 
   smp_wmb(); /* a memory barrier: make sure the new L->h_revisions are visible
@@ -779,22 +754,12 @@
       assert(!(R->h_tid & GCFLAG_STOLEN));
       assert(R->h_revision != localrev);
 
-      /* XXX compactify and don't leak! */
-      revision_t *handle_block = stm_malloc(3 * WORD);
-      handle_block = (revision_t *)
-        ((((intptr_t)handle_block) + HANDLE_BLOCK_SIZE-1)
-         & ~(HANDLE_BLOCK_SIZE-1));
-      handle_block[0] = d->public_descriptor_index;
-      handle_block[1] = v;
-
-      revision_t w = ((revision_t)(handle_block + 1)) + 2;
-
 #ifdef DUMP_EXTRA
-      fprintf(stderr, "%p->h_revision = %p (UpdateChainHeads2)\n",
-              R, (gcptr)w);
+      fprintf(stderr, "%p->h_revision = %p (stub to %p)\n",
+              R, (gcptr)v, (gcptr)item->val->h_revision);
       /*mark*/
 #endif
-      ACCESS_ONCE(R->h_revision) = w;
+      ACCESS_ONCE(R->h_revision) = v;
 
 #if 0
       if (R->h_tid & GCFLAG_PREBUILT_ORIGINAL)
diff --git a/c4/et.h b/c4/et.h
--- a/c4/et.h
+++ b/c4/et.h
@@ -13,9 +13,7 @@
 
 #define MAX_THREADS         1024
 #define LOCKED              (INTPTR_MAX - 2*(MAX_THREADS-1))
-
 #define WORD                sizeof(gcptr)
-#define HANDLE_BLOCK_SIZE   (2 * WORD)
 
 /* Description of the flags
  * ------------------------
@@ -52,8 +50,9 @@
  * GCFLAG_STOLEN is set of protected objects after we notice that they
  * have been stolen.
  *
- * GCFLAG_STUB is used for debugging: it's set on stub objects made by
- * stealing or by major collections.
+ * GCFLAG_STUB is set on stub objects made by stealing or by major
+ * collections.  It's removed once the stub's protected h_revision
+ * target is stolen and replaced by a regular public object.
  */
 #define GCFLAG_OLD               (STM_FIRST_GCFLAG << 0)
 #define GCFLAG_VISITED           (STM_FIRST_GCFLAG << 1)
@@ -64,7 +63,7 @@
 #define GCFLAG_WRITE_BARRIER     (STM_FIRST_GCFLAG << 6)
 #define GCFLAG_NURSERY_MOVED     (STM_FIRST_GCFLAG << 7)
 #define GCFLAG_STOLEN            (STM_FIRST_GCFLAG << 8)
-#define GCFLAG_STUB              (STM_FIRST_GCFLAG << 9)   /* debugging */
+#define GCFLAG_STUB              (STM_FIRST_GCFLAG << 9)
 
 /* this value must be reflected in PREBUILT_FLAGS in stmgc.h */
 #define GCFLAG_PREBUILT  (GCFLAG_VISITED           | \
@@ -106,6 +105,8 @@
  * thread shuts down.  It is reused the next time a thread starts. */
 struct tx_public_descriptor {
   revision_t collection_lock;
+  struct stub_block_s *stub_blocks;
+  gcptr stub_free_list;
   struct GcPtrList stolen_objects;
   struct GcPtrList active_backup_copies;
   revision_t free_list_next;
diff --git a/c4/steal.c b/c4/steal.c
new file mode 100644
--- /dev/null
+++ b/c4/steal.c
@@ -0,0 +1,57 @@
+#include "stmimpl.h"
+
+
+#define STUB_PAGE         (4096 - 2*WORD)
+#define STUB_NB_OBJS      ((STUB_BLOCK_SIZE - 2*WORD) /    \
+                             sizeof(struct stm_object_s))
+
+struct stub_block_s {
+    struct tx_public_descriptor *thread;
+    struct stub_block_s *next;
+    struct stm_object_s stubs[STUB_NB_OBJS];
+};
+
+gcptr stm_stub_malloc(struct tx_public_descriptor *pd)
+{
+    gcptr p = pd->stub_free_list;
+    if (p == NULL) {
+        assert(sizeof(struct stub_block_s) == STUB_BLOCK_SIZE);
+
+        char *page = stm_malloc(STUB_PAGE);
+        char *page_end = page + STUB_PAGE;
+        page += (-(revision_t)page) & (STUB_BLOCK_SIZE-1);  /* round up */
+
+        struct stub_block_s *b = (struct stub_block_s *)page;
+        struct stub_block_s *nextb = NULL;
+        gcptr nextp = NULL;
+        int i;
+
+        while (((char *)(b + 1)) <= page_end) {
+            b->thread = pd;
+            b->next = nextb;
+            for (i = 0; i < STUB_NB_OBJS; i++) {
+                b->stubs[i].h_revision = (revision_t)nextp;
+                nextp = &b->stubs[i];
+            }
+            b++;
+        }
+        assert(nextp != NULL);
+        p = nextp;
+    }
+    pd->stub_free_list = (gcptr)p->h_revision;
+    assert(STUB_THREAD(p) == pd);
+    return p;
+}
+
+void stm_steal_stub(gcptr P)
+{
+    abort();
+  struct tx_public_descriptor *foreign_pd;
+  revision_t target_descriptor_index;
+  revision_t v = ACCESS_ONCE(P->h_revision);
+  if ((v & 3) != 2)
+    return;
+  target_descriptor_index = *(revision_t *)(v & ~(STUB_BLOCK_SIZE-1));
+  foreign_pd = stm_descriptor_array[target_descriptor_index];
+  abort();
+}
diff --git a/c4/steal.h b/c4/steal.h
new file mode 100644
--- /dev/null
+++ b/c4/steal.h
@@ -0,0 +1,14 @@
+#ifndef _SRCSTM_STEAL_H
+#define _SRCSTM_STEAL_H
+
+
+#define STUB_BLOCK_SIZE   (16 * WORD)    /* power of two */
+
+#define STUB_THREAD(h)    (*(struct tx_public_descriptor **)           \
+                            (((revision_t)(h)) & ~(STUB_BLOCK_SIZE-1)))
+
+gcptr stm_stub_malloc(struct tx_public_descriptor *);
+void stm_steal_stub(gcptr);
+
+
+#endif
diff --git a/c4/stmimpl.h b/c4/stmimpl.h
--- a/c4/stmimpl.h
+++ b/c4/stmimpl.h
@@ -31,6 +31,7 @@
 #include "lists.h"
 #include "dbgmem.h"
 #include "et.h"
+#include "steal.h"
 #include "stmsync.h"
 
 #endif
diff --git a/c4/test/support.py b/c4/test/support.py
--- a/c4/test/support.py
+++ b/c4/test/support.py
@@ -5,11 +5,11 @@
 parent_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
 
 header_files = [os.path.join(parent_dir, _n) for _n in
-                "et.h lists.h "
+                "et.h lists.h steal.h "
                 "stmsync.h dbgmem.h fprintcolor.h "
                 "stmgc.h stmimpl.h atomic_ops.h".split()]
 source_files = [os.path.join(parent_dir, _n) for _n in
-                "et.c lists.c "
+                "et.c lists.c steal.c "
                 "stmsync.c dbgmem.c fprintcolor.c".split()]
 
 _pycache_ = os.path.join(parent_dir, 'test', '__pycache__')
@@ -70,6 +70,7 @@
     void AbortTransaction(int);
     gcptr stm_get_backup_copy(gcptr);
     gcptr stm_get_read_obj(long index);
+    void *STUB_THREAD(gcptr);
 
     gcptr getptr(gcptr, long);
     void setptr(gcptr, long, gcptr);
@@ -84,7 +85,7 @@
     gcptr pseudoprebuilt(size_t size, int tid);
     revision_t get_private_rev_num(void);
     revision_t get_start_time(void);
-    revision_t get_descriptor_index(void);
+    void *my_stub_thread(void);
 
     //gcptr *addr_of_thread_local(void);
     //int in_nursery(gcptr);
@@ -93,7 +94,7 @@
     /* some constants normally private that are useful in the tests */
     #define WORD                     ...
     #define GC_PAGE_SIZE             ...
-    #define HANDLE_BLOCK_SIZE        ...
+    #define STUB_BLOCK_SIZE          ...
     #define GCFLAG_OLD               ...
     #define GCFLAG_VISITED           ...
     #define GCFLAG_PUBLIC            ...
@@ -206,9 +207,9 @@
         return thread_descriptor->start_time;
     }
 
-    revision_t get_descriptor_index(void)
+    void *my_stub_thread(void)
     {
-        return thread_descriptor->public_descriptor_index;
+        return (void *)thread_descriptor->public_descriptor;
     }
 
     /*gcptr *addr_of_thread_local(void)
@@ -526,10 +527,14 @@
     private = p.h_revision == lib.get_private_rev_num()
     public  = (p.h_tid & GCFLAG_PUBLIC) != 0
     backup  = (p.h_tid & GCFLAG_BACKUP_COPY) != 0
+    stub    = (p.h_tid & GCFLAG_STUB) != 0
     assert private + public + backup <= 1
+    assert stub <= public
     if private:
         return "private"
     if public:
+        if stub:
+            return "stub"
         return "public"
     if backup:
         return "backup"
@@ -547,10 +552,4 @@
         index += 1
     return result
 
-def decode_handle(r):
-    assert (r & 3) == 2
-    p = r & ~(lib.HANDLE_BLOCK_SIZE-1)
-    dindex = ffi.cast("revision_t *", p)[0]
-    assert 0 <= dindex < 20
-    ptr = ffi.cast("gcptr *", r - 2)[0]
-    return ptr, dindex
+stub_thread = lib.STUB_THREAD
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
@@ -80,10 +80,9 @@
     assert p.h_revision == lib.get_private_rev_num()
     lib.stm_commit_transaction()
     lib.stm_begin_inevitable_transaction()
-    assert lib.stm_get_backup_copy(p) == ffi.NULL
     assert classify(p) == "protected"
     assert classify(pback) == "backup"
-    assert ffi.cast("revision_t *", p.h_revision) == pback
+    assert ffi.cast("gcptr", p.h_revision) == pback
 
 def test_protected_backup_reused():
     p = nalloc(HDR + WORD)
@@ -95,7 +94,6 @@
     assert pback != p
     lib.stm_commit_transaction()
     lib.stm_begin_inevitable_transaction()
-    assert lib.stm_get_backup_copy(p) == ffi.NULL
     assert classify(p) == "protected"
     assert classify(pback) == "backup"
     assert lib.rawgetlong(p, 0) == 927122
@@ -138,7 +136,9 @@
     lib.stm_begin_inevitable_transaction()
     assert classify(p) == "public"
     assert classify(p2) == "protected"
-    assert decode_handle(p.h_revision) == (p2, lib.get_descriptor_index())
+    pstub = ffi.cast("gcptr", p.h_revision)
+    assert classify(pstub) == "stub"
+    assert stub_thread(pstub) == lib.my_stub_thread()
     assert lib.rawgetlong(p, 0) == 28971289
     assert lib.rawgetlong(p2, 0) == 1289222
 
@@ -241,7 +241,7 @@
         assert classify(p1) == "protected"
         plist.append(p1)
         # now p's most recent revision is protected
-        assert p.h_revision % 4 == 2    # a handle
+        assert classify(ffi.cast("gcptr", p.h_revision)) == "stub"
         r.set(2)
         r.wait(3)
         assert lib.list_stolen_objects() == plist[-2:]
_______________________________________________
pypy-commit mailing list
pypy-commit@python.org
http://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to