[pypy-commit] pypy stmgc-c8: import stmgc branch 'queue'

arigo noreply at buildbot.pypy.org
Thu Jun 18 18:56:15 CEST 2015


Author: Armin Rigo <arigo at tunes.org>
Branch: stmgc-c8
Changeset: r78188:c12cb756db2e
Date: 2015-06-18 17:52 +0100
http://bitbucket.org/pypy/pypy/changeset/c12cb756db2e/

Log:	import stmgc branch 'queue'

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 @@
-d083e426a17d
+0a10e04f2119
diff --git a/rpython/translator/stm/src_stm/stm/core.c b/rpython/translator/stm/src_stm/stm/core.c
--- a/rpython/translator/stm/src_stm/stm/core.c
+++ b/rpython/translator/stm/src_stm/stm/core.c
@@ -495,6 +495,32 @@
 static void readd_wb_executed_flags(void);
 static void check_all_write_barrier_flags(char *segbase, struct list_s *list);
 
+static void wait_for_inevitable(void)
+{
+    intptr_t detached = 0;
+
+    s_mutex_lock();
+ wait_some_more:
+    if (safe_point_requested()) {
+        /* XXXXXX if the safe point below aborts, in
+           _validate_and_attach(), 'new' leaks */
+        enter_safe_point_if_requested();
+    }
+    else if (STM_PSEGMENT->last_commit_log_entry->next == INEV_RUNNING) {
+        /* loop until C_SEGMENT_FREE_OR_SAFE_POINT_REQ is signalled, but
+           try to detach an inevitable transaction regularly */
+        detached = fetch_detached_transaction();
+        if (detached == 0) {
+            if (!cond_wait_timeout(C_SEGMENT_FREE_OR_SAFE_POINT_REQ, 0.00001))
+                goto wait_some_more;
+        }
+    }
+    s_mutex_unlock();
+
+    if (detached != 0)
+        commit_fetched_detached_transaction(detached);
+}
+
 /* This is called to do stm_validate() and then attach 'new' at the
    head of the 'commit_log_root' chained list.  This function sleeps
    and retries until it succeeds or aborts.
@@ -523,24 +549,10 @@
 #endif
 
     if (STM_PSEGMENT->last_commit_log_entry->next == INEV_RUNNING) {
-        s_mutex_lock();
-        if (safe_point_requested()) {
-            /* XXXXXX if the safe point below aborts, 'new' leaks */
-            enter_safe_point_if_requested();
-        }
-        else if (STM_PSEGMENT->last_commit_log_entry->next == INEV_RUNNING) {
-            cond_wait(C_SEGMENT_FREE_OR_SAFE_POINT);
-        }
-        s_mutex_unlock();
+        wait_for_inevitable();
         goto retry_from_start;   /* redo _stm_validate() now */
     }
 
-    intptr_t detached = fetch_detached_transaction();
-    if (detached != 0) {
-        commit_fetched_detached_transaction(detached);
-        goto retry_from_start;
-    }
-
     /* we must not remove the WB_EXECUTED flags before validation as
        it is part of a condition in import_objects() called by
        copy_bk_objs_in_page_from to not overwrite our modifications.
@@ -1119,7 +1131,7 @@
 {
     assert(!_stm_in_transaction(tl));
 
-    while (!acquire_thread_segment(tl)) {}
+    acquire_thread_segment(tl);
     /* GS invalid before this point! */
 
     assert(STM_PSEGMENT->safe_point == SP_NO_TRANSACTION);
@@ -1571,13 +1583,33 @@
             timing_become_inevitable(); /* for tests: another transaction */
             stm_abort_transaction();    /* is already inevitable, abort   */
 #endif
+
+            bool timed_out = false;
+
             s_mutex_lock();
             if (any_soon_finished_or_inevitable_thread_segment() &&
                     !safe_point_requested()) {
-                cond_wait(C_SEGMENT_FREE_OR_SAFE_POINT);
+
+                /* wait until C_SEGMENT_FREE_OR_SAFE_POINT_REQ is signalled */
+                if (!cond_wait_timeout(C_SEGMENT_FREE_OR_SAFE_POINT_REQ,
+                                       0.000054321))
+                    timed_out = true;
             }
             s_mutex_unlock();
-            num_waits++;
+
+            if (timed_out) {
+                /* try to detach another inevitable transaction, but
+                   only after waiting a bit.  This is necessary to avoid
+                   deadlocks in some situations, which are hopefully
+                   not too common.  We don't want two threads constantly
+                   detaching each other. */
+                intptr_t detached = fetch_detached_transaction();
+                if (detached != 0)
+                    commit_fetched_detached_transaction(detached);
+            }
+            else {
+                num_waits++;
+            }
             goto retry_from_start;
         }
         if (!_validate_and_turn_inevitable())
diff --git a/rpython/translator/stm/src_stm/stm/sync.c b/rpython/translator/stm/src_stm/stm/sync.c
--- a/rpython/translator/stm/src_stm/stm/sync.c
+++ b/rpython/translator/stm/src_stm/stm/sync.c
@@ -203,10 +203,11 @@
 #endif
 
 
-static bool acquire_thread_segment(stm_thread_local_t *tl)
+static void acquire_thread_segment(stm_thread_local_t *tl)
 {
     /* This function acquires a segment for the currently running thread,
        and set up the GS register if it changed. */
+ retry_from_start:
     assert(_has_mutex());
     assert(_is_tl_registered(tl));
 
@@ -240,13 +241,13 @@
         }
     }
     /* No segment available.  Wait until release_thread_segment()
-       signals that one segment has been freed. */
+       signals that one segment has been freed.  Note that we prefer
+       waiting rather than detaching an inevitable transaction, here. */
     timing_event(tl, STM_WAIT_FREE_SEGMENT);
     cond_wait(C_SEGMENT_FREE);
     timing_event(tl, STM_WAIT_DONE);
 
-    /* Return false to the caller, which will call us again */
-    return false;
+    goto retry_from_start;
 
  got_num:
     OPT_ASSERT(num >= 0 && num < NB_SEGMENTS-1);
@@ -257,7 +258,6 @@
     assert(!in_transaction(tl));
     STM_SEGMENT->running_thread = tl;
     assert(in_transaction(tl));
-    return true;
 }
 
 static void release_thread_segment(stm_thread_local_t *tl)
@@ -266,7 +266,7 @@
     assert(_has_mutex());
 
     cond_signal(C_SEGMENT_FREE);
-    cond_broadcast(C_SEGMENT_FREE_OR_SAFE_POINT);   /* often no listener */
+    cond_broadcast(C_SEGMENT_FREE_OR_SAFE_POINT_REQ);  /* often no listener */
 
     assert(STM_SEGMENT->running_thread == tl);
     segnum = STM_SEGMENT->segment_num;
@@ -362,7 +362,7 @@
     assert(!pause_signalled);
     pause_signalled = true;
     dprintf(("request to pause\n"));
-    cond_broadcast(C_SEGMENT_FREE_OR_SAFE_POINT);
+    cond_broadcast(C_SEGMENT_FREE_OR_SAFE_POINT_REQ);
 }
 
 static inline long count_other_threads_sp_running(void)
diff --git a/rpython/translator/stm/src_stm/stm/sync.h b/rpython/translator/stm/src_stm/stm/sync.h
--- a/rpython/translator/stm/src_stm/stm/sync.h
+++ b/rpython/translator/stm/src_stm/stm/sync.h
@@ -5,7 +5,7 @@
     C_AT_SAFE_POINT,
     C_REQUEST_REMOVED,
     C_SEGMENT_FREE,
-    C_SEGMENT_FREE_OR_SAFE_POINT,
+    C_SEGMENT_FREE_OR_SAFE_POINT_REQ,
     C_QUEUE_OLD_ENTRIES,
     C_QUEUE_FINISHED_MORE_TASKS,
     _C_TOTAL
@@ -25,7 +25,7 @@
 
 /* acquire and release one of the segments for running the given thread
    (must have the mutex acquired!) */
-static bool acquire_thread_segment(stm_thread_local_t *tl);
+static void acquire_thread_segment(stm_thread_local_t *tl);
 static void release_thread_segment(stm_thread_local_t *tl);
 static void soon_finished_or_inevitable_thread_segment(void);
 static bool any_soon_finished_or_inevitable_thread_segment(void);


More information about the pypy-commit mailing list