]> granicus.if.org Git - gc/commitdiff
Fix gctest crash if configure --enable-handle-fork on Darwin
authorIvan Maidanski <ivmai@mail.ru>
Wed, 28 Jun 2017 22:04:35 +0000 (01:04 +0300)
committerIvan Maidanski <ivmai@mail.ru>
Sun, 2 Jul 2017 09:38:58 +0000 (12:38 +0300)
(Cherry-pick commits 6bfc840b9ecb3a from 'master' 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
mark.c
misc.c
os_dep.c
pthread_support.c
win32_threads.c

index f750a3db6d813c0c3bb63fd0dda70f35aa577577..b95e528357794a5f076aea3ff4311889fdfe682f 100644 (file)
@@ -1519,7 +1519,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 */
@@ -2115,11 +2116,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);
@@ -2139,7 +2135,10 @@ GC_EXTERN GC_bool GC_print_back_height;
                 /* pointer-free system call buffers in the heap are     */
                 /* not protected.                                       */
 
-  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 e4dc791502cd72dc9ae0ab9342fc56d5b56ca88c..46e3e5185e1529b9fef2593c1e603139deddbc73 100644 (file)
--- a/mark.c
+++ b/mark.c
@@ -249,13 +249,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) {
@@ -1398,7 +1400,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
@@ -1925,7 +1927,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 ac4882e46a9848911f6cb8bf8c02f7326650df22..4ada4777a6cf8377b05dd9a2c50ad6870cf016b0 100644 (file)
--- a/misc.c
+++ b/misc.c
@@ -1204,9 +1204,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
 
@@ -1331,15 +1330,15 @@ 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) {
           UNLOCK();
+          GC_incremental = TRUE; /* indicate intention to turn it on */
           GC_init();
           LOCK();
         } 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. */
index 4eb8fa8cf582caa40df318b523dffbd45ba6d75b..e7e7b282cf6ec5ae94387e846d2bb6dc6aadc6d4 100644 (file)
--- a/os_dep.c
+++ b/os_dep.c
@@ -2715,9 +2715,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(GWW_VDB) || defined(MPROTECT_VDB) || defined(PROC_VDB) \
     || defined(MANUAL_VDB)
@@ -2774,19 +2771,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)
@@ -2873,10 +2866,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.     */
@@ -2908,11 +2901,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.     */
@@ -3307,7 +3300,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));
@@ -3327,7 +3320,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;
@@ -3344,7 +3337,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");
     }
@@ -3401,7 +3393,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);
@@ -3417,6 +3409,7 @@ GC_INNER void GC_remove_protection(struct hblk *h, word nblocks,
 #   if defined(CPPCHECK) && defined(ADDRESS_SANITIZER)
       GC_noop1((word)&__asan_default_options);
 #   endif
+    return TRUE;
   }
 #endif /* !DARWIN */
 
@@ -3558,7 +3551,7 @@ GC_INNER void GC_read_dirty(void)
   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];
 
@@ -3573,15 +3566,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
@@ -3677,9 +3671,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) {
@@ -3689,6 +3682,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)
@@ -4029,7 +4023,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;
@@ -4041,13 +4035,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
 
@@ -4057,7 +4051,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");
   }
@@ -4065,6 +4058,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)");
 
@@ -4119,6 +4113,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      */
index 2c571256f88ef291a26b10e6bada3430d6d05599..86d345d12f48b71b96fb1c3f4565536b346acb37 100644 (file)
@@ -1063,7 +1063,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");
       }
index ab698b5b2a1492ddecb1d06b44c07d324d499106..df5bdc118e2c86d654dbddd120a473ae05b2de65 100644 (file)
@@ -616,8 +616,7 @@ GC_API void GC_CALL GC_register_altstack(void *stack GC_ATTR_UNUSED,
 /* 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