]> granicus.if.org Git - gc/commitdiff
Add public GC_start_mark_threads() to allow parallel marker in fork child
authorIvan Maidanski <ivmai@mail.ru>
Mon, 19 Nov 2012 15:58:51 +0000 (19:58 +0400)
committerIvan Maidanski <ivmai@mail.ru>
Mon, 19 Nov 2012 15:58:51 +0000 (19:58 +0400)
* include/gc.h (GC_start_mark_threads): New API function prototype.
* misc.c (GC_start_mark_threads): New API function definition (empty)
if THREADS but not PARALLEL_MARK or not CAN_HANDLE_FORK.
* pthread_support.c (available_markers_m1): New static variable or
macro (redirecting to GC_markers_m1) depending on CAN_HANDLE_FORK
(only if PARALLEL_MARK).
* win32_threads.c (available_markers_m1): Likewise.
* pthread_support.c (start_mark_threads): Redirect to
GC_start_mark_threads (and decorate with GC_API/GC_CALL) if
CAN_HANDLE_FORK (and PARALLEL_MARK); skip start if parallel markers
are disabled or already started if CAN_HANDLE_FORK; iterate up to
available_markers_m1 (instead of GC_markers_m1); always set
GC_markers_m1 value.
* win32_threads.c (start_mark_threads): Likewise.
* pthread_support.c (GC_thr_init): Set (and test) available_markers_m1
value instead of GC_markers_m1/GC_parallel (only if PARALLEL_MARK).
* win32_threads.c (GC_thr_init): Likewise.
* tests/test.c (NO_TEST_HANDLE_FORK): Do not define if
TEST_HANDLE_FORK.
* tests/test.c (run_one_test): Invoke GC_start_mark_threads (and
additional GC_gcollect) in forked child (only if THREADS but not
NO_TEST_HANDLE_FORK); do not call tiny_reverse_test if not THREADS.
* win32_threads.c (start_mark_threads): Add assertion that the caller
is not holding the allocation lock (to match that in
pthread_support.c) if GC_PTHREADS_PARAMARK.

include/gc.h
misc.c
pthread_support.c
tests/test.c
win32_threads.c

index 4f32b485860b17bec5f67c26f2e590413f856fb0..c7c4f00b78b09091a13ec3cc491b20fe70d6836b 100644 (file)
@@ -1218,6 +1218,10 @@ GC_API void * GC_CALL GC_call_with_stack_base(GC_stack_base_func /* fn */,
   /* systems.  Return -1 otherwise.                                     */
   GC_API int GC_CALL GC_get_thr_restart_signal(void);
 
+  /* Restart marker threads after POSIX fork in child.  Meaningless in  */
+  /* other situations.  Should not be called if fork followed by exec.  */
+  GC_API void GC_CALL GC_start_mark_threads(void);
+
   /* Explicitly enable GC_register_my_thread() invocation.              */
   /* Done implicitly if a GC thread-creation function is called (or     */
   /* implicit thread registration is activated).  Otherwise, it must    */
diff --git a/misc.c b/misc.c
index 2c197ff6cb3e0f2509909d574a3e30a6bab6ef84..861f00d717e55837aec70883b7cf124564e6075a 100644 (file)
--- a/misc.c
+++ b/misc.c
@@ -1231,6 +1231,14 @@ GC_API void GC_CALL GC_enable_incremental(void)
   GC_init();
 }
 
+#if defined(THREADS) && (!defined(PARALLEL_MARK) || !defined(CAN_HANDLE_FORK))
+  GC_API void GC_CALL GC_start_mark_threads(void)
+  {
+    /* No action since parallel markers are disabled (or no POSIX fork). */
+    GC_ASSERT(I_DONT_HOLD_LOCK());
+  }
+#endif
+
 #if defined(MSWIN32) || defined(MSWINCE)
 
 # if defined(_MSC_VER) && defined(_DEBUG) && !defined(MSWINCE)
index b5fe6962c4f333019264e30e0df08ab964fc6382..84c95fbfcec483d1c6d5ca5f01e8754175270f2b 100644 (file)
@@ -390,12 +390,25 @@ STATIC void * GC_mark_thread(void * id)
 
 STATIC pthread_t GC_mark_threads[MAX_MARKERS];
 
-static void start_mark_threads(void)
+#ifdef CAN_HANDLE_FORK
+  static int available_markers_m1 = 0;
+# define start_mark_threads GC_start_mark_threads
+  GC_API void GC_CALL
+#else
+# define available_markers_m1 GC_markers_m1
+  static void
+#endif
+start_mark_threads(void)
 {
     int i;
     pthread_attr_t attr;
 
     GC_ASSERT(I_DONT_HOLD_LOCK());
+#   ifdef CAN_HANDLE_FORK
+      if (available_markers_m1 <= 0 || GC_parallel) return;
+                /* Skip if parallel markers disabled or already started. */
+#   endif
+
     INIT_REAL_SYMS(); /* for pthread_create */
 
     if (0 != pthread_attr_init(&attr)) ABORT("pthread_attr_init failed");
@@ -418,16 +431,16 @@ static void start_mark_threads(void)
         }
       }
 #   endif /* HPUX || GC_DGUX386_THREADS */
-    for (i = 0; i < GC_markers_m1; ++i) {
+    for (i = 0; i < available_markers_m1; ++i) {
       if (0 != REAL_FUNC(pthread_create)(GC_mark_threads + i, &attr,
                               GC_mark_thread, (void *)(word)i)) {
         WARN("Marker thread creation failed, errno = %" WARN_PRIdPTR "\n",
              errno);
         /* Don't try to create other marker threads.    */
-        GC_markers_m1 = i;
         break;
       }
     }
+    GC_markers_m1 = i;
     pthread_attr_destroy(&attr);
     GC_COND_LOG_PRINTF("Started %d mark helper threads\n", GC_markers_m1);
 }
@@ -1054,7 +1067,7 @@ GC_INNER void GC_thr_init(void)
     WARN("GC_get_nprocs() returned %" WARN_PRIdPTR "\n", GC_nprocs);
     GC_nprocs = 2; /* assume dual-core */
 #   ifdef PARALLEL_MARK
-      GC_parallel = FALSE; /* but use only one marker */
+      available_markers_m1 = 0; /* but use only one marker */
 #   endif
   } else {
 #  ifdef PARALLEL_MARK
@@ -1078,13 +1091,13 @@ GC_INNER void GC_thr_init(void)
          if (markers_m1 >= MAX_MARKERS)
            markers_m1 = MAX_MARKERS - 1; /* silently limit the value */
        }
-       GC_markers_m1 = markers_m1;
+       available_markers_m1 = markers_m1;
      }
 #  endif
   }
   GC_COND_LOG_PRINTF("Number of processors = %d\n", GC_nprocs);
 # ifdef PARALLEL_MARK
-    if (GC_markers_m1 <= 0) {
+    if (available_markers_m1 <= 0) {
       /* Disable parallel marking.      */
       GC_parallel = FALSE;
       GC_COND_LOG_PRINTF(
index 6e993a99e7432337be0876fd08d8a1b59944887d..583df924c33fda039327c52e16d58eb93df4b0c3 100644 (file)
@@ -89,7 +89,7 @@
 # if (!defined(THREADS) || !defined(HANDLE_FORK) \
       || (defined(DARWIN) && defined(MPROTECT_VDB) \
           && !defined(NO_INCREMENTAL) && !defined(MAKE_BACK_GRAPH))) \
-     && !defined(NO_TEST_HANDLE_FORK)
+     && !defined(NO_TEST_HANDLE_FORK) && !defined(TEST_HANDLE_FORK)
 #   define NO_TEST_HANDLE_FORK
 # endif
 
@@ -1301,9 +1301,17 @@ void run_one_test(void)
     (void)GC_call_with_alloc_lock(inc_int_counter, &n_tests);
 #   ifndef NO_TEST_HANDLE_FORK
       if (fork() == 0) {
+#       ifdef THREADS
+#         ifdef PARALLEL_MARK
+            GC_gcollect(); /* no parallel markers */
+#         endif
+          GC_start_mark_threads();
+#       endif
         GC_gcollect();
-        tiny_reverse_test(0);
-        GC_gcollect();
+#       ifdef THREADS
+          tiny_reverse_test(0);
+          GC_gcollect();
+#       endif
         if (print_stats)
           GC_log_printf("Finished a child process\n");
         exit(0);
index bddafa0a3dbde7cb4f0bcd4b75f70b3e9cac1207..45466beee51a17a979d323313f43641570056df2 100644 (file)
@@ -1704,6 +1704,10 @@ GC_INNER void GC_get_next_stack(char *start, char *limit,
 
   /* GC_mark_threads[] is unused here unlike that in pthread_support.c  */
 
+# ifndef CAN_HANDLE_FORK
+#   define available_markers_m1 GC_markers_m1
+# endif
+
 # ifdef GC_PTHREADS_PARAMARK
 #   include <pthread.h>
 
@@ -1713,26 +1717,39 @@ GC_INNER void GC_get_next_stack(char *start, char *limit,
 
     /* start_mark_threads is the same as in pthread_support.c except    */
     /* for thread stack that is assumed to be large enough.             */
-    static void start_mark_threads(void)
+#   ifdef CAN_HANDLE_FORK
+      static int available_markers_m1 = 0;
+#     define start_mark_threads GC_start_mark_threads
+      GC_API void GC_CALL
+#   else
+      static void
+#   endif
+    start_mark_threads(void)
     {
       int i;
       pthread_attr_t attr;
       pthread_t new_thread;
 
+      GC_ASSERT(I_DONT_HOLD_LOCK());
+#     ifdef CAN_HANDLE_FORK
+        if (available_markers_m1 <= 0 || GC_parallel) return;
+                /* Skip if parallel markers disabled or already started. */
+#     endif
+
       if (0 != pthread_attr_init(&attr)) ABORT("pthread_attr_init failed");
       if (0 != pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED))
         ABORT("pthread_attr_setdetachstate failed");
 
-      for (i = 0; i < GC_markers_m1; ++i) {
+      for (i = 0; i < available_markers_m1; ++i) {
         marker_last_stack_min[i] = ADDR_LIMIT;
         if (0 != pthread_create(&new_thread, &attr,
                                 GC_mark_thread, (void *)(word)i)) {
           WARN("Marker thread creation failed.\n", 0);
           /* Don't try to create other marker threads.    */
-          GC_markers_m1 = i;
           break;
         }
       }
+      GC_markers_m1 = i;
       pthread_attr_destroy(&attr);
       GC_COND_LOG_PRINTF("Started %d mark helper threads\n", GC_markers_m1);
     }
@@ -2442,7 +2459,7 @@ GC_INNER void GC_thr_init(void)
         if (markers_m1 >= MAX_MARKERS)
           markers_m1 = MAX_MARKERS - 1; /* silently limit the value */
       }
-      GC_markers_m1 = markers_m1;
+      available_markers_m1 = markers_m1;
     }
 
     /* Check whether parallel mode could be enabled.    */
@@ -2452,7 +2469,7 @@ GC_INNER void GC_thr_init(void)
         HMODULE hK32;
         /* SignalObjectAndWait() API call works only under NT.          */
 #     endif
-      if (GC_win32_dll_threads || GC_markers_m1 <= 0
+      if (GC_win32_dll_threads || available_markers_m1 <= 0
 #         if !defined(GC_PTHREADS_PARAMARK) && !defined(MSWINCE) \
                 && !defined(DONT_USE_SIGNALANDWAIT)
             || GC_wnt == FALSE
@@ -2490,7 +2507,9 @@ GC_INNER void GC_thr_init(void)
   GC_register_my_thread_inner(&sb, GC_main_thread);
 
 # ifdef PARALLEL_MARK
-    if (GC_parallel)
+#   ifndef CAN_HANDLE_FORK
+      if (GC_parallel)
+#   endif
     {
       /* If we are using a parallel marker, actually start helper threads. */
       start_mark_threads();