diff options
-rw-r--r-- | doc/README.environment | 14 | ||||
-rw-r--r-- | doc/README.macros | 6 | ||||
-rw-r--r-- | include/private/gc_priv.h | 5 | ||||
-rw-r--r-- | include/private/gcconfig.h | 22 | ||||
-rw-r--r-- | mark.c | 7 | ||||
-rw-r--r-- | os_dep.c | 97 | ||||
-rw-r--r-- | tests/test.c | 10 |
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 @@ -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, @@ -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 |