# 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 */
#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);
/* 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. */
* 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)
/* 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)
/* 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. */
#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. */
# 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));
}
#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;
# 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");
}
# 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);
# if defined(CPPCHECK) && defined(ADDRESS_SANITIZER)
GC_noop1((word)&__asan_default_options);
# endif
+ return TRUE;
}
#endif /* !DARWIN */
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];
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
/* 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) {
!= PCR_ERes_okay) {
ABORT("Dirty bit initialization failed");
}
+ return TRUE;
}
GC_INNER void GC_read_dirty(void)
}
#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;
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
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");
}
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)");
}
}
# endif /* BROKEN_EXCEPTION_HANDLING */
+ return TRUE;
}
/* The source code for Apple's GDB was used as a reference for the */