[pypy-commit] stmgc default: More tweaks

arigo noreply at buildbot.pypy.org
Fri Feb 28 21:47:24 CET 2014


Author: Armin Rigo <arigo at tunes.org>
Branch: 
Changeset: r904:032926d523bb
Date: 2014-02-28 21:47 +0100
http://bitbucket.org/pypy/stmgc/changeset/032926d523bb/

Log:	More tweaks

diff --git a/c7/stm/core.c b/c7/stm/core.c
--- a/c7/stm/core.c
+++ b/c7/stm/core.c
@@ -323,11 +323,6 @@
 
 static void _finish_transaction(void)
 {
-    /* signal all the threads blocked in wait_for_other_safe_points() */
-    if (STM_SEGMENT->nursery_end == NSE_SIGNAL) {
-        STM_SEGMENT->nursery_end = NURSERY_END;
-    }
-
     STM_PSEGMENT->safe_point = SP_NO_TRANSACTION;
     STM_PSEGMENT->transaction_state = TS_NONE;
 
@@ -355,10 +350,18 @@
     minor_collection(/*commit=*/ true);
 
     mutex_lock();
+
+ retry:
+    if (STM_SEGMENT->nursery_end != NURSERY_END)
+        collectable_safe_point();
+
     STM_PSEGMENT->safe_point = SP_SAFE_POINT;
 
     /* wait until the other thread is at a safe-point */
-    wait_for_other_safe_points();
+    if (!try_wait_for_other_safe_points()) {
+        STM_PSEGMENT->safe_point = SP_RUNNING;
+        goto retry;
+    }
 
     /* the rest of this function either runs atomically without
        releasing the mutex, or aborts the current thread. */
@@ -369,6 +372,7 @@
     /* cannot abort any more from here */
     dprintf(("commit_transaction\n"));
 
+    assert(STM_SEGMENT->nursery_end == NURSERY_END);
     assert(STM_PSEGMENT->transaction_state != TS_MUST_ABORT);
     STM_SEGMENT->jmpbuf_ptr = NULL;
 
@@ -392,6 +396,8 @@
     /* done */
     _finish_transaction();
 
+    assert(STM_SEGMENT->nursery_end == NURSERY_END);
+
     mutex_unlock();
 }
 
@@ -473,6 +479,8 @@
 
     _finish_transaction();
 
+    STM_SEGMENT->nursery_end = NURSERY_END;
+
     mutex_unlock();
 
     /* It seems to be a good idea, at least in some examples, to sleep
diff --git a/c7/stm/sync.c b/c7/stm/sync.c
--- a/c7/stm/sync.c
+++ b/c7/stm/sync.c
@@ -3,13 +3,24 @@
 #include <asm/prctl.h>
 
 
-/* XXX Getting the most efficient locks is hard, but the following
-   simplification is probably good enough for small numbers of threads:
-   when a thread wants to check or change any global state (e.g. start
-   running a transaction, etc.), it acquires this single mutex.  If
-   additionally it wants to wait until the global state is changed by
-   someone else, it waits on the condition variable.  This should be
-   all we need for synchronization.
+/* Each segment can be in one of three possible states, described by
+   the segment variable 'safe_point':
+
+   - SP_NO_TRANSACTION: no thread is running any transaction using this
+     segment.
+
+   - SP_RUNNING: a thread is running a transaction using this segment.
+
+   - SP_SAFE_POINT: the thread that owns this segment is currently
+     suspended in a safe-point.  (A safe-point means that it is not
+     changing anything right now, and the current shadowstack is correct.)
+
+   Synchronization is done with a single mutex / condition variable.  A
+   thread needs to have acquired the mutex in order to do things like
+   acquiring or releasing ownership of a segment or updating this
+   segment's state.  No other thread can acquire the mutex concurrently,
+   and so there is no race: the (single) thread owning the mutex can
+   freely inspect or even change the state of other segments too.
 */
 
 
@@ -268,8 +279,7 @@
         struct stm_priv_segment_info_s *other_pseg = get_priv_segment(i);
         if (other_pseg->safe_point == SP_RUNNING) {
             /* we need to wait for this thread.  Use NSE_SIGNAL to ask
-               it (and possibly all other threads in the same case) to
-               enter a safe-point soon. */
+               it to enter a safe-point soon. */
             other_pseg->pub.nursery_end = NSE_SIGNAL;
             wait = true;
         }
@@ -292,13 +302,6 @@
     return true;
 }
 
-static void wait_for_other_safe_points(void)
-{
-    while (!try_wait_for_other_safe_points()) {
-        /* loop */
-    }
-}
-
 void _stm_collectable_safe_point(void)
 {
     /* If _stm_nursery_end was set to NSE_SIGNAL by another thread,
@@ -315,6 +318,7 @@
 
 static void collectable_safe_point(void)
 {
+    assert(_has_mutex());
     assert(STM_PSEGMENT->safe_point == SP_RUNNING);
 
     while (STM_SEGMENT->nursery_end == NSE_SIGNAL) {
@@ -330,5 +334,6 @@
 
         STM_PSEGMENT->safe_point = SP_RUNNING;
     }
+    assert(STM_SEGMENT->nursery_end == NURSERY_END);
     dprintf(("collectable_safe_point done\n"));
 }
diff --git a/c7/stm/sync.h b/c7/stm/sync.h
--- a/c7/stm/sync.h
+++ b/c7/stm/sync.h
@@ -20,6 +20,5 @@
 static void wait_for_end_of_inevitable_transaction(bool can_abort);
 
 /* see the source for an exact description */
-static void wait_for_other_safe_points(void);
 static bool try_wait_for_other_safe_points(void);
 static void collectable_safe_point(void);


More information about the pypy-commit mailing list