summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--doc/README.environment14
-rw-r--r--doc/README.macros6
-rw-r--r--include/private/gc_priv.h5
-rw-r--r--include/private/gcconfig.h22
-rw-r--r--mark.c7
-rw-r--r--os_dep.c97
-rw-r--r--tests/test.c10
7 files changed, 101 insertions, 60 deletions
diff --git a/doc/README.environment b/doc/README.environment
index 16df12f5..16e527d4 100644
--- a/doc/README.environment
+++ b/doc/README.environment
@@ -104,13 +104,13 @@ GC_RETRY_SIGNALS - Try to compensate for lost
was turned into a runtime flag to enable last-minute
work-arounds. "0" value means "do not retry signals".
-GC_USE_GETWRITEWATCH=<n> - Only if MPROTECT_VDB and GWW_VDB are both defined
- (Win32 only). Explicitly specify which strategy of
- keeping track of dirtied pages should be used.
- If n=0 then GetWriteWatch() is not used (falling back to
- protecting pages and catching memory faults strategy)
- else the collector tries to use GetWriteWatch-based
- strategy (GWW_VDB) first if available.
+GC_USE_GETWRITEWATCH=<n> - Only if MPROTECT_VDB and (GWW_VDB or SOFT_VDB) are
+ both defined (Win32 and Linux only). Explicitly specify
+ which strategy of keeping track of dirtied pages should
+ be used. If n=0, then fall back to protecting pages and
+ catching memory faults strategy), else the collector
+ tries to use GetWriteWatch-based strategy (GWW_VDB) or
+ soft-dirty bits strategy (SOFT_VDB) first if available.
GC_DISABLE_INCREMENTAL - Ignore runtime requests to enable incremental GC.
Useful for debugging.
diff --git a/doc/README.macros b/doc/README.macros
index 45577b9a..3df6a2d7 100644
--- a/doc/README.macros
+++ b/doc/README.macros
@@ -541,9 +541,9 @@ DONT_USE_USER32_DLL (Win32 only) Don't use "user32" DLL import library
(containing MessageBox() entry); useful for a static GC library.
GC_PREFER_MPROTECT_VDB Choose MPROTECT_VDB manually in case of multiple
- virtual dirty bit strategies are implemented (at present useful on Win32 and
- Solaris to force MPROTECT_VDB strategy instead of the default GWW_VDB,
- PROC_VDB or SOFT_VDB ones, respectively).
+ virtual dirty bit strategies are implemented (at present useful on Win32,
+ Solaris and Linux to force MPROTECT_VDB strategy instead of the default
+ GWW_VDB, PROC_VDB or SOFT_VDB ones, respectively).
GC_IGNORE_GCJ_INFO Disable GCJ-style type information (useful for
debugging on WinCE).
diff --git a/include/private/gc_priv.h b/include/private/gc_priv.h
index 5e6d31a2..8dfb1d01 100644
--- a/include/private/gc_priv.h
+++ b/include/private/gc_priv.h
@@ -2419,6 +2419,11 @@ GC_EXTERN GC_bool GC_print_back_height;
/* pointer-free system call buffers in the heap are */
/* not protected. */
+# if !defined(NO_VDB_FOR_STATIC_ROOTS) && !defined(PROC_VDB)
+ GC_INNER GC_bool GC_is_vdb_for_static_roots(void);
+ /* Is VDB working for static roots? */
+# endif
+
# ifdef CAN_HANDLE_FORK
# if defined(PROC_VDB) || defined(SOFT_VDB)
GC_INNER void GC_dirty_update_child(void);
diff --git a/include/private/gcconfig.h b/include/private/gcconfig.h
index 1b2710b6..70668751 100644
--- a/include/private/gcconfig.h
+++ b/include/private/gcconfig.h
@@ -1180,9 +1180,8 @@ EXTERN_C_BEGIN
# define LINUX_STACKBOTTOM
# endif
# define SEARCH_FOR_DATA_START
-# if defined(__GLIBC__) && !defined(__UCLIBC__) \
- && !defined(DEFAULT_VDB) && !defined(SOFT_VDB) \
- && !defined(GC_PREFER_MPROTECT_VDB)
+# if defined(__GLIBC__) && !defined(__UCLIBC__) && !defined(SOFT_VDB) \
+ && !defined(DEFAULT_VDB) && !defined(NO_SOFT_VDB)
EXTERN_C_END
# include <linux/version.h> /* for LINUX_VERSION[_CODE] */
EXTERN_C_BEGIN
@@ -1545,9 +1544,8 @@ EXTERN_C_BEGIN
# include <gnu/libc-version.h> /* for gnu_get_libc_version() */
EXTERN_C_BEGIN
# endif
-# if defined(__GLIBC__) && !defined(__UCLIBC__) \
- && !defined(DEFAULT_VDB) && !defined(SOFT_VDB) \
- && !defined(GC_PREFER_MPROTECT_VDB)
+# if defined(__GLIBC__) && !defined(__UCLIBC__) && !defined(SOFT_VDB) \
+ && !defined(DEFAULT_VDB) && !defined(NO_SOFT_VDB)
EXTERN_C_END
# include <linux/version.h> /* for LINUX_VERSION[_CODE] */
EXTERN_C_BEGIN
@@ -2368,9 +2366,8 @@ EXTERN_C_BEGIN
# include <gnu/libc-version.h> /* for gnu_get_libc_version() */
EXTERN_C_BEGIN
# endif
-# if defined(__GLIBC__) && !defined(__UCLIBC__) \
- && !defined(DEFAULT_VDB) && !defined(SOFT_VDB) \
- && !defined(GC_PREFER_MPROTECT_VDB)
+# if defined(__GLIBC__) && !defined(__UCLIBC__) && !defined(SOFT_VDB) \
+ && !defined(DEFAULT_VDB) && !defined(NO_SOFT_VDB)
EXTERN_C_END
# include <linux/version.h> /* for LINUX_VERSION[_CODE] */
EXTERN_C_BEGIN
@@ -2815,12 +2812,11 @@ EXTERN_C_BEGIN
/* Choose MPROTECT_VDB manually (if multiple strategies available). */
# undef PCR_VDB
# undef PROC_VDB
-# undef SOFT_VDB
- /* #undef GWW_VDB - handled in os_dep.c */
+ /* GWW_VDB, SOFT_VDB are handled in os_dep.c. */
#endif
-#if defined(PROC_VDB) || defined(SOFT_VDB)
- /* Multi-VDB mode is not implemented. */
+#if defined(PROC_VDB)
+ /* Mutually exclusive VDB implementations (for now). */
# undef MPROTECT_VDB
#endif
diff --git a/mark.c b/mark.c
index bb6ff4ae..324d518c 100644
--- a/mark.c
+++ b/mark.c
@@ -1406,11 +1406,10 @@ GC_API void GC_CALL GC_push_all(void *bottom, void *top)
# ifndef NO_VDB_FOR_STATIC_ROOTS
# ifndef PROC_VDB
/* Same as GC_page_was_dirty but h is allowed to point to some */
- /* page in the registered static roots only. */
+ /* page in the registered static roots only. Not used if */
+ /* manual VDB is on. */
STATIC GC_bool GC_static_page_was_dirty(struct hblk *h)
{
- if (GC_manual_vdb) return TRUE;
-
return get_pht_entry_from_index(GC_grungy_pages, PHT_HASH(h));
}
# endif
@@ -1424,7 +1423,7 @@ GC_API void GC_CALL GC_push_all(void *bottom, void *top)
/* process memory. */
GC_push_conditional(bottom, top, all);
# else
- if (all) {
+ if (all || !GC_is_vdb_for_static_roots()) {
GC_push_all(bottom, top);
} else {
GC_push_selected((ptr_t)bottom, (ptr_t)top,
diff --git a/os_dep.c b/os_dep.c
index 90370ca3..bc651c90 100644
--- a/os_dep.c
+++ b/os_dep.c
@@ -2916,12 +2916,15 @@ GC_API GC_push_other_roots_proc GC_CALL GC_get_push_other_roots(void)
* dirty bits for entire address space. Implementations tend
* to assume that the client is a (slow) debugger.
* SOFT_VDB: Use the /proc facility for reading soft-dirty PTEs.
- * Works on Linux 3.18 or later. The proposed implementation
- * iterates over GC_heap_sects and GC_static_roots examining
- * the soft-dirty bit of the words in /proc/self/pagemap
- * corresponding to the pages of the sections; finally all
- * soft-dirty bits of the process are cleared (by writing
- * some special value to /proc/self/clear_refs file).
+ * Works on Linux 3.18+ if the kernel is properly configured.
+ * The proposed implementation iterates over GC_heap_sects and
+ * GC_static_roots examining the soft-dirty bit of the words
+ * in /proc/self/pagemap corresponding to the pages of the
+ * sections; finally all soft-dirty bits of the process are
+ * cleared (by writing some special value to
+ * /proc/self/clear_refs file). In case the soft-dirty bit is
+ * not supported by the kernel, MPROTECT_VDB may be defined as
+ * a fallback strategy.
* MPROTECT_VDB:Protect pages and then catch the faults to keep track of
* dirtied pages. The implementation (and implementability)
* is highly system dependent. This usually fails when system
@@ -3037,9 +3040,12 @@ GC_API GC_push_other_roots_proc GC_CALL GC_get_push_other_roots(void)
GC_or_pages(GC_written_pages, GC_grungy_pages);
# endif
}
+
+#elif defined(SOFT_VDB)
+# define GC_GWW_AVAILABLE() (clear_refs_fd != -1)
#else
# define GC_GWW_AVAILABLE() FALSE
-#endif /* !GWW_VDB */
+#endif /* !GWW_VDB && !SOFT_VDB */
#ifdef DEFAULT_VDB
/* All of the following assume the allocation lock is held. */
@@ -3384,9 +3390,11 @@ GC_API GC_push_other_roots_proc GC_CALL GC_get_push_other_roots(void)
SetUnhandledExceptionFilter(GC_write_fault_handler);
}
# endif
-#endif /* !DARWIN */
-#if !defined(DARWIN)
+# ifdef SOFT_VDB
+ static GC_bool soft_dirty_init(void);
+# endif
+
GC_INNER GC_bool GC_dirty_init(void)
{
# if !defined(MSWIN32) && !defined(MSWINCE)
@@ -3407,7 +3415,25 @@ GC_API GC_push_other_roots_proc GC_CALL GC_get_push_other_roots(void)
if (GC_page_size % HBLKSIZE != 0) {
ABORT("Page size not multiple of HBLKSIZE");
}
-# if !defined(MSWIN32) && !defined(MSWINCE)
+# ifdef GWW_VDB
+ if (GC_gww_dirty_init())
+ return TRUE;
+# elif defined(SOFT_VDB)
+ if (soft_dirty_init())
+ return TRUE;
+# endif
+# ifdef MSWIN32
+ GC_old_segv_handler = SetUnhandledExceptionFilter(
+ GC_write_fault_handler);
+ if (GC_old_segv_handler != NULL) {
+ GC_COND_LOG_PRINTF("Replaced other UnhandledExceptionFilter\n");
+ } else {
+ GC_old_segv_handler = SIG_DFL;
+ }
+# elif defined(MSWINCE)
+ /* MPROTECT_VDB is unsupported for WinCE at present. */
+ /* FIXME: implement it (if possible). */
+# else
/* act.sa_restorer is deprecated and should not be initialized. */
# if defined(GC_IRIX_THREADS)
sigaction(SIGSEGV, 0, &oldact);
@@ -3455,21 +3481,6 @@ GC_API GC_push_other_roots_proc GC_CALL GC_get_push_other_roots(void)
}
# endif /* HPUX || LINUX || HURD || (FREEBSD && SUNOS5SIGS) */
# endif /* ! MS windows */
-# if defined(GWW_VDB)
- if (GC_gww_dirty_init())
- return TRUE;
-# endif
-# if defined(MSWIN32)
- GC_old_segv_handler = SetUnhandledExceptionFilter(GC_write_fault_handler);
- if (GC_old_segv_handler != NULL) {
- GC_COND_LOG_PRINTF("Replaced other UnhandledExceptionFilter\n");
- } else {
- GC_old_segv_handler = SIG_DFL;
- }
-# elif defined(MSWINCE)
- /* MPROTECT_VDB is unsupported for WinCE at present. */
- /* FIXME: implement it (if possible). */
-# endif
# if defined(CPPCHECK) && defined(ADDRESS_SANITIZER)
GC_noop1((word)&__asan_default_options);
# endif
@@ -3812,22 +3823,36 @@ GC_INLINE void GC_proc_read_dirty(GC_bool output_unneeded)
return (buf[PM_SOFTDIRTY_OFS] & PM_SOFTDIRTY_MASK) != 0;
}
- GC_INNER GC_bool GC_dirty_init(void)
+# ifdef MPROTECT_VDB
+ static GC_bool soft_dirty_init(void)
+# else
+ GC_INNER GC_bool GC_dirty_init(void)
+# endif
{
+# ifdef MPROTECT_VDB
+ char * str = GETENV("GC_USE_GETWRITEWATCH");
+# ifdef GC_PREFER_MPROTECT_VDB
+ if (str == NULL || (*str == '0' && *(str + 1) == '\0'))
+ return FALSE; /* the environment variable is unset or set to "0" */
+# else
+ if (str != NULL && *str == '0' && *(str + 1) == '\0')
+ return FALSE; /* the environment variable is set "0" */
+# endif
+# endif
if (!soft_dirty_open_files())
return FALSE;
- soft_vdb_buf = (unsigned char *)GC_scratch_alloc(VDB_BUF_SZ);
+ if (NULL == soft_vdb_buf)
+ soft_vdb_buf = (unsigned char *)GC_scratch_alloc(VDB_BUF_SZ);
if (NULL == soft_vdb_buf)
ABORT("Insufficient space for /proc pagemap buffer");
if (!detect_soft_dirty_supported((ptr_t)soft_vdb_buf)) {
GC_COND_LOG_PRINTF("Soft-dirty bit is not supported by kernel\n");
/* Release the resources. */
- /* TODO: recycle soft_vdb_buf */
+ /* TODO: recycle soft_vdb_buf, add assert it is null on enter */
close(clear_refs_fd);
clear_refs_fd = -1;
close(pagemap_fd);
pagemap_fd = -1;
- /* TODO: fallback to MPROTECT_VDB */
return FALSE;
}
return TRUE;
@@ -4073,6 +4098,20 @@ GC_INNER GC_bool GC_dirty_init(void)
# endif
}
+# if !defined(NO_VDB_FOR_STATIC_ROOTS) && !defined(PROC_VDB)
+ GC_INNER GC_bool GC_is_vdb_for_static_roots(void)
+ {
+ if (GC_manual_vdb) return FALSE;
+# if defined(MPROTECT_VDB)
+ /* Currently used only in conjunction with SOFT_VDB. */
+ return GC_GWW_AVAILABLE();
+# else
+ GC_ASSERT(GC_incremental);
+ return TRUE;
+# endif
+ }
+# endif
+
/* Is the HBLKSIZE sized page at h marked dirty in the local buffer? */
/* If the actual page size is different, this returns TRUE if any */
/* of the pages overlapping h are dirty. This routine may err on the */
diff --git a/tests/test.c b/tests/test.c
index 0e02b408..5081ff9a 100644
--- a/tests/test.c
+++ b/tests/test.c
@@ -1899,12 +1899,14 @@ void enable_incremental_mode(void)
GC_printf("Reading dirty bits from /proc\n");
# elif defined(GWW_VDB)
GC_printf("Using GetWriteWatch-based implementation\n");
-# ifdef MPROTECT_VDB
+# endif
+# ifdef MPROTECT_VDB
+# if defined(GWW_VDB) || defined(SOFT_VDB)
GC_printf("Or emulating dirty bits with mprotect/signals\n");
+# else
+ GC_printf("Emulating dirty bits with mprotect/signals\n");
# endif
-# elif defined(MPROTECT_VDB)
- GC_printf("Emulating dirty bits with mprotect/signals\n");
-# endif
+# endif /* MPROTECT_VDB */
}
}
# endif