Decide between memory unmapping and mprotect-based dirty bits at runtime
authorIvan Maidanski <ivmai@mail.ru>
Thu, 29 Jun 2017 07:47:50 +0000 (10:47 +0300)
committerIvan Maidanski <ivmai@mail.ru>
Thu, 29 Jun 2017 07:47:50 +0000 (10:47 +0300)
* allchblk.c [USE_MUNMAP && MPROTECT_VDB] (GC_has_unmapped_memory): New
function.
* include/private/gcconfig.h [USE_MUNMAP] (MPROTECT_VDB): Do not
undefine unless GWW_VDB; update comment.
* os_dep.c [MPROTECT_VDB && USE_MUNMAP] (GC_has_unmapped_memory,
GC_mprotect_dirty_init): Declare function.
* os_dep.c [MPROTECT_VDB && USE_MUNMAP] (GC_dirty_init): Ensure
mprotect-based virtual dirty bits and memory unmapping are not both
turned on (disable on of them and call WARN with the appropriate
message), and call GC_mprotect_dirty_init (unless memory unmapping is
requested or some pages are already unmapped).
* os_dep.c [MPROTECT_VDB && !USE_MUNMAP] (GC_mprotect_dirty_init):
Define as a macro (to GC_dirty_init).
* os_dep.c [MPROTECT_VDB] (GC_dirty_init): Rename to
GC_mprotect_dirty_init.

allchblk.c
include/private/gcconfig.h
os_dep.c

index 90331dc..8b84aab 100644 (file)
@@ -417,6 +417,24 @@ GC_INNER void GC_unmap_old(void)
     }
 }
 
+# ifdef MPROTECT_VDB
+    GC_INNER GC_bool GC_has_unmapped_memory(void)
+    {
+      int i;
+
+      for (i = 0; i <= N_HBLK_FLS; ++i) {
+        struct hblk * h;
+        hdr * hhdr;
+
+        for (h = GC_hblkfreelist[i]; h != NULL; h = hhdr -> hb_next) {
+          hhdr = HDR(h);
+          if (!IS_MAPPED(hhdr)) return TRUE;
+        }
+      }
+      return FALSE;
+    }
+# endif /* MPROTECT_VDB */
+
 /* Merge all unmapped blocks that are adjacent to other free            */
 /* blocks.  This may involve remapping, since all blocks are either     */
 /* fully mapped or fully unmapped.                                      */
index 6a79da0..a7887d8 100644 (file)
 # undef GWW_VDB
 #endif
 
-#ifdef USE_MUNMAP
-  /* FIXME: Remove this undef if possible.      */
-# undef MPROTECT_VDB  /* Can't deal with address space holes.   */
+#if defined(USE_MUNMAP) && defined(GWW_VDB)
+# undef MPROTECT_VDB  /* TODO: Cannot deal with address space holes. */
+  /* Else if MPROTECT_VDB is available but not GWW_VDB then decide      */
+  /* whether to disable memory unmapping or mprotect-based virtual      */
+  /* dirty bits at runtime when GC_enable_incremental is called.        */
 #endif
 
 /* PARALLEL_MARK does not cause undef MPROTECT_VDB any longer.  */
index fa8ab52..76b5ce7 100644 (file)
--- a/os_dep.c
+++ b/os_dep.c
@@ -3324,9 +3324,37 @@ GC_INNER void GC_remove_protection(struct hblk *h, word nblocks,
     UNPROTECT(h_trunc, (ptr_t)h_end - (ptr_t)h_trunc);
 }
 
-#if !defined(DARWIN)
+#ifdef USE_MUNMAP
+  GC_INNER GC_bool GC_has_unmapped_memory(void); /* from allchblk.c */
+  GC_INNER GC_bool GC_mprotect_dirty_init(void);
+
+  /* MPROTECT_VDB cannot deal with address space holes (for now),   */
+  /* so if the collector is configured with both MPROTECT_VDB and   */
+  /* USE_MUNMAP then, as a work around, select only one of them     */
+  /* during GC_init or GC_enable_incremental.                       */
   GC_INNER GC_bool GC_dirty_init(void)
   {
+    if (GC_unmap_threshold != 0) {
+      if (GETENV("GC_UNMAP_THRESHOLD") != NULL
+          || GETENV("GC_FORCE_UNMAP_ON_GCOLLECT") != NULL
+          || GC_has_unmapped_memory()) {
+        WARN("Can't maintain mprotect-based dirty bits"
+             " in case of unmapping\n", 0);
+        return FALSE;
+      }
+      GC_unmap_threshold = 0; /* in favor of incremental collection */
+      WARN("Memory unmapping is disabled as incompatible"
+           " with MPROTECT_VDB\n", 0);
+    }
+    return GC_mprotect_dirty_init();
+  }
+#else
+# define GC_mprotect_dirty_init GC_dirty_init
+#endif /* !USE_MUNMAP */
+
+#if !defined(DARWIN)
+  GC_INNER GC_bool GC_mprotect_dirty_init(void)
+  {
 #   if !defined(MSWIN32) && !defined(MSWINCE)
       struct sigaction act, oldact;
       act.sa_flags = SA_RESTART | SA_SIGINFO;
@@ -4054,7 +4082,7 @@ STATIC void *GC_mprotect_thread(void *arg)
   }
 #endif /* BROKEN_EXCEPTION_HANDLING */
 
-GC_INNER GC_bool GC_dirty_init(void)
+GC_INNER GC_bool GC_mprotect_dirty_init(void)
 {
   kern_return_t r;
   mach_port_t me;