diff options
-rw-r--r-- | include/private/gc_priv.h | 11 | ||||
-rw-r--r-- | os_dep.c | 39 | ||||
-rw-r--r-- | pthread_support.c | 5 |
3 files changed, 43 insertions, 12 deletions
diff --git a/include/private/gc_priv.h b/include/private/gc_priv.h index 7b9bab1c..6685c07a 100644 --- a/include/private/gc_priv.h +++ b/include/private/gc_priv.h @@ -2416,6 +2416,17 @@ GC_EXTERN GC_bool GC_print_back_height; /* pointer-free system call buffers in the heap are */ /* not protected. */ +# ifdef CAN_HANDLE_FORK +# if defined(PROC_VDB) + GC_INNER void GC_dirty_update_child(void); + /* Update pid-specific resources (like /proc file */ + /* descriptors) needed by the dirty bits implementation */ + /* after fork in the child process. */ +# else +# define GC_dirty_update_child() (void)0 +# endif +# endif /* CAN_HANDLE_FORK */ + 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 */ @@ -3603,29 +3603,46 @@ STATIC void GC_protect_heap(void) # define INITIAL_BUF_SZ 16384 STATIC size_t GC_proc_buf_size = INITIAL_BUF_SZ; STATIC char *GC_proc_buf = NULL; - STATIC int GC_proc_fd = 0; + STATIC int GC_proc_fd = -1; -GC_INNER GC_bool GC_dirty_init(void) -{ + static GC_bool proc_dirty_open_files(void) + { char buf[40]; - if (GC_bytes_allocd != 0 || GC_bytes_allocd_before_gc != 0) { - memset(GC_written_pages, 0xff, sizeof(page_hash_table)); - GC_VERBOSE_LOG_PRINTF( - "Allocated %lu bytes: all pages may have been written\n", - (unsigned long)(GC_bytes_allocd + GC_bytes_allocd_before_gc)); - } - (void)snprintf(buf, sizeof(buf), "/proc/%ld/pagedata", (long)getpid()); buf[sizeof(buf) - 1] = '\0'; GC_proc_fd = open(buf, O_RDONLY); - if (GC_proc_fd < 0) { + if (-1 == GC_proc_fd) { 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); + return TRUE; + } + +# ifdef CAN_HANDLE_FORK + GC_INNER void GC_dirty_update_child(void) + { + if (-1 == GC_proc_fd) + return; /* GC incremental mode is off */ + + close(GC_proc_fd); + if (!proc_dirty_open_files()) + GC_incremental = FALSE; /* should be safe to turn it off */ + } +# endif /* CAN_HANDLE_FORK */ +GC_INNER GC_bool GC_dirty_init(void) +{ + if (GC_bytes_allocd != 0 || GC_bytes_allocd_before_gc != 0) { + memset(GC_written_pages, 0xff, sizeof(page_hash_table)); + GC_VERBOSE_LOG_PRINTF( + "Allocated %lu bytes: all pages may have been written\n", + (unsigned long)(GC_bytes_allocd + GC_bytes_allocd_before_gc)); + } + if (!proc_dirty_open_files()) + return FALSE; GC_proc_buf = GC_scratch_alloc(GC_proc_buf_size); if (GC_proc_buf == NULL) ABORT("Insufficient space for /proc read"); diff --git a/pthread_support.c b/pthread_support.c index 84d2d971..6153717a 100644 --- a/pthread_support.c +++ b/pthread_support.c @@ -1170,7 +1170,10 @@ static void fork_child_proc(void) /* Turn off parallel marking in the child, since we are probably */ /* just going to exec, and we would have to restart mark threads. */ GC_parallel = FALSE; -# endif /* PARALLEL_MARK */ +# endif +# ifndef GC_DISABLE_INCREMENTAL + GC_dirty_update_child(); +# endif RESTORE_CANCEL(fork_cancel_state); UNLOCK(); /* Even though after a fork the child only inherits the single */ |