]> granicus.if.org Git - gc/commitdiff
FIX: Disable incremental mode on Darwin if fork handling requested
authorIvan Maidanski <ivmai@mail.ru>
Mon, 2 Apr 2012 18:31:22 +0000 (22:31 +0400)
committerIvan Maidanski <ivmai@mail.ru>
Tue, 3 Apr 2012 04:15:54 +0000 (08:15 +0400)
* doc/README.macros (NO_HANDLE_FORK): Replace back with HANDLE_FORK
and update.
* include/private/gcconfig.h (CAN_HANDLE_FORK): Define also for Darwin
in case of MPROTECT_VDB.
* misc.c (GC_set_handle_fork): Handle Darwin properly; add comment.
* os_dep.c (GC_dirty_init): Do not turn on GC_dirty_maintained for
Darwin if GC_handle_fork is on; add comment; remove FIXME.
* pthread_support.c (GC_fork_prepare_proc): Remove WARN for Darwin
(since GC_dirty_maintained is off in that case).
* pthread_support.c (GC_fork_child_proc): Remove comment (for Darwin).

doc/README.macros
include/private/gcconfig.h
misc.c
os_dep.c
pthread_support.c

index c745eb35c92dd7e21de94d77ef58e684162d7836..cf6a14d8bce631d1dbf76becb87dea691102668f 100644 (file)
@@ -433,9 +433,9 @@ STUBBORN_ALLOC  Allows allocation of "hard to change" objects, and thus
   makes incremental collection easier.  Was enabled by default until 6.0.
   Rarely used, to my knowledge.
 
-NO_HANDLE_FORK (Unix only)      Do not attempt to make GC_malloc() work in
-  a child process fork()'ed from a multi-threaded parent.  (Might be required
-  if pthread_atfork is missing.)
+HANDLE_FORK (Unix and Cygwin only)      Attempt by default to make GC_malloc()
+  work in a child process fork()'ed from a multi-threaded parent.  Not fully
+  POSIX-compliant and could be disabled at runtime (before GC_INIT).
 
 TEST_WITH_SYSTEM_MALLOC         Causes gctest to allocate (and leak) large
   chunks of memory with the standard system malloc.  This will cause the root
index 7ecc80f7bc85f7f49387f8778fe01928767c2ab7..4d27bde4fdc2fa9cacfa01e2c85efad4b8aa518d 100644 (file)
 #if !defined(CAN_HANDLE_FORK) && !defined(NO_HANDLE_FORK) \
     && ((defined(GC_PTHREADS) && !defined(HURD) && !defined(NACL) \
          && !defined(PLATFORM_ANDROID) && !defined(GC_WIN32_PTHREADS)) \
-        || defined(HANDLE_FORK))
+        || (defined(DARWIN) && defined(MPROTECT_VDB)) || defined(HANDLE_FORK))
   /* Attempts (where supported and requested) to make GC_malloc work in */
   /* a child process fork'ed from a multi-threaded parent.              */
 # define CAN_HANDLE_FORK
diff --git a/misc.c b/misc.c
index fac069aaa893b4a35e9df6aacd9dd23eb3419322..5267998b0975e39d832c994ee94fc76108c3c9c5 100644 (file)
--- a/misc.c
+++ b/misc.c
@@ -169,10 +169,11 @@ GC_API void GC_CALL GC_set_handle_fork(int value)
 # ifdef CAN_HANDLE_FORK
     if (!GC_is_initialized)
       GC_handle_fork = (GC_bool)value;
-# elif defined(THREADS)
-    /* FIXME: Handle Darwin case. */
+# elif defined(THREADS) || (defined(DARWIN) && defined(MPROTECT_VDB))
     if (!GC_is_initialized && value)
       ABORT("fork() handling disabled");
+# else
+    /* No at-fork handler is needed in the single-threaded mode.        */
 # endif
 }
 
index 070756aaee3f18a9945ad4ea764f20629c1e972b..17dabcdd40bac7e5e024eb3228ae4d963cb0fa5a 100644 (file)
--- a/os_dep.c
+++ b/os_dep.c
@@ -4094,6 +4094,21 @@ GC_INNER void GC_dirty_init(void)
   pthread_attr_t attr;
   exception_mask_t mask;
 
+# ifdef CAN_HANDLE_FORK
+    if (GC_handle_fork) {
+      /* To both support GC incremental mode and GC functions usage in  */
+      /* the forked child, pthread_atfork should be used to install     */
+      /* handlers that switch off GC_dirty_maintained in the child      */
+      /* gracefully (unprotecting all pages and clearing                */
+      /* GC_mach_handler_thread).  For now, we just disable incremental */
+      /* mode if fork() handling is requested by the client.            */
+      if (GC_print_stats)
+        GC_log_printf(
+            "GC incremental mode disabled since fork() handling requested\n");
+      return;
+    }
+# endif
+
   if (GC_print_stats == VERBOSE)
     GC_log_printf(
       "Initializing mach/darwin mprotect virtual dirty bit implementation\n");
@@ -4142,10 +4157,6 @@ GC_INNER void GC_dirty_init(void)
   if (pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED) != 0)
     ABORT("pthread_attr_setdetachedstate failed");
 
-# if defined(HANDLE_FORK) && !defined(THREADS)
-    /* FIXME: See comment in GC_fork_prepare_proc.      */
-# endif
-
 # undef pthread_create
   /* This will call the real pthread function, not our wrapper */
   if (pthread_create(&thread, &attr, GC_mprotect_thread, NULL) != 0)
index 41234ab1816184edeb69f2a6cb6756f7a1d95943..652e4a7972ab349694a00a4c4fd9024e4b33f16a 100644 (file)
@@ -846,14 +846,6 @@ STATIC void GC_fork_prepare_proc(void)
     /* Wait for an ongoing GC to finish, since we can't finish it in    */
     /* the (one remaining thread in) the child.                         */
       LOCK();
-#     if defined(GC_DARWIN_THREADS) && defined(MPROTECT_VDB)
-        if (GC_dirty_maintained) {
-          WARN("GC incremental mode is incompatible with fork() for now\n", 0);
-          /* Currently, it is not allowed to use any GC allocated data  */
-          /* or call any GC function in the child (before exec).        */
-          /* FIXME: Remove warning when mode implemented in child_proc. */
-        }
-#     endif
       DISABLE_CANCEL(fork_cancel_state);
                 /* Following waits may include cancellation points. */
 #     if defined(PARALLEL_MARK)
@@ -885,11 +877,6 @@ STATIC void GC_fork_child_proc(void)
 #   if defined(PARALLEL_MARK)
       if (GC_parallel)
         GC_release_mark_lock();
-#   endif
-#   if defined(GC_DARWIN_THREADS) && defined(MPROTECT_VDB)
-      /* FIXME: Since GC_mprotect_thread is not running in the child,   */
-      /* GC_dirty_maintained should be switched off gracefully          */
-      /* (unprotecting all pages and clearing GC_mach_handler_thread).  */
 #   endif
     GC_remove_all_threads_but_me();
 #   ifdef PARALLEL_MARK