[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