Author: Remi Meier <[email protected]>
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
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit