Author: Armin Rigo <[email protected]>
Branch: 
Changeset: r323:d97c6375a312
Date: 2013-06-30 19:36 +0200
http://bitbucket.org/pypy/stmgc/changeset/d97c6375a312/

Log:    Tests for should_break_transaction() and set_transaction_length().

diff --git a/c4/et.c b/c4/et.c
--- a/c4/et.c
+++ b/c4/et.c
@@ -86,6 +86,8 @@
   gcptr P = G;
   revision_t v;
 
+  d->count_reads++;
+
  restart_all:
   if (P->h_tid & GCFLAG_PRIVATE_FROM_PROTECTED)
     {
@@ -213,7 +215,6 @@
   /* The risks are that the following assert fails, because the flag was
      added just now by a parallel thread during stealing... */
   /*assert(!(P->h_tid & GCFLAG_NURSERY_MOVED));*/
-  d->count_reads++;
   fxcache_add(&d->recent_reads_cache, P);
   return P;
 
@@ -601,7 +602,6 @@
       record_write_barrier(W);
     }
 
-  d->count_reads++;
   spinlock_release(d->public_descriptor->collection_lock);
 
   dprintf(("write_barrier: %p -> %p -> %p\n", P, R, W));
diff --git a/c4/stmgc.h b/c4/stmgc.h
--- a/c4/stmgc.h
+++ b/c4/stmgc.h
@@ -57,7 +57,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
@@ -70,8 +71,11 @@
 /* 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);
 
 /* callback: get the size of an object */
 extern size_t stmcb_size(gcptr);
diff --git a/c4/stmsync.c b/c4/stmsync.c
--- a/c4/stmsync.c
+++ b/c4/stmsync.c
@@ -6,6 +6,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)
 {
@@ -16,6 +17,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;
@@ -67,8 +100,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;
@@ -235,7 +266,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;
diff --git a/c4/test/support.py b/c4/test/support.py
--- a/c4/test/support.py
+++ b/c4/test/support.py
@@ -61,6 +61,7 @@
     void stm_commit_transaction(void);
     void stm_begin_inevitable_transaction(void);
     void stm_set_transaction_length(long length_max);
+    _Bool stm_should_break_transaction(void);
 
     /* extra non-public code */
     void printfcolor(char *msg);
@@ -665,5 +666,7 @@
     assert (r % 4) == 0
     return ffi.cast("gcptr", r)
 
+should_break_transaction = lib.stm_should_break_transaction
+
     
 nrb_protected = ffi.cast("gcptr", -1)
diff --git a/c4/test/test_atomic.py b/c4/test/test_atomic.py
new file mode 100644
--- /dev/null
+++ b/c4/test/test_atomic.py
@@ -0,0 +1,33 @@
+import py
+from support import *
+
+
+def setup_function(f):
+    lib.stm_clear_between_tests()
+    lib.stm_initialize_tests(getattr(f, 'max_aborts', 0))
+
+def teardown_function(_):
+    lib.stm_finalize()
+
+
+def test_should_break_transaction():
+    # we're inevitable here, so:
+    assert should_break_transaction() == True
+    #
+    @perform_transaction
+    def run(retry_counter):
+        assert should_break_transaction() == False
+
+def test_set_transaction_length():
+    lib.stm_set_transaction_length(5)    # breaks after 4 read-or-writes
+    plist = [palloc(HDR) for i in range(6)]
+    should_br = ['?'] * (len(plist) + 1)
+    #
+    @perform_transaction
+    def run(retry_counter):
+        should_br[0] = should_break_transaction()
+        for i in range(len(plist)):
+            lib.stm_write_barrier(plist[i])
+            should_br[i + 1] = should_break_transaction()
+    #
+    assert should_br == [False, False, False, False, True, True, True]
_______________________________________________
pypy-commit mailing list
[email protected]
http://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to