[pypy-commit] pypy stmgc-c7-rewindjmp: Forgot to add these files
arigo
noreply at buildbot.pypy.org
Thu Aug 14 16:22:16 CEST 2014
Author: Armin Rigo <arigo at tunes.org>
Branch: stmgc-c7-rewindjmp
Changeset: r72802:52e94842f3f8
Date: 2014-08-14 16:21 +0200
http://bitbucket.org/pypy/pypy/changeset/52e94842f3f8/
Log: Forgot to add these files
diff --git a/rpython/translator/stm/src_stm/stm/rewind_setjmp.c b/rpython/translator/stm/src_stm/stm/rewind_setjmp.c
new file mode 100644
--- /dev/null
+++ b/rpython/translator/stm/src_stm/stm/rewind_setjmp.c
@@ -0,0 +1,208 @@
+/* Imported by rpython/translator/stm/import_stmgc.py */
+#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 stack_size;
+ size_t shadowstack_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, void *ssbase)
+{
+ /* Copy away part of the stack and shadowstack. Sets moved_off_base to
+ the current frame_base.
+
+ The stack is copied between 'base' (lower limit, i.e. newest bytes)
+ and 'rjthread->head->frame_base' (upper limit, i.e. oldest bytes).
+ The shadowstack is copied between 'ssbase' (upper limit, newest)
+ and 'rjthread->head->shadowstack_base' (lower limit, oldest).
+ */
+ struct _rewind_jmp_moved_s *next;
+ char *stop;
+ void *ssstop;
+ size_t stack_size, ssstack_size;
+
+ assert(rjthread->head != NULL);
+ stop = rjthread->head->frame_base;
+ ssstop = rjthread->head->shadowstack_base;
+ assert(stop >= base);
+ assert(ssstop <= ssbase);
+ stack_size = stop - base;
+ ssstack_size = ssbase - ssstop;
+
+ next = (struct _rewind_jmp_moved_s *)
+ rj_malloc(RJM_HEADER + stack_size + ssstack_size);
+ assert(next != NULL); /* XXX out of memory */
+ next->next = rjthread->moved_off;
+ next->stack_size = stack_size;
+ next->shadowstack_size = ssstack_size;
+
+ memcpy(((char *)next) + RJM_HEADER, base, stack_size);
+ memcpy(((char *)next) + RJM_HEADER + stack_size, ssstop,
+ ssstack_size);
+
+ rjthread->moved_off_base = stop;
+ rjthread->moved_off_ssbase = ssstop;
+ rjthread->moved_off = next;
+}
+
+__attribute__((noinline))
+long rewind_jmp_setjmp(rewind_jmp_thread *rjthread, void *ss)
+{
+ /* saves the current stack frame to the list of slices and
+ calls setjmp(). It returns the number of times a longjmp()
+ jumped back to this setjmp() */
+ if (rjthread->moved_off) {
+ /* old stack slices are not needed anymore (next longjmp()
+ will restore only to this setjmp()) */
+ _rewind_jmp_free_stack_slices(rjthread);
+ }
+ /* all locals of this function that need to be saved and restored
+ across the setjmp() should be stored inside this structure */
+ struct { void *ss1; rewind_jmp_thread *rjthread1; } volatile saved =
+ { ss, rjthread };
+
+ int result;
+ if (__builtin_setjmp(rjthread->jmpbuf) == 0) {
+ rjthread = saved.rjthread1;
+ rjthread->initial_head = rjthread->head;
+ result = 0;
+ }
+ else {
+ rjthread = saved.rjthread1;
+ rjthread->head = rjthread->initial_head;
+ result = rjthread->repeat_count + 1;
+ }
+ rjthread->repeat_count = result;
+
+ /* snapshot of top frame: needed every time because longjmp() frees
+ the previous one. Note that this function is called with the
+ mutex already acquired. Although it's not the job of this file,
+ we assert it is indeed acquired here. This is needed, otherwise a
+ concurrent GC may get garbage while saving shadow stack */
+#ifdef _STM_CORE_H_
+ assert(_has_mutex());
+#endif
+ copy_stack(rjthread, (char *)&saved, saved.ss1);
+
+ return result;
+}
+
+__attribute__((noinline, noreturn))
+static void do_longjmp(rewind_jmp_thread *rjthread, char *stack_free)
+{
+ /* go through list of copied stack-slices and copy them back to the
+ current stack, expanding it if necessary. The shadowstack should
+ already be restored at this point (restore_shadowstack()) */
+ 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;
+ /* CPU stack grows downwards: */
+ target -= p->stack_size;
+ if (target < stack_free) {
+ /* need more stack space! */
+ do_longjmp(rjthread, alloca(stack_free - target));
+ abort(); /* unreachable */
+ }
+ memcpy(target, ((char *)p) + RJM_HEADER, p->stack_size);
+
+ rjthread->moved_off_base = target;
+ rjthread->moved_off = p->next;
+ rj_free(p);
+ }
+
+#ifdef _STM_CORE_H_
+ /* This function must be called with the mutex held. It will
+ remain held across the longjmp that follows and into the
+ target rewind_jmp_setjmp() function. */
+ assert(_has_mutex());
+#endif
+ __builtin_longjmp(rjthread->jmpbuf, 1);
+}
+
+__attribute__((noreturn))
+void rewind_jmp_longjmp(rewind_jmp_thread *rjthread)
+{
+ char _rewind_jmp_marker;
+ do_longjmp(rjthread, &_rewind_jmp_marker);
+}
+
+
+char *rewind_jmp_enum_shadowstack(rewind_jmp_thread *rjthread,
+ void *callback(void *, const void *, size_t))
+{
+ /* enumerate all saved shadow-stack slices */
+ struct _rewind_jmp_moved_s *p = rjthread->moved_off;
+ char *sstarget = rjthread->moved_off_ssbase;
+
+#ifdef _STM_CORE_H_
+ assert(_has_mutex());
+#endif
+
+ while (p) {
+ if (p->shadowstack_size) {
+ void *ss_slice = ((char *)p) + RJM_HEADER + p->stack_size;
+ callback(sstarget, ss_slice, p->shadowstack_size);
+
+ sstarget += p->shadowstack_size;
+ }
+ p = p->next;
+ }
+ return sstarget;
+}
+
+
+char *rewind_jmp_restore_shadowstack(rewind_jmp_thread *rjthread)
+{
+ return rewind_jmp_enum_shadowstack(rjthread, memcpy);
+}
+
+__attribute__((noinline))
+void _rewind_jmp_copy_stack_slice(rewind_jmp_thread *rjthread)
+{
+ /* called when leaving a frame. copies the now-current frame
+ to the list of stack-slices */
+#ifdef _STM_CORE_H_
+ /* A transaction should be running now. This means in particular
+ that it's not possible that a major GC runs concurrently with
+ this code (and tries to read the shadowstack slice). */
+ assert(_seems_to_be_running_transaction());
+#endif
+ 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, rjthread->moved_off_ssbase);
+}
+
+void _rewind_jmp_free_stack_slices(rewind_jmp_thread *rjthread)
+{
+ /* frees all saved stack copies */
+ struct _rewind_jmp_moved_s *p = rjthread->moved_off;
+ while (p) {
+ struct _rewind_jmp_moved_s *pnext = p->next;
+ rj_free(p);
+ p = pnext;
+ }
+ rjthread->moved_off = NULL;
+ rjthread->moved_off_base = NULL;
+ rjthread->moved_off_ssbase = NULL;
+}
diff --git a/rpython/translator/stm/src_stm/stm/rewind_setjmp.h b/rpython/translator/stm/src_stm/stm/rewind_setjmp.h
new file mode 100644
--- /dev/null
+++ b/rpython/translator/stm/src_stm/stm/rewind_setjmp.h
@@ -0,0 +1,109 @@
+/* Imported by rpython/translator/stm/import_stmgc.py */
+#ifndef _REWIND_SETJMP_H_
+#define _REWIND_SETJMP_H_
+
+
+#include <stddef.h>
+
+/************************************************************
+There is a singly-linked list of frames in each thread
+rjthread->head->prev->prev->prev
+
+Another singly-linked list is the list of copied stack-slices.
+When doing a setjmp(), we copy the top-frame, free all old
+stack-slices, and link it to the top-frame->moved_off.
+When returning from the top-frame while moved_off still points
+to a slice, we also need to copy the top-frame->prev frame/slice
+and add it to this list (pointed to by moved_off).
+--------------------------------------------------------------
+
+ : : ^^^^^
+ |-------------------| 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;
+ char *shadowstack_base;
+ struct _rewind_jmp_buf *prev;
+} rewind_jmp_buf;
+
+typedef struct {
+ rewind_jmp_buf *head;
+ rewind_jmp_buf *initial_head;
+ char *moved_off_base;
+ char *moved_off_ssbase;
+ struct _rewind_jmp_moved_s *moved_off;
+ void *jmpbuf[5];
+ long repeat_count;
+} rewind_jmp_thread;
+
+
+/* remember the current stack and ss_stack positions */
+#define rewind_jmp_enterframe(rjthread, rjbuf, ss) do { \
+ (rjbuf)->frame_base = __builtin_frame_address(0); \
+ (rjbuf)->shadowstack_base = (char *)(ss); \
+ (rjbuf)->prev = (rjthread)->head; \
+ (rjthread)->head = (rjbuf); \
+} while (0)
+
+/* go up one frame. if there was a setjmp call in this frame,
+ */
+#define rewind_jmp_leaveframe(rjthread, rjbuf, ss) do { \
+ assert((rjbuf)->shadowstack_base == (char *)(ss)); \
+ (rjthread)->head = (rjbuf)->prev; \
+ if ((rjbuf)->frame_base == (rjthread)->moved_off_base) { \
+ assert((rjthread)->moved_off_ssbase == (char *)(ss));\
+ _rewind_jmp_copy_stack_slice(rjthread); \
+ } \
+} while (0)
+
+long rewind_jmp_setjmp(rewind_jmp_thread *rjthread, void *ss);
+void rewind_jmp_longjmp(rewind_jmp_thread *rjthread) __attribute__((noreturn));
+char *rewind_jmp_restore_shadowstack(rewind_jmp_thread *rjthread);
+char *rewind_jmp_enum_shadowstack(rewind_jmp_thread *rjthread,
+ void *callback(void *, const void *, size_t));
+
+#define rewind_jmp_forget(rjthread) do { \
+ if ((rjthread)->moved_off) _rewind_jmp_free_stack_slices(rjthread); \
+ (rjthread)->moved_off_base = 0; \
+ (rjthread)->moved_off_ssbase = 0; \
+} while (0)
+
+void _rewind_jmp_copy_stack_slice(rewind_jmp_thread *);
+void _rewind_jmp_free_stack_slices(rewind_jmp_thread *);
+
+#define rewind_jmp_armed(rjthread) ((rjthread)->moved_off_base != 0)
+
+#endif
More information about the pypy-commit
mailing list