[pypy-commit] stmgc c8-marker: Generate the markers in case of inevitable transactions

arigo noreply at buildbot.pypy.org
Mon Mar 9 10:04:51 CET 2015


Author: Armin Rigo <arigo at tunes.org>
Branch: c8-marker
Changeset: r1702:5a56584dbe4b
Date: 2015-03-09 10:05 +0100
http://bitbucket.org/pypy/stmgc/changeset/5a56584dbe4b/

Log:	Generate the markers in case of inevitable transactions

diff --git a/c8/stm/core.c b/c8/stm/core.c
--- a/c8/stm/core.c
+++ b/c8/stm/core.c
@@ -5,6 +5,7 @@
 /* *** MISC *** */
 static void free_bk(struct stm_undo_s *undo)
 {
+    assert(undo->type != TYPE_POSITION_MARKER);
     free(undo->backup);
     assert(undo->backup = (char*)-88);
     increment_total_allocated(-SLICE_SIZE(undo->slice));
@@ -455,6 +456,17 @@
 }
 
 
+static void wait_for_other_inevitable(struct stm_commit_log_entry_s *old)
+{
+    timing_wait_other_inevitable();
+
+    while (old->next == INEV_RUNNING && !safe_point_requested()) {
+        spin_loop();
+        usleep(10);    /* XXXXXX */
+    }
+    timing_event(STM_SEGMENT->running_thread, STM_WAIT_DONE);
+}
+
 static void reset_wb_executed_flags(void);
 static void readd_wb_executed_flags(void);
 static void check_all_write_barrier_flags(char *segbase, struct list_s *list);
@@ -506,13 +518,6 @@
 
             if (__sync_bool_compare_and_swap(&old->next, NULL, new))
                 break;   /* success! */
-        } else if (old->next == INEV_RUNNING) {
-            /* we failed because there is an INEV transaction running */
-            /* XXXXXX for now just sleep (XXX with the lock acquired?
-               isn't it a bad idea?).  We should really ask to inev
-               transaction to do the commit for us, and then we can
-               continue running. */
-            usleep(10);
         }
 
         if (is_commit) {
@@ -523,6 +528,16 @@
             readd_wb_executed_flags();
         }
 
+        if (old->next == INEV_RUNNING && !safe_point_requested()) {
+            /* we failed because there is an INEV transaction running */
+            /* XXXXXX for now just sleep.  We should really ask to inev
+               transaction to do the commit for us, and then we can
+               continue running. */
+            dprintf(("_validate_and_attach(%p) failed, "
+                     "waiting for inevitable\n", new));
+            wait_for_other_inevitable(old);
+        }
+
         dprintf(("_validate_and_attach(%p) failed, enter safepoint\n", new));
 
         /* check for requested safe point. otherwise an INEV transaction
@@ -1150,7 +1165,7 @@
 
 /************************************************************/
 
-static void _finish_transaction(enum stm_event_e event)
+static void _finish_transaction(enum stm_event_e event, bool was_inev)
 {
     stm_thread_local_t *tl = STM_SEGMENT->running_thread;
 
@@ -1161,7 +1176,10 @@
     list_clear(STM_PSEGMENT->objects_pointing_to_nursery);
     list_clear(STM_PSEGMENT->old_objects_with_cards_set);
     list_clear(STM_PSEGMENT->large_overflow_objects);
-    timing_event(tl, event);
+    if (was_inev)
+        timing_commit_inev_position();
+    else
+        timing_event(tl, event);
 
     release_thread_segment(tl);
     /* cannot access STM_SEGMENT or STM_PSEGMENT from here ! */
@@ -1223,6 +1241,7 @@
 
     push_large_overflow_objects_to_other_segments();
     /* push before validate. otherwise they are reachable too early */
+
     bool was_inev = STM_PSEGMENT->transaction_state == TS_INEVITABLE;
     _validate_and_add_to_commit_log();
 
@@ -1264,7 +1283,7 @@
 
     /* done */
     stm_thread_local_t *tl = STM_SEGMENT->running_thread;
-    _finish_transaction(STM_TRANSACTION_COMMIT);
+    _finish_transaction(STM_TRANSACTION_COMMIT, was_inev);
     /* cannot access STM_SEGMENT or STM_PSEGMENT from here ! */
 
     s_mutex_unlock();
@@ -1399,7 +1418,7 @@
                                                    : NURSERY_END;
     }
 
-    _finish_transaction(STM_TRANSACTION_ABORT);
+    _finish_transaction(STM_TRANSACTION_ABORT, false);
     /* cannot access STM_SEGMENT or STM_PSEGMENT from here ! */
 
     return tl;
@@ -1441,6 +1460,8 @@
 
         _validate_and_turn_inevitable();
         STM_PSEGMENT->transaction_state = TS_INEVITABLE;
+        timing_record_inev_position();
+
         stm_rewind_jmp_forget(STM_SEGMENT->running_thread);
         invoke_and_clear_user_callbacks(0);   /* for commit */
     }
diff --git a/c8/stm/core.h b/c8/stm/core.h
--- a/c8/stm/core.h
+++ b/c8/stm/core.h
@@ -141,6 +141,9 @@
     pthread_t running_pthread;
 #endif
 
+    /* marker where this thread became inevitable */
+    stm_loc_marker_t marker_inev;
+
     /* light finalizers */
     struct list_s *young_objects_with_light_finalizers;
     struct list_s *old_objects_with_light_finalizers;
diff --git a/c8/stm/gcpage.c b/c8/stm/gcpage.c
--- a/c8/stm/gcpage.c
+++ b/c8/stm/gcpage.c
@@ -401,6 +401,9 @@
             if (modified->type == TYPE_POSITION_MARKER)
                 mark_visit_possibly_new_object(modified->marker_object, pseg);
         }
+
+        if (pseg->transaction_state == TS_INEVITABLE)
+            mark_visit_possibly_new_object(pseg->marker_inev.object, pseg);
     }
 }
 
diff --git a/c8/stm/marker.c b/c8/stm/marker.c
--- a/c8/stm/marker.c
+++ b/c8/stm/marker.c
@@ -26,6 +26,8 @@
     }
     else {
         /* no marker found */
+        out_marker->odd_number = 0;
+        out_marker->object = NULL;
         return false;
     }
 }
@@ -87,6 +89,34 @@
                        STM_CONTENTION_WRITE_READ, &marker);
 }
 
+static void _timing_record_inev_position(void)
+{
+    stm_loc_marker_t marker;
+    marker_fetch(STM_SEGMENT->running_thread, &marker);
+    STM_PSEGMENT->marker_inev.odd_number = marker.odd_number;
+    STM_PSEGMENT->marker_inev.object = marker.object;
+}
+
+static void _timing_commit_inev_position(void)
+{
+    stm_loc_marker_t marker;
+    marker.odd_number = STM_PSEGMENT->marker_inev.odd_number;
+    marker.object = STM_PSEGMENT->marker_inev.object;
+    stmcb_timing_event(STM_SEGMENT->running_thread,
+                       STM_TRANSACTION_COMMIT, &marker);
+}
+
+static void timing_wait_other_inevitable(void)
+{
+    if (stmcb_timing_event == NULL)
+        return;
+
+    stm_loc_marker_t marker;
+    marker_fetch(STM_SEGMENT->running_thread, &marker);
+    stmcb_timing_event(STM_SEGMENT->running_thread,
+                       STM_WAIT_OTHER_INEVITABLE, &marker);
+}
+
 
 void (*stmcb_timing_event)(stm_thread_local_t *tl, /* the local thread */
                            enum stm_event_e event,
diff --git a/c8/stm/marker.h b/c8/stm/marker.h
--- a/c8/stm/marker.h
+++ b/c8/stm/marker.h
@@ -2,10 +2,21 @@
 static void _timing_record_write_position(void);
 static void timing_write_read_contention(struct stm_undo_s *start,
                                          struct stm_undo_s *contention);
+static void _timing_record_inev_position(void);
+static void _timing_commit_inev_position(void);
+static void timing_wait_other_inevitable(void);
 
 
+#define timing_enabled()   (stmcb_timing_event != NULL)
+
 #define timing_event(tl, event)                                         \
-    (stmcb_timing_event != NULL ? stmcb_timing_event(tl, event, NULL) : (void)0)
+    (timing_enabled() ? stmcb_timing_event(tl, event, NULL) : (void)0)
 
 #define timing_record_write_position()                                  \
-    (stmcb_timing_event != NULL ? _timing_record_write_position() : (void)0)
+    (timing_enabled() ? _timing_record_write_position() : (void)0)
+
+#define timing_record_inev_position()                                   \
+    (timing_enabled() ? _timing_record_inev_position() : (void)0)
+
+#define timing_commit_inev_position()                                   \
+    (timing_enabled() ? _timing_commit_inev_position() : (void)0)
diff --git a/c8/stm/nursery.c b/c8/stm/nursery.c
--- a/c8/stm/nursery.c
+++ b/c8/stm/nursery.c
@@ -425,6 +425,13 @@
         if (undo->type == TYPE_POSITION_MARKER)
             minor_trace_if_young(&undo->marker_object);
     }
+
+    if (STM_PSEGMENT->transaction_state == TS_INEVITABLE) {
+        object_t **pmarker_inev_obj = (object_t **)
+            REAL_ADDRESS(STM_SEGMENT->segment_base,
+                         &STM_PSEGMENT->marker_inev.object);
+        minor_trace_if_young(pmarker_inev_obj);
+    }
 }
 
 static void collect_objs_still_young_but_with_finalizers(void)
diff --git a/c8/stm/sync.h b/c8/stm/sync.h
--- a/c8/stm/sync.h
+++ b/c8/stm/sync.h
@@ -33,3 +33,5 @@
 
 static bool pause_signalled, globally_unique_transaction;
 static void enter_safe_point_if_requested(void);
+
+#define safe_point_requested()  (STM_SEGMENT->nursery_end != NURSERY_END)
diff --git a/c8/stmgc.h b/c8/stmgc.h
--- a/c8/stmgc.h
+++ b/c8/stmgc.h
@@ -354,6 +354,12 @@
        saying where the write was done.  Followed by STM_TRANSACTION_ABORT. */
     STM_CONTENTION_WRITE_READ,
 
+    /* inevitable contention: the thread that waited is
+       STM_WAIT_OTHER_INEVITABLE (with a marker) and the thread that
+       it waited for is the next STM_TRANSACTION_COMMIT (with a marker
+       as well; both markers point to the place that made each
+       transaction inevitable). */
+
     /* always one STM_WAIT_xxx followed later by STM_WAIT_DONE */
     STM_WAIT_FREE_SEGMENT,
     STM_WAIT_OTHER_INEVITABLE,
diff --git a/c8/test/test_marker.py b/c8/test/test_marker.py
--- a/c8/test/test_marker.py
+++ b/c8/test/test_marker.py
@@ -119,20 +119,25 @@
         py.test.raises(Conflict, self.switch, 1)
         self.check_recording(19, ffi.NULL)
 
-    def test_double_abort_markers_cb_inevitable(self):
-        self.recording(lib.STM_CONTENTION_INEVITABLE)
+    def test_commit_marker_for_inev(self):
+        self.recording(lib.STM_TRANSACTION_COMMIT)
+        #
+        self.switch(1)
+        self.start_transaction()
+        self.push_root(ffi.cast("object_t *", 19))
+        self.push_root(ffi.cast("object_t *", ffi.NULL))
+        self.become_inevitable()
+        self.pop_root()
+        self.pop_root()
+        self.commit_transaction()
+        #
+        self.check_recording(19, ffi.NULL)
+
+    def test_abort_markers_cb_inevitable(self):
+        self.recording(lib.STM_WAIT_OTHER_INEVITABLE)
         #
         self.start_transaction()
-        p = stm_allocate(16)
-        stm_set_char(p, 'A')
-        self.push_root(ffi.cast("object_t *", 19))
-        self.push_root(ffi.cast("object_t *", p))
         self.become_inevitable()
-        self.pop_root()
-        self.pop_root()
-        self.push_root(ffi.cast("object_t *", 17))
-        self.push_root(ffi.cast("object_t *", ffi.NULL))
-        stm_minor_collect()
         #
         self.switch(1)
         self.start_transaction()
@@ -142,7 +147,9 @@
         self.push_root(ffi.cast("object_t *", p))
         py.test.raises(Conflict, self.become_inevitable)
         #
-        self.check_recording(21, p, 19, p)
+        py.test.skip("XXX only during tests does become_inevitable() abort"
+                     " and then it doesn't record anything")
+        self.check_recording(21, p)
 
     def test_read_write_contention(self):
         self.recording(lib.STM_CONTENTION_WRITE_READ)
@@ -167,63 +174,6 @@
         py.test.raises(Conflict, self.switch, 1)
         self.check_recording(19, ffi.NULL)
 
-    def test_double_remote_markers_cb_write_write(self):
-        self.recording(lib.STM_CONTENTION_WRITE_WRITE,
-                       lib.STM_ABORTING_OTHER_CONTENTION)
-        p = stm_allocate_old(16)
-        #
-        self.start_transaction()
-        self.push_root(ffi.cast("object_t *", 19))
-        self.push_root(ffi.cast("object_t *", ffi.NULL))
-        stm_set_char(p, 'A')
-        self.pop_root()
-        self.pop_root()
-        self.push_root(ffi.cast("object_t *", 17))
-        self.push_root(ffi.cast("object_t *", ffi.NULL))
-        tl0 = self.get_stm_thread_local()
-        #
-        self.switch(1)
-        self.start_transaction()
-        self.become_inevitable()
-        self.push_root(ffi.cast("object_t *", 21))
-        self.push_root(ffi.cast("object_t *", ffi.NULL))
-        stm_set_char(p, 'B')    # aborts in #0
-        self.pop_root()
-        self.pop_root()
-        self.push_root(ffi.cast("object_t *", 23))
-        self.push_root(ffi.cast("object_t *", ffi.NULL))
-        #
-        py.test.raises(Conflict, self.switch, 0)
-        #
-        self.check_recording(21, ffi.NULL, 19, ffi.NULL,
-                             extra=lib.STM_ABORTING_OTHER_CONTENTION)
-
-    def test_double_remote_markers_cb_write_read(self):
-        self.recording(lib.STM_CONTENTION_WRITE_READ,
-                       lib.STM_ABORTING_OTHER_CONTENTION)
-        p = stm_allocate_old(16)
-        #
-        self.start_transaction()
-        assert stm_get_char(p) == '\x00'    # read
-        tl0 = self.get_stm_thread_local()
-        #
-        self.switch(1)
-        self.start_transaction()
-        self.become_inevitable()
-        self.push_root(ffi.cast("object_t *", 21))
-        self.push_root(ffi.cast("object_t *", ffi.NULL))
-        stm_set_char(p, 'B')                # write, will abort #0
-        self.pop_root()
-        self.pop_root()
-        self.push_root(ffi.cast("object_t *", 23))
-        self.push_root(ffi.cast("object_t *", ffi.NULL))
-        self.commit_transaction()
-        #
-        py.test.raises(Conflict, self.switch, 0)
-        #
-        self.check_recording(21, ffi.NULL, 0, ffi.NULL,
-                             extra=lib.STM_ABORTING_OTHER_CONTENTION)
-
     def test_all(self):
         self.recording()     # all events
         self.start_transaction()


More information about the pypy-commit mailing list