[pypy-commit] stmgc rewind_setjmp: Adapt the API for rewind_jmpbuf.
arigo
noreply at buildbot.pypy.org
Sat Aug 9 16:14:14 CEST 2014
Author: Armin Rigo <arigo at tunes.org>
Branch: rewind_setjmp
Changeset: r1276:327596f0760e
Date: 2014-08-09 16:04 +0200
http://bitbucket.org/pypy/stmgc/changeset/327596f0760e/
Log: Adapt the API for rewind_jmpbuf.
diff --git a/c7/stm/rewind_setjmp.c b/c7/stm/rewind_setjmp.c
new file mode 100644
--- /dev/null
+++ b/c7/stm/rewind_setjmp.c
@@ -0,0 +1,109 @@
+#include "rewind_setjmp.h"
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include <alloca.h>
+
+
+struct _rewind_jmp_moved_s {
+ struct _rewind_jmp_moved_s *next;
+ size_t size;
+};
+#define RJM_HEADER sizeof(struct _rewind_jmp_moved_s)
+
+#ifndef RJBUF_CUSTOM_MALLOC
+#define rj_malloc malloc
+#define rj_free free
+#else
+void *rj_malloc(size_t);
+void rj_free(void *);
+#endif
+
+
+static void copy_stack(rewind_jmp_thread *rjthread, char *base)
+{
+ char *stop = rjthread->head->frame_base;
+ assert(stop > base);
+ struct _rewind_jmp_moved_s *next = (struct _rewind_jmp_moved_s *)
+ rj_malloc(RJM_HEADER + (stop - base));
+ assert(next != NULL); /* XXX out of memory */
+ next->next = rjthread->moved_off;
+ next->size = stop - base;
+ memcpy(((char *)next) + RJM_HEADER, base, stop - base);
+
+ rjthread->moved_off_base = stop;
+ rjthread->moved_off = next;
+}
+
+__attribute__((noinline))
+int rewind_jmp_setjmp(rewind_jmp_thread *rjthread)
+{
+ if (rjthread->moved_off) {
+ _rewind_jmp_free_stack_slices(rjthread);
+ }
+ rewind_jmp_thread *volatile rjthread1 = rjthread;
+ int result;
+ if (__builtin_setjmp(rjthread->jmpbuf) == 0) {
+ rjthread = rjthread1;
+ rjthread->initial_head = rjthread->head;
+ result = 0;
+ }
+ else {
+ rjthread = rjthread1;
+ rjthread->head = rjthread->initial_head;
+ result = 1;
+ }
+ copy_stack(rjthread, (char *)&rjthread1);
+ return result;
+}
+
+__attribute__((noinline))
+static void do_longjmp(rewind_jmp_thread *rjthread, char *stack_free)
+{
+ assert(rjthread->moved_off_base != NULL);
+
+ while (rjthread->moved_off) {
+ struct _rewind_jmp_moved_s *p = rjthread->moved_off;
+ char *target = rjthread->moved_off_base;
+ target -= p->size;
+ if (target < stack_free) {
+ /* need more stack space! */
+ do_longjmp(rjthread, alloca(stack_free - target));
+ }
+ memcpy(target, ((char *)p) + RJM_HEADER, p->size);
+ rjthread->moved_off_base = target;
+ rjthread->moved_off = p->next;
+ rj_free(p);
+ }
+ __builtin_longjmp(rjthread->jmpbuf, 1);
+}
+
+void rewind_jmp_longjmp(rewind_jmp_thread *rjthread)
+{
+ char _rewind_jmp_marker;
+ do_longjmp(rjthread, &_rewind_jmp_marker);
+}
+
+__attribute__((noinline))
+void _rewind_jmp_copy_stack_slice(rewind_jmp_thread *rjthread)
+{
+ if (rjthread->head == NULL) {
+ _rewind_jmp_free_stack_slices(rjthread);
+ return;
+ }
+ assert(rjthread->moved_off_base < (char *)rjthread->head);
+ copy_stack(rjthread, rjthread->moved_off_base);
+}
+
+void _rewind_jmp_free_stack_slices(rewind_jmp_thread *rjthread)
+{
+ struct _rewind_jmp_moved_s *p = rjthread->moved_off;
+ struct _rewind_jmp_moved_s *pnext;
+ while (p) {
+ pnext = p->next;
+ rj_free(p);
+ p = pnext;
+ }
+ rjthread->moved_off = NULL;
+ rjthread->moved_off_base = NULL;
+}
diff --git a/c7/stm/rewind_setjmp.h b/c7/stm/rewind_setjmp.h
new file mode 100644
--- /dev/null
+++ b/c7/stm/rewind_setjmp.h
@@ -0,0 +1,79 @@
+#ifndef _REWIND_SETJMP_H_
+#define _REWIND_SETJMP_H_
+
+/************************************************************
+
+ : : ^^^^^
+ |-------------------| older frames in the stack
+ | prev=0 |
+ ,---> | rewind_jmp_buf |
+ | |-------------------|
+ | | |
+ | : :
+ | : :
+ | | |
+ | |-------------------|
+ `---------prev |
+ ,----> | rewind_jmp_buf |
+ | +-------------------|
+ | | |
+ | : :
+ | | |
+ | |-------------------|
+ `----------prev |
+ ,---> | rewind_jmp_buf | <--------------- MOVED_OFF_BASE
+ | |---------------- +-------------+
+ | | | STACK COPY |
+ | | : :
+ | : | size |
+ | | | next | <---- MOVED_OFF
+ | | +---|------ +-------------+
+ | | | | | STACK COPY |
+ | |-------------------| | : (SEQUEL) :
+ `---------prev | | : :
+HEAD-----> | rewind_jmp_buf | | | |
+ |-------------------| | | size |
+ `------> | next=0 |
+ +-------------+
+
+
+************************************************************/
+
+typedef struct _rewind_jmp_buf {
+ char *frame_base;
+ struct _rewind_jmp_buf *prev;
+} rewind_jmp_buf;
+
+typedef struct {
+ rewind_jmp_buf *head;
+ rewind_jmp_buf *initial_head;
+ char *moved_off_base;
+ struct _rewind_jmp_moved_s *moved_off;
+ void *jmpbuf[5];
+} rewind_jmp_thread;
+
+
+#define rewind_jmp_enterframe(rjthread, rjbuf) do { \
+ (rjbuf)->frame_base = __builtin_frame_address(0); \
+ (rjbuf)->prev = (rjthread)->head; \
+ (rjthread)->head = (rjbuf); \
+} while (0)
+
+#define rewind_jmp_leaveframe(rjthread, rjbuf) do { \
+ (rjthread)->head = (rjbuf)->prev; \
+ if ((rjbuf)->frame_base == (rjthread)->moved_off_base) \
+ _rewind_jmp_copy_stack_slice(rjthread); \
+} while (0)
+
+int rewind_jmp_setjmp(rewind_jmp_thread *rjthread);
+void rewind_jmp_longjmp(rewind_jmp_thread *rjthread);
+
+#define rewind_jmp_forget(rjthread) do { \
+ if ((rjthread)->moved_off) _rewind_jmp_free_stack_slices(rjthread); \
+ (rjthread)->moved_off_base = 0; \
+} while (0)
+
+void _rewind_jmp_copy_stack_slice(rewind_jmp_thread *);
+void _rewind_jmp_free_stack_slices(rewind_jmp_thread *);
+
+#endif
diff --git a/c7/stmgc.h b/c7/stmgc.h
--- a/c7/stmgc.h
+++ b/c7/stmgc.h
@@ -13,6 +13,8 @@
#include <limits.h>
#include <unistd.h>
+#include "stm/rewind_setjmp.h"
+
#if LONG_MAX == 2147483647
# error "Requires a 64-bit environment"
#endif
@@ -25,7 +27,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.
@@ -44,7 +45,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)
@@ -77,6 +77,7 @@
#define _STM_MARKER_LEN 80
typedef struct stm_thread_local_s {
+ rewind_jmp_thread rjthread;
/* every thread should handle the shadow stack itself */
struct stm_shadowentry_s *shadowstack, *shadowstack_base;
/* a generic optional thread-local object */
@@ -114,7 +115,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: */
@@ -326,39 +326,38 @@
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_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. */
static inline void stm_become_inevitable(stm_thread_local_t *tl,
const char* msg) {
+ abort();/* XXX
assert(STM_SEGMENT->running_thread == tl);
if (STM_SEGMENT->jmpbuf_ptr != NULL)
- _stm_become_inevitable(msg);
+ _stm_become_inevitable(msg);*/
}
static inline int stm_is_inevitable(void) {
- return (STM_SEGMENT->jmpbuf_ptr == NULL);
+ return 0; /* XXX
+ return (STM_SEGMENT->jmpbuf_ptr == NULL); */
}
/* Forces a safe-point if needed. Normally not needed: this is
More information about the pypy-commit
mailing list