[pypy-commit] pypy stmgc-c7-rewindjmp: import stmgc/bdc151305c79

arigo noreply at buildbot.pypy.org
Sun Aug 10 21:42:37 CEST 2014


Author: Armin Rigo <arigo at tunes.org>
Branch: stmgc-c7-rewindjmp
Changeset: r72749:ad844f52f065
Date: 2014-08-10 18:01 +0200
http://bitbucket.org/pypy/pypy/changeset/ad844f52f065/

Log:	import stmgc/bdc151305c79

diff --git a/rpython/translator/stm/src_stm/revision b/rpython/translator/stm/src_stm/revision
--- a/rpython/translator/stm/src_stm/revision
+++ b/rpython/translator/stm/src_stm/revision
@@ -1,1 +1,1 @@
-f18bff5ab704
+bdc151305c79
diff --git a/rpython/translator/stm/src_stm/stm/core.c b/rpython/translator/stm/src_stm/stm/core.c
--- a/rpython/translator/stm/src_stm/stm/core.c
+++ b/rpython/translator/stm/src_stm/stm/core.c
@@ -325,14 +325,14 @@
     STM_SEGMENT->transaction_read_version = 1;
 }
 
-void _stm_start_transaction(stm_thread_local_t *tl, stm_jmpbuf_t *jmpbuf)
+static void _stm_start_transaction(stm_thread_local_t *tl, bool inevitable)
 {
     assert(!_stm_in_transaction(tl));
 
     s_mutex_lock();
 
   retry:
-    if (jmpbuf == NULL) {
+    if (inevitable) {
         wait_for_end_of_inevitable_transaction(tl);
     }
 
@@ -347,11 +347,9 @@
     STM_PSEGMENT->signalled_to_commit_soon = false;
     STM_PSEGMENT->safe_point = SP_RUNNING;
     STM_PSEGMENT->marker_inev[1] = 0;
-    if (jmpbuf == NULL)
+    if (inevitable)
         marker_fetch_inev();
-    STM_PSEGMENT->transaction_state = (jmpbuf != NULL ? TS_REGULAR
-                                                      : TS_INEVITABLE);
-    STM_SEGMENT->jmpbuf_ptr = jmpbuf;
+    STM_PSEGMENT->transaction_state = (inevitable ? TS_INEVITABLE : TS_REGULAR);
 #ifndef NDEBUG
     STM_PSEGMENT->running_pthread = pthread_self();
 #endif
@@ -391,6 +389,22 @@
     check_nursery_at_transaction_start();
 }
 
+long stm_start_transaction(stm_thread_local_t *tl)
+{
+#ifdef STM_NO_AUTOMATIC_SETJMP
+    long repeat_count = 0;    /* test/support.py */
+#else
+    long repeat_count = rewind_jmp_setjmp(&tl->rjthread);
+#endif
+    _stm_start_transaction(tl, false);
+    return repeat_count;
+}
+
+void stm_start_inevitable_transaction(stm_thread_local_t *tl)
+{
+    _stm_start_transaction(tl, true);
+}
+
 
 /************************************************************/
 
@@ -815,7 +829,7 @@
     dprintf(("commit_transaction\n"));
 
     assert(STM_SEGMENT->nursery_end == NURSERY_END);
-    STM_SEGMENT->jmpbuf_ptr = NULL;
+    rewind_jmp_forget(&STM_SEGMENT->running_thread->rjthread);
 
     /* if a major collection is required, do it here */
     if (is_major_collection_requested()) {
@@ -893,7 +907,7 @@
                WRITE_BARRIER flag, unless they have been modified
                recently.  Ignore the old flag; after copying from the
                other segment, we should have the flag. */
-            assert(item->stm_flags & GCFLAG_WRITE_BARRIER);
+            assert(((struct object_s *)dst)->stm_flags & GCFLAG_WRITE_BARRIER);
 
             /* write all changes to the object before we release the
                write lock below.  This is needed because we need to
@@ -988,6 +1002,18 @@
 #pragma pop_macro("STM_PSEGMENT")
 }
 
+#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
+
 static void abort_with_mutex(void)
 {
     assert(_has_mutex());
@@ -997,10 +1023,9 @@
 
     abort_data_structures_from_segment_num(STM_SEGMENT->segment_num);
 
-    stm_jmpbuf_t *jmpbuf_ptr = STM_SEGMENT->jmpbuf_ptr;
+    stm_thread_local_t *tl = STM_SEGMENT->running_thread;
 
     /* clear memory registered on the thread-local */
-    stm_thread_local_t *tl = STM_SEGMENT->running_thread;
     if (tl->mem_clear_on_abort)
         memset(tl->mem_clear_on_abort, 0, tl->mem_bytes_to_clear_on_abort);
 
@@ -1036,9 +1061,11 @@
     */
     usleep(1);
 
-    assert(jmpbuf_ptr != NULL);
-    assert(jmpbuf_ptr != (stm_jmpbuf_t *)-1);    /* for tests only */
-    __builtin_longjmp(*jmpbuf_ptr, 1);
+#ifdef STM_NO_AUTOMATIC_SETJMP
+    _test_run_abort(tl);
+#else
+    rewind_jmp_longjmp(&tl->rjthread);
+#endif
 }
 
 void _stm_become_inevitable(const char *msg)
@@ -1052,12 +1079,11 @@
         marker_fetch_inev();
         wait_for_end_of_inevitable_transaction(NULL);
         STM_PSEGMENT->transaction_state = TS_INEVITABLE;
-        STM_SEGMENT->jmpbuf_ptr = NULL;
+        rewind_jmp_forget(&STM_SEGMENT->running_thread->rjthread);
         clear_callbacks_on_abort();
     }
     else {
         assert(STM_PSEGMENT->transaction_state == TS_INEVITABLE);
-        assert(STM_SEGMENT->jmpbuf_ptr == NULL);
     }
 
     s_mutex_unlock();
diff --git a/rpython/translator/stm/src_stm/stm/forksupport.c b/rpython/translator/stm/src_stm/stm/forksupport.c
--- a/rpython/translator/stm/src_stm/stm/forksupport.c
+++ b/rpython/translator/stm/src_stm/stm/forksupport.c
@@ -177,21 +177,25 @@
 static void fork_abort_thread(long i)
 {
     struct stm_priv_segment_info_s *pr = get_priv_segment(i);
+    stm_thread_local_t *tl = pr->pub.running_thread;
     dprintf(("forksupport_child: abort in seg%ld\n", i));
-    assert(pr->pub.running_thread->associated_segment_num == i);
+    assert(tl->associated_segment_num == i);
     assert(pr->transaction_state == TS_REGULAR);
     set_gs_register(get_segment_base(i));
 
-    stm_jmpbuf_t jmpbuf;
-    if (__builtin_setjmp(jmpbuf) == 0) {
-        pr->pub.jmpbuf_ptr = &jmpbuf;
+    rewind_jmp_buf rjbuf;
+    stm_rewind_jmp_enterframe(tl, &rjbuf);
+    if (rewind_jmp_setjmp(&tl->rjthread) == 0) {
 #ifndef NDEBUG
         pr->running_pthread = pthread_self();
 #endif
         pr->pub.running_thread->shadowstack = (
             pr->shadowstack_at_start_of_transaction);
+        strcpy(pr->marker_self, "fork");
         stm_abort_transaction();
     }
+    rewind_jmp_forget(&tl->rjthread);
+    stm_rewind_jmp_leaveframe(tl, &rjbuf);
 }
 
 static void forksupport_child(void)
diff --git a/rpython/translator/stm/src_stm/stm/gcpage.c b/rpython/translator/stm/src_stm/stm/gcpage.c
--- a/rpython/translator/stm/src_stm/stm/gcpage.c
+++ b/rpython/translator/stm/src_stm/stm/gcpage.c
@@ -525,17 +525,15 @@
     /* this is called by _stm_largemalloc_sweep() */
     object_t *obj = (object_t *)(data - stm_object_pages);
     if (!mark_visited_test_and_clear(obj)) {
-#ifndef NDEBUG
         /* This is actually needed in order to avoid random write-read
-           conflicts with objects read and freed long in the past. Still,
-           it is probably rare enough so that we don't need this additional
-           overhead. (test_random hits it sometimes) */
+           conflicts with objects read and freed long in the past.
+           It is probably rare enough, but still, we want to avoid any
+           false conflict. (test_random hits it sometimes) */
         long i;
         for (i = 1; i <= NB_SEGMENTS; i++) {
             ((struct stm_read_marker_s *)
              (get_segment_base(i) + (((uintptr_t)obj) >> 4)))->rm = 0;
         }
-#endif
         return false;
     }
     return true;
diff --git a/rpython/translator/stm/src_stm/stm/nursery.c b/rpython/translator/stm/src_stm/stm/nursery.c
--- a/rpython/translator/stm/src_stm/stm/nursery.c
+++ b/rpython/translator/stm/src_stm/stm/nursery.c
@@ -462,8 +462,10 @@
 
         TREE_LOOP_FORWARD(*pseg->young_outside_nursery, item) {
             object_t *obj = (object_t*)item->addr;
+            assert(!_is_in_nursery(obj));
 
-            /* mark slot as unread */
+            /* mark slot as unread (it can only have the read marker
+               in this segment) */
             ((struct stm_read_marker_s *)
              (pseg->pub.segment_base + (((uintptr_t)obj) >> 4)))->rm = 0;
 
diff --git a/rpython/translator/stm/src_stm/stmgc.c b/rpython/translator/stm/src_stm/stmgc.c
--- a/rpython/translator/stm/src_stm/stmgc.c
+++ b/rpython/translator/stm/src_stm/stmgc.c
@@ -37,3 +37,4 @@
 #include "stm/weakref.c"
 #include "stm/timing.c"
 #include "stm/marker.c"
+#include "stm/rewind_setjmp.c"
diff --git a/rpython/translator/stm/src_stm/stmgc.h b/rpython/translator/stm/src_stm/stmgc.h
--- a/rpython/translator/stm/src_stm/stmgc.h
+++ b/rpython/translator/stm/src_stm/stmgc.h
@@ -14,6 +14,8 @@
 #include <limits.h>
 #include <unistd.h>
 
+#include "stm/rewind_setjmp.h"
+
 #if LONG_MAX == 2147483647
 # error "Requires a 64-bit environment"
 #endif
@@ -26,7 +28,6 @@
 typedef TLPREFIX struct stm_read_marker_s stm_read_marker_t;
 typedef TLPREFIX struct stm_creation_marker_s stm_creation_marker_t;
 typedef TLPREFIX char stm_char;
-typedef void* stm_jmpbuf_t[5];  /* for use with __builtin_setjmp() */
 
 struct stm_read_marker_s {
     /* In every segment, every object has a corresponding read marker.
@@ -45,7 +46,6 @@
     stm_char *nursery_current;
     uintptr_t nursery_end;
     struct stm_thread_local_s *running_thread;
-    stm_jmpbuf_t *jmpbuf_ptr;
 };
 #define STM_SEGMENT           ((stm_segment_info_t *)4352)
 
@@ -80,6 +80,8 @@
 typedef struct stm_thread_local_s {
     /* every thread should handle the shadow stack itself */
     struct stm_shadowentry_s *shadowstack, *shadowstack_base;
+    /* rewind_setjmp's interface */
+    rewind_jmp_thread rjthread;
     /* a generic optional thread-local object */
     object_t *thread_local_obj;
     /* in case this thread runs a transaction that aborts,
@@ -115,7 +117,6 @@
 object_t *_stm_allocate_slowpath(ssize_t);
 object_t *_stm_allocate_external(ssize_t);
 void _stm_become_inevitable(const char*);
-void _stm_start_transaction(stm_thread_local_t *, stm_jmpbuf_t *);
 void _stm_collectable_safe_point(void);
 
 /* for tests, but also used in duhton: */
@@ -327,40 +328,42 @@
 void stm_register_thread_local(stm_thread_local_t *tl);
 void stm_unregister_thread_local(stm_thread_local_t *tl);
 
+/* At some key places, like the entry point of the thread and in the
+   function with the interpreter's dispatch loop, you need to declare
+   a local variable of type 'rewind_jmp_buf' and call these macros. */
+#define stm_rewind_jmp_enterframe(tl, rjbuf)       \
+    rewind_jmp_enterframe(&(tl)->rjthread, rjbuf)
+#define stm_rewind_jmp_leaveframe(tl, rjbuf)       \
+    rewind_jmp_leaveframe(&(tl)->rjthread, rjbuf)
+
 /* Starting and ending transactions.  stm_read(), stm_write() and
    stm_allocate() should only be called from within a transaction.
-   Use the macro STM_START_TRANSACTION() to start a transaction that
-   can be restarted using the 'jmpbuf' (a local variable of type
-   stm_jmpbuf_t). */
-#define STM_START_TRANSACTION(tl, jmpbuf)  ({                   \
-    while (__builtin_setjmp(jmpbuf) == 1) { /*redo setjmp*/ }   \
-    _stm_start_transaction(tl, &jmpbuf);                        \
-})
-
-/* Start an inevitable transaction, if it's going to return from the
-   current function immediately. */
-static inline void stm_start_inevitable_transaction(stm_thread_local_t *tl) {
-    _stm_start_transaction(tl, NULL);
-}
-
-/* Commit a transaction. */
+   The stm_start_transaction() call returns the number of times it
+   returned, starting at 0.  If it is > 0, then the transaction was
+   aborted and restarted this number of times. */
+long stm_start_transaction(stm_thread_local_t *tl);
+void stm_start_inevitable_transaction(stm_thread_local_t *tl);
 void stm_commit_transaction(void);
 
-/* Abort the currently running transaction. */
+/* Abort the currently running transaction.  This function never
+   returns: it jumps back to the stm_start_transaction(). */
 void stm_abort_transaction(void) __attribute__((noreturn));
 
-/* Turn the current transaction inevitable.  The 'jmpbuf' passed to
-   STM_START_TRANSACTION() is not going to be used any more after
-   this call (but the stm_become_inevitable() itself may still abort). */
+/* Turn the current transaction inevitable.
+   The stm_become_inevitable() itself may still abort. */
+#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_SEGMENT->jmpbuf_ptr != NULL)
+    if (!stm_is_inevitable())
         _stm_become_inevitable(msg);
 }
-static inline int stm_is_inevitable(void) {
-    return (STM_SEGMENT->jmpbuf_ptr == NULL);
-}
 
 /* Forces a safe-point if needed.  Normally not needed: this is
    automatic if you call stm_allocate(). */


More information about the pypy-commit mailing list