Author: Remi Meier <remi.me...@inf.ethz.ch>
Branch: 
Changeset: r1381:9adaf26befd4
Date: 2014-09-10 13:24 +0200
http://bitbucket.org/pypy/stmgc/changeset/9adaf26befd4/

Log:    fix some demos and some bugs

diff --git a/c8/demo/Makefile b/c8/demo/Makefile
new file mode 100644
--- /dev/null
+++ b/c8/demo/Makefile
@@ -0,0 +1,36 @@
+#
+# Makefile for the demos.
+#
+
+DEBUG_EXE = debug-demo2
+BUILD_EXE = build-demo2
+RELEASE_EXE = release-demo2
+
+debug: $(DEBUG_EXE)       # with prints and asserts
+build: $(BUILD_EXE)       # without prints, but with asserts
+release: $(RELEASE_EXE)   # without prints nor asserts
+
+clean:
+       rm -f $(BUILD_EXE) $(DEBUG_EXE) $(RELEASE_EXE)
+
+
+H_FILES = ../stmgc.h ../stm/*.h
+C_FILES = ../stmgc.c ../stm/*.c
+
+COMMON = -I.. -pthread -lrt -g -Wall -Werror -DSTM_LARGEMALLOC_TEST 
+
+
+# note that 'build' is partially optimized but still contains all asserts
+debug-%: %.c ${H_FILES} ${C_FILES}
+       clang $(COMMON) -DSTM_DEBUGPRINT -DSTM_GC_NURSERY=128 -O0 \
+        $< -o debug-$* ../stmgc.c
+
+build-%: %.c ${H_FILES} ${C_FILES}
+       clang $(COMMON) -DSTM_GC_NURSERY=128 -O1 $< -o build-$* ../stmgc.c
+
+release-%: %.c ${H_FILES} ${C_FILES}
+       clang $(COMMON) -DNDEBUG -O2 $< -o release-$* ../stmgc.c
+
+
+release-htm-%: %.c ../../htm-c7/stmgc.? ../../htm-c7/htm.h
+       clang $(COMMON) -O2 $< -o release-htm-$* ../../htm-c7/stmgc.c -DUSE_HTM
diff --git a/c8/demo/demo2.c b/c8/demo/demo2.c
new file mode 100644
--- /dev/null
+++ b/c8/demo/demo2.c
@@ -0,0 +1,322 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include <assert.h>
+#include <pthread.h>
+#include <semaphore.h>
+
+#ifdef USE_HTM
+#  include "../../htm-c7/stmgc.h"
+#else
+#  include "stmgc.h"
+#endif
+
+#define LIST_LENGTH 4000
+#define NTHREADS    2
+
+#ifdef USE_HTM
+#  define BUNCH       200
+#else
+#  define BUNCH       200
+#endif
+
+typedef TLPREFIX struct node_s node_t;
+typedef node_t* nodeptr_t;
+typedef object_t* objptr_t;
+
+struct node_s {
+    struct object_s hdr;
+    long value;
+    nodeptr_t next;
+};
+
+__thread stm_thread_local_t stm_thread_local;
+
+
+ssize_t stmcb_size_rounded_up(struct object_s *ob)
+{
+    return sizeof(struct node_s);
+}
+
+void stmcb_trace(struct object_s *obj, void visit(object_t **))
+{
+    struct node_s *n;
+    n = (struct node_s*)obj;
+    visit((object_t **)&n->next);
+}
+long stmcb_obj_supports_cards(struct object_s *obj)
+{
+    return 0;
+}
+void stmcb_get_card_base_itemsize(struct object_s *obj,
+                                  uintptr_t offset_itemsize[2])
+{
+    abort();
+}
+void stmcb_trace_cards(struct object_s *obj, void visit(object_t **),
+                       uintptr_t start, uintptr_t stop)
+{
+    abort();
+}
+void stmcb_commit_soon() {}
+
+static void expand_marker(char *base, uintptr_t odd_number,
+                          object_t *following_object,
+                          char *outputbuf, size_t outputbufsize)
+{
+    assert(following_object == NULL);
+    snprintf(outputbuf, outputbufsize, "<%p %lu>", base, odd_number);
+}
+
+
+nodeptr_t global_chained_list;
+
+
+long check_sorted(void)
+{
+    nodeptr_t r_n;
+    long prev, sum;
+
+    stm_start_transaction(&stm_thread_local);
+
+    stm_read((objptr_t)global_chained_list);
+    r_n = global_chained_list;
+    assert(r_n->value == -1);
+
+    prev = -1;
+    sum = 0;
+    while (r_n->next) {
+        r_n = r_n->next;
+        stm_read((objptr_t)r_n);
+        sum += r_n->value;
+
+        stm_safe_point();
+        if (prev >= r_n->value) {
+            stm_commit_transaction();
+            return -1;
+        }
+
+        prev = r_n->value;
+    }
+
+    stm_commit_transaction();
+    return sum;
+}
+
+nodeptr_t swap_nodes(nodeptr_t initial)
+{
+    assert(initial != NULL);
+
+    stm_start_transaction(&stm_thread_local);
+
+    if (stm_thread_local.longest_marker_state != 0) {
+        fprintf(stderr, "[%p] marker %d for %.6f seconds:\n",
+                &stm_thread_local,
+                stm_thread_local.longest_marker_state,
+                stm_thread_local.longest_marker_time);
+        fprintf(stderr, "\tself:\t\"%s\"\n\tother:\t\"%s\"\n",
+                stm_thread_local.longest_marker_self,
+                stm_thread_local.longest_marker_other);
+        stm_thread_local.longest_marker_state = 0;
+        stm_thread_local.longest_marker_time = 0.0;
+    }
+
+    nodeptr_t prev = initial;
+    stm_read((objptr_t)prev);
+
+    int i;
+    for (i=0; i<BUNCH; i++) {
+        nodeptr_t current = prev->next;
+        if (current == NULL) {
+            stm_commit_transaction();
+            return NULL;
+        }
+        stm_read((objptr_t)current);
+        nodeptr_t next = current->next;
+        if (next == NULL) {
+            stm_commit_transaction();
+            return NULL;
+        }
+        stm_read((objptr_t)next);
+
+        if (next->value < current->value) {
+            stm_write((objptr_t)prev);
+            stm_write((objptr_t)current);
+            stm_write((objptr_t)next);
+
+            prev->next = next;
+            current->next = next->next;
+            next->next = current;
+
+            stm_safe_point();
+        }
+        prev = current;
+    }
+
+    stm_commit_transaction();
+    return prev;
+}
+
+
+
+void bubble_run(void)
+{
+    nodeptr_t r_current;
+
+    r_current = global_chained_list;
+    while (r_current) {
+        r_current = swap_nodes(r_current);
+    }
+}
+
+
+/* initialize list with values in decreasing order */
+void setup_list(void)
+{
+    int i;
+    nodeptr_t w_newnode, w_prev;
+
+    stm_start_inevitable_transaction(&stm_thread_local);
+
+    global_chained_list = (nodeptr_t)stm_allocate(sizeof(struct node_s));
+    global_chained_list->value = -1;
+    global_chained_list->next = NULL;
+
+    STM_PUSH_ROOT(stm_thread_local, global_chained_list);
+
+    w_prev = global_chained_list;
+    for (i = 0; i < LIST_LENGTH; i++) {
+        STM_PUSH_ROOT(stm_thread_local, w_prev);
+        w_newnode = (nodeptr_t)stm_allocate(sizeof(struct node_s));
+
+        STM_POP_ROOT(stm_thread_local, w_prev);
+        w_newnode->value = LIST_LENGTH - i;
+        w_newnode->next = NULL;
+
+        stm_write((objptr_t)w_prev);
+        w_prev->next = w_newnode;
+        w_prev = w_newnode;
+    }
+
+    STM_POP_ROOT(stm_thread_local, global_chained_list);   /* update value */
+    assert(global_chained_list->value == -1);
+    STM_PUSH_ROOT(stm_thread_local, global_chained_list);
+
+    stm_commit_transaction();
+
+    stm_start_transaction(&stm_thread_local);
+    STM_POP_ROOT(stm_thread_local, global_chained_list);   /* update value */
+    assert(global_chained_list->value == -1);
+    STM_PUSH_ROOT(stm_thread_local, global_chained_list);  /* remains forever 
in the shadow stack */
+    stm_commit_transaction();
+
+    printf("setup ok\n");
+}
+
+void teardown_list(void)
+{
+    STM_POP_ROOT_RET(stm_thread_local);
+}
+
+
+static sem_t done;
+
+
+void unregister_thread_local(void)
+{
+    stm_flush_timing(&stm_thread_local, 1);
+    stm_unregister_thread_local(&stm_thread_local);
+}
+
+void *demo2(void *arg)
+{
+    int status;
+    rewind_jmp_buf rjbuf;
+    stm_register_thread_local(&stm_thread_local);
+    stm_rewind_jmp_enterframe(&stm_thread_local, &rjbuf);
+    char *org = (char *)stm_thread_local.shadowstack;
+
+    STM_PUSH_ROOT(stm_thread_local, global_chained_list);  /* remains forever 
in the shadow stack */
+
+    int loops = 0;
+
+    while (check_sorted() == -1) {
+
+        STM_PUSH_MARKER(stm_thread_local, 2 * loops + 1, NULL);
+
+        bubble_run();
+
+        STM_POP_MARKER(stm_thread_local);
+        loops++;
+    }
+
+    STM_POP_ROOT(stm_thread_local, global_chained_list);
+    OPT_ASSERT(org == (char *)stm_thread_local.shadowstack);
+
+    stm_rewind_jmp_leaveframe(&stm_thread_local, &rjbuf);
+    unregister_thread_local();
+    status = sem_post(&done); assert(status == 0);
+    return NULL;
+}
+
+void final_check(void)
+{
+    long sum;
+
+    printf("final check\n");
+
+    sum = check_sorted();
+
+    // little Gauss:
+    if (sum == (1 + LIST_LENGTH) * (LIST_LENGTH / 2))
+        printf("check ok\n");
+    else
+        printf("check ERROR\n");
+}
+
+
+void newthread(void*(*func)(void*), void *arg)
+{
+    pthread_t th;
+    int status = pthread_create(&th, NULL, func, arg);
+    if (status != 0)
+        abort();
+    pthread_detach(th);
+    printf("started new thread\n");
+}
+
+
+
+int main(void)
+{
+    int status, i;
+    rewind_jmp_buf rjbuf;
+
+    status = sem_init(&done, 0, 0); assert(status == 0);
+
+    stm_setup();
+    stm_register_thread_local(&stm_thread_local);
+    stm_rewind_jmp_enterframe(&stm_thread_local, &rjbuf);
+    stmcb_expand_marker = expand_marker;
+
+
+    setup_list();
+
+
+    for (i = 1; i <= NTHREADS; i++) {
+        newthread(demo2, (void*)(uintptr_t)i);
+    }
+
+    for (i = 1; i <= NTHREADS; i++) {
+        status = sem_wait(&done); assert(status == 0);
+    }
+
+    final_check();
+
+    teardown_list();
+
+    stm_rewind_jmp_leaveframe(&stm_thread_local, &rjbuf);
+    unregister_thread_local();
+    //stm_teardown();
+
+    return 0;
+}
diff --git a/c8/demo/demo_largemalloc.c b/c8/demo/demo_largemalloc.c
new file mode 100644
--- /dev/null
+++ b/c8/demo/demo_largemalloc.c
@@ -0,0 +1,86 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdbool.h>
+#include <time.h>
+
+#include "stmgc.h"
+#include "../stm/largemalloc.h"
+
+static inline double get_stm_time(void)
+{
+    struct timespec tp;
+    clock_gettime(CLOCK_MONOTONIC, &tp);
+    return tp.tv_sec + tp.tv_nsec * 0.000000001;
+}
+
+ssize_t stmcb_size_rounded_up(struct object_s *ob)
+{
+    abort();
+}
+
+void stmcb_trace(struct object_s *obj, void visit(object_t **))
+{
+    abort();
+}
+
+void stmcb_commit_soon() {}
+long stmcb_obj_supports_cards(struct object_s *obj)
+{
+    return 0;
+}
+void stmcb_trace_cards(struct object_s *obj, void cb(object_t **),
+                       uintptr_t start, uintptr_t stop) {
+    abort();
+}
+void stmcb_get_card_base_itemsize(struct object_s *obj,
+                                  uintptr_t offset_itemsize[2]) {
+    abort();
+}
+
+/************************************************************/
+
+#define ARENA_SIZE  (1024*1024*1024)
+
+static char *arena_data;
+extern bool (*_stm_largemalloc_keep)(char *data);   /* a hook for tests */
+void _stm_mutex_pages_lock(void);
+
+
+static bool keep_me(char *data) {
+    static bool last_answer = false;
+    last_answer = !last_answer;
+    return last_answer;
+}
+
+void timing(int scale)
+{
+    long limit = 1L << scale;
+    _stm_largemalloc_init_arena(arena_data, ARENA_SIZE);
+    double start = get_stm_time();
+
+    long i;
+    for (i = 0; i < limit; i++) {
+        _stm_large_malloc(16 + 8 * (i % 4));  /* may return NULL */
+    }
+    _stm_largemalloc_keep = keep_me;
+    _stm_largemalloc_sweep();
+    for (i = 0; i < limit; i++) {
+        _stm_large_malloc(16 + 8 * (i % 4));  /* may return NULL */
+    }
+
+    double stop = get_stm_time();
+    printf("scale %2d: %.9f\n", scale, stop - start);
+}
+
+
+
+int main(void)
+{
+    int i;
+    arena_data = malloc(ARENA_SIZE);
+    assert(arena_data != NULL);
+    //_stm_mutex_pages_lock();
+    for (i = 0; i < 25; i++)
+        timing(i);
+    return 0;
+}
diff --git a/c8/demo/demo_random.c b/c8/demo/demo_random.c
new file mode 100644
--- /dev/null
+++ b/c8/demo/demo_random.c
@@ -0,0 +1,517 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include <assert.h>
+#include <pthread.h>
+#include <semaphore.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+
+#include "stmgc.h"
+
+#define NUMTHREADS 3
+#define STEPS_PER_THREAD 500
+#define THREAD_STARTS 1000 // how many restarts of threads
+#define PREBUILT_ROOTS 3
+#define MAXROOTS 1000
+#define FORKS 3
+
+// SUPPORT
+struct node_s;
+typedef TLPREFIX struct node_s node_t;
+typedef node_t* nodeptr_t;
+typedef object_t* objptr_t;
+int num_forked_children = 0;
+
+struct node_s {
+    struct object_s hdr;
+    int sig;
+    long my_size;
+    long my_id;
+    long my_hash;
+    nodeptr_t next;
+};
+
+#define SIGNATURE 0x01234567
+
+
+static sem_t done;
+__thread stm_thread_local_t stm_thread_local;
+
+// global and per-thread-data
+time_t default_seed;
+objptr_t prebuilt_roots[PREBUILT_ROOTS];
+
+struct thread_data {
+    unsigned int thread_seed;
+    objptr_t roots[MAXROOTS];
+    int num_roots;
+    int num_roots_at_transaction_start;
+    int steps_left;
+};
+__thread struct thread_data td;
+
+struct thread_data *_get_td(void)
+{
+    return &td;     /* for gdb */
+}
+
+
+ssize_t stmcb_size_rounded_up(struct object_s *ob)
+{
+    return ((struct node_s*)ob)->my_size;
+}
+
+void stmcb_trace(struct object_s *obj, void visit(object_t **))
+{
+    struct node_s *n;
+    n = (struct node_s*)obj;
+
+    /* and the same value at the end: */
+    /* note, ->next may be the same as last_next */
+    nodeptr_t *last_next = (nodeptr_t*)((char*)n + n->my_size - sizeof(void*));
+
+    assert(n->next == *last_next);
+
+    visit((object_t **)&n->next);
+    visit((object_t **)last_next);
+
+    assert(n->next == *last_next);
+}
+
+void stmcb_commit_soon() {}
+long stmcb_obj_supports_cards(struct object_s *obj)
+{
+    return 0;
+}
+void stmcb_trace_cards(struct object_s *obj, void cb(object_t **),
+                       uintptr_t start, uintptr_t stop) {
+    abort();
+}
+void stmcb_get_card_base_itemsize(struct object_s *obj,
+                                  uintptr_t offset_itemsize[2]) {
+    abort();
+}
+
+int get_rand(int max)
+{
+    if (max == 0)
+        return 0;
+    return (int)(rand_r(&td.thread_seed) % (unsigned int)max);
+}
+
+objptr_t get_random_root()
+{
+    int num = get_rand(2);
+    if (num == 0 && td.num_roots > 0) {
+        num = get_rand(td.num_roots);
+        return td.roots[num];
+    }
+    else {
+        num = get_rand(PREBUILT_ROOTS);
+        return prebuilt_roots[num];
+    }
+}
+
+void reload_roots()
+{
+    int i;
+    assert(td.num_roots == td.num_roots_at_transaction_start);
+    for (i = td.num_roots_at_transaction_start - 1; i >= 0; i--) {
+        if (td.roots[i])
+            STM_POP_ROOT(stm_thread_local, td.roots[i]);
+    }
+
+    for (i = 0; i < td.num_roots_at_transaction_start; i++) {
+        if (td.roots[i])
+            STM_PUSH_ROOT(stm_thread_local, td.roots[i]);
+    }
+}
+
+void push_roots()
+{
+    int i;
+    for (i = td.num_roots_at_transaction_start; i < td.num_roots; i++) {
+        if (td.roots[i])
+            STM_PUSH_ROOT(stm_thread_local, td.roots[i]);
+    }
+}
+
+void pop_roots()
+{
+    int i;
+    for (i = td.num_roots - 1; i >= td.num_roots_at_transaction_start; i--) {
+        if (td.roots[i])
+            STM_POP_ROOT(stm_thread_local, td.roots[i]);
+    }
+}
+
+void del_root(int idx)
+{
+    int i;
+    assert(idx >= td.num_roots_at_transaction_start);
+
+    for (i = idx; i < td.num_roots - 1; i++)
+        td.roots[i] = td.roots[i + 1];
+    td.num_roots--;
+}
+
+void add_root(objptr_t r)
+{
+    if (r && td.num_roots < MAXROOTS) {
+        td.roots[td.num_roots++] = r;
+    }
+}
+
+
+void read_barrier(objptr_t p)
+{
+    if (p != NULL) {
+        stm_read(p);
+    }
+}
+
+void write_barrier(objptr_t p)
+{
+    if (p != NULL) {
+        stm_write(p);
+    }
+}
+
+void set_next(objptr_t p, objptr_t v)
+{
+    if (p != NULL) {
+        nodeptr_t n = (nodeptr_t)p;
+
+        /* and the same value at the end: */
+        nodeptr_t TLPREFIX *last_next = (nodeptr_t TLPREFIX *)((stm_char*)n + 
n->my_size - sizeof(void*));
+        assert(n->next == *last_next);
+        n->next = (nodeptr_t)v;
+        *last_next = (nodeptr_t)v;
+    }
+}
+
+nodeptr_t get_next(objptr_t p)
+{
+    nodeptr_t n = (nodeptr_t)p;
+
+    /* and the same value at the end: */
+    nodeptr_t TLPREFIX *last_next = (nodeptr_t TLPREFIX *)((stm_char*)n + 
n->my_size - sizeof(void*));
+    OPT_ASSERT(n->next == *last_next);
+
+    return n->next;
+}
+
+
+objptr_t simple_events(objptr_t p, objptr_t _r)
+{
+    int k = get_rand(10);
+    int num;
+
+    switch (k) {
+    case 0: // remove a root
+        if (td.num_roots > td.num_roots_at_transaction_start) {
+            num = td.num_roots_at_transaction_start
+                + get_rand(td.num_roots - td.num_roots_at_transaction_start);
+            del_root(num);
+        }
+        break;
+    case 1: // add 'p' to roots
+        add_root(p);
+        break;
+    case 2: // set 'p' to point to a root
+        if (_r)
+            p = _r;
+        break;
+    case 3: // allocate fresh 'p'
+        push_roots();
+        size_t sizes[4] = {sizeof(struct node_s),
+                           sizeof(struct node_s) + (get_rand(100000) & ~15),
+                           sizeof(struct node_s) + 4096,
+                           sizeof(struct node_s) + 4096*70};
+        size_t size = sizes[get_rand(4)];
+        p = stm_allocate(size);
+        ((nodeptr_t)p)->sig = SIGNATURE;
+        ((nodeptr_t)p)->my_size = size;
+        ((nodeptr_t)p)->my_id = 0;
+        ((nodeptr_t)p)->my_hash = 0;
+        pop_roots();
+        /* reload_roots not necessary, all are old after start_transaction */
+        break;
+    case 4:  // read and validate 'p'
+        read_barrier(p);
+        break;
+    case 5: // only do a stm_write_barrier
+        write_barrier(p);
+        break;
+    case 6: // follow p->next
+        if (p) {
+            read_barrier(p);
+            p = (objptr_t)(get_next(p));
+        }
+        break;
+    case 7: // set 'p' as *next in one of the roots
+        write_barrier(_r);
+        set_next(_r, p);
+        break;
+    case 8: // id checking
+        if (p) {
+            nodeptr_t n = (nodeptr_t)p;
+            if (n->my_id == 0) {
+                write_barrier(p);
+                n->my_id = stm_id(p);
+            }
+            else {
+                read_barrier(p);
+                assert(n->my_id == stm_id(p));
+            }
+        }
+        break;
+    case 9:
+        if (p) {
+            nodeptr_t n = (nodeptr_t)p;
+            if (n->my_hash == 0) {
+                write_barrier(p);
+                n->my_hash = stm_identityhash(p);
+            }
+            else {
+                read_barrier(p);
+                assert(n->my_hash == stm_identityhash(p));
+            }
+        }
+        break;
+    }
+    return p;
+}
+
+
+objptr_t do_step(objptr_t p)
+{
+    objptr_t _r;
+    int k;
+
+    _r = get_random_root();
+    k = get_rand(12);
+
+    if (k < 10) {
+        p = simple_events(p, _r);
+    } else if (get_rand(20) == 1) {
+        return (objptr_t)-1; // break current
+    } else if (get_rand(20) == 1) {
+        push_roots();
+        stm_become_inevitable(&stm_thread_local, "please");
+        pop_roots();
+        return NULL;
+    } else if (get_rand(240) == 1) {
+        push_roots();
+        stm_become_globally_unique_transaction(&stm_thread_local, "really");
+        fprintf(stderr, "[GUT/%d]", (int)STM_SEGMENT->segment_num);
+        pop_roots();
+        return NULL;
+    }
+    return p;
+}
+
+
+
+void setup_thread()
+{
+    memset(&td, 0, sizeof(struct thread_data));
+
+    /* stupid check because gdb shows garbage
+       in td.roots: */
+    int i;
+    for (i = 0; i < MAXROOTS; i++)
+        assert(td.roots[i] == NULL);
+
+    td.thread_seed = default_seed++;
+    td.steps_left = STEPS_PER_THREAD;
+    td.num_roots = 0;
+    td.num_roots_at_transaction_start = 0;
+}
+
+
+
+void *demo_random(void *arg)
+{
+    int status;
+    rewind_jmp_buf rjbuf;
+    stm_register_thread_local(&stm_thread_local);
+    stm_rewind_jmp_enterframe(&stm_thread_local, &rjbuf);
+
+    setup_thread();
+
+    objptr_t p;
+
+    stm_start_transaction(&stm_thread_local);
+    assert(td.num_roots >= td.num_roots_at_transaction_start);
+    td.num_roots = td.num_roots_at_transaction_start;
+    p = NULL;
+    pop_roots();                /* does nothing.. */
+    reload_roots();
+
+    while (td.steps_left-->0) {
+        if (td.steps_left % 8 == 0)
+            fprintf(stdout, "#");
+
+        assert(p == NULL || ((nodeptr_t)p)->sig == SIGNATURE);
+
+        p = do_step(p);
+
+        if (p == (objptr_t)-1) {
+            push_roots();
+
+            long call_fork = (arg != NULL && *(long *)arg);
+            if (call_fork == 0) {   /* common case */
+                stm_commit_transaction();
+                td.num_roots_at_transaction_start = td.num_roots;
+                if (get_rand(100) < 98) {
+                    stm_start_transaction(&stm_thread_local);
+                } else {
+                    stm_start_inevitable_transaction(&stm_thread_local);
+                }
+                td.num_roots = td.num_roots_at_transaction_start;
+                p = NULL;
+                pop_roots();
+                reload_roots();
+            }
+            else {
+                /* run a fork() inside the transaction */
+                printf("==========   FORK  =========\n");
+                *(long*)arg = 0;
+                pid_t child = fork();
+                printf("=== in process %d thread %lx, fork() returned %d\n",
+                       (int)getpid(), (long)pthread_self(), (int)child);
+                if (child == -1) {
+                    fprintf(stderr, "fork() error: %m\n");
+                    abort();
+                }
+                if (child != 0)
+                    num_forked_children++;
+                else
+                    num_forked_children = 0;
+
+                pop_roots();
+                p = NULL;
+            }
+        }
+    }
+    push_roots();
+    stm_commit_transaction();
+
+    /* even out the shadow stack before leaveframe: */
+    stm_start_inevitable_transaction(&stm_thread_local);
+    while (td.num_roots > 0) {
+        td.num_roots--;
+        objptr_t t;
+        STM_POP_ROOT(stm_thread_local, t);
+    }
+    stm_commit_transaction();
+
+    stm_rewind_jmp_leaveframe(&stm_thread_local, &rjbuf);
+    stm_unregister_thread_local(&stm_thread_local);
+
+    status = sem_post(&done); assert(status == 0);
+    return NULL;
+}
+
+void newthread(void*(*func)(void*), void *arg)
+{
+    pthread_t th;
+    int status = pthread_create(&th, NULL, func, arg);
+    if (status != 0)
+        abort();
+    pthread_detach(th);
+    printf("started new thread\n");
+}
+
+
+void setup_globals()
+{
+    int i;
+
+    struct node_s prebuilt_template = {
+        .sig = SIGNATURE,
+        .my_size = sizeof(struct node_s),
+        .my_id = 0,
+        .my_hash = 0,
+        .next = NULL
+    };
+
+    stm_start_inevitable_transaction(&stm_thread_local);
+    for (i = 0; i < PREBUILT_ROOTS; i++) {
+        void* new_templ = malloc(sizeof(struct node_s));
+        memcpy(new_templ, &prebuilt_template, sizeof(struct node_s));
+        prebuilt_roots[i] = stm_setup_prebuilt((objptr_t)(long)new_templ);
+
+        if (i % 2 == 0) {
+            int hash = i + 5;
+            stm_set_prebuilt_identityhash(prebuilt_roots[i],
+                                          hash);
+            ((nodeptr_t)prebuilt_roots[i])->my_hash = hash;
+        }
+    }
+    stm_commit_transaction();
+}
+
+int main(void)
+{
+    int i, status;
+    rewind_jmp_buf rjbuf;
+
+    /* pick a random seed from the time in seconds.
+       A bit pointless for now... because the interleaving of the
+       threads is really random. */
+    default_seed = time(NULL);
+    printf("running with seed=%lld\n", (long long)default_seed);
+
+    status = sem_init(&done, 0, 0);
+    assert(status == 0);
+
+
+    stm_setup();
+    stm_register_thread_local(&stm_thread_local);
+    stm_rewind_jmp_enterframe(&stm_thread_local, &rjbuf);
+
+    setup_globals();
+
+    int thread_starts = NUMTHREADS * THREAD_STARTS;
+    for (i = 0; i < NUMTHREADS; i++) {
+        newthread(demo_random, NULL);
+        thread_starts--;
+    }
+
+    for (i=0; i < NUMTHREADS * THREAD_STARTS; i++) {
+        status = sem_wait(&done);
+        assert(status == 0);
+        printf("thread finished\n");
+        if (thread_starts) {
+            long forkbase = NUMTHREADS * THREAD_STARTS / (FORKS + 1);
+            long _fork = (thread_starts % forkbase) == 0;
+            thread_starts--;
+            newthread(demo_random, &_fork);
+        }
+    }
+
+    for (i = 0; i < num_forked_children; i++) {
+        pid_t child = wait(&status);
+        if (child == -1)
+            perror("wait");
+        printf("From %d: child %d terminated with exit status %d\n",
+               (int)getpid(), (int)child, status);
+        if (WIFEXITED(status) && WEXITSTATUS(status) == 0)
+            ;
+        else {
+            printf("*** error from the child ***\n");
+            return 1;
+        }
+    }
+
+    printf("Test OK!\n");
+
+    stm_rewind_jmp_leaveframe(&stm_thread_local, &rjbuf);
+    stm_unregister_thread_local(&stm_thread_local);
+    stm_teardown();
+
+    return 0;
+}
diff --git a/c8/demo/demo_random2.c b/c8/demo/demo_random2.c
new file mode 100644
--- /dev/null
+++ b/c8/demo/demo_random2.c
@@ -0,0 +1,540 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include <assert.h>
+#include <pthread.h>
+#include <semaphore.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+
+#include "stmgc.h"
+
+#define NUMTHREADS 3
+#define STEPS_PER_THREAD 500
+#define THREAD_STARTS 1000 // how many restarts of threads
+#define PREBUILT_ROOTS 3
+#define FORKS 3
+
+#define ACTIVE_ROOTS_SET_SIZE 100 // max num of roots created/alive in one 
transaction
+#define MAX_ROOTS_ON_SS 1000 // max on shadow stack
+
+// SUPPORT
+struct node_s;
+typedef TLPREFIX struct node_s node_t;
+typedef node_t* nodeptr_t;
+typedef object_t* objptr_t;
+int num_forked_children = 0;
+
+struct node_s {
+    struct object_s hdr;
+    int sig;
+    long my_size;
+    long my_id;
+    long my_hash;
+    nodeptr_t next;
+};
+
+#define SIGNATURE 0x01234567
+
+
+static sem_t done;
+__thread stm_thread_local_t stm_thread_local;
+__thread void *thread_may_fork;
+
+// global and per-thread-data
+time_t default_seed;
+objptr_t prebuilt_roots[PREBUILT_ROOTS];
+
+struct thread_data {
+    unsigned int thread_seed;
+    int steps_left;
+    objptr_t active_roots_set[ACTIVE_ROOTS_SET_SIZE];
+    int active_roots_num;
+    long roots_on_ss;
+    long roots_on_ss_at_tr_start;
+};
+__thread struct thread_data td;
+
+struct thread_data *_get_td(void)
+{
+    return &td;     /* for gdb */
+}
+
+
+ssize_t stmcb_size_rounded_up(struct object_s *ob)
+{
+    return ((struct node_s*)ob)->my_size;
+}
+
+void stmcb_trace(struct object_s *obj, void visit(object_t **))
+{
+    struct node_s *n;
+    n = (struct node_s*)obj;
+
+    /* and the same value at the end: */
+    /* note, ->next may be the same as last_next */
+    nodeptr_t *last_next = (nodeptr_t*)((char*)n + n->my_size - sizeof(void*));
+
+    assert(n->next == *last_next);
+
+    visit((object_t **)&n->next);
+    visit((object_t **)last_next);
+
+    assert(n->next == *last_next);
+}
+
+void stmcb_commit_soon() {}
+
+long stmcb_obj_supports_cards(struct object_s *obj)
+{
+    return 0;
+}
+void stmcb_trace_cards(struct object_s *obj, void cb(object_t **),
+                       uintptr_t start, uintptr_t stop) {
+    abort();
+}
+void stmcb_get_card_base_itemsize(struct object_s *obj,
+                                  uintptr_t offset_itemsize[2]) {
+    abort();
+}
+
+int get_rand(int max)
+{
+    if (max == 0)
+        return 0;
+    return (int)(rand_r(&td.thread_seed) % (unsigned int)max);
+}
+
+objptr_t get_random_root()
+{
+    /* get some root from shadowstack or active_root_set or prebuilt_roots */
+    int num = get_rand(3);
+    intptr_t ss_size = td.roots_on_ss;
+    if (num == 0 && ss_size > 0) {
+        num = get_rand(ss_size);
+        /* XXX: impl detail: there is already a "-1" on the SS -> +1 */
+        objptr_t r = (objptr_t)stm_thread_local.shadowstack_base[num+1].ss;
+        OPT_ASSERT((((uintptr_t)r) & 3) == 0);
+    }
+
+    if (num == 1 && td.active_roots_num > 0) {
+        num = get_rand(td.active_roots_num);
+        return td.active_roots_set[num];
+    } else {
+        num = get_rand(PREBUILT_ROOTS);
+        return prebuilt_roots[num];
+    }
+}
+
+
+long push_roots()
+{
+    int i;
+    long to_push = td.active_roots_num;
+    long not_pushed = 0;
+    for (i = to_push - 1; i >= 0; i--) {
+        td.active_roots_num--;
+        if (td.roots_on_ss < MAX_ROOTS_ON_SS) {
+            STM_PUSH_ROOT(stm_thread_local, td.active_roots_set[i]);
+            td.roots_on_ss++;
+        } else {
+            not_pushed++;
+        }
+    }
+    return to_push - not_pushed;
+}
+
+void add_root(objptr_t r);
+void pop_roots(long to_pop)
+{
+    int i;
+    for (i = 0; i < to_pop; i++) {
+        objptr_t t;
+        STM_POP_ROOT(stm_thread_local, t);
+        add_root(t);
+        td.roots_on_ss--;
+    }
+}
+
+void del_root(int idx)
+{
+    int i;
+
+    for (i = idx; i < td.active_roots_num - 1; i++)
+        td.active_roots_set[i] = td.active_roots_set[i + 1];
+    td.active_roots_num--;
+}
+
+void add_root(objptr_t r)
+{
+    if (r && td.active_roots_num < ACTIVE_ROOTS_SET_SIZE) {
+        td.active_roots_set[td.active_roots_num++] = r;
+    }
+}
+
+
+void read_barrier(objptr_t p)
+{
+    if (p != NULL) {
+        stm_read(p);
+    }
+}
+
+void write_barrier(objptr_t p)
+{
+    if (p != NULL) {
+        stm_write(p);
+    }
+}
+
+void set_next(objptr_t p, objptr_t v)
+{
+    if (p != NULL) {
+        nodeptr_t n = (nodeptr_t)p;
+
+        /* and the same value at the end: */
+        nodeptr_t TLPREFIX *last_next = (nodeptr_t TLPREFIX *)((stm_char*)n + 
n->my_size - sizeof(void*));
+        assert(n->next == *last_next);
+        n->next = (nodeptr_t)v;
+        *last_next = (nodeptr_t)v;
+    }
+}
+
+nodeptr_t get_next(objptr_t p)
+{
+    nodeptr_t n = (nodeptr_t)p;
+
+    /* and the same value at the end: */
+    nodeptr_t TLPREFIX *last_next = (nodeptr_t TLPREFIX *)((stm_char*)n + 
n->my_size - sizeof(void*));
+    OPT_ASSERT(n->next == *last_next);
+
+    return n->next;
+}
+
+
+objptr_t simple_events(objptr_t p, objptr_t _r)
+{
+    int k = get_rand(10);
+    long pushed;
+
+    switch (k) {
+    case 0: // remove a root
+        if (td.active_roots_num) {
+            del_root(get_rand(td.active_roots_num));
+        }
+        break;
+    case 1: // add 'p' to roots
+        add_root(p);
+        break;
+    case 2: // set 'p' to point to a root
+        if (_r)
+            p = _r;
+        break;
+    case 3: // allocate fresh 'p'
+        pushed = push_roots();
+        size_t sizes[4] = {sizeof(struct node_s),
+                           sizeof(struct node_s) + (get_rand(100000) & ~15),
+                           sizeof(struct node_s) + 4096,
+                           sizeof(struct node_s) + 4096*70};
+        size_t size = sizes[get_rand(4)];
+        p = stm_allocate(size);
+        ((nodeptr_t)p)->sig = SIGNATURE;
+        ((nodeptr_t)p)->my_size = size;
+        ((nodeptr_t)p)->my_id = 0;
+        ((nodeptr_t)p)->my_hash = 0;
+        pop_roots(pushed);
+        break;
+    case 4:  // read and validate 'p'
+        read_barrier(p);
+        break;
+    case 5: // only do a stm_write_barrier
+        write_barrier(p);
+        break;
+    case 6: // follow p->next
+        if (p) {
+            read_barrier(p);
+            p = (objptr_t)(get_next(p));
+        }
+        break;
+    case 7: // set 'p' as *next in one of the roots
+        write_barrier(_r);
+        set_next(_r, p);
+        break;
+    case 8: // id checking
+        if (p) {
+            nodeptr_t n = (nodeptr_t)p;
+            if (n->my_id == 0) {
+                write_barrier(p);
+                n->my_id = stm_id(p);
+            }
+            else {
+                read_barrier(p);
+                assert(n->my_id == stm_id(p));
+            }
+        }
+        break;
+    case 9:
+        if (p) {
+            nodeptr_t n = (nodeptr_t)p;
+            if (n->my_hash == 0) {
+                write_barrier(p);
+                n->my_hash = stm_identityhash(p);
+            }
+            else {
+                read_barrier(p);
+                assert(n->my_hash == stm_identityhash(p));
+            }
+        }
+        break;
+    }
+    return p;
+}
+
+void frame_loop();
+objptr_t do_step(objptr_t p)
+{
+    objptr_t _r;
+    int k;
+
+    _r = get_random_root();
+    k = get_rand(12);
+
+    if (k < 10) {
+        p = simple_events(p, _r);
+    } else if (get_rand(20) == 1) {
+        long pushed = push_roots();
+        stm_commit_transaction();
+        td.roots_on_ss_at_tr_start = td.roots_on_ss;
+
+        if (get_rand(100) < 98) {
+            stm_start_transaction(&stm_thread_local);
+        } else {
+            stm_start_inevitable_transaction(&stm_thread_local);
+        }
+        td.roots_on_ss = td.roots_on_ss_at_tr_start;
+        td.active_roots_num = 0;
+        pop_roots(pushed);
+        p = NULL;
+    } else if (get_rand(10) == 1) {
+        long pushed = push_roots();
+        /* leaving our frame */
+        frame_loop();
+        /* back in our frame */
+        pop_roots(pushed);
+        p = NULL;
+    } else if (get_rand(20) == 1) {
+        long pushed = push_roots();
+        stm_become_inevitable(&stm_thread_local, "please");
+        assert(stm_is_inevitable());
+        pop_roots(pushed);
+        p= NULL;
+    } else if (get_rand(20) == 1) {
+        p = (objptr_t)-1; // possibly fork
+    } else if (get_rand(20) == 1) {
+        long pushed = push_roots();
+        stm_become_globally_unique_transaction(&stm_thread_local, "really");
+        fprintf(stderr, "[GUT/%d]", (int)STM_SEGMENT->segment_num);
+        pop_roots(pushed);
+        p = NULL;
+    }
+    return p;
+}
+
+void frame_loop()
+{
+    objptr_t p = NULL;
+    rewind_jmp_buf rjbuf;
+
+    stm_rewind_jmp_enterframe(&stm_thread_local, &rjbuf);
+    //fprintf(stderr,"%p F: %p\n", STM_SEGMENT->running_thread,  
__builtin_frame_address(0));
+
+    long roots_on_ss = td.roots_on_ss;
+    /* "interpreter main loop": this is one "application-frame" */
+    while (td.steps_left-->0 && get_rand(10) != 0) {
+        if (td.steps_left % 8 == 0)
+            fprintf(stdout, "#");
+
+        assert(p == NULL || ((nodeptr_t)p)->sig == SIGNATURE);
+
+        p = do_step(p);
+
+
+        if (p == (objptr_t)-1) {
+            p = NULL;
+
+            long call_fork = (thread_may_fork != NULL && *(long 
*)thread_may_fork);
+            if (call_fork) {   /* common case */
+                long pushed = push_roots();
+                /* run a fork() inside the transaction */
+                printf("==========   FORK  =========\n");
+                *(long*)thread_may_fork = 0;
+                pid_t child = fork();
+                printf("=== in process %d thread %lx, fork() returned %d\n",
+                       (int)getpid(), (long)pthread_self(), (int)child);
+                if (child == -1) {
+                    fprintf(stderr, "fork() error: %m\n");
+                    abort();
+                }
+                if (child != 0)
+                    num_forked_children++;
+                else
+                    num_forked_children = 0;
+
+                pop_roots(pushed);
+            }
+        }
+    }
+    OPT_ASSERT(roots_on_ss == td.roots_on_ss);
+
+    stm_rewind_jmp_leaveframe(&stm_thread_local, &rjbuf);
+}
+
+
+
+void setup_thread()
+{
+    memset(&td, 0, sizeof(struct thread_data));
+
+    /* stupid check because gdb shows garbage
+       in td.roots: */
+    int i;
+    for (i = 0; i < ACTIVE_ROOTS_SET_SIZE; i++)
+        assert(td.active_roots_set[i] == NULL);
+
+    td.thread_seed = default_seed++;
+    td.steps_left = STEPS_PER_THREAD;
+    td.active_roots_num = 0;
+    td.roots_on_ss = 0;
+    td.roots_on_ss_at_tr_start = 0;
+}
+
+
+
+void *demo_random(void *arg)
+{
+    int status;
+    rewind_jmp_buf rjbuf;
+    stm_register_thread_local(&stm_thread_local);
+    stm_rewind_jmp_enterframe(&stm_thread_local, &rjbuf);
+
+    setup_thread();
+
+    td.roots_on_ss_at_tr_start = 0;
+    stm_start_transaction(&stm_thread_local);
+    td.roots_on_ss = td.roots_on_ss_at_tr_start;
+    td.active_roots_num = 0;
+
+    thread_may_fork = arg;
+    while (td.steps_left-->0) {
+        frame_loop();
+    }
+
+    stm_commit_transaction();
+
+    stm_rewind_jmp_leaveframe(&stm_thread_local, &rjbuf);
+    stm_unregister_thread_local(&stm_thread_local);
+
+    status = sem_post(&done); assert(status == 0);
+    return NULL;
+}
+
+void newthread(void*(*func)(void*), void *arg)
+{
+    pthread_t th;
+    int status = pthread_create(&th, NULL, func, arg);
+    if (status != 0)
+        abort();
+    pthread_detach(th);
+    printf("started new thread\n");
+}
+
+
+void setup_globals()
+{
+    int i;
+
+    struct node_s prebuilt_template = {
+        .sig = SIGNATURE,
+        .my_size = sizeof(struct node_s),
+        .my_id = 0,
+        .my_hash = 0,
+        .next = NULL
+    };
+
+    stm_start_inevitable_transaction(&stm_thread_local);
+    for (i = 0; i < PREBUILT_ROOTS; i++) {
+        void* new_templ = malloc(sizeof(struct node_s));
+        memcpy(new_templ, &prebuilt_template, sizeof(struct node_s));
+        prebuilt_roots[i] = stm_setup_prebuilt((objptr_t)(long)new_templ);
+
+        if (i % 2 == 0) {
+            int hash = i + 5;
+            stm_set_prebuilt_identityhash(prebuilt_roots[i],
+                                          hash);
+            ((nodeptr_t)prebuilt_roots[i])->my_hash = hash;
+        }
+    }
+    stm_commit_transaction();
+}
+
+int main(void)
+{
+    int i, status;
+    rewind_jmp_buf rjbuf;
+
+    /* pick a random seed from the time in seconds.
+       A bit pointless for now... because the interleaving of the
+       threads is really random. */
+    default_seed = time(NULL);
+    printf("running with seed=%lld\n", (long long)default_seed);
+
+    status = sem_init(&done, 0, 0);
+    assert(status == 0);
+
+
+    stm_setup();
+    stm_register_thread_local(&stm_thread_local);
+    stm_rewind_jmp_enterframe(&stm_thread_local, &rjbuf);
+
+    setup_globals();
+
+    int thread_starts = NUMTHREADS * THREAD_STARTS;
+    for (i = 0; i < NUMTHREADS; i++) {
+        newthread(demo_random, NULL);
+        thread_starts--;
+    }
+
+    for (i=0; i < NUMTHREADS * THREAD_STARTS; i++) {
+        status = sem_wait(&done);
+        assert(status == 0);
+        printf("thread finished\n");
+        if (thread_starts) {
+            long forkbase = NUMTHREADS * THREAD_STARTS / (FORKS + 1);
+            long _fork = (thread_starts % forkbase) == 0;
+            thread_starts--;
+            newthread(demo_random, &_fork);
+        }
+    }
+
+    for (i = 0; i < num_forked_children; i++) {
+        pid_t child = wait(&status);
+        if (child == -1)
+            perror("wait");
+        printf("From %d: child %d terminated with exit status %d\n",
+               (int)getpid(), (int)child, status);
+        if (WIFEXITED(status) && WEXITSTATUS(status) == 0)
+            ;
+        else {
+            printf("*** error from the child ***\n");
+            return 1;
+        }
+    }
+
+    printf("Test OK!\n");
+
+    stm_rewind_jmp_leaveframe(&stm_thread_local, &rjbuf);
+    stm_unregister_thread_local(&stm_thread_local);
+    stm_teardown();
+
+    return 0;
+}
diff --git a/c8/demo/demo_simple.c b/c8/demo/demo_simple.c
new file mode 100644
--- /dev/null
+++ b/c8/demo/demo_simple.c
@@ -0,0 +1,128 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include <assert.h>
+#include <pthread.h>
+#include <semaphore.h>
+
+#ifdef USE_HTM
+#  include "../../htm-c7/stmgc.h"
+#else
+#  include "stmgc.h"
+#endif
+
+#define ITERS 100000
+#define NTHREADS    2
+
+
+typedef TLPREFIX struct node_s node_t;
+typedef node_t* nodeptr_t;
+typedef object_t* objptr_t;
+
+struct node_s {
+    struct object_s hdr;
+    long value;
+    nodeptr_t next;
+};
+
+__thread stm_thread_local_t stm_thread_local;
+
+
+ssize_t stmcb_size_rounded_up(struct object_s *ob)
+{
+    return sizeof(struct node_s);
+}
+
+void stmcb_trace(struct object_s *obj, void visit(object_t **))
+{
+    struct node_s *n;
+    n = (struct node_s*)obj;
+    visit((object_t **)&n->next);
+}
+long stmcb_obj_supports_cards(struct object_s *obj)
+{
+    return 0;
+}
+void stmcb_commit_soon() {}
+
+void stmcb_trace_cards(struct object_s *obj, void cb(object_t **),
+                       uintptr_t start, uintptr_t stop) {
+    abort();
+}
+void stmcb_get_card_base_itemsize(struct object_s *obj,
+                                  uintptr_t offset_itemsize[2]) {
+    abort();
+}
+
+
+static sem_t done;
+
+static __thread int tl_counter = 0;
+//static int gl_counter = 0;
+
+void *demo2(void *arg)
+{
+    int status;
+    rewind_jmp_buf rjbuf;
+    stm_register_thread_local(&stm_thread_local);
+    stm_rewind_jmp_enterframe(&stm_thread_local, &rjbuf);
+    char *org = (char *)stm_thread_local.shadowstack;
+    tl_counter = 0;
+
+    object_t *tmp;
+    int i = 0;
+    while (i < ITERS) {
+        stm_start_transaction(&stm_thread_local);
+        tl_counter++;
+        if (i % 500 < 250)
+            STM_PUSH_ROOT(stm_thread_local, stm_allocate(16));//gl_counter++;
+        else
+            STM_POP_ROOT(stm_thread_local, tmp);
+        stm_commit_transaction();
+        i++;
+    }
+
+    OPT_ASSERT(org == (char *)stm_thread_local.shadowstack);
+
+    stm_rewind_jmp_leaveframe(&stm_thread_local, &rjbuf);
+    stm_unregister_thread_local(&stm_thread_local);
+    status = sem_post(&done); assert(status == 0);
+    return NULL;
+}
+
+
+void newthread(void*(*func)(void*), void *arg)
+{
+    pthread_t th;
+    int status = pthread_create(&th, NULL, func, arg);
+    if (status != 0)
+        abort();
+    pthread_detach(th);
+    printf("started new thread\n");
+}
+
+
+
+int main(void)
+{
+    int status, i;
+
+    status = sem_init(&done, 0, 0); assert(status == 0);
+
+    stm_setup();
+    stm_register_thread_local(&stm_thread_local);
+
+
+    for (i = 1; i <= NTHREADS; i++) {
+        newthread(demo2, (void*)(uintptr_t)i);
+    }
+
+    for (i = 1; i <= NTHREADS; i++) {
+        status = sem_wait(&done); assert(status == 0);
+    }
+
+
+    stm_unregister_thread_local(&stm_thread_local);
+    stm_teardown();
+
+    return 0;
+}
diff --git a/c8/demo/test_shadowstack.c b/c8/demo/test_shadowstack.c
new file mode 100644
--- /dev/null
+++ b/c8/demo/test_shadowstack.c
@@ -0,0 +1,74 @@
+#include <stdlib.h>
+#include <assert.h>
+#include "stmgc.h"
+
+stm_thread_local_t stm_thread_local;
+
+typedef TLPREFIX struct node_s node_t;
+
+struct node_s {
+    struct object_s hdr;
+    long value;
+};
+
+ssize_t stmcb_size_rounded_up(struct object_s *ob)
+{
+    return sizeof(struct node_s);
+}
+void stmcb_trace(struct object_s *obj, void visit(object_t **))
+{
+}
+long stmcb_obj_supports_cards(struct object_s *obj)
+{
+    return 0;
+}
+void stmcb_get_card_base_itemsize(struct object_s *obj,
+                                  uintptr_t offset_itemsize[2])
+{
+    abort();
+}
+void stmcb_trace_cards(struct object_s *obj, void visit(object_t **),
+                       uintptr_t start, uintptr_t stop)
+{
+    abort();
+}
+void stmcb_commit_soon() {}
+
+
+int main(void)
+{
+    rewind_jmp_buf rjbuf;
+
+    stm_setup();
+    stm_register_thread_local(&stm_thread_local);
+    stm_rewind_jmp_enterframe(&stm_thread_local, &rjbuf);
+
+    stm_start_transaction(&stm_thread_local);
+    node_t *node = (node_t *)stm_allocate(sizeof(struct node_s));
+    node->value = 129821;
+    STM_PUSH_ROOT(stm_thread_local, node);
+    STM_PUSH_ROOT(stm_thread_local, 333);  /* odd value */
+    stm_commit_transaction();
+
+    /* now in a new transaction, pop the node off the shadowstack, but
+       then do a major collection.  It should still be found by the
+       tracing logic. */
+    stm_start_transaction(&stm_thread_local);
+    STM_POP_ROOT_RET(stm_thread_local);
+    STM_POP_ROOT(stm_thread_local, node);
+    assert(node->value == 129821);
+    STM_PUSH_ROOT(stm_thread_local, NULL);
+    stm_collect(9);
+
+    node_t *node2 = (node_t *)stm_allocate(sizeof(struct node_s));
+    assert(node2 != node);
+    assert(node->value == 129821);
+
+    STM_PUSH_ROOT(stm_thread_local, node2);
+    stm_collect(0);
+    STM_POP_ROOT(stm_thread_local, node2);
+    assert(node2 != node);
+    assert(node->value == 129821);
+
+    return 0;
+}
diff --git a/c8/stm/core.c b/c8/stm/core.c
--- a/c8/stm/core.c
+++ b/c8/stm/core.c
@@ -39,7 +39,7 @@
     char *realobj = REAL_ADDRESS(STM_SEGMENT->segment_base, obj);
     uintptr_t pagenum = (uintptr_t)obj / 4096UL;
 
-    assert(!is_shared_log_page(pagenum));
+    OPT_ASSERT(!is_shared_log_page(pagenum));
     assert(is_private_log_page_in(STM_SEGMENT->segment_num, pagenum));
     assert(is_private_log_page_in(from_seg, pagenum));
 
@@ -229,7 +229,7 @@
     }
     set_page_private_in(0, pagenum);
 
-    assert(is_private_log_page_in(my_segnum, pagenum));
+    OPT_ASSERT(is_private_log_page_in(my_segnum, pagenum));
     assert(!is_shared_log_page(pagenum));
 }
 
@@ -437,8 +437,9 @@
     invoke_and_clear_user_callbacks(0);   /* for commit */
 
     s_mutex_lock();
+    enter_safe_point_if_requested();
+    assert(STM_SEGMENT->nursery_end == NURSERY_END);
 
-    assert(STM_SEGMENT->nursery_end == NURSERY_END);
     stm_rewind_jmp_forget(STM_SEGMENT->running_thread);
 
     if (globally_unique_transaction && STM_PSEGMENT->transaction_state == 
TS_INEVITABLE) {
@@ -590,11 +591,9 @@
 
 void _stm_become_inevitable(const char *msg)
 {
-    s_mutex_lock();
-    enter_safe_point_if_requested();
-
     if (STM_PSEGMENT->transaction_state == TS_REGULAR) {
         dprintf(("become_inevitable: %s\n", msg));
+        _stm_collectable_safe_point();
 
         _validate_and_turn_inevitable();
         STM_PSEGMENT->transaction_state = TS_INEVITABLE;
@@ -604,8 +603,6 @@
     else {
         assert(STM_PSEGMENT->transaction_state == TS_INEVITABLE);
     }
-
-    s_mutex_unlock();
 }
 
 void stm_become_globally_unique_transaction(stm_thread_local_t *tl,
diff --git a/c8/stm/core.h b/c8/stm/core.h
--- a/c8/stm/core.h
+++ b/c8/stm/core.h
@@ -130,7 +130,6 @@
 static bool _is_tl_registered(stm_thread_local_t *tl);
 static bool _seems_to_be_running_transaction(void);
 
-static void teardown_core(void);
 static void abort_with_mutex(void) __attribute__((noreturn));
 static stm_thread_local_t *abort_with_mutex_no_longjmp(void);
 static void abort_data_structures_from_segment_num(int segment_num);
diff --git a/c8/stm/gcpage.c b/c8/stm/gcpage.c
--- a/c8/stm/gcpage.c
+++ b/c8/stm/gcpage.c
@@ -19,9 +19,12 @@
 }
 
 
+static int lock_growth_large = 0;
+
 static char *allocate_outside_nursery_large(uint64_t size)
 {
     /* XXX: real allocation */
+    spinlock_acquire(lock_growth_large);
     char *addr = uninitialized_page_start;
 
     char *start = uninitialized_page_start;
@@ -42,7 +45,7 @@
              size, addr, get_segment_of_linear_address(addr),
              (addr - STM_SEGMENT->segment_base) / 4096UL));
 
-
+    spinlock_release(lock_growth_large);
     return addr;
 }
 
diff --git a/c8/stm/list.h b/c8/stm/list.h
--- a/c8/stm/list.h
+++ b/c8/stm/list.h
@@ -199,8 +199,8 @@
 #define TREE_LOOP_END     } }
 #define TREE_LOOP_END_AND_COMPRESS                                       \
                          } if (_deleted_factor > 9) _tree_compress(_tree); }
-#define TREE_LOOP_DELETE(tree, item)  { (tree)->count--; (item)->addr = NULL; 
_deleted_factor += 6; }
-#define TREE_FIND_DELETE(tree, item)  { (tree)->count--; (item)->addr = NULL; }
+#define TREE_LOOP_DELETE(tree, item)  { (tree)->count--; (item)->addr = 0; 
_deleted_factor += 6; }
+#define TREE_FIND_DELETE(tree, item)  { (tree)->count--; (item)->addr = 0; }
 
 
 #define TREE_FIND(tree, addr1, result, goto_not_found)          \
diff --git a/c8/stm/sync.c b/c8/stm/sync.c
--- a/c8/stm/sync.c
+++ b/c8/stm/sync.c
@@ -137,11 +137,10 @@
     }
     /* No segment available.  Wait until release_thread_segment()
        signals that one segment has been freed. */
-    abort();                    /* XXX */
+    cond_wait(C_SEGMENT_FREE);
 
     /* Return false to the caller, which will call us again */
     return false;
-
  got_num:
     sync_ctl.in_use1[num] = 1;
     assert(STM_SEGMENT->segment_num == num);
@@ -154,6 +153,8 @@
 {
     assert(_has_mutex());
 
+    cond_signal(C_SEGMENT_FREE);
+
     assert(STM_SEGMENT->running_thread == tl);
     STM_SEGMENT->running_thread = NULL;
 
@@ -218,7 +219,7 @@
     assert(_has_mutex());
 
     long i;
-    for (i = 1; i <= NB_SEGMENTS; i++) {
+    for (i = 0; i < NB_SEGMENTS; i++) {
         if (get_segment(i)->nursery_end == NURSERY_END)
             get_segment(i)->nursery_end = NSE_SIGPAUSE;
     }
@@ -234,7 +235,7 @@
     long result = 0;
     int my_num = STM_SEGMENT->segment_num;
 
-    for (i = 1; i <= NB_SEGMENTS; i++) {
+    for (i = 0; i < NB_SEGMENTS; i++) {
         if (i != my_num && get_priv_segment(i)->safe_point == SP_RUNNING) {
             assert(get_segment(i)->nursery_end <= _STM_NSE_SIGNAL_MAX);
             result++;
@@ -251,7 +252,7 @@
     assert((_safe_points_requested = false, 1));
 
     long i;
-    for (i = 1; i <= NB_SEGMENTS; i++) {
+    for (i = 0; i < NB_SEGMENTS; i++) {
         assert(get_segment(i)->nursery_end != NURSERY_END);
         if (get_segment(i)->nursery_end == NSE_SIGPAUSE)
             get_segment(i)->nursery_end = NURSERY_END;
diff --git a/c8/stm/sync.h b/c8/stm/sync.h
--- a/c8/stm/sync.h
+++ b/c8/stm/sync.h
@@ -4,6 +4,7 @@
 enum cond_type_e {
     C_AT_SAFE_POINT,
     C_REQUEST_REMOVED,
+    C_SEGMENT_FREE,
     _C_TOTAL
 };
 
diff --git a/c8/stmgc.c b/c8/stmgc.c
--- a/c8/stmgc.c
+++ b/c8/stmgc.c
@@ -2,28 +2,28 @@
 #include "stmgc.h"
 #include "stm/atomic.h"
 #include "stm/list.h"
+#include "stm/core.h"
 #include "stm/pagecopy.h"
-#include "stm/core.h"
 #include "stm/pages.h"
 #include "stm/gcpage.h"
-#include "stm/nursery.h"
 #include "stm/sync.h"
 #include "stm/setup.h"
+#include "stm/nursery.h"
+#include "stm/extra.h"
 #include "stm/fprintcolor.h"
 #include "stm/rewind_setjmp.h"
-#include "stm/extra.h"
 
+#include "stm/misc.c"
 #include "stm/list.c"
 #include "stm/pagecopy.c"
+#include "stm/pages.c"
+#include "stm/prebuilt.c"
+#include "stm/gcpage.c"
 #include "stm/nursery.c"
-#include "stm/core.c"
-#include "stm/pages.c"
-#include "stm/gcpage.c"
 #include "stm/sync.c"
 #include "stm/setup.c"
+#include "stm/hash_id.c"
+#include "stm/core.c"
+#include "stm/extra.c"
 #include "stm/fprintcolor.c"
 #include "stm/rewind_setjmp.c"
-#include "stm/hash_id.c"
-#include "stm/prebuilt.c"
-#include "stm/misc.c"
-#include "stm/extra.c"
diff --git a/c8/test/test_demo.py b/c8/test/test_demo.py
new file mode 100644
--- /dev/null
+++ b/c8/test/test_demo.py
@@ -0,0 +1,40 @@
+import py
+import os
+
+
+class TestDemo:
+
+    def _do(self, cmd):
+        print cmd
+        err = os.system(cmd)
+        if err: py.test.fail("'%s' failed (result %r)" % (cmd, err))
+
+    def make_and_run(self, target):
+        self._do("make -C ../demo %s" % target)
+        self._do("../demo/%s > /dev/null" % target)
+
+    def test_shadowstack(self):
+        py.test.xfail("no major gc yet")
+        self.make_and_run("debug-test_shadowstack")
+
+    def test_demo_simple_build(self):   self.make_and_run("build-demo_simple")
+
+    def test_demo_largemalloc_build(self):
+        py.test.xfail("no largemalloc")
+        self.make_and_run("build-demo_largemalloc")
+
+
+
+    # def test_demo2_debug(self):   self.make_and_run("debug-demo2")
+    def test_demo2_build(self):
+        py.test.xfail("no markers yet")
+        self.make_and_run("build-demo2")
+    # def test_demo2_release(self): self.make_and_run("release-demo2")
+
+    # def test_demo_random_debug(self):   
self.make_and_run("debug-demo_random")
+    def test_demo_random_build(self):   self.make_and_run("build-demo_random")
+    def test_demo_random_release(self): 
self.make_and_run("release-demo_random")
+
+    # def test_demo_random2_debug(self):   
self.make_and_run("debug-demo_random2")
+    def test_demo_random2_build(self):   
self.make_and_run("build-demo_random2")
+    def test_demo_random2_release(self): 
self.make_and_run("release-demo_random2")
_______________________________________________
pypy-commit mailing list
pypy-commit@python.org
https://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to