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 |  136 ++++++++++++++++++++++++++++++++++++++++++++++++++++----------
 1 files changed, 114 insertions(+), 22 deletions(-)

diff --git a/vm/gc.c b/vm/gc.c
index 949a6c9..921add3 100644
--- a/vm/gc.c
+++ b/vm/gc.c
@@ -20,6 +20,14 @@ static unsigned int nr_in_safepoint = 0;
 static pthread_cond_t can_continue_cond = PTHREAD_COND_INITIALIZER;
 static bool can_continue;
 
+static pthread_cond_t can_attach_cond = PTHREAD_COND_INITIALIZER;
+static bool can_attach = true;
+
+static pthread_barrier_t safepoint_barrier;
+
+bool gc_enabled;
+bool verbose_gc;
+
 void gc_init(void)
 {
        gc_safepoint_page = alloc_guard_page(false);
@@ -30,7 +38,24 @@ void gc_init(void)
 void gc_attach_thread(void)
 {
        pthread_mutex_lock(&safepoint_mutex);
+
+       /* Block until GC has finished */
+       while (!can_attach)
+               pthread_cond_wait(&can_attach_cond, &safepoint_mutex);
+
+       if (nr_in_safepoint != 0)
+               die("threads in safepoint");
+
+       if (nr_threads > 0) {
+               if (pthread_barrier_destroy(&safepoint_barrier) != 0)
+                       die("pthread_barrier_destroy");
+       }
+
        ++nr_threads;
+
+       if (pthread_barrier_init(&safepoint_barrier, NULL, nr_threads) < 0)
+               die("pthread_barrier_init");
+
        pthread_mutex_unlock(&safepoint_mutex);
 }
 
@@ -39,10 +64,46 @@ void gc_detach_thread(void)
        assert(nr_threads > 0);
 
        pthread_mutex_lock(&safepoint_mutex);
+
+       if (nr_in_safepoint != 0)
+               die("threads in safepoint");
+
+       if (nr_threads > 0) {
+               if (pthread_barrier_destroy(&safepoint_barrier) != 0)
+                       die("pthread_barrier_destroy");
+       }
+
        --nr_threads;
+
+       if (pthread_barrier_init(&safepoint_barrier, NULL, nr_threads) < 0)
+               die("pthread_barrier_init");
+
        pthread_mutex_unlock(&safepoint_mutex);
 }
 
+static void gc_safepoint_barrier_wait(void)
+{
+       int err;
+
+       /*
+        * Ensure nobody enters a new safepoint until everyone is out of the
+        * current one.
+        */
+       err = pthread_barrier_wait(&safepoint_barrier);
+       switch (err) {
+       case PTHREAD_BARRIER_SERIAL_THREAD: {
+               pthread_mutex_lock(&safepoint_mutex);
+               can_attach = true;
+               pthread_cond_broadcast(&can_attach_cond);
+               pthread_mutex_unlock(&safepoint_mutex);
+       }
+       case 0:
+               break;
+       default:
+               die("pthread_barrier_wait");
+       }
+}
+
 static void hide_safepoint_guard_page(void)
 {
        hide_guard_page(gc_safepoint_page);
@@ -53,12 +114,59 @@ 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 == 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);
+}
+
+void gc_safepoint(void)
 {
        pthread_mutex_lock(&safepoint_mutex);
 
-       assert(nr_in_safepoint == 0);
+       do_gc_safepoint();
+
+       pthread_mutex_unlock(&safepoint_mutex);
+
+       gc_safepoint_barrier_wait();
+}
 
+void gc_start(void)
+{
+       pthread_mutex_lock(&safepoint_mutex);
+
+       /* There are no threads running during early bootstrap. */
+       if (nr_threads == 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_attach = false;
        can_continue = false;
        hide_safepoint_guard_page();
 
@@ -68,33 +176,17 @@ void gc_start(void)
        /* 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 */
+       --nr_in_safepoint;
        can_continue = true;
        pthread_cond_broadcast(&can_continue_cond);
 
        while (nr_in_safepoint != 0)
                pthread_cond_wait(&everyone_out_cond, &safepoint_mutex);
-
+out:
        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);
-
-       pthread_mutex_unlock(&safepoint_mutex);
+       gc_safepoint_barrier_wait();
 }
-- 
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