[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