From fe43907c5fd9ddc6863b6fdac6898530e08262cd Mon Sep 17 00:00:00 2001 From: Ivan Maidanski Date: Thu, 29 Jun 2017 01:04:35 +0300 Subject: [PATCH] Fix gctest crash if configure --enable-handle-fork on Darwin (Cherry-pick commit 457297d from 'release-7_6' branch.) * include/private/gc_priv.h [!GC_DISABLE_INCREMENTAL] (GC_incremental): Refine comment. * include/private/gc_priv.h [!GC_DISABLE_INCREMENTAL] (GC_dirty_maintained): Remove variable declaration. * include/private/gc_priv.h [!GC_DISABLE_INCREMENTAL] (GC_dirty_init): Change return type from void to GC_bool; update comment. * mark.c [!GC_DISABLE_INCREMENTAL || CHECKSUMS] (GC_initiate_gc): Replace GC_dirty_maintained with GC_incremental. * mark.c [!GC_DISABLE_INCREMENTAL && PROC_VDB] (GC_push_conditional): Likewise. * mark.c [!GC_DISABLE_INCREMENTAL] (GC_push_next_marked_dirty): Likewise. * misc.c [!GC_DISABLE_INCREMENTAL && !KEEP_BACK_PTRS] (GC_enable_incremental): Likewise. * os_dep.c [MPROTECT_VDB] (GC_remove_protection): Likewise. * pthread_support.c [CAN_HANDLE_FORK && GC_DARWIN_THREADS && MPROTECT_VDB] (GC_atfork_prepare): Likewise. * win32_threads.c [MPROTECT_VDB] (UNPROTECT_THREAD): Likewise. * misc.c [!GC_DISABLE_INCREMENTAL] (GC_init): Set GC_incremental value to the result of GC_dirty_init(). * misc.c [!GC_DISABLE_INCREMENTAL && !KEEP_BACK_PTRS] (GC_enable_incremental): Likewise. * misc.c [!GC_DISABLE_INCREMENTAL && !KEEP_BACK_PTRS] (GC_enable_incremental): Set GC_incremental to true just before GC_init call (to indicate the intention to turn on GC incremental mode). * os_dep.c [!GC_DISABLE_INCREMENTAL] (GC_dirty_maintained): Remove global variable. * os_dep.c [GWW_VDB && !MPROTECT_VDB] (GC_gww_dirty_init): Define macro to GC_dirty_init. * os_dep.c [GWW_VDB && !MPROTECT_VDB] (GC_dirty_init): Remove function. * os_dep.c [DEFAULT_VDB || MANUAL_VDB || MPROTECT_VDB || PCR_VDB] (GC_dirty_init): Change return type to GC_bool; return true; remove assignment of GC_dirty_maintained. * os_dep.c [PROC_VDB] (GC_dirty_init): Replace ABORT with WARN and return false if "pagedata" file open failed. * os_dep.c [MPROTECT_VDB && DARWIN && CAN_HANDLE_FORK] (GC_dirty_init): Replace GC_COND_LOG_PRINTF() with WARN() which is called before return; refine WARN message. * os_dep.c [MPROTECT_VDB && DARWIN] (GC_dirty_init): Return false if GC_handle_fork; add TODO item to replace ABORT with WARN (and return false). --- include/private/gc_priv.h | 13 +++++---- mark.c | 10 ++++--- misc.c | 9 +++---- os_dep.c | 55 ++++++++++++++++++--------------------- pthread_support.c | 2 +- win32_threads.c | 3 +-- 6 files changed, 43 insertions(+), 49 deletions(-) diff --git a/include/private/gc_priv.h b/include/private/gc_priv.h index 1bc589e9..64bfd646 100644 --- a/include/private/gc_priv.h +++ b/include/private/gc_priv.h @@ -1471,7 +1471,8 @@ GC_EXTERN word GC_black_list_spacing; # define TRUE_INCREMENTAL FALSE #else GC_EXTERN GC_bool GC_incremental; - /* Using incremental/generational collection. */ + /* Using incremental/generational collection. */ + /* Assumes dirty bits are being maintained. */ # define TRUE_INCREMENTAL \ (GC_incremental && GC_time_limit != GC_TIME_UNLIMITED) /* True incremental, not just generational, mode */ @@ -2060,11 +2061,6 @@ GC_EXTERN GC_bool GC_print_back_height; #endif #ifndef GC_DISABLE_INCREMENTAL - GC_EXTERN GC_bool GC_dirty_maintained; - /* Dirty bits are being maintained, */ - /* either for incremental collection, */ - /* or to limit the root set. */ - /* Virtual dirty bit implementation: */ /* Each implementation exports the following: */ GC_INNER void GC_read_dirty(void); @@ -2077,7 +2073,10 @@ GC_EXTERN GC_bool GC_print_back_height; /* that it's not write protected by the virtual */ /* dirty bit implementation. */ - GC_INNER void GC_dirty_init(void); + GC_INNER GC_bool GC_dirty_init(void); + /* Returns true if dirty bits are maintained (otherwise */ + /* it is OK to be called again if the client invokes */ + /* GC_enable_incremental once more). */ #endif /* !GC_DISABLE_INCREMENTAL */ /* Same as GC_base but excepts and returns a pointer to const object. */ diff --git a/mark.c b/mark.c index 11929a55..a03addac 100644 --- a/mark.c +++ b/mark.c @@ -258,13 +258,15 @@ GC_INNER void GC_clear_marks(void) GC_INNER void GC_initiate_gc(void) { # ifndef GC_DISABLE_INCREMENTAL - if (GC_dirty_maintained) GC_read_dirty(); + if (GC_incremental) { + GC_read_dirty(); + } # endif # ifdef STUBBORN_ALLOC GC_read_changed(); # endif # ifdef CHECKSUMS - if (GC_dirty_maintained) GC_check_dirty(); + if (GC_incremental) GC_check_dirty(); # endif GC_n_rescuing_pages = 0; if (GC_mark_state == MS_NONE) { @@ -1368,7 +1370,7 @@ GC_API void GC_CALL GC_push_all(char *bottom, char *top) GC_push_selected((ptr_t)bottom, (ptr_t)top, GC_page_was_dirty); } else { # ifdef PROC_VDB - if (GC_dirty_maintained) { + if (GC_incremental) { /* Pages that were never dirtied cannot contain pointers. */ GC_push_selected((ptr_t)bottom, (ptr_t)top, GC_page_was_ever_dirty); } else @@ -1893,7 +1895,7 @@ STATIC struct hblk * GC_push_next_marked(struct hblk *h) { hdr * hhdr = HDR(h); - if (!GC_dirty_maintained) ABORT("Dirty bits not set up"); + if (!GC_incremental) ABORT("Dirty bits not set up"); for (;;) { if (EXPECT(IS_FORWARDING_ADDR_OR_NIL(hhdr) || HBLK_IS_FREE(hhdr), FALSE)) { diff --git a/misc.c b/misc.c index 17ba5186..3e4d6fc1 100644 --- a/misc.c +++ b/misc.c @@ -1137,9 +1137,8 @@ GC_API void GC_CALL GC_init(void) if (GC_incremental || 0 != GETENV("GC_ENABLE_INCREMENTAL")) { /* For GWW_VDB on Win32, this needs to happen before any */ /* heap memory is allocated. */ - GC_dirty_init(); + GC_incremental = GC_dirty_init(); GC_ASSERT(GC_bytes_allocd == 0); - GC_incremental = TRUE; } # endif @@ -1243,13 +1242,13 @@ GC_API void GC_CALL GC_enable_incremental(void) GC_setpagesize(); /* if (GC_no_win32_dlls) goto out; Should be win32S test? */ maybe_install_looping_handler(); /* Before write fault handler! */ - GC_incremental = TRUE; if (!GC_is_initialized) { + GC_incremental = TRUE; /* indicate intention to turn it on */ GC_init(); } else { - GC_dirty_init(); + GC_incremental = GC_dirty_init(); } - if (GC_dirty_maintained && !GC_dont_gc) { + if (GC_incremental && !GC_dont_gc) { /* Can't easily do it if GC_dont_gc. */ if (GC_bytes_allocd > 0) { /* There may be unmarked reachable objects. */ diff --git a/os_dep.c b/os_dep.c index 1d7e61a0..cf1adc87 100644 --- a/os_dep.c +++ b/os_dep.c @@ -2676,9 +2676,6 @@ GC_API GC_push_other_roots_proc GC_CALL GC_get_push_other_roots(void) * are running on Windows 95, Windows 2000 or earlier), * MPROTECT_VDB may be defined as a fallback strategy. */ -#ifndef GC_DISABLE_INCREMENTAL - GC_INNER GC_bool GC_dirty_maintained = FALSE; -#endif #if defined(PROC_VDB) || defined(GWW_VDB) /* Add all pages in pht2 to pht1 */ @@ -2733,19 +2730,15 @@ GC_API GC_push_other_roots_proc GC_CALL GC_get_push_other_roots(void) /* and everything is dirty. */ static PVOID gww_buf[GC_GWW_BUF_LEN]; -# ifdef MPROTECT_VDB +# ifndef MPROTECT_VDB +# define GC_gww_dirty_init GC_dirty_init +# endif + GC_INNER GC_bool GC_gww_dirty_init(void) { detect_GetWriteWatch(); return GC_GWW_AVAILABLE(); } -# else - GC_INNER void GC_dirty_init(void) - { - detect_GetWriteWatch(); - GC_dirty_maintained = GC_GWW_AVAILABLE(); - } -# endif /* !MPROTECT_VDB */ # ifdef MPROTECT_VDB STATIC void GC_gww_read_dirty(void) @@ -2830,10 +2823,10 @@ GC_API GC_push_other_roots_proc GC_CALL GC_get_push_other_roots(void) /* written. */ /* Initialize virtual dirty bit implementation. */ - GC_INNER void GC_dirty_init(void) + GC_INNER GC_bool GC_dirty_init(void) { GC_VERBOSE_LOG_PRINTF("Initializing DEFAULT_VDB...\n"); - GC_dirty_maintained = TRUE; + return TRUE; } /* Retrieve system dirty bits for heap to a local buffer. */ @@ -2875,11 +2868,11 @@ GC_API GC_push_other_roots_proc GC_CALL GC_get_push_other_roots(void) #ifdef MANUAL_VDB /* Initialize virtual dirty bit implementation. */ - GC_INNER void GC_dirty_init(void) + GC_INNER GC_bool GC_dirty_init(void) { GC_VERBOSE_LOG_PRINTF("Initializing MANUAL_VDB...\n"); /* GC_dirty_pages and GC_grungy_pages are already cleared. */ - GC_dirty_maintained = TRUE; + return TRUE; } /* Retrieve system dirty bits for heap to a local buffer. */ @@ -3286,7 +3279,7 @@ GC_INNER void GC_remove_protection(struct hblk *h, word nblocks, # if defined(GWW_VDB) if (GC_GWW_AVAILABLE()) return; # endif - if (!GC_dirty_maintained) return; + if (!GC_incremental) return; h_trunc = (struct hblk *)((word)h & ~(GC_page_size-1)); h_end = (struct hblk *)(((word)(h + nblocks) + GC_page_size-1) & ~(GC_page_size-1)); @@ -3306,7 +3299,7 @@ GC_INNER void GC_remove_protection(struct hblk *h, word nblocks, } #if !defined(DARWIN) - GC_INNER void GC_dirty_init(void) + GC_INNER GC_bool GC_dirty_init(void) { # if !defined(MSWIN32) && !defined(MSWINCE) struct sigaction act, oldact; @@ -3323,7 +3316,6 @@ GC_INNER void GC_remove_protection(struct hblk *h, word nblocks, # endif /* !MSWIN32 */ GC_VERBOSE_LOG_PRINTF( "Initializing mprotect virtual dirty bit implementation\n"); - GC_dirty_maintained = TRUE; if (GC_page_size % HBLKSIZE != 0) { ABORT("Page size not multiple of HBLKSIZE"); } @@ -3380,7 +3372,7 @@ GC_INNER void GC_remove_protection(struct hblk *h, word nblocks, # endif /* ! MS windows */ # if defined(GWW_VDB) if (GC_gww_dirty_init()) - return; + return TRUE; # endif # if defined(MSWIN32) GC_old_segv_handler = SetUnhandledExceptionFilter(GC_write_fault_handler); @@ -3393,6 +3385,7 @@ GC_INNER void GC_remove_protection(struct hblk *h, word nblocks, /* MPROTECT_VDB is unsupported for WinCE at present. */ /* FIXME: implement it (if possible). */ # endif + return TRUE; } #endif /* !DARWIN */ @@ -3662,7 +3655,7 @@ ssize_t read(int fd, void *buf, size_t nbyte) STATIC char *GC_proc_buf = NULL; STATIC int GC_proc_fd = 0; -GC_INNER void GC_dirty_init(void) +GC_INNER GC_bool GC_dirty_init(void) { char buf[40]; @@ -3677,15 +3670,16 @@ GC_INNER void GC_dirty_init(void) buf[sizeof(buf) - 1] = '\0'; GC_proc_fd = open(buf, O_RDONLY); if (GC_proc_fd < 0) { - ABORT("/proc open failed"); + WARN("/proc open failed; cannot enable GC incremental mode\n", 0); + return FALSE; } if (syscall(SYS_fcntl, GC_proc_fd, F_SETFD, FD_CLOEXEC) == -1) WARN("Could not set FD_CLOEXEC for /proc\n", 0); - GC_dirty_maintained = TRUE; GC_proc_buf = GC_scratch_alloc(GC_proc_buf_size); if (GC_proc_buf == NULL) ABORT("Insufficient space for /proc read"); + return TRUE; } # define READ read @@ -3783,9 +3777,8 @@ STATIC ptr_t GC_vd_base = NULL; /* Address corresponding to GC_grungy_bits[0] */ /* HBLKSIZE aligned. */ -GC_INNER void GC_dirty_init(void) +GC_INNER GC_bool GC_dirty_init(void) { - GC_dirty_maintained = TRUE; /* For the time being, we assume the heap generally grows up */ GC_vd_base = GC_heap_sects[0].hs_start; if (GC_vd_base == 0) { @@ -3795,6 +3788,7 @@ GC_INNER void GC_dirty_init(void) != PCR_ERes_okay) { ABORT("Dirty bit initialization failed"); } + return TRUE; } GC_INNER void GC_read_dirty(void) @@ -4132,7 +4126,7 @@ STATIC void *GC_mprotect_thread(void *arg) } #endif /* BROKEN_EXCEPTION_HANDLING */ -GC_INNER void GC_dirty_init(void) +GC_INNER GC_bool GC_dirty_init(void) { kern_return_t r; mach_port_t me; @@ -4144,13 +4138,13 @@ GC_INNER void GC_dirty_init(void) 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 */ + /* handlers that switch off GC_incremental 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. */ - GC_COND_LOG_PRINTF("GC incremental mode disabled since fork()" - " handling requested\n"); - return; + WARN("Can't turn on GC incremental mode as fork()" + " handling requested\n", 0); + return FALSE; } # endif @@ -4160,7 +4154,6 @@ GC_INNER void GC_dirty_init(void) WARN("Enabling workarounds for various darwin " "exception handling bugs\n", 0); # endif - GC_dirty_maintained = TRUE; if (GC_page_size % HBLKSIZE != 0) { ABORT("Page size not multiple of HBLKSIZE"); } @@ -4168,6 +4161,7 @@ GC_INNER void GC_dirty_init(void) GC_task_self = me = mach_task_self(); r = mach_port_allocate(me, MACH_PORT_RIGHT_RECEIVE, &GC_ports.exception); + /* TODO: WARN and return FALSE in case of a failure. */ if (r != KERN_SUCCESS) ABORT("mach_port_allocate failed (exception port)"); @@ -4222,6 +4216,7 @@ GC_INNER void GC_dirty_init(void) } } # endif /* BROKEN_EXCEPTION_HANDLING */ + return TRUE; } /* The source code for Apple's GDB was used as a reference for the */ diff --git a/pthread_support.c b/pthread_support.c index 3d688ff9..cc8d3f50 100644 --- a/pthread_support.c +++ b/pthread_support.c @@ -996,7 +996,7 @@ static void fork_child_proc(void) { if (!EXPECT(GC_is_initialized, TRUE)) GC_init(); # if defined(GC_DARWIN_THREADS) && defined(MPROTECT_VDB) - if (GC_dirty_maintained) { + if (GC_incremental) { GC_ASSERT(0 == GC_handle_fork); ABORT("Unable to fork while mprotect_thread is running"); } diff --git a/win32_threads.c b/win32_threads.c index 7af26bd7..8f23f487 100644 --- a/win32_threads.c +++ b/win32_threads.c @@ -604,8 +604,7 @@ GC_API int GC_CALL GC_thread_is_registered(void) /* lock may be required for fault handling. */ #if defined(MPROTECT_VDB) # define UNPROTECT_THREAD(t) \ - if (!GC_win32_dll_threads && GC_dirty_maintained \ - && t != &first_thread) { \ + if (!GC_win32_dll_threads && GC_incremental && t != &first_thread) { \ GC_ASSERT(SMALL_OBJ(GC_size(t))); \ GC_remove_protection(HBLKPTR(t), 1, FALSE); \ } else (void)0 -- 2.40.0