[pypy-commit] stmgc c7-refactor: Progress

arigo noreply at buildbot.pypy.org
Sat Feb 15 23:42:09 CET 2014


Author: Armin Rigo <arigo at tunes.org>
Branch: c7-refactor
Changeset: r743:8201455ea6be
Date: 2014-02-15 23:41 +0100
http://bitbucket.org/pypy/stmgc/changeset/8201455ea6be/

Log:	Progress

diff --git a/c7/stm/contention.c b/c7/stm/contention.c
--- a/c7/stm/contention.c
+++ b/c7/stm/contention.c
@@ -3,7 +3,7 @@
 #endif
 
 
-static void contention_management(uint8_t other_segment_num)
+static void contention_management(uint8_t other_segment_num, bool wait)
 {
     /* A simple contention manager.  Called when we do stm_write()
        on an object, but some other thread already holds the write
@@ -16,12 +16,6 @@
     struct stm_priv_segment_info_s* other_pseg;
     other_pseg = get_priv_segment(other_segment_num);
 
-    /* note: other_pseg is currently running a transaction, and it cannot
-       commit or abort unexpectedly, because to do that it would need to
-       suspend us.  So the reading of other_pseg->start_time and
-       other_pseg->transaction_state is stable, with one exception: the
-       'transaction_state' can go from TS_REGULAR to TS_INEVITABLE under
-       our feet. */
     if (STM_PSEGMENT->transaction_state == TS_INEVITABLE) {
         /* I'm inevitable, so the other is not. */
         assert(other_pseg->transaction_state != TS_INEVITABLE);
@@ -42,7 +36,7 @@
            abort. */
         abort_with_mutex();
     }
-    else {
+    else if (wait) {
         /* otherwise, we will issue a safe point and wait: */
         STM_PSEGMENT->safe_point = SP_SAFE_POINT;
 
diff --git a/c7/stm/contention.h b/c7/stm/contention.h
--- a/c7/stm/contention.h
+++ b/c7/stm/contention.h
@@ -1,2 +1,2 @@
 
-static void contention_management(uint8_t other_segment_num);
+static void contention_management(uint8_t other_segment_num, bool wait);
diff --git a/c7/stm/core.c b/c7/stm/core.c
--- a/c7/stm/core.c
+++ b/c7/stm/core.c
@@ -7,8 +7,6 @@
 
 static uint8_t write_locks[READMARKER_END - READMARKER_START];
 
-static void abort_with_mutex(void) __attribute__((noreturn));
-
 static void teardown_core(void)
 {
     memset(write_locks, 0, sizeof(write_locks));
@@ -58,7 +56,7 @@
            By construction it should not be possible that the owner
            of the object is already us */
         mutex_lock();
-        contention_management(prev_owner - 1);
+        contention_management(prev_owner - 1, true);
         mutex_unlock();
     } while (1);
 
@@ -120,15 +118,31 @@
 }
 
 
-static bool detect_write_read_conflicts(void)
+/************************************************************/
+
+#if NB_SEGMENTS != 2
+# error "The logic in the functions below only works with two segments"
+#endif
+
+static void wait_for_other_safe_points(void)
+{
+    long remote_num = 1 - STM_SEGMENT->segment_num;
+    while (get_priv_segment(remote_num)->safe_point == SP_RUNNING) {
+        cond_wait();
+    }
+}
+
+static void detect_write_read_conflicts(void)
 {
     long remote_num = 1 - STM_SEGMENT->segment_num;
     char *remote_base = get_segment_base(remote_num);
     uint8_t remote_version = get_segment(remote_num)->transaction_read_version;
 
-#if NB_SEGMENTS != 2
-# error "This logic only works with two segments"
-#endif
+    switch (get_priv_segment(remote_num)->transaction_state) {
+    case TS_NONE:
+    case TS_MUST_ABORT:
+        return;    /* no need to do any check */
+    }
 
     LIST_FOREACH_R(
         STM_PSEGMENT->modified_objects,
@@ -136,11 +150,13 @@
         ({
             if (was_read_remote(remote_base, item, remote_version)) {
                 /* A write-read conflict! */
-                contention_management(remote_num);
-                return true;
+                contention_management(remote_num, false);
+
+                /* If we reach this point, it means we aborted the other
+                   thread.  We're done here. */
+                return;
             }
         }));
-    return false;
 }
 
 static void push_modified_to_other_segments(void)
@@ -148,17 +164,18 @@
     long remote_num = 1 - STM_SEGMENT->segment_num;
     char *local_base = STM_SEGMENT->segment_base;
     char *remote_base = get_segment_base(remote_num);
-
-#if NB_SEGMENTS != 2
-# error "This logic only works with two segments"
-#endif
+    bool remote_active =
+        (get_priv_segment(remote_num)->transaction_state == TS_REGULAR ||
+         get_priv_segment(remote_num)->transaction_state == TS_INEVITABLE);
 
     LIST_FOREACH_R(
         STM_PSEGMENT->modified_objects,
         object_t * /*item*/,
         ({
-            assert(!was_read_remote(remote_base, item,
+            if (remote_active) {
+                assert(!was_read_remote(remote_base, item,
                           get_segment(remote_num)->transaction_read_version));
+            }
 
             /* clear the write-lock */
             uintptr_t lock_idx = (((uintptr_t)item) >> 4) - READMARKER_START;
@@ -176,8 +193,6 @@
 void stm_commit_transaction(void)
 {
     mutex_lock();
-
- restart:
     assert(STM_PSEGMENT->safe_point = SP_RUNNING);
 
     switch (STM_PSEGMENT->transaction_state) {
@@ -193,9 +208,11 @@
         assert(!"commit: bad transaction_state");
     }
 
+    /* wait until the other thread is at a safe-point */
+    wait_for_other_safe_points();
+
     /* detect conflicts */
-    if (detect_write_read_conflicts())
-        goto restart;
+    detect_write_read_conflicts();
 
     /* cannot abort any more from here */
     assert(STM_PSEGMENT->transaction_state != TS_MUST_ABORT);
@@ -223,9 +240,6 @@
 
 static void abort_with_mutex(void)
 {
-    stm_thread_local_t *tl = STM_SEGMENT->running_thread;
-    stm_jmpbuf_t *jmpbuf_ptr = STM_SEGMENT->jmpbuf_ptr;
-
     switch (STM_PSEGMENT->transaction_state) {
     case TS_REGULAR:
     case TS_MUST_ABORT:
@@ -236,6 +250,8 @@
         assert(!"abort: bad transaction_state");
     }
 
+    stm_jmpbuf_t *jmpbuf_ptr = STM_SEGMENT->jmpbuf_ptr;
+    stm_thread_local_t *tl = STM_SEGMENT->running_thread;
     release_thread_segment(tl);   /* includes the cond_broadcast(); */
     STM_PSEGMENT->safe_point = SP_NO_TRANSACTION;
     STM_PSEGMENT->transaction_state = TS_NONE;
diff --git a/c7/stm/core.h b/c7/stm/core.h
--- a/c7/stm/core.h
+++ b/c7/stm/core.h
@@ -109,3 +109,4 @@
 }
 
 static void teardown_core(void);
+static void abort_with_mutex(void) __attribute__((noreturn));
diff --git a/c7/stm/sync.c b/c7/stm/sync.c
--- a/c7/stm/sync.c
+++ b/c7/stm/sync.c
@@ -80,11 +80,19 @@
 
 static inline void cond_wait(void)
 {
+#ifdef STM_NO_COND_WAIT
+    fprintf(stderr, "*** cond_wait called!");
+    abort();
+#endif
+
     if (UNLIKELY(pthread_cond_wait(&sync_ctl.global_cond,
                                    &sync_ctl.global_mutex) != 0)) {
         perror("pthread_cond_wait");
         abort();
     }
+
+    if (STM_PSEGMENT->transaction_state == TS_MUST_ABORT)
+        abort_with_mutex();
 }
 
 static inline void cond_broadcast(void)
@@ -166,12 +174,19 @@
     assert(STM_SEGMENT->running_thread == tl);
 }
 
-void _stm_start_safe_point(int flags)
+#if STM_TESTS
+void _stm_start_safe_point(void)
 {
-    //...
+    assert(STM_PSEGMENT->safe_point == SP_RUNNING);
+    STM_PSEGMENT->safe_point = SP_SAFE_POINT_CAN_COLLECT;
 }
 
-void _stm_stop_safe_point(int flags)
+void _stm_stop_safe_point(void)
 {
-    //...
+    assert(STM_PSEGMENT->safe_point == SP_SAFE_POINT_CAN_COLLECT);
+    STM_PSEGMENT->safe_point = SP_RUNNING;
+
+    if (STM_PSEGMENT->transaction_state == TS_MUST_ABORT)
+        stm_abort_transaction();
 }
+#endif
diff --git a/c7/stmgc.h b/c7/stmgc.h
--- a/c7/stmgc.h
+++ b/c7/stmgc.h
@@ -81,8 +81,6 @@
 stm_char *_stm_allocate_slowpath(ssize_t);
 void _stm_become_inevitable(char*);
 void _stm_start_transaction(stm_thread_local_t *, stm_jmpbuf_t *);
-void _stm_start_safe_point(int flags);
-void _stm_stop_safe_point(int flags);
 
 #ifdef STM_TESTS
 bool _stm_was_read(object_t *obj);
@@ -94,6 +92,8 @@
 void _stm_test_switch(stm_thread_local_t *tl);
 object_t *_stm_allocate_old(ssize_t size_rounded_up);
 void _stm_large_dump(void);
+void _stm_start_safe_point(void);
+void _stm_stop_safe_point(void);
 #endif
 
 #define _STM_GCFLAG_WRITE_BARRIER_CALLED  0x80
diff --git a/c7/test/support.py b/c7/test/support.py
--- a/c7/test/support.py
+++ b/c7/test/support.py
@@ -66,12 +66,8 @@
 void _set_type_id(object_t *obj, uint32_t h);
 uint32_t _get_type_id(object_t *obj);
 
-#define LOCK_COLLECT   ...
-#define LOCK_EXCLUSIVE ...
-#define THREAD_YIELD   ...
-
-void _stm_start_safe_point(int);
-bool _check_stop_safe_point(int);
+void _stm_start_safe_point(void);
+bool _check_stop_safe_point(void);
 """)
 
 
@@ -138,12 +134,6 @@
 typedef TLPREFIX struct myobj_s myobj_t;
 #define SIZEOF_MYOBJ sizeof(struct myobj_s)
 
-enum {
-    LOCK_COLLECT = 1,
-    LOCK_EXCLUSIVE = 2,
-    THREAD_YIELD = 4,
-};
-
 
 uint8_t _stm_get_flags(object_t *obj) {
     return obj->stm_flags;
@@ -195,13 +185,13 @@
 }
 #endif
 
-bool _check_stop_safe_point(int flags) {
+bool _check_stop_safe_point(void) {
     stm_jmpbuf_t here;
     stm_segment_info_t *segment = STM_SEGMENT;
     if (__builtin_setjmp(here) == 0) { // returned directly
          assert(segment->jmpbuf_ptr == (stm_jmpbuf_t *)-1);
          segment->jmpbuf_ptr = &here;
-         _stm_stop_safe_point(flags);
+         _stm_stop_safe_point();
          segment->jmpbuf_ptr = (stm_jmpbuf_t *)-1;
          return 0;
     }
@@ -287,7 +277,7 @@
 }
 
 ''', sources=source_files,
-     define_macros=[('STM_TESTS', '1')],
+     define_macros=[('STM_TESTS', '1'), ('STM_NO_COND_WAIT', '1')],
      undef_macros=['NDEBUG'],
      include_dirs=[parent_dir],
      extra_compile_args=['-g', '-O0', '-Werror'],
@@ -369,10 +359,10 @@
 
 
 def stm_start_safe_point():
-    lib._stm_start_safe_point(lib.LOCK_COLLECT)
+    lib._stm_start_safe_point()
 
 def stm_stop_safe_point():
-    if lib._check_stop_safe_point(lib.LOCK_COLLECT):
+    if lib._check_stop_safe_point():
         raise Conflict()
 
 def stm_become_inevitable():
diff --git a/c7/test/test_basic.py b/c7/test/test_basic.py
--- a/c7/test/test_basic.py
+++ b/c7/test/test_basic.py
@@ -96,7 +96,7 @@
         self.commit_transaction()
         #
         py.test.raises(Conflict, self.switch, 0) # detects rw conflict
-        
+
     def test_commit_fresh_objects(self):
         self.start_transaction()
         lp = stm_allocate(16)


More information about the pypy-commit mailing list