From cad34343056a5f9b4598b5ddc36ed8ce0e264399 Mon Sep 17 00:00:00 2001 From: Ivan Maidanski Date: Mon, 2 Apr 2012 22:31:22 +0400 Subject: [PATCH] FIX: Disable incremental mode on Darwin if fork handling requested * 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 | 6 +++--- include/private/gcconfig.h | 2 +- misc.c | 5 +++-- os_dep.c | 19 +++++++++++++++---- pthread_support.c | 13 ------------- 5 files changed, 22 insertions(+), 23 deletions(-) diff --git a/doc/README.macros b/doc/README.macros index c745eb35..cf6a14d8 100644 --- a/doc/README.macros +++ b/doc/README.macros @@ -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 diff --git a/include/private/gcconfig.h b/include/private/gcconfig.h index 7ecc80f7..4d27bde4 100644 --- a/include/private/gcconfig.h +++ b/include/private/gcconfig.h @@ -2594,7 +2594,7 @@ #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 fac069aa..5267998b 100644 --- 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 } diff --git a/os_dep.c b/os_dep.c index 070756aa..17dabcdd 100644 --- 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) diff --git a/pthread_support.c b/pthread_support.c index 41234ab1..652e4a79 100644 --- a/pthread_support.c +++ b/pthread_support.c @@ -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 -- 2.40.0