Author: Armin Rigo <[email protected]>
Branch: 
Changeset: r925:96659ea5511f
Date: 2014-03-02 18:43 +0100
http://bitbucket.org/pypy/stmgc/changeset/96659ea5511f/

Log:    Add "gil-c7", a small file that presents the same API to programs
        but is implemented with a GIL. It contains the minor collector but
        no major collector.

diff --git a/duhton/Makefile b/duhton/Makefile
--- a/duhton/Makefile
+++ b/duhton/Makefile
@@ -16,5 +16,14 @@
 duhton_debug: *.c *.h $(C7SOURCES) $(C7HEADERS)
        clang -DSTM_DEBUGPRINT -pthread -g -DDu_DEBUG -o duhton_debug *.c 
../c7/stmgc.c -Wall
 
+
+duhton_nostm: *.c *.h ../gil-c7/stmgc.?
+       clang -pthread -g -DNDEBUG -O2 -o duhton_nostm *.c ../gil-c7/stmgc.c 
-Wall  -DUSE_GIL
+
+
+duhton_debug_nostm: *.c *.h ../gil-c7/stmgc.?
+       clang -DSTM_DEBUGPRINT -pthread -g -DDu_DEBUG -o duhton_debug_nostm *.c 
../gil-c7/stmgc.c -Wall -DUSE_GIL -ferror-limit=1
+
+
 clean:
        rm -f duhton duhton_debug duhton_release
diff --git a/duhton/duhton.h b/duhton/duhton.h
--- a/duhton/duhton.h
+++ b/duhton/duhton.h
@@ -1,14 +1,18 @@
 #ifndef _DUHTON_H_
 #define _DUHTON_H_
 
+/* #undef USE_GIL */            /* forces "gil-c7" instead of "c7" */
+
 #include <stdio.h>
 #include <stdlib.h>
 #include <assert.h>
-#include "../c7/stmgc.h"
+#ifdef USE_GIL
+#  include "../gil-c7/stmgc.h"
+#else
+#  include "../c7/stmgc.h"
+#endif
 
-#define STM 1                   /* hackish removal of all read/write
-                                   barriers. synchronization is up to
-                                   the program */
+
 #define DEFAULT_NUM_THREADS 2
 
 extern __thread stm_thread_local_t stm_thread_local;
@@ -179,17 +183,8 @@
                                   p1 = (typeof(p1))_pop_root())
 
 
-#if STM
 #define _du_read1(p1)           stm_read((object_t *)(p1))
 #define _du_write1(p1)          stm_write((object_t *)(p1))
-#else
-#define _du_read1(p1)
-#define _du_write1(p1)          {                                       \
-    if (UNLIKELY(((object_t *)(p1))->stm_flags & GCFLAG_WRITE_BARRIER)) { \
-        LIST_APPEND(_STM_TL->old_objects_to_trace, ((object_t *)(p1))); \
-        ((object_t *)(p1))->stm_flags &= ~GCFLAG_WRITE_BARRIER;         \
-    }}
-#endif
 
 
 #ifndef NDEBUG
diff --git a/gil-c7/stmgc.c b/gil-c7/stmgc.c
new file mode 100644
--- /dev/null
+++ b/gil-c7/stmgc.c
@@ -0,0 +1,280 @@
+#include "stmgc.h"
+#include <string.h>
+#include <stdio.h>
+
+pthread_mutex_t _stm_gil = PTHREAD_MUTEX_INITIALIZER;
+stm_thread_local_t *_stm_tloc;
+
+
+/************************************************************/
+
+struct list_s {
+    uintptr_t count;
+    uintptr_t last_allocated;
+    uintptr_t items[];
+};
+
+static struct list_s *list_create(void);
+
+static inline void list_free(struct list_s *lst)
+{
+    free(lst);
+}
+
+#define LIST_FREE(lst)  (list_free(lst), (lst) = NULL)
+
+
+static struct list_s *_list_grow(struct list_s *, uintptr_t);
+
+static inline struct list_s *list_append(struct list_s *lst, uintptr_t item)
+{
+    uintptr_t index = lst->count++;
+    if (UNLIKELY(index > lst->last_allocated))
+        lst = _list_grow(lst, index);
+    lst->items[index] = item;
+    return lst;
+}
+
+#define LIST_APPEND(lst, e)   ((lst) = list_append((lst), (uintptr_t)(e)))
+
+
+__attribute__((unused))
+static inline void list_clear(struct list_s *lst)
+{
+    lst->count = 0;
+}
+
+static inline bool list_is_empty(struct list_s *lst)
+{
+    return (lst->count == 0);
+}
+
+__attribute__((unused))
+static inline uintptr_t list_count(struct list_s *lst)
+{
+    return lst->count;
+}
+
+static inline uintptr_t list_pop_item(struct list_s *lst)
+{
+    assert(lst->count > 0);
+    return lst->items[--lst->count];
+}
+
+__attribute__((unused))
+static inline uintptr_t list_item(struct list_s *lst, uintptr_t index)
+{
+    return lst->items[index];
+}
+
+__attribute__((unused))
+static inline void list_set_item(struct list_s *lst, uintptr_t index,
+                                 uintptr_t newitem)
+{
+    lst->items[index] = newitem;
+}
+
+#define LIST_FOREACH_R(lst, TYPE, CODE)         \
+    do {                                        \
+        struct list_s *_lst = (lst);            \
+        uintptr_t _i;                           \
+        for (_i = _lst->count; _i--; ) {        \
+            TYPE item = (TYPE)_lst->items[_i];  \
+            CODE;                               \
+        }                                       \
+    } while (0)
+
+#define LIST_SETSIZE(n)    (sizeof(struct list_s) + LIST_ITEMSSIZE(n))
+#define LIST_ITEMSSIZE(n)  ((n) * sizeof(uintptr_t))
+#define LIST_OVERCNT(n)    (33 + ((((n) / 2) * 3) | 1))
+
+static struct list_s *list_create(void)
+{
+    uintptr_t initial_allocation = 32;
+    struct list_s *lst = malloc(LIST_SETSIZE(initial_allocation));
+    if (lst == NULL)
+        abort();
+
+    lst->count = 0;
+    lst->last_allocated = initial_allocation - 1;
+    return lst;
+}
+
+static struct list_s *_list_grow(struct list_s *lst, uintptr_t nalloc)
+{
+    nalloc = LIST_OVERCNT(nalloc);
+    lst = realloc(lst, LIST_SETSIZE(nalloc));
+    if (lst == NULL)
+        abort();
+
+    lst->last_allocated = nalloc - 1;
+    return lst;
+}
+
+/************************************************************/
+
+#define GCFLAG_WRITE_BARRIER  _STM_GCFLAG_WRITE_BARRIER
+
+static struct list_s *objects_pointing_to_nursery;
+
+void stm_setup(void)
+{
+    objects_pointing_to_nursery = list_create();
+}
+
+void stm_teardown(void)
+{
+    list_free(objects_pointing_to_nursery);
+}
+
+void _stm_write_slowpath(object_t *obj)
+{
+    obj->gil_flags &= ~GCFLAG_WRITE_BARRIER;
+    LIST_APPEND(objects_pointing_to_nursery, obj);
+}
+
+object_t *_stm_allocate_old(ssize_t size)
+{
+    char *p = malloc(size);
+    assert(p);
+    memset(p, 0, size);
+    ((object_t *)p)->gil_flags = STM_FLAGS_PREBUILT;
+    return (object_t *)p;
+}
+
+object_t *_stm_allocate_external(ssize_t size)
+{
+    char *p = malloc(size);
+    assert(p);
+    memset(p, 0, size);
+    _stm_write_slowpath((object_t *)p);
+    return (object_t *)p;
+}
+
+/************************************************************/
+
+
+#define NB_NURSERY_PAGES    1024          // 4MB
+#define NURSERY_SIZE        (NB_NURSERY_PAGES * 4096UL)
+
+char *_stm_nursery_base    = NULL;
+char *_stm_nursery_current = NULL;
+char *_stm_nursery_end     = NULL;
+
+static bool _is_in_nursery(object_t *obj)
+{
+    return ((char *)obj >= _stm_nursery_base &&
+            (char *)obj < _stm_nursery_end);
+}
+
+#define GCWORD_MOVED  ((object_t *) -42)
+
+static void minor_trace_if_young(object_t **pobj)
+{
+    object_t *obj = *pobj;
+    object_t *nobj;
+
+    if (obj == NULL)
+        return;
+
+    if (_is_in_nursery(obj)) {
+        /* If the object was already seen here, its first word was set
+           to GCWORD_MOVED.  In that case, the forwarding location, i.e.
+           where the object moved to, is stored in the second word in 'obj'. */
+        object_t *TLPREFIX *pforwarded_array = (object_t *TLPREFIX *)obj;
+
+        if (pforwarded_array[0] == GCWORD_MOVED) {
+            *pobj = pforwarded_array[1];    /* already moved */
+            return;
+        }
+
+        /* We need to make a copy of this object.
+         */
+        size_t size = stmcb_size_rounded_up(obj);
+
+        nobj = malloc(size);
+        assert(nobj);
+
+        /* Copy the object  */
+        memcpy(nobj, obj, size);
+
+        /* Done copying the object. */
+        //dprintf(("\t\t\t\t\t%p -> %p\n", obj, nobj));
+        pforwarded_array[0] = GCWORD_MOVED;
+        pforwarded_array[1] = nobj;
+        *pobj = nobj;
+    }
+
+    else {
+        /* The object was not in the nursery at all */
+        return;
+    }
+
+    /* Must trace the object later */
+    LIST_APPEND(objects_pointing_to_nursery, nobj);
+}
+
+static void collect_roots_in_nursery(void)
+{
+    object_t **current = _stm_tloc->shadowstack;
+    object_t **base = _stm_tloc->shadowstack_base;
+    while (current-- != base) {
+        minor_trace_if_young(current);
+    }
+    minor_trace_if_young(&_stm_tloc->thread_local_obj);
+}
+
+static inline void _collect_now(object_t *obj)
+{
+    assert(!_is_in_nursery(obj));
+
+    /* We must not have GCFLAG_WRITE_BARRIER so far.  Add it now. */
+    assert(!(obj->gil_flags & GCFLAG_WRITE_BARRIER));
+    obj->gil_flags |= GCFLAG_WRITE_BARRIER;
+
+    /* Trace the 'obj' to replace pointers to nursery with pointers
+       outside the nursery, possibly forcing nursery objects out and
+       adding them to 'objects_pointing_to_nursery' as well. */
+    stmcb_trace(obj, &minor_trace_if_young);
+}
+
+static void collect_oldrefs_to_nursery(void)
+{
+    struct list_s *lst = objects_pointing_to_nursery;
+
+    while (!list_is_empty(lst)) {
+        object_t *obj = (object_t *)list_pop_item(lst);
+
+        _collect_now(obj);
+
+        /* the list could have moved while appending */
+        lst = objects_pointing_to_nursery;
+    }
+}
+
+static void throw_away_nursery(void)
+{
+    if (_stm_nursery_base == NULL) {
+        _stm_nursery_base = malloc(NURSERY_SIZE);
+        assert(_stm_nursery_base);
+        _stm_nursery_end = _stm_nursery_base + NURSERY_SIZE;
+    }
+
+    _stm_nursery_current = _stm_nursery_base;
+    memset(_stm_nursery_base, 0, NURSERY_SIZE);
+}
+
+object_t *_stm_allocate_slowpath(ssize_t size_rounded_up)
+{
+    /* run minor collection */
+    //fprintf(stderr, "minor collect\n");
+    collect_roots_in_nursery();
+    collect_oldrefs_to_nursery();
+    throw_away_nursery();
+
+    char *p = _stm_nursery_current;
+    char *end = p + size_rounded_up;
+    assert(end <= _stm_nursery_end);
+    _stm_nursery_current = end;
+    return (object_t *)p;
+}
diff --git a/gil-c7/stmgc.h b/gil-c7/stmgc.h
new file mode 100644
--- /dev/null
+++ b/gil-c7/stmgc.h
@@ -0,0 +1,105 @@
+#include <stddef.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <assert.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <pthread.h>
+
+#define TLPREFIX    /* nothing */
+
+
+typedef struct { /* empty */ } stm_jmpbuf_t;
+
+typedef struct object_s {
+    uint32_t gil_flags;
+} object_t;
+
+typedef struct {
+    object_t **shadowstack;
+    object_t **shadowstack_base;
+    object_t *thread_local_obj;
+}  stm_thread_local_t;
+
+extern stm_thread_local_t *_stm_tloc;
+extern char *_stm_nursery_current, *_stm_nursery_end;
+
+#ifdef NDEBUG
+#define OPT_ASSERT(cond) do { if (!(cond)) __builtin_unreachable(); } while (0)
+#else
+#define OPT_ASSERT(cond) assert(cond)
+#endif
+#define UNLIKELY(x) __builtin_expect(x, false)
+
+#define _STM_GCFLAG_WRITE_BARRIER      0x01
+#define _STM_FAST_ALLOC           (66*1024)
+#define STM_FLAGS_PREBUILT   _STM_GCFLAG_WRITE_BARRIER
+
+
+object_t *_stm_allocate_old(ssize_t size);
+
+object_t *_stm_allocate_external(ssize_t);
+object_t *_stm_allocate_slowpath(ssize_t);
+
+inline static object_t *stm_allocate(ssize_t size_rounded_up) {
+    OPT_ASSERT(size_rounded_up >= 16);
+    OPT_ASSERT((size_rounded_up & 7) == 0);
+
+    if (UNLIKELY(size_rounded_up >= _STM_FAST_ALLOC))
+        return _stm_allocate_external(size_rounded_up);
+
+    char *p = _stm_nursery_current;
+    char *end = p + size_rounded_up;
+    _stm_nursery_current = end;
+    if (UNLIKELY(end > _stm_nursery_end))
+        return _stm_allocate_slowpath(size_rounded_up);
+
+    return (object_t *)p;
+}
+
+inline static void stm_register_thread_local(stm_thread_local_t *tl) {
+    tl->thread_local_obj = NULL;
+    tl->shadowstack_base = (object_t **)malloc(768*1024);
+    assert(tl->shadowstack_base);
+    tl->shadowstack = tl->shadowstack_base;
+}
+inline static void stm_unregister_thread_local(stm_thread_local_t *tl) {
+    free(tl->shadowstack_base);
+}
+
+extern pthread_mutex_t _stm_gil;
+
+void stm_setup(void);
+void stm_teardown(void);
+
+inline static void stm_start_inevitable_transaction(stm_thread_local_t *tl) {
+    if (pthread_mutex_lock(&_stm_gil) != 0) abort();
+    _stm_tloc = tl;
+}
+inline static void stm_commit_transaction(void) {
+    _stm_tloc = NULL;
+    if (pthread_mutex_unlock(&_stm_gil) != 0) abort();
+}
+inline static void stm_become_inevitable(const char *msg) { }
+inline static void stm_read(object_t *ob) { }
+
+void _stm_write_slowpath(object_t *);
+
+inline static void stm_write(object_t *ob) {
+    if (UNLIKELY(ob->gil_flags & _STM_GCFLAG_WRITE_BARRIER))
+        _stm_write_slowpath(ob);
+}
+
+inline static char *_stm_real_address(object_t *ob) { return (char *)ob; }
+
+#define STM_START_TRANSACTION(tl, here)   do {  \
+    (void)&(here);                              \
+    stm_start_inevitable_transaction(tl);       \
+} while (0)
+
+#define STM_PUSH_ROOT(tl, p)   (*((tl).shadowstack++) = (object_t *)(p))
+#define STM_POP_ROOT(tl, p)    ((p) = (typeof(p))*(--(tl).shadowstack))
+
+
+extern ssize_t stmcb_size_rounded_up(struct object_s *);
+extern void stmcb_trace(struct object_s *, void (object_t **));
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to