This fixes various of deadlocks and race conditions in gc_start() when
called from object allocator:

  (1) Don't deadlock during early bootstrap when there are no running
      threads.

  (2) Use vm_nr_threads_running() that accurately keeps track of
      running threads so that we don't deadlock on a thread that waits
      on a monitor.

  (3) Make gc_start() re-entrant while waiting for threads to arrive
      at a safepoint by turning gc_start() into a safepoint.

  (4) Make sure all threads exit their safepoint before letting a thread
      stop the world.

Cc: Vegard Nossum <vegard.nos...@gmail.com>
Signed-off-by: Pekka Enberg <penb...@cs.helsinki.fi>
---
 vm/gc.c |  118 +++++++++++++++++++++++++++++++++++++++++++-------------------
 1 files changed, 82 insertions(+), 36 deletions(-)

diff --git a/vm/gc.c b/vm/gc.c
index 949a6c9..7ab37b7 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,11 +15,11 @@ 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 unsigned int nr_exiting_safepoint;
+static unsigned int nr_in_safepoint;
 
 static pthread_cond_t can_continue_cond = PTHREAD_COND_INITIALIZER;
-static bool can_continue;
+static bool can_continue = true;
 
 void gc_init(void)
 {
@@ -29,18 +30,10 @@ 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);
 }
 
 static void hide_safepoint_guard_page(void)
@@ -53,48 +46,101 @@ static void unhide_safepoint_guard_page(void)
        unhide_guard_page(gc_safepoint_page);
 }
 
-void gc_start(void)
+static void do_gc_reclaim(void)
 {
-       pthread_mutex_lock(&safepoint_mutex);
+       /* TODO: Do main GC work here. */
+}
 
-       assert(nr_in_safepoint == 0);
+/* Callers must hold safepoint_mutex */
+static void gc_safepoint_exit(void)
+{
+       assert(nr_exiting_safepoint > 0);
+
+       /*
+        * Don't let threads stop the world until everyone is out of their
+        * safepoint.
+        */
+       if (--nr_exiting_safepoint == 0)
+               pthread_cond_broadcast(&everyone_out_cond);
+}
 
-       can_continue = false;
-       hide_safepoint_guard_page();
+/* 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);
 
-       while (nr_in_safepoint != nr_threads)
-               pthread_cond_wait(&everyone_in_cond, &safepoint_mutex);
+       /* Block until GC has finished */
+       while (!can_continue)
+               pthread_cond_wait(&can_continue_cond, &safepoint_mutex);
 
-       /* At this point, we know that everyone is in the safepoint. */
-       unhide_safepoint_guard_page();
+       assert(nr_in_safepoint > 0);
+       --nr_in_safepoint;
+}
 
-       /* TODO: Do main GC work here. */
+void gc_safepoint(void)
+{
+       pthread_mutex_lock(&safepoint_mutex);
 
-       /* Resume other threads */
-       can_continue = true;
-       pthread_cond_broadcast(&can_continue_cond);
+       do_gc_safepoint();
 
-       while (nr_in_safepoint != 0)
-               pthread_cond_wait(&everyone_out_cond, &safepoint_mutex);
+       gc_safepoint_exit();
 
        pthread_mutex_unlock(&safepoint_mutex);
 }
 
-void gc_safepoint(void)
+/*
+ * This is the main entrypoint to the stop-the-world GC.
+ */
+void gc_start(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);
+       /* Don't deadlock during early boostrap. */
+       if (vm_nr_threads_running() == 0)
+               goto out_unlock;
 
-       /* Block until GC has finished */
-       while (!can_continue)
-               pthread_cond_wait(&can_continue_cond, &safepoint_mutex);
+       /*
+        * Wait until all threads have exited their safepoint before stopping
+        * the world again.
+        */
+       while (nr_exiting_safepoint > 0)
+               pthread_cond_wait(&everyone_out_cond, &safepoint_mutex);
 
-       /* Only the GC thread will be waiting for this. */
-       if (--nr_in_safepoint == 0)
-               pthread_cond_signal(&everyone_out_cond);
+       /*
+        * If someone stopped the world before us, put the current thread in a
+        * safepoint.
+        */
+       if (nr_in_safepoint != 0) {
+               do_gc_safepoint();
+               goto out_exit_safepoint;
+       }
+
+       /* Only one thread can stop the world at a time. */
+       assert(can_continue);
+
+       ++nr_in_safepoint;
+       can_continue = false;
+       hide_safepoint_guard_page();
+
+       /* Wait for all other threads to enter a safepoint. */
+       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();
+
+       do_gc_reclaim();
+
+       /* Resume other threads */
+       assert(nr_in_safepoint > 0);
+       nr_exiting_safepoint = nr_in_safepoint--;
+       can_continue = true;
+       pthread_cond_broadcast(&can_continue_cond);
 
+out_exit_safepoint:
+       gc_safepoint_exit();
+out_unlock:
        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

Reply via email to