Author: Armin Rigo <ar...@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 _______________________________________________ pypy-commit mailing list pypy-commit@python.org https://mail.python.org/mailman/listinfo/pypy-commit