Author: Armin Rigo <[email protected]>
Branch: 
Changeset: r1082:a5f0a9669efe
Date: 2014-03-22 19:59 +0100
http://bitbucket.org/pypy/stmgc/changeset/a5f0a9669efe/

Log:    stm_become_globally_unique_transaction()

diff --git a/c7/stm/core.c b/c7/stm/core.c
--- a/c7/stm/core.c
+++ b/c7/stm/core.c
@@ -461,7 +461,7 @@
     /* force all other threads to be paused.  They will unpause
        automatically when we are done here, i.e. at mutex_unlock().
        Important: we should not call cond_wait() in the meantime. */
-    synchronize_all_threads();
+    synchronize_all_threads(STOP_OTHERS_UNTIL_MUTEX_UNLOCK);
 
     /* detect conflicts */
     if (detect_write_read_conflicts())
@@ -500,6 +500,8 @@
     if (STM_PSEGMENT->transaction_state == TS_INEVITABLE) {
         /* wake up one thread in wait_for_end_of_inevitable_transaction() */
         cond_signal(C_INEVITABLE);
+        if (globally_unique_transaction)
+            committed_globally_unique_transaction();
     }
 
     /* done */
@@ -672,3 +674,12 @@
 
     s_mutex_unlock();
 }
+
+void stm_become_globally_unique_transaction(const char *msg)
+{
+    stm_become_inevitable(msg);   /* may still abort */
+
+    s_mutex_lock();
+    synchronize_all_threads(STOP_OTHERS_AND_BECOME_GLOBALLY_UNIQUE);
+    s_mutex_unlock();
+}
diff --git a/c7/stm/forksupport.c b/c7/stm/forksupport.c
--- a/c7/stm/forksupport.c
+++ b/c7/stm/forksupport.c
@@ -68,7 +68,7 @@
     }
 
     s_mutex_lock();
-    synchronize_all_threads();
+    synchronize_all_threads(STOP_OTHERS_UNTIL_MUTEX_UNLOCK);
     mutex_pages_lock();
 
     /* Make a new mmap at some other address, but of the same size as
diff --git a/c7/stm/gcpage.c b/c7/stm/gcpage.c
--- a/c7/stm/gcpage.c
+++ b/c7/stm/gcpage.c
@@ -134,7 +134,7 @@
 
     if (is_major_collection_requested()) {   /* if still true */
 
-        synchronize_all_threads();
+        synchronize_all_threads(STOP_OTHERS_UNTIL_MUTEX_UNLOCK);
 
         if (is_major_collection_requested()) {   /* if *still* true */
             major_collection_now_at_safe_point();
diff --git a/c7/stm/sync.c b/c7/stm/sync.c
--- a/c7/stm/sync.c
+++ b/c7/stm/sync.c
@@ -319,7 +319,9 @@
 
         /* If we are requested to enter a safe-point, we cannot proceed now.
            Wait until the safe-point request is removed for us. */
-
+#ifdef STM_TESTS
+        abort_with_mutex();
+#endif
         cond_signal(C_AT_SAFE_POINT);
         STM_PSEGMENT->safe_point = SP_WAIT_FOR_C_REQUEST_REMOVED;
         cond_wait(C_REQUEST_REMOVED);
@@ -327,7 +329,7 @@
     }
 }
 
-static void synchronize_all_threads(void)
+static void synchronize_all_threads(enum sync_type_e sync_type)
 {
     enter_safe_point_if_requested();
 
@@ -335,7 +337,13 @@
        why: if several threads call this function, the first one that
        goes past this point will set the "request safe point" on all
        other threads; then none of the other threads will go past the
-       enter_safe_point_if_requested() above. */
+       enter_safe_point_if_requested() above.
+    */
+    if (UNLIKELY(globally_unique_transaction)) {
+        assert(count_other_threads_sp_running() == 0);
+        return;
+    }
+
     signal_everybody_to_pause_running();
 
     /* If some other threads are SP_RUNNING, we cannot proceed now.
@@ -352,6 +360,13 @@
         }
     }
 
+    if (UNLIKELY(sync_type == STOP_OTHERS_AND_BECOME_GLOBALLY_UNIQUE)) {
+        globally_unique_transaction = true;
+        assert(STM_SEGMENT->nursery_end == NSE_SIGPAUSE);
+        STM_SEGMENT->nursery_end = NURSERY_END;
+        return;  /* don't remove the requests for safe-points in this case */
+    }
+
     /* Remove the requests for safe-points now.  In principle we should
        remove it later, when the caller is done, but this is equivalent
        as long as we hold the mutex.
@@ -359,6 +374,15 @@
     remove_requests_for_safe_point();    /* => C_REQUEST_REMOVED */
 }
 
+static void committed_globally_unique_transaction(void)
+{
+    assert(globally_unique_transaction);
+    assert(STM_SEGMENT->nursery_end == NURSERY_END);
+    STM_SEGMENT->nursery_end = NSE_SIGPAUSE;
+    globally_unique_transaction = false;
+    remove_requests_for_safe_point();
+}
+
 void _stm_collectable_safe_point(void)
 {
     /* If 'nursery_end' was set to NSE_SIGxxx by another thread,
diff --git a/c7/stm/sync.h b/c7/stm/sync.h
--- a/c7/stm/sync.h
+++ b/c7/stm/sync.h
@@ -29,6 +29,12 @@
 static void release_thread_segment(stm_thread_local_t *tl);
 
 static void wait_for_end_of_inevitable_transaction(bool can_abort);
-static void synchronize_all_threads(void);
 
-static bool pause_signalled;
+enum sync_type_e {
+    STOP_OTHERS_UNTIL_MUTEX_UNLOCK,
+    STOP_OTHERS_AND_BECOME_GLOBALLY_UNIQUE,
+};
+static void synchronize_all_threads(enum sync_type_e sync_type);
+static void committed_globally_unique_transaction(void);
+
+static bool pause_signalled, globally_unique_transaction;
diff --git a/c7/stmgc.h b/c7/stmgc.h
--- a/c7/stmgc.h
+++ b/c7/stmgc.h
@@ -325,6 +325,14 @@
 void stm_call_on_abort(stm_thread_local_t *, void *key, void callback(void *));
 
 
+/* Similar to stm_become_inevitable(), but additionally suspend all
+   other threads.  A very heavy-handed way to make sure that no other
+   transaction is running concurrently.  Avoid as much as possible.
+   Other transactions will continue running only after this transaction
+   commits. */
+void stm_become_globally_unique_transaction(const char *msg);
+
+
 /* ==================== END ==================== */
 
 #endif
diff --git a/c7/test/support.py b/c7/test/support.py
--- a/c7/test/support.py
+++ b/c7/test/support.py
@@ -54,6 +54,7 @@
 bool _check_commit_transaction(void);
 bool _check_abort_transaction(void);
 bool _check_become_inevitable(void);
+bool _check_become_globally_unique_transaction(void);
 int stm_is_inevitable(void);
 
 void _set_type_id(object_t *obj, uint32_t h);
@@ -161,6 +162,10 @@
     CHECKED(stm_become_inevitable("TEST"));
 }
 
+bool _check_become_globally_unique_transaction() {
+    CHECKED(stm_become_globally_unique_transaction("TESTGUT"));
+}
+
 #undef CHECKED
 
 
@@ -357,6 +362,10 @@
     if lib._check_become_inevitable():
         raise Conflict()
 
+def stm_become_globally_unique_transaction():
+    if lib._check_become_globally_unique_transaction():
+        raise Conflict()
+
 def stm_minor_collect():
     lib.stm_collect(0)
 
@@ -412,6 +421,10 @@
         self.current_thread = 0
 
     def teardown_method(self, meth):
+        tl = self.tls[self.current_thread]
+        if lib._stm_in_transaction(tl) and lib.stm_is_inevitable():
+            self.commit_transaction()      # must succeed!
+        #
         for n, tl in enumerate(self.tls):
             if lib._stm_in_transaction(tl):
                 if self.current_thread != n:
@@ -420,6 +433,7 @@
                     self.commit_transaction()   # must succeed!
                 else:
                     self.abort_transaction()
+        #
         for tl in self.tls:
             lib.stm_unregister_thread_local(tl)
         lib.stm_teardown()
diff --git a/c7/test/test_extra.py b/c7/test/test_extra.py
--- a/c7/test/test_extra.py
+++ b/c7/test/test_extra.py
@@ -80,3 +80,13 @@
         self.start_transaction()
         self.abort_transaction()
         assert seen == []
+
+    def test_stm_become_globally_unique_transaction(self):
+        self.start_transaction()
+        #
+        self.switch(1)
+        self.start_transaction()
+        lib._check_become_globally_unique_transaction()
+        assert lib.stm_is_inevitable()
+        #
+        py.test.raises(Conflict, self.switch, 0)
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to