diff --git a/api/gc-api.h b/api/gc-api.h index 502a6abe2..01ad113a8 100644 --- a/api/gc-api.h +++ b/api/gc-api.h @@ -53,8 +53,12 @@ GC_API_ void gc_heap_set_extern_space(struct gc_heap *heap, GC_API_ struct gc_mutator* gc_init_for_thread(struct gc_stack_addr base, struct gc_heap *heap); GC_API_ void gc_finish_for_thread(struct gc_mutator *mut); -GC_API_ void* gc_call_without_gc(struct gc_mutator *mut, void* (*f)(void*), - void *data) GC_NEVER_INLINE; +GC_API_ void* gc_deactivate_for_call(struct gc_mutator *mut, + void* (*f)(struct gc_mutator*, void*), + void *data) GC_NEVER_INLINE; +GC_API_ void* gc_reactivate_for_call(struct gc_mutator *mut, + void* (*f)(struct gc_mutator*, void*), + void *data) GC_NEVER_INLINE; GC_API_ void gc_collect(struct gc_mutator *mut, enum gc_collection_kind requested_kind); diff --git a/benchmarks/ephemerons.c b/benchmarks/ephemerons.c index c74db9d43..f0459dab4 100644 --- a/benchmarks/ephemerons.c +++ b/benchmarks/ephemerons.c @@ -183,7 +183,7 @@ static void* run_one_test_in_thread(void *arg) { } struct join_data { int status; pthread_t thread; }; -static void *join_thread(void *data) { +static void *join_thread(struct gc_mutator *unused, void *data) { struct join_data *join_data = data; void *ret; join_data->status = pthread_join(join_data->thread, &ret); @@ -256,7 +256,7 @@ int main(int argc, char *argv[]) { run_one_test(&main_thread); for (size_t i = 1; i < nthreads; i++) { struct join_data data = { 0, threads[i] }; - gc_call_without_gc(mut, join_thread, &data); + gc_deactivate_for_call(mut, join_thread, &data); if (data.status) { errno = data.status; perror("Failed to join thread"); diff --git a/benchmarks/finalizers.c b/benchmarks/finalizers.c index 79a2660c3..8d4b5c25a 100644 --- a/benchmarks/finalizers.c +++ b/benchmarks/finalizers.c @@ -190,7 +190,7 @@ static void* run_one_test_in_thread(void *arg) { } struct join_data { int status; pthread_t thread; }; -static void *join_thread(void *data) { +static void *join_thread(struct gc_mutator *unused, void *data) { struct join_data *join_data = data; void *ret; join_data->status = pthread_join(join_data->thread, &ret); @@ -263,7 +263,7 @@ int main(int argc, char *argv[]) { ssize_t outstanding = (size_t)run_one_test(&main_thread); for (size_t i = 1; i < nthreads; i++) { struct join_data data = { 0, threads[i] }; - void *ret = gc_call_without_gc(mut, join_thread, &data); + void *ret = gc_deactivate_for_call(mut, join_thread, &data); if (data.status) { errno = data.status; perror("Failed to join thread"); diff --git a/benchmarks/mt-gcbench.c b/benchmarks/mt-gcbench.c index 62fdc7154..e705702bb 100644 --- a/benchmarks/mt-gcbench.c +++ b/benchmarks/mt-gcbench.c @@ -319,7 +319,7 @@ static void* run_one_test_in_thread(void *arg) { } struct join_data { int status; pthread_t thread; }; -static void *join_thread(void *data) { +static void *join_thread(struct gc_mutator *unused, void *data) { struct join_data *join_data = data; void *ret; join_data->status = pthread_join(join_data->thread, &ret); @@ -389,7 +389,7 @@ int main(int argc, char *argv[]) { run_one_test(&main_thread); for (size_t i = 1; i < nthreads; i++) { struct join_data data = { 0, threads[i] }; - gc_call_without_gc(mut, join_thread, &data); + gc_deactivate_for_call(mut, join_thread, &data); if (data.status) { errno = data.status; perror("Failed to join thread"); diff --git a/src/bdw.c b/src/bdw.c index e9268ef81..c6e2b4341 100644 --- a/src/bdw.c +++ b/src/bdw.c @@ -657,10 +657,29 @@ void gc_finish_for_thread(struct gc_mutator *mut) { GC_unregister_my_thread(); } -void* gc_call_without_gc(struct gc_mutator *mut, - void* (*f)(void*), - void *data) { - return GC_do_blocking(f, data); +struct call_with_mutator_data { + void* (*proc) (struct gc_mutator*, void*); + struct gc_mutator *mutator; + void *data; +}; + +static void* call_with_mutator (void *p) { + struct call_with_mutator_data *data = p; + return data->proc(data->mutator, data->data); +} + +void* gc_deactivate_for_call(struct gc_mutator *mut, + void* (*f)(struct gc_mutator *, void*), + void *data) { + struct call_with_mutator_data d = { f, mut, data }; + return GC_do_blocking(call_with_mutator, &d); +} + +void* gc_reactivate_for_call(struct gc_mutator *mut, + void* (*f)(struct gc_mutator *, void*), + void *data) { + struct call_with_mutator_data d = { f, mut, data }; + return GC_call_with_gc_active(call_with_mutator, &d); } void gc_mutator_set_roots(struct gc_mutator *mut, diff --git a/src/mmc.c b/src/mmc.c index f67621b93..a1329e239 100644 --- a/src/mmc.c +++ b/src/mmc.c @@ -88,6 +88,7 @@ struct gc_mutator { void *event_listener_data; struct gc_mutator *next; struct gc_mutator *prev; + int active; }; struct gc_trace_worker_data { @@ -216,6 +217,7 @@ add_mutator(struct gc_heap *heap, struct gc_mutator *mut) { while (mutators_are_stopping(heap)) pthread_cond_wait(&heap->mutator_cond, &heap->lock); mut->next = mut->prev = NULL; + mut->active = 1; struct gc_mutator *tail = heap->mutators; if (tail) { mut->next = tail; @@ -235,6 +237,7 @@ remove_mutator(struct gc_heap *heap, struct gc_mutator *mut) { mut->heap = NULL; heap_lock(heap); heap->mutator_count--; + mut->active = 0; if (mut->next) mut->next->prev = mut->prev; if (mut->prev) @@ -1277,6 +1280,7 @@ deactivate_mutator(struct gc_heap *heap, struct gc_mutator *mut) { gc_field_set_writer_release_buffer(&mut->logger); heap_lock(heap); heap->inactive_mutator_count++; + mut->active = 0; gc_stack_capture_hot(&mut->stack); if (all_mutators_stopped(heap)) pthread_cond_signal(&heap->collector_cond); @@ -1288,15 +1292,32 @@ reactivate_mutator(struct gc_heap *heap, struct gc_mutator *mut) { heap_lock(heap); while (mutators_are_stopping(heap)) pthread_cond_wait(&heap->mutator_cond, &heap->lock); + mut->active = 1; heap->inactive_mutator_count--; heap_unlock(heap); } void* -gc_call_without_gc(struct gc_mutator *mut, void* (*f)(void*), void *data) { +gc_deactivate_for_call(struct gc_mutator *mut, + void* (*f)(struct gc_mutator*, void*), + void *data) { struct gc_heap *heap = mutator_heap(mut); deactivate_mutator(heap, mut); - void *ret = f(data); + void *ret = f(mut, data); reactivate_mutator(heap, mut); return ret; } + +void* +gc_reactivate_for_call(struct gc_mutator *mut, + void* (*f)(struct gc_mutator*, void*), + void *data) { + struct gc_heap *heap = mutator_heap(mut); + int reactivate = !mut->active; + if (reactivate) + reactivate_mutator(heap, mut); + void *ret = f(mut, data); + if (reactivate) + deactivate_mutator(heap, mut); + return ret; +} diff --git a/src/pcc.c b/src/pcc.c index bda42730b..609160a15 100644 --- a/src/pcc.c +++ b/src/pcc.c @@ -96,6 +96,7 @@ struct gc_mutator { void *event_listener_data; struct gc_mutator *next; struct gc_mutator *prev; + int active; }; struct gc_trace_worker_data { @@ -501,6 +502,7 @@ static void add_mutator(struct gc_heap *heap, struct gc_mutator *mut) { while (mutators_are_stopping(heap)) pthread_cond_wait(&heap->mutator_cond, &heap->lock); mut->next = mut->prev = NULL; + mut->active = 1; struct gc_mutator *tail = heap->mutators; if (tail) { mut->next = tail; @@ -520,6 +522,7 @@ static void remove_mutator(struct gc_heap *heap, struct gc_mutator *mut) { mut->heap = NULL; heap_lock(heap); heap->mutator_count--; + mut->active = 0; if (mut->next) mut->next->prev = mut->prev; if (mut->prev) @@ -1357,31 +1360,48 @@ void gc_finish_for_thread(struct gc_mutator *mut) { static void deactivate_mutator(struct gc_heap *heap, struct gc_mutator *mut) { GC_ASSERT(mut->next == NULL); + GC_ASSERT(mut->active); copy_space_allocator_finish(&mut->allocator, heap_allocation_space(heap)); if (GC_GENERATIONAL) gc_field_set_writer_release_buffer(mutator_field_logger(mut)); heap_lock(heap); heap->inactive_mutator_count++; + mut->active = 0; if (all_mutators_stopped(heap)) pthread_cond_signal(&heap->collector_cond); heap_unlock(heap); } static void reactivate_mutator(struct gc_heap *heap, struct gc_mutator *mut) { + GC_ASSERT(!mut->active); heap_lock(heap); while (mutators_are_stopping(heap)) pthread_cond_wait(&heap->mutator_cond, &heap->lock); + mut->active = 1; heap->inactive_mutator_count--; maybe_increase_max_active_mutator_count(heap); heap_unlock(heap); } -void* gc_call_without_gc(struct gc_mutator *mut, - void* (*f)(void*), - void *data) { +void* gc_deactivate_for_call(struct gc_mutator *mut, + void* (*f)(struct gc_mutator*, void*), + void *data) { struct gc_heap *heap = mutator_heap(mut); deactivate_mutator(heap, mut); - void *ret = f(data); + void *ret = f(mut, data); reactivate_mutator(heap, mut); return ret; } + +void* gc_reactivate_for_call(struct gc_mutator *mut, + void* (*f)(struct gc_mutator*, void*), + void *data) { + struct gc_heap *heap = mutator_heap(mut); + int reactivate = !mut->active; + if (reactivate) + reactivate_mutator(heap, mut); + void *ret = f(mut, data); + if (reactivate) + deactivate_mutator(heap, mut); + return ret; +} diff --git a/src/semi.c b/src/semi.c index 41c78a178..913c983c1 100644 --- a/src/semi.c +++ b/src/semi.c @@ -763,8 +763,16 @@ struct gc_mutator* gc_init_for_thread(struct gc_stack_addr base, void gc_finish_for_thread(struct gc_mutator *space) { } -void* gc_call_without_gc(struct gc_mutator *mut, void* (*f)(void*), - void *data) { +void* gc_deactivate_for_call(struct gc_mutator *mut, + void* (*f)(struct gc_mutator *, void*), + void *data) { // Can't be threads, then there won't be collection. - return f(data); + return f(mut, data); +} + +void* gc_reactivate_for_call(struct gc_mutator *mut, + void* (*f)(struct gc_mutator *mut, void*), + void *data) { + // Can't be threads, then there won't be collection. + return f(mut, data); }