This patch fixes various problems with safepoints. (1) We must increase ->nr_in_safepoint from gc_start(); otherwise we'll deadlock as the tread that called gc_start() will never enter gc_safepoint().
(2) Don't let threads enter gc_start() until we've returned from gc_start() for a previous safepoint. (3) Let only one thread wait in gc_start() when it's called concurrently. Only the first thread will wait and others will be be treated just as if they had entered gc_safepoint(). (4) Fix gc_start() when called during early bootstrap code when no threads are started. With the above fixes, GcTortureTest passes when gc_start() is called from object allocator. Cc: Vegard Nossum <vegard.nos...@gmail.com> Signed-off-by: Pekka Enberg <penb...@cs.helsinki.fi> --- vm/gc.c | 99 +++++++++++++++++++++++++++++++++++++++++--------------------- 1 files changed, 65 insertions(+), 34 deletions(-) diff --git a/vm/gc.c b/vm/gc.c index 949a6c9..37a2143 100644 --- a/vm/gc.c +++ b/vm/gc.c @@ -4,6 +4,7 @@ #include <pthread.h> #include "lib/guard-page.h" +#include "vm/thread.h" #include "vm/die.h" #include "vm/gc.h" @@ -14,12 +15,14 @@ static pthread_mutex_t safepoint_mutex = PTHREAD_MUTEX_INITIALIZER; /* Protected by safepoint_mutex */ static pthread_cond_t everyone_in_cond = PTHREAD_COND_INITIALIZER; static pthread_cond_t everyone_out_cond = PTHREAD_COND_INITIALIZER; -static unsigned int nr_threads = 0; static unsigned int nr_in_safepoint = 0; static pthread_cond_t can_continue_cond = PTHREAD_COND_INITIALIZER; static bool can_continue; +bool gc_enabled; +bool verbose_gc; + void gc_init(void) { gc_safepoint_page = alloc_guard_page(false); @@ -29,18 +32,24 @@ void gc_init(void) void gc_attach_thread(void) { - pthread_mutex_lock(&safepoint_mutex); - ++nr_threads; - pthread_mutex_unlock(&safepoint_mutex); } void gc_detach_thread(void) { - assert(nr_threads > 0); +} - pthread_mutex_lock(&safepoint_mutex); - --nr_threads; - pthread_mutex_unlock(&safepoint_mutex); +/* Callers must hold safepoint_mutex */ +static void gc_safepoint_barrier_wait(void) +{ + /* Only the GC thread will be waiting for this. */ + if (--nr_in_safepoint == 0) { + pthread_cond_broadcast(&everyone_out_cond); + return; + } + + /* Block until GC has finished */ + while (nr_in_safepoint > 0) + pthread_cond_wait(&everyone_out_cond, &safepoint_mutex); } static void hide_safepoint_guard_page(void) @@ -53,48 +62,70 @@ static void unhide_safepoint_guard_page(void) unhide_guard_page(gc_safepoint_page); } -void gc_start(void) +static void do_gc_reclaim(void) +{ + /* TODO: Do main GC work here. */ +} + +/* Callers must hold safepoint_mutex */ +static void do_gc_safepoint(void) +{ + /* Only the GC thread will be waiting for this. */ + if (++nr_in_safepoint == vm_nr_threads_running()) + pthread_cond_signal(&everyone_in_cond); + + /* Block until GC has finished */ + while (!can_continue) + pthread_cond_wait(&can_continue_cond, &safepoint_mutex); +} + +void gc_safepoint(void) { pthread_mutex_lock(&safepoint_mutex); - assert(nr_in_safepoint == 0); + do_gc_safepoint(); + + gc_safepoint_barrier_wait(); + pthread_mutex_unlock(&safepoint_mutex); +} + +void gc_start(void) +{ + pthread_mutex_lock(&safepoint_mutex); + + /* There are no threads running during early bootstrap. */ + if (vm_nr_threads_running() == 0) { + pthread_mutex_unlock(&safepoint_mutex); + return; + } + + /* + * If someone entered the reclaim path before us, make the current + * thread enter a regular safepoint. + */ + if (nr_in_safepoint != 0) { + do_gc_safepoint(); + goto out; + } + + ++nr_in_safepoint; can_continue = false; hide_safepoint_guard_page(); - while (nr_in_safepoint != nr_threads) + while (nr_in_safepoint != vm_nr_threads_running()) pthread_cond_wait(&everyone_in_cond, &safepoint_mutex); /* At this point, we know that everyone is in the safepoint. */ unhide_safepoint_guard_page(); - /* TODO: Do main GC work here. */ + do_gc_reclaim(); /* Resume other threads */ can_continue = true; pthread_cond_broadcast(&can_continue_cond); - - while (nr_in_safepoint != 0) - pthread_cond_wait(&everyone_out_cond, &safepoint_mutex); - - pthread_mutex_unlock(&safepoint_mutex); -} - -void gc_safepoint(void) -{ - pthread_mutex_lock(&safepoint_mutex); - - /* Only the GC thread will be waiting for this. */ - if (++nr_in_safepoint == nr_threads) - pthread_cond_signal(&everyone_in_cond); - - /* Block until GC has finished */ - while (!can_continue) - pthread_cond_wait(&can_continue_cond, &safepoint_mutex); - - /* Only the GC thread will be waiting for this. */ - if (--nr_in_safepoint == 0) - pthread_cond_signal(&everyone_out_cond); +out: + gc_safepoint_barrier_wait(); pthread_mutex_unlock(&safepoint_mutex); } -- 1.5.6.3 ------------------------------------------------------------------------------ Let Crystal Reports handle the reporting - Free Crystal Reports 2008 30-Day trial. Simplify your report design, integration and deployment - and focus on what you do best, core application coding. Discover what's new with Crystal Reports now. http://p.sf.net/sfu/bobj-july _______________________________________________ Jatovm-devel mailing list Jatovm-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/jatovm-devel