[pypy-commit] stmgc default: add inevitable transactions

Raemi noreply at buildbot.pypy.org
Mon Sep 8 11:20:39 CEST 2014


Author: Remi Meier <remi.meier at inf.ethz.ch>
Branch: 
Changeset: r1364:5b5ed3773ccf
Date: 2014-09-08 11:22 +0200
http://bitbucket.org/pypy/stmgc/changeset/5b5ed3773ccf/

Log:	add inevitable transactions

diff --git a/c8/stm/core.c b/c8/stm/core.c
--- a/c8/stm/core.c
+++ b/c8/stm/core.c
@@ -110,13 +110,17 @@
 
 void _dbg_print_commit_log()
 {
-    volatile struct stm_commit_log_entry_s *cl = (volatile struct stm_commit_log_entry_s *)
-        &commit_log_root;
+    volatile struct stm_commit_log_entry_s *cl;
+    cl = (volatile struct stm_commit_log_entry_s *)&commit_log_root;
 
     fprintf(stderr, "root (%p, %d)\n", cl->next, cl->segment_num);
     while ((cl = cl->next)) {
+        if ((uintptr_t)cl == -1) {
+            fprintf(stderr, "INEVITABLE\n");
+            return;
+        }
         size_t i = 0;
-        fprintf(stderr, "elem (%p, %d)\n", cl->next, cl->segment_num);
+        fprintf(stderr, "  elem (%p, %d)\n", cl->next, cl->segment_num);
         object_t *obj;
         while ((obj = cl->written[i])) {
             fprintf(stderr, "-> %p\n", obj);
@@ -176,13 +180,21 @@
        most current one and apply all changes done
        by other transactions. Abort if we read one of
        the committed objs. */
-    volatile struct stm_commit_log_entry_s *cl = (volatile struct stm_commit_log_entry_s *)
+    volatile struct stm_commit_log_entry_s *cl, *prev_cl;
+    cl = prev_cl = (volatile struct stm_commit_log_entry_s *)
         STM_PSEGMENT->last_commit_log_entry;
 
-    acquire_privatization_lock(STM_SEGMENT->segment_num);
     bool needs_abort = false;
     /* Don't check 'cl'. This entry is already checked */
     while ((cl = cl->next)) {
+        if ((uintptr_t)cl == -1) {
+            /* there is an inevitable transaction running */
+            cl = prev_cl;
+            usleep(1);          /* XXX */
+            continue;
+        }
+        prev_cl = cl;
+
         OPT_ASSERT(cl->segment_num >= 0 && cl->segment_num < NB_SEGMENTS);
 
         object_t *obj;
@@ -200,7 +212,6 @@
         /* last fully validated entry */
         STM_PSEGMENT->last_commit_log_entry = (struct stm_commit_log_entry_s *)cl;
     }
-    release_privatization_lock(STM_SEGMENT->segment_num);
 
     if (needs_abort) {
         free(free_if_abort);
@@ -241,6 +252,16 @@
     volatile struct stm_commit_log_entry_s **to;
 
     new = _create_commit_log_entry();
+    if (STM_PSEGMENT->transaction_state == TS_INEVITABLE) {
+        OPT_ASSERT((uintptr_t)STM_PSEGMENT->last_commit_log_entry->next == -1);
+
+        to = &(STM_PSEGMENT->last_commit_log_entry->next);
+        bool yes = __sync_bool_compare_and_swap(to, -1, new);
+        OPT_ASSERT(yes);
+        return;
+    }
+
+    /* regular transaction: */
     do {
         stm_validate(new);
 
@@ -249,6 +270,20 @@
     } while (!__sync_bool_compare_and_swap(to, NULL, new));
 }
 
+static void _validate_and_turn_inevitable()
+{
+    struct stm_commit_log_entry_s *new;
+    volatile struct stm_commit_log_entry_s **to;
+
+    new = (struct stm_commit_log_entry_s*)-1;
+    do {
+        stm_validate(NULL);
+
+        /* try attaching to commit log: */
+        to = &(STM_PSEGMENT->last_commit_log_entry->next);
+    } while (!__sync_bool_compare_and_swap(to, NULL, new));
+}
+
 /* ############# STM ############# */
 
 void _privatize_and_protect_other_segments(object_t *obj)
@@ -382,7 +417,7 @@
 }
 
 
-static void _stm_start_transaction(stm_thread_local_t *tl, bool inevitable)
+static void _stm_start_transaction(stm_thread_local_t *tl)
 {
     assert(!_stm_in_transaction(tl));
 
@@ -392,6 +427,8 @@
         goto retry;
     /* GS invalid before this point! */
 
+    assert(STM_PSEGMENT->transaction_state == TS_NONE);
+    STM_PSEGMENT->transaction_state = TS_REGULAR;
 #ifndef NDEBUG
     STM_PSEGMENT->running_pthread = pthread_self();
 #endif
@@ -421,10 +458,28 @@
 #else
     long repeat_count = stm_rewind_jmp_setjmp(tl);
 #endif
-    _stm_start_transaction(tl, false);
+    _stm_start_transaction(tl);
     return repeat_count;
 }
 
+void stm_start_inevitable_transaction(stm_thread_local_t *tl)
+{
+    s_mutex_lock();
+    _stm_start_transaction(tl);
+    _stm_become_inevitable("stm_start_inevitable_transaction");
+}
+
+#ifdef STM_NO_AUTOMATIC_SETJMP
+void _test_run_abort(stm_thread_local_t *tl) __attribute__((noreturn));
+int stm_is_inevitable(void)
+{
+    switch (STM_PSEGMENT->transaction_state) {
+    case TS_REGULAR: return 0;
+    case TS_INEVITABLE: return 1;
+    default: abort();
+    }
+}
+#endif
 
 /************************************************************/
 
@@ -432,6 +487,7 @@
 {
     stm_thread_local_t *tl = STM_SEGMENT->running_thread;
 
+    STM_PSEGMENT->transaction_state = TS_NONE;
     list_clear(STM_PSEGMENT->objects_pointing_to_nursery);
 
     release_thread_segment(tl);
@@ -443,6 +499,7 @@
     assert(!_has_mutex());
     assert(STM_PSEGMENT->running_pthread == pthread_self());
 
+    dprintf(("stm_commit_transaction()\n"));
     minor_collection(1);
 
     _validate_and_add_to_commit_log();
@@ -469,7 +526,6 @@
     assert(STM_SEGMENT->nursery_end == NURSERY_END);
     stm_rewind_jmp_forget(STM_SEGMENT->running_thread);
 
-
     /* done */
     _finish_transaction();
     /* cannot access STM_SEGMENT or STM_PSEGMENT from here ! */
@@ -519,6 +575,16 @@
 #undef STM_SEGMENT
     struct stm_priv_segment_info_s *pseg = get_priv_segment(segment_num);
 
+    switch (pseg->transaction_state) {
+    case TS_REGULAR:
+        break;
+    case TS_INEVITABLE:
+        stm_fatalerror("abort: transaction_state == TS_INEVITABLE");
+    default:
+        stm_fatalerror("abort: bad transaction_state == %d",
+                       (int)pseg->transaction_state);
+    }
+
     throw_away_nursery(pseg);
 
     reset_modified_from_backup_copies(segment_num);
@@ -582,3 +648,22 @@
     stm_rewind_jmp_longjmp(tl);
 #endif
 }
+
+
+void _stm_become_inevitable(const char *msg)
+{
+    s_mutex_lock();
+
+    if (STM_PSEGMENT->transaction_state == TS_REGULAR) {
+        dprintf(("become_inevitable: %s\n", msg));
+
+        _validate_and_turn_inevitable();
+        STM_PSEGMENT->transaction_state = TS_INEVITABLE;
+        stm_rewind_jmp_forget(STM_SEGMENT->running_thread);
+    }
+    else {
+        assert(STM_PSEGMENT->transaction_state == TS_INEVITABLE);
+    }
+
+    s_mutex_unlock();
+}
diff --git a/c8/stm/core.h b/c8/stm/core.h
--- a/c8/stm/core.h
+++ b/c8/stm/core.h
@@ -53,6 +53,8 @@
     struct list_s *objects_pointing_to_nursery;
     uint8_t privatization_lock;
 
+    uint8_t transaction_state;
+
     struct stm_commit_log_entry_s *last_commit_log_entry;
 
     struct stm_shadowentry_s *shadowstack_at_start_of_transaction;
@@ -63,6 +65,12 @@
 #endif
 };
 
+enum /* transaction_state */ {
+    TS_NONE=0,
+    TS_REGULAR,
+    TS_INEVITABLE,
+};
+
 /* Commit Log things */
 struct stm_commit_log_entry_s {
     volatile struct stm_commit_log_entry_s *next;
diff --git a/c8/stmgc.h b/c8/stmgc.h
--- a/c8/stmgc.h
+++ b/c8/stmgc.h
@@ -69,6 +69,7 @@
 
 void _stm_write_slowpath(object_t *);
 object_t *_stm_allocate_slowpath(ssize_t);
+void _stm_become_inevitable(const char*);
 
 object_t *_stm_allocate_old(ssize_t size_rounded_up);
 char *_stm_real_address(object_t *o);
@@ -186,10 +187,27 @@
 
 
 long stm_start_transaction(stm_thread_local_t *tl);
+void stm_start_inevitable_transaction(stm_thread_local_t *tl);
+
 void stm_commit_transaction(void);
 void stm_abort_transaction(void) __attribute__((noreturn));
 
 
+#ifdef STM_NO_AUTOMATIC_SETJMP
+int stm_is_inevitable(void);
+#else
+static inline int stm_is_inevitable(void) {
+    return !rewind_jmp_armed(&STM_SEGMENT->running_thread->rjthread);
+}
+#endif
+static inline void stm_become_inevitable(stm_thread_local_t *tl,
+                                         const char* msg) {
+    assert(STM_SEGMENT->running_thread == tl);
+    if (!stm_is_inevitable())
+        _stm_become_inevitable(msg);
+}
+
+
 /* ==================== END ==================== */
 
 #endif
diff --git a/c8/test/support.py b/c8/test/support.py
--- a/c8/test/support.py
+++ b/c8/test/support.py
@@ -57,6 +57,8 @@
 long stm_start_transaction(stm_thread_local_t *tl);
 bool _check_commit_transaction(void);
 bool _check_abort_transaction(void);
+bool _check_become_inevitable(stm_thread_local_t *tl);
+int stm_is_inevitable(void);
 
 void _set_type_id(object_t *obj, uint32_t h);
 uint32_t _get_type_id(object_t *obj);
@@ -134,6 +136,10 @@
     CHECKED(stm_abort_transaction());
 }
 
+bool _check_become_inevitable(stm_thread_local_t *tl) {
+    CHECKED(stm_become_inevitable(tl, "TEST"));
+}
+
 bool _check_stm_validate(void) {
     CHECKED(stm_validate(NULL));
 }
@@ -413,12 +419,18 @@
     def teardown_method(self, meth):
         lib.stmcb_expand_marker = ffi.NULL
         lib.stmcb_debug_print = ffi.NULL
+        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:
                     self.switch(n)
-                self.abort_transaction()
+                if lib.stm_is_inevitable():
+                    self.commit_transaction()   # must succeed!
+                else:
+                    self.abort_transaction()
         #
         for tl in self.tls:
             lib.stm_unregister_thread_local(tl)
@@ -504,3 +516,8 @@
     def set_thread_local_obj(self, newobj):
         tl = self.tls[self.current_thread]
         tl.thread_local_obj = newobj
+
+    def become_inevitable(self):
+        tl = self.tls[self.current_thread]
+        if lib._check_become_inevitable(tl):
+            raise Conflict()


More information about the pypy-commit mailing list