diff --git a/gc.c b/gc.c index 4fd5bdd0..72f7dd44 100644 --- a/gc.c +++ b/gc.c @@ -12,6 +12,19 @@ #include "cyclone/types.h" +static gc_thread_data **Cyc_mutators; +static int Cyc_num_mutators; + +void gc_init_mutators() +{ + // TODO: alloca this using a vpbuffer, or maybe another type of data structure?? + // Will need this list for later use, but only by the collector thread. so it would be + // nice if there was a way to allocate mutators that avoids expensive synchronization... + // need to think on this when adding thread support, after upgrading the collector + Cyc_num_mutators = 1; + Cyc_mutators = calloc(Cyc_num_mutators, sizeof(gc_thread_data *)); +} + gc_heap *gc_heap_create(size_t size, size_t max_size, size_t chunk_size) { gc_free_list *free, *next; @@ -488,63 +501,38 @@ void gc_mark_gray(gc_thread_data *thd, object obj) // either object type or mark. Both should be stable once the object is placed // into the heap, with the collector being the only thread that changes marks. if (is_object_type(obj) && mark(obj) == gc_color_clear) { // TODO: sync?? -//TODO: // TODO: lock mark buffer (not ideal, but a possible first step)? -//TODO: pthread_mutex_lock(&(thd->lock)); -//TODO: thd->mark_buffer = vpbuffer_add(thd->mark_buffer, -//TODO: &(thd->mark_buffer_len), -//TODO: thd->last_write, -//TODO: obj); -//TODO: pthread_mutex_unlock(&(thd->lock)); -//TODO: ATOMIC_INC(&(thd->last_write)); + // Place marked object in a buffer to avoid repeated scans of the heap. +// TODO: +// Note that ideally this should be a lock-free data structure to make the +// algorithm more efficient. So this code (and the corresponding collector +// trace code) should be converted at some point. + pthread_mutex_lock(&(thd->lock)); + thd->mark_buffer = vpbuffer_add(thd->mark_buffer, + &(thd->mark_buffer_len), + thd->last_write, + obj); + (thd->last_write)++; // Already locked, just do it... + pthread_mutex_unlock(&(thd->lock)); } } void gc_collector_trace() { - int clean = 0; -// while (!clean) { -// clean = 1; -// } -// TODO: need a list of mutators. -// could keep a buffer or linked list of them. a list may be more efficient -// also need to consider how to map thread back to its gc_thread_data, -// which we will need during GC (cooperate). maybe use a (platform-specific) -// call like below to get a unique ID for the thread, and then use a -// hashtable to get the thread info. how often will we be accessing this data? -// seems we will need to be able to access it from 2 places: -// - from mutator (can compute thread id here) -// - from collector (need to be able to iterate across all mutators) -// #include -// printf("tid = %d\n", syscall(SYS_gettid)); -// -// TODO: -// ACTION - I think the most efficient solution is to have each thread pass around -// the pointer to it's thread data. this param would have to be passed to all -// continuation calls made by the thread. -// the collector/runtime will need to maintain a list of the thread data structures, -// and will need to maintain it when a thread is created or terminated (either -// explicitly or when it returns). -// practically the required changes are: -// - stabilize this branch so it builds and runs (hope this just means commenting out -// the pthread calls for right now) -// - extend the runtime and compiled code to have a new thread_data (sp?) param -// also need to judge if there are issues that would prevent being able to add -// one, but it seems like it should be no problem -// - build the code and test that the value is actually maintained across calls -// (maybe assign it to a global at start and exit from GC if cur val != global val) - -// note - can atomic operations be used for last read/write, to prevent -// coarser-grained synchronization there? -// TODO: -// clean = FALSE -// while (!(clean)) -// clean = TRUE + int clean = 0, i; + while (!clean) { + clean = 1; + // TODO: need to sync access to mutator int/void data, UNLESS + // the collector thread is the only one that is using these + // fields. + for (i = 0; i < Cyc_num_mutators; i++) { + } // For each m in mutators // while (lastread[m] < lastwrite[m]) // TODO: use atomic sub to compare? // clean = FALSE // lastread[m] = lastread[m] + 1 // TODO: atomic increment // markBlack(markbuffer[m][lastread[m]]) // EmptyCollectorStack() + } } // TODO: seriously consider changing the mark() macro to color(), diff --git a/include/cyclone/runtime-main.h b/include/cyclone/runtime-main.h index 7fb99c6a..9f7edf8e 100644 --- a/include/cyclone/runtime-main.h +++ b/include/cyclone/runtime-main.h @@ -28,12 +28,7 @@ static void Cyc_heap_init(long heap_size) printf("main: Allocating and initializing heap...\n"); #endif Cyc_heap = gc_heap_create(heap_size / 2, 0, 0); - // TODO: alloca this using a vpbuffer, or maybe another type of data structure?? - // Will need this list for later use, but only by the collector thread. so it would be - // nice if there was a way to allocate mutators that avoids expensive synchronization... - // need to think on this when adding thread support, after upgrading the collector - Cyc_num_mutators = 1; - Cyc_mutators = calloc(Cyc_num_mutators, sizeof(gc_thread_data *)); + gc_init_mutators(); } #endif /* CYCLONE_RUNTIME_MAIN_H */ diff --git a/include/cyclone/runtime.h b/include/cyclone/runtime.h index 45968c1a..4b0232eb 100644 --- a/include/cyclone/runtime.h +++ b/include/cyclone/runtime.h @@ -209,8 +209,6 @@ void do_dispatch(void *data, int argc, function_type func, object clo, object *b /* Global variables. */ extern gc_heap *Cyc_heap; -extern gc_thread_data **Cyc_mutators; -extern int Cyc_num_mutators; extern long no_gcs; /* Count the number of GC's. */ extern long no_major_gcs; /* Count the number of GC's. */ diff --git a/include/cyclone/types.h b/include/cyclone/types.h index 2432cd11..330fb5d0 100644 --- a/include/cyclone/types.h +++ b/include/cyclone/types.h @@ -16,7 +16,7 @@ #include #include #include -// TODO: #include +#include // Maximum number of args that GC will accept #define NUM_GC_ANS 128 @@ -58,7 +58,7 @@ struct gc_thread_data_t { int last_read; void **mark_buffer; int mark_buffer_len; -// TODO: pthread_mutex_t lock; + pthread_mutex_t lock; }; /* GC data structures */ @@ -125,6 +125,7 @@ void **vpbuffer_add(void **buf, int *len, int i, void *obj); void vpbuffer_free(void **buf); /* GC prototypes */ +void gc_init_mutators(); gc_heap *gc_heap_create(size_t size, size_t max_size, size_t chunk_size); int gc_grow_heap(gc_heap *h, size_t size, size_t chunk_size); void *gc_try_alloc(gc_heap *h, size_t size);