diff --git a/gc.c b/gc.c index 04eb126a..34d27d03 100644 --- a/gc.c +++ b/gc.c @@ -105,6 +105,17 @@ void gc_add_mutator(gc_thread_data *thd) pthread_mutex_unlock(&mutators_lock); } +void gc_remove_mutator(gc_thread_data *thd) +{ + pthread_mutex_lock(&mutators_lock); + if (!ck_array_remove(&Cyc_mutators, (void *)thd)) { + fprintf(stderr, "Unable to remove thread data, exiting\n"); + exit(1); + } + ck_array_commit(&Cyc_mutators); + pthread_mutex_unlock(&mutators_lock); +} + gc_heap *gc_heap_create(size_t size, size_t max_size, size_t chunk_size) { gc_free_list *free, *next; @@ -1084,7 +1095,7 @@ void gc_wait_handshake() { ck_array_iterator_t iterator; gc_thread_data *m; - int statusm, statusc; + int statusm, statusc, thread_status; struct timespec tim; tim.tv_sec = 0; tim.tv_nsec = 1000000; // 1 millisecond @@ -1093,11 +1104,17 @@ void gc_wait_handshake() while (1) { statusc = ATOMIC_GET(&gc_status_col); statusm = ATOMIC_GET(&(m->gc_status)); + thread_status = ATOMIC_GET(&(m->thread_state)); if (statusc == statusm) { // Handshake succeeded, check next mutator break; } + if (thread_status == CYC_THREAD_STATE_TERMINATED) { + // Thread is no longer running + break; + } + // At least for now, just give up quantum and come back to // this quickly to test again. This probably could be more // efficient. diff --git a/include/cyclone/types.h b/include/cyclone/types.h index 7d3b7006..b2c23252 100644 --- a/include/cyclone/types.h +++ b/include/cyclone/types.h @@ -171,6 +171,7 @@ void vpbuffer_free(void **buf); /* GC prototypes */ void gc_initialize(); void gc_add_mutator(gc_thread_data *thd); +void gc_remove_mutator(gc_thread_data *thd); 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); char *gc_copy_obj(object hp, char *obj, gc_thread_data *thd); diff --git a/runtime.c b/runtime.c index 160f8680..3d8911a6 100644 --- a/runtime.c +++ b/runtime.c @@ -2493,9 +2493,6 @@ TODO: should rename this function to make it more clear what is really going on */ void Cyc_start_thread(gc_thread_data *thd) { -// TODO: should use an atomic set to modify this - thd->thread_state = CYC_THREAD_STATE_RUNNABLE; - /* Tank, load the jump program... */ setjmp(*(thd->jmp_start)); @@ -3211,7 +3208,12 @@ void Cyc_exit_thread(gc_thread_data *thd) // terminating the thread printf("DEBUG - exiting thread\n"); +// TODO: race condition, cannot free thread data if the collector is using it + gc_remove_mutator(thd); ATOMIC_SET_IF_EQ(&(thd->thread_state), CYC_THREAD_STATE_RUNNABLE, CYC_THREAD_STATE_TERMINATED); +// TODO: could maintain a dedicated list of old thread data to clean up... +// collector could do it at a time that is safe +// gc_thread_data_free(thd); pthread_exit(NULL); // For now, just a proof of concept }