[pypy-commit] stmgc marker: Minimum work to pass test_double_abort_markers_cb_write_write

arigo noreply at buildbot.pypy.org
Sat Apr 26 18:38:20 CEST 2014


Author: Armin Rigo <arigo at tunes.org>
Branch: marker
Changeset: r1182:64af26e96549
Date: 2014-04-26 18:38 +0200
http://bitbucket.org/pypy/stmgc/changeset/64af26e96549/

Log:	Minimum work to pass test_double_abort_markers_cb_write_write

diff --git a/c7/stm/contention.c b/c7/stm/contention.c
--- a/c7/stm/contention.c
+++ b/c7/stm/contention.c
@@ -99,7 +99,8 @@
 
 
 static void contention_management(uint8_t other_segment_num,
-                                  enum contention_kind_e kind)
+                                  enum contention_kind_e kind,
+                                  object_t *obj)
 {
     assert(_has_mutex());
     assert(other_segment_num != STM_SEGMENT->segment_num);
@@ -182,6 +183,8 @@
     else if (!contmgr.abort_other) {
         dprintf(("abort in contention\n"));
         STM_SEGMENT->nursery_end = abort_category;
+        if (kind == WRITE_WRITE_CONTENTION)
+            lookup_other_thread_recorded_marker(other_segment_num, obj);
         abort_with_mutex();
     }
 
@@ -259,7 +262,8 @@
     }
 }
 
-static void write_write_contention_management(uintptr_t lock_idx)
+static void write_write_contention_management(uintptr_t lock_idx,
+                                              object_t *obj)
 {
     s_mutex_lock();
 
@@ -270,7 +274,7 @@
         assert(get_priv_segment(other_segment_num)->write_lock_num ==
                prev_owner);
 
-        contention_management(other_segment_num, WRITE_WRITE_CONTENTION);
+        contention_management(other_segment_num, WRITE_WRITE_CONTENTION, obj);
 
         /* now we return into _stm_write_slowpath() and will try again
            to acquire the write lock on our object. */
@@ -281,10 +285,10 @@
 
 static void write_read_contention_management(uint8_t other_segment_num)
 {
-    contention_management(other_segment_num, WRITE_READ_CONTENTION);
+    contention_management(other_segment_num, WRITE_READ_CONTENTION, NULL);
 }
 
 static void inevitable_contention_management(uint8_t other_segment_num)
 {
-    contention_management(other_segment_num, INEVITABLE_CONTENTION);
+    contention_management(other_segment_num, INEVITABLE_CONTENTION, NULL);
 }
diff --git a/c7/stm/contention.h b/c7/stm/contention.h
--- a/c7/stm/contention.h
+++ b/c7/stm/contention.h
@@ -1,5 +1,6 @@
 
-static void write_write_contention_management(uintptr_t lock_idx);
+static void write_write_contention_management(uintptr_t lock_idx,
+                                              object_t *obj);
 static void write_read_contention_management(uint8_t other_segment_num);
 static void inevitable_contention_management(uint8_t other_segment_num);
 
diff --git a/c7/stm/core.c b/c7/stm/core.c
--- a/c7/stm/core.c
+++ b/c7/stm/core.c
@@ -76,9 +76,15 @@
     assert(lock_idx < sizeof(write_locks));
  retry:
     if (write_locks[lock_idx] == 0) {
+        /* A lock to prevent reading garbage from
+           lookup_other_thread_recorded_marker() */
+        acquire_segment_lock(STM_SEGMENT->segment_base);
+
         if (UNLIKELY(!__sync_bool_compare_and_swap(&write_locks[lock_idx],
-                                                   0, lock_num)))
+                                                   0, lock_num))) {
+            release_segment_lock(STM_SEGMENT->segment_base);
             goto retry;
+        }
 
         dprintf_test(("write_slowpath %p -> mod_old\n", obj));
 
@@ -93,6 +99,8 @@
             list_append2(STM_PSEGMENT->modified_old_objects_markers,
                          marker[0], marker[1]);
 
+        release_segment_lock(STM_SEGMENT->segment_base);
+
         /* We need to privatize the pages containing the object, if they
            are still SHARED_PAGE.  The common case is that there is only
            one page in total. */
@@ -134,7 +142,7 @@
     else {
         /* call the contention manager, and then retry (unless we were
            aborted). */
-        write_write_contention_management(lock_idx);
+        write_write_contention_management(lock_idx, obj);
         goto retry;
     }
 
diff --git a/c7/stm/core.h b/c7/stm/core.h
--- a/c7/stm/core.h
+++ b/c7/stm/core.h
@@ -156,6 +156,10 @@
     /* For sleeping contention management */
     bool signal_when_done;
 
+    /* When we mutate 'modified_old_objects' but we don't have the
+       global mutex, we must acquire this lock. */
+    uint8_t segment_lock;
+
     /* In case of abort, we restore the 'shadowstack' field and the
        'thread_local_obj' field. */
     struct stm_shadowentry_s *shadowstack_at_start_of_transaction;
@@ -169,6 +173,7 @@
 
     /* Temporarily stores the marker information */
     char marker_self[_STM_MARKER_LEN];
+    char marker_other[_STM_MARKER_LEN];
 };
 
 enum /* safe_point */ {
@@ -238,3 +243,17 @@
 
 static void copy_object_to_shared(object_t *obj, int source_segment_num);
 static void synchronize_object_now(object_t *obj);
+
+static inline void acquire_segment_lock(char *segment_base)
+{
+    uint8_t *lock = (uint8_t *)REAL_ADDRESS(segment_base,
+                                            &STM_PSEGMENT->segment_lock);
+    spinlock_acquire(*lock);
+}
+
+static inline void release_segment_lock(char *segment_base)
+{
+    uint8_t *lock = (uint8_t *)REAL_ADDRESS(segment_base,
+                                            &STM_PSEGMENT->segment_lock);
+    spinlock_release(*lock);
+}
diff --git a/c7/stm/marker.c b/c7/stm/marker.c
--- a/c7/stm/marker.c
+++ b/c7/stm/marker.c
@@ -79,6 +79,46 @@
         tl->longest_marker_state = attribute_to;
         tl->longest_marker_time = time;
         memcpy(tl->longest_marker_self, pseg->marker_self, _STM_MARKER_LEN);
+        memcpy(tl->longest_marker_other, pseg->marker_other, _STM_MARKER_LEN);
     }
     pseg->marker_self[0] = 0;
 }
+
+static void lookup_other_thread_recorded_marker(uint8_t other_segment_num,
+                                                object_t *obj)
+{
+    struct stm_priv_segment_info_s *my_pseg, *other_pseg;
+    char *other_segment_base = get_segment_base(other_segment_num);
+    acquire_segment_lock(other_segment_base);
+    assert(_has_mutex());
+    STM_PSEGMENT->marker_other[0] = 0;
+
+    /* here, we acquired the other thread's segment_lock, which means that:
+
+       (1) it has finished filling 'modified_old_objects' after it sets
+           up the write_locks[] value that we're conflicting with
+
+       (2) it is not mutating 'modified_old_objects' right now (we have
+           the global mutex_lock at this point too).
+    */
+
+    other_pseg = get_priv_segment(other_segment_num);
+    long i;
+    struct list_s *mlst = other_pseg->modified_old_objects;
+    struct list_s *mlstm = other_pseg->modified_old_objects_markers;
+    for (i = list_count(mlst); --i >= 0; ) {
+        if (list_item(mlst, i) == (uintptr_t)obj) {
+            uintptr_t marker[2];
+            assert(list_count(mlstm) == 2 * list_count(mlst));
+            marker[0] = list_item(mlstm, i * 2 + 0);
+            marker[1] = list_item(mlstm, i * 2 + 1);
+
+            my_pseg = get_priv_segment(STM_SEGMENT->segment_num);
+            marker_expand(marker, other_pseg->pub.segment_base,
+                          my_pseg->marker_other);
+            break;
+        }
+    }
+
+    release_segment_lock(other_segment_base);
+}
diff --git a/c7/stm/marker.h b/c7/stm/marker.h
--- a/c7/stm/marker.h
+++ b/c7/stm/marker.h
@@ -6,3 +6,5 @@
 static void marker_copy(stm_thread_local_t *tl,
                         struct stm_priv_segment_info_s *pseg,
                         enum stm_time_e attribute_to, double time);
+static void lookup_other_thread_recorded_marker(uint8_t other_segment_num,
+                                                object_t *obj);
diff --git a/c7/test/test_marker.py b/c7/test/test_marker.py
--- a/c7/test/test_marker.py
+++ b/c7/test/test_marker.py
@@ -175,7 +175,7 @@
         assert ffi.string(raw).startswith('29 ')
         assert seen == [29]
 
-    def test_double_abort_markers_cb(self):
+    def test_double_abort_markers_cb_write_write(self):
         @ffi.callback("void(char *, uintptr_t, object_t *, char *, size_t)")
         def expand_marker(base, number, ptr, outbuf, outbufsize):
             s = '%d\x00' % (number,)


More information about the pypy-commit mailing list