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