[pypy-commit] pypy stmgc-c4: Import stmgc/59eb9a85c3d1.

arigo noreply at buildbot.pypy.org
Sun Jun 30 19:58:32 CEST 2013


Author: Armin Rigo <arigo at tunes.org>
Branch: stmgc-c4
Changeset: r65124:674cdae07936
Date: 2013-06-30 19:49 +0200
http://bitbucket.org/pypy/pypy/changeset/674cdae07936/

Log:	Import stmgc/59eb9a85c3d1.

diff --git a/rpython/translator/stm/src_stm/et.c b/rpython/translator/stm/src_stm/et.c
--- a/rpython/translator/stm/src_stm/et.c
+++ b/rpython/translator/stm/src_stm/et.c
@@ -87,6 +87,8 @@
   gcptr P = G;
   revision_t v;
 
+  d->count_reads++;
+
  restart_all:
   if (P->h_tid & GCFLAG_PRIVATE_FROM_PROTECTED)
     {
@@ -902,6 +904,15 @@
   d->reads_size_limit = d->atomic ? ULONG_MAX : d->reads_size_limit_nonatomic;
 }
 
+long stm_atomic(long delta)
+{
+  struct tx_descriptor *d = thread_descriptor;
+  d->atomic += delta;
+  assert(d->atomic >= 0);
+  update_reads_size_limit(d);
+  return d->atomic;
+}
+
 static void init_transaction(struct tx_descriptor *d)
 {
   assert(d->active == 0);
diff --git a/rpython/translator/stm/src_stm/gcpage.c b/rpython/translator/stm/src_stm/gcpage.c
--- a/rpython/translator/stm/src_stm/gcpage.c
+++ b/rpython/translator/stm/src_stm/gcpage.c
@@ -321,13 +321,20 @@
 
 static void mark_roots(gcptr *root, gcptr *end)
 {
-    //assert(*root == END_MARKER);
-    //root++;
+    assert(*root == END_MARKER_ON);
+    root++;
+
     while (root != end) {
-        gcptr o = *root;
-        visit(root);
-        dprintf(("visit stack root: %p -> %p\n", o, *root));
-        (void)o;   /* silence "warning: unused variable 'o'" */
+        gcptr item = *root;
+        if (((revision_t)item) & ~((revision_t)END_MARKER_OFF |
+                                   (revision_t)END_MARKER_ON)) {
+            /* 'item' is a regular, non-null pointer */
+            visit(root);
+            dprintf(("visit stack root: %p -> %p\n", item, *root));
+        }
+        else if (item == END_MARKER_OFF) {
+            *root = END_MARKER_ON;
+        }
         root++;
     }
 }
diff --git a/rpython/translator/stm/src_stm/nursery.c b/rpython/translator/stm/src_stm/nursery.c
--- a/rpython/translator/stm/src_stm/nursery.c
+++ b/rpython/translator/stm/src_stm/nursery.c
@@ -324,12 +324,30 @@
 
 static void mark_young_roots(struct tx_descriptor *d)
 {
-    gcptr *root = d->shadowstack;
+    /* we walk the shadowstack from the end, replacing any END_MARKER_OFF
+       found with END_MARKER_ON.  When we reach an END_MARKER_ON, we know
+       that we have already seen the rest of the stack in the previous
+       nursery collection, so we stop.
+    */
     gcptr *end = *d->shadowstack_end_ref;
 
-    /* XXX use a way to avoid walking all roots again and again */
-    for (; root != end; root++) {
-        visit_if_young(root);
+    while (1) {
+        assert(end > d->shadowstack);
+        gcptr item = *--end;
+
+        if (((revision_t)item) & ~((revision_t)END_MARKER_OFF |
+                                   (revision_t)END_MARKER_ON)) {
+            /* 'item' is a regular, non-null pointer */
+            visit_if_young(end);
+        }
+        else if (item != NULL) {
+            if (item == END_MARKER_OFF)
+                *end = END_MARKER_ON;
+            else {
+                assert(item == END_MARKER_ON);
+                break;
+            }
+        }
     }
 }
 
diff --git a/rpython/translator/stm/src_stm/nursery.h b/rpython/translator/stm/src_stm/nursery.h
--- a/rpython/translator/stm/src_stm/nursery.h
+++ b/rpython/translator/stm/src_stm/nursery.h
@@ -19,6 +19,9 @@
 # error "GC_NURSERY must be a multiple of GC_NURSERY_SECTION"
 #endif
 
+#define END_MARKER_OFF  ((gcptr) 16)
+#define END_MARKER_ON   ((gcptr) 24)
+
 
 #define NURSERY_FIELDS_DECL                                             \
     /* the nursery */                                                   \
diff --git a/rpython/translator/stm/src_stm/revision b/rpython/translator/stm/src_stm/revision
--- a/rpython/translator/stm/src_stm/revision
+++ b/rpython/translator/stm/src_stm/revision
@@ -1,1 +1,1 @@
-1ba74b051c7b
+59eb9a85c3d1
diff --git a/rpython/translator/stm/src_stm/stmgc.h b/rpython/translator/stm/src_stm/stmgc.h
--- a/rpython/translator/stm/src_stm/stmgc.h
+++ b/rpython/translator/stm/src_stm/stmgc.h
@@ -58,7 +58,8 @@
 /* start a new transaction, calls callback(), and when it returns
    finish that transaction.  callback() is called with the 'arg'
    provided, and with a retry_counter number.  Must save roots around
-   this call. */
+   this call.  The callback() is called repeatedly as long as it
+   returns a value > 0. */
 void stm_perform_transaction(gcptr arg, int (*callback)(gcptr, int));
 
 /* finish the current transaction, start a new one, or turn the current
@@ -71,8 +72,18 @@
 /* debugging: check if we're currently running a transaction or not. */
 int stm_in_transaction(void);
 
-/* change the default transaction length */
+/* change the default transaction length, and ask if now would be a good
+   time to break the transaction (by returning from the 'callback' above
+   with a positive value). */
 void stm_set_transaction_length(long length_max);
+_Bool stm_should_break_transaction(void);
+
+/* change the atomic counter by 'delta' and return the new value.  Used
+   with +1 to enter or with -1 to leave atomic mode, or with 0 to just
+   know the current value of the counter.  The current transaction is
+   *never* interrupted as long as this counter is positive. */
+long stm_atomic(long delta);
+
 
 /* callback: get the size of an object */
 extern size_t stmcb_size(gcptr);
diff --git a/rpython/translator/stm/src_stm/stmsync.c b/rpython/translator/stm/src_stm/stmsync.c
--- a/rpython/translator/stm/src_stm/stmsync.c
+++ b/rpython/translator/stm/src_stm/stmsync.c
@@ -7,6 +7,7 @@
 
 __thread gcptr *stm_shadowstack;
 static unsigned long stm_regular_length_limit = 10000;
+static revision_t sync_required = 0;
 
 void stm_set_transaction_length(long length_max)
 {
@@ -17,6 +18,38 @@
     stm_regular_length_limit = length_max;
 }
 
+_Bool stm_should_break_transaction(void)
+{
+    struct tx_descriptor *d = thread_descriptor;
+
+    /* a single comparison to handle all cases:
+
+     - first, if sync_required == -1, this should return True.
+
+     - if d->atomic, then we should return False.  This is done by
+       forcing reads_size_limit to ULONG_MAX as soon as atomic > 0.
+
+     - otherwise, if is_inevitable(), then we should return True.
+       This is done by forcing both reads_size_limit and
+       reads_size_limit_nonatomic to 0 in that case.
+
+     - finally, the default case: return True if d->count_reads is
+       greater than reads_size_limit == reads_size_limit_nonatomic.
+    */
+#ifdef _GC_DEBUG
+    /* reads_size_limit is ULONG_MAX if d->atomic, or else it is equal to
+       reads_size_limit_nonatomic. */
+    assert(d->reads_size_limit == (d->atomic ? ULONG_MAX :
+                                   d->reads_size_limit_nonatomic));
+    /* if is_inevitable(), reads_size_limit_nonatomic should be 0
+       (and thus reads_size_limit too, if !d->atomic.) */
+    if (d->active == 2)
+        assert(d->reads_size_limit_nonatomic == 0);
+#endif
+
+    return (sync_required | d->count_reads) >= d->reads_size_limit;
+}
+
 static void init_shadowstack(void)
 {
     struct tx_descriptor *d = thread_descriptor;
@@ -26,14 +59,14 @@
     }
     stm_shadowstack = d->shadowstack;
     d->shadowstack_end_ref = &stm_shadowstack;
-    //stm_push_root(END_MARKER);
+    stm_push_root(END_MARKER_ON);
 }
 
 static void done_shadowstack(void)
 {
     struct tx_descriptor *d = thread_descriptor;
-    //gcptr x = stm_pop_root();
-    //assert(x == END_MARKER);
+    gcptr x = stm_pop_root();
+    assert(x == END_MARKER_ON);
     assert(stm_shadowstack == d->shadowstack);
     stm_shadowstack = NULL;
     free(d->shadowstack);
@@ -68,8 +101,6 @@
 
 /************************************************************/
 
-static revision_t sync_required = 0;
-
 void stm_perform_transaction(gcptr arg, int (*callback)(gcptr, int))
 {   /* must save roots around this call */
     jmp_buf _jmpbuf;
@@ -78,6 +109,7 @@
     long volatile v_atomic;
 
     stm_push_root(arg);
+    stm_push_root(END_MARKER_OFF);
 
     if (!(v_atomic = thread_descriptor->atomic))
         CommitTransaction();
@@ -99,14 +131,7 @@
     long counter, result;
     counter = v_counter;
     d->atomic = v_atomic;
-    stm_shadowstack = v_saved_value + 1;    /* skip the 'arg', pushed above */
-    //    if (!d->atomic) {
-    //        /* In non-atomic mode, we are now between two transactions.
-    //           It means that in the next transaction's collections we know
-    //           that we won't need to access the shadow stack beyond its
-    //           current position.  So we add an end marker. */
-    //        stm_push_root(END_MARKER);
-    //    }
+    stm_shadowstack = v_saved_value + 2;   /*skip the two values pushed above*/
 
     do {
         v_counter = counter + 1;
@@ -136,7 +161,7 @@
         /* invoke the callback in the new transaction */
         arg = v_saved_value[0];
         result = callback(arg, counter);
-        assert(stm_shadowstack == v_saved_value + 1);
+        assert(stm_shadowstack == v_saved_value + 2);
 
         v_atomic = d->atomic;
         if (!d->atomic)
@@ -155,7 +180,9 @@
         BeginInevitableTransaction();
     }
 
-    stm_pop_root();      /* pop the 'arg' */
+    gcptr x = stm_pop_root();   /* pop the END_MARKER */
+    assert(x == END_MARKER_OFF || x == END_MARKER_ON);
+    stm_pop_root();             /* pop the 'arg' */
     assert(stm_shadowstack == v_saved_value);
 }
 
@@ -240,7 +267,7 @@
        which prevents any other thread from running in a transaction.
        Warning, may block waiting for rwlock_in_transaction while another
        thread runs a major GC itself! */
-    ACCESS_ONCE(sync_required) = 1;
+    ACCESS_ONCE(sync_required) = -1;
     stm_stop_sharedlock();
     start_exclusivelock();
     ACCESS_ONCE(sync_required) = 0;


More information about the pypy-commit mailing list