Updates from 0.2.1 into 0.2.1-inu-1.5

This commit is contained in:
Akinori Ito
2001-11-09 04:59:17 +00:00
parent 68a07bf03b
commit 6c63633545
246 changed files with 32763 additions and 21814 deletions

View File

@@ -26,13 +26,15 @@
* None of this is safe with dlclose and incremental collection.
* But then not much of anything is safe in the presence of dlclose.
*/
#ifndef MACOS
#if !defined(MACOS) && !defined(_WIN32_WCE)
# include <sys/types.h>
#endif
#include "gc_priv.h"
#include "private/gc_priv.h"
/* BTL: avoid circular redefinition of dlopen if SOLARIS_THREADS defined */
# if defined(SOLARIS_THREADS) && defined(dlopen)
# if (defined(LINUX_THREADS) || defined(SOLARIS_THREADS) \
|| defined(HPUX_THREADS) || defined(IRIX_THREADS)) && defined(dlopen) \
&& !defined(GC_USE_LD_WRAP)
/* To support threads in Solaris, gc.h interposes on dlopen by */
/* defining "dlopen" to be "GC_dlopen", which is implemented below. */
/* However, both GC_FirstDLOpenedLinkMap() and GC_dlopen() use the */
@@ -44,11 +46,14 @@
# undef GC_must_restore_redefined_dlopen
# endif
#if (defined(DYNAMIC_LOADING) || defined(MSWIN32)) && !defined(PCR)
#if (defined(DYNAMIC_LOADING) || defined(MSWIN32) || defined(MSWINCE)) \
&& !defined(PCR)
#if !defined(SUNOS4) && !defined(SUNOS5DL) && !defined(IRIX5) && \
!defined(MSWIN32) && !(defined(ALPHA) && defined(OSF1)) && \
!defined(HP_PA) && !(defined(LINUX) && defined(__ELF__)) && \
!defined(RS6000) && !defined(SCO_ELF)
!defined(MSWIN32) && !defined(MSWINCE) && \
!(defined(ALPHA) && defined(OSF1)) && \
!defined(HPUX) && !(defined(LINUX) && defined(__ELF__)) && \
!defined(RS6000) && !defined(SCO_ELF) && \
!(defined(NETBSD) && defined(__ELF__)) && !defined(HURD)
--> We only know how to find data segments of dynamic libraries for the
--> above. Additional SVR4 variants might not be too
--> hard to add.
@@ -119,6 +124,11 @@ GC_FirstDLOpenedLinkMap()
#endif /* SUNOS5DL ... */
/* BTL: added to fix circular dlopen definition if SOLARIS_THREADS defined */
# if defined(GC_must_restore_redefined_dlopen)
# define dlopen GC_dlopen
# endif
#if defined(SUNOS4) && !defined(USE_PROC_FOR_LIBRARIES)
#ifdef LINT
@@ -167,34 +177,6 @@ static ptr_t GC_first_common()
# endif /* We assume M3 programs don't call dlopen for now */
# endif
# ifdef SOLARIS_THREADS
/* Redefine dlopen to guarantee mutual exclusion with */
/* GC_register_dynamic_libraries. */
/* assumes that dlopen doesn't need to call GC_malloc */
/* and friends. */
# include <thread.h>
# include <synch.h>
void * GC_dlopen(const char *path, int mode)
{
void * result;
# ifndef USE_PROC_FOR_LIBRARIES
mutex_lock(&GC_allocate_ml);
# endif
result = dlopen(path, mode);
# ifndef USE_PROC_FOR_LIBRARIES
mutex_unlock(&GC_allocate_ml);
# endif
return(result);
}
# endif /* SOLARIS_THREADS */
/* BTL: added to fix circular dlopen definition if SOLARIS_THREADS defined */
# if defined(GC_must_restore_redefined_dlopen)
# define dlopen GC_dlopen
# endif
# ifndef USE_PROC_FOR_LIBRARIES
void GC_register_dynamic_libraries()
{
@@ -260,14 +242,193 @@ void GC_register_dynamic_libraries()
# endif /* !USE_PROC ... */
# endif /* SUNOS */
#if defined(LINUX) && defined(__ELF__) || defined(SCO_ELF)
#if defined(LINUX) && defined(__ELF__) || defined(SCO_ELF) || \
(defined(NETBSD) && defined(__ELF__)) || defined(HURD)
#ifdef USE_PROC_FOR_LIBRARIES
#include <string.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#define MAPS_BUF_SIZE (32*1024)
extern ssize_t GC_repeat_read(int fd, char *buf, size_t count);
/* Repeatedly read until buffer is filled, or EOF is encountered */
/* Defined in os_dep.c. */
static char *parse_map_entry(char *buf_ptr, word *start, word *end,
char *prot_buf, unsigned int *maj_dev);
void GC_register_dynamic_libraries()
{
int f;
int result;
char prot_buf[5];
int maps_size;
char maps_temp[32768];
char *maps_buf;
char *buf_ptr;
int count;
word start, end;
unsigned int maj_dev, min_dev;
word least_ha, greatest_ha;
unsigned i;
word datastart = (word)(DATASTART);
/* Read /proc/self/maps */
/* Note that we may not allocate, and thus can't use stdio. */
f = open("/proc/self/maps", O_RDONLY);
if (-1 == f) ABORT("Couldn't open /proc/self/maps");
/* stat() doesn't work for /proc/self/maps, so we have to
read it to find out how large it is... */
maps_size = 0;
do {
result = GC_repeat_read(f, maps_temp, sizeof(maps_temp));
if (result <= 0) ABORT("Couldn't read /proc/self/maps");
maps_size += result;
} while (result == sizeof(maps_temp));
if (maps_size > sizeof(maps_temp)) {
/* If larger than our buffer, close and re-read it. */
close(f);
f = open("/proc/self/maps", O_RDONLY);
if (-1 == f) ABORT("Couldn't open /proc/self/maps");
maps_buf = alloca(maps_size);
if (NULL == maps_buf) ABORT("/proc/self/maps alloca failed");
result = GC_repeat_read(f, maps_buf, maps_size);
if (result <= 0) ABORT("Couldn't read /proc/self/maps");
} else {
/* Otherwise use the fixed size buffer */
maps_buf = maps_temp;
}
close(f);
maps_buf[result] = '\0';
buf_ptr = maps_buf;
/* Compute heap bounds. Should be done by add_to_heap? */
least_ha = (word)(-1);
greatest_ha = 0;
for (i = 0; i < GC_n_heap_sects; ++i) {
word sect_start = (word)GC_heap_sects[i].hs_start;
word sect_end = sect_start + GC_heap_sects[i].hs_bytes;
if (sect_start < least_ha) least_ha = sect_start;
if (sect_end > greatest_ha) greatest_ha = sect_end;
}
if (greatest_ha < (word)GC_scratch_last_end_ptr)
greatest_ha = (word)GC_scratch_last_end_ptr;
for (;;) {
buf_ptr = parse_map_entry(buf_ptr, &start, &end, prot_buf, &maj_dev);
if (buf_ptr == NULL) return;
if (prot_buf[1] == 'w') {
/* This is a writable mapping. Add it to */
/* the root set unless it is already otherwise */
/* accounted for. */
if (start <= (word)GC_stackbottom && end >= (word)GC_stackbottom) {
/* Stack mapping; discard */
continue;
}
if (start <= datastart && end > datastart && maj_dev != 0) {
/* Main data segment; discard */
continue;
}
# ifdef THREADS
if (GC_segment_is_thread_stack(start, end)) continue;
# endif
/* The rest of this assumes that there is no mapping */
/* spanning the beginning of the data segment, or extending */
/* beyond the entire heap at both ends. */
/* Empirically these assumptions hold. */
if (start < (word)DATAEND && end > (word)DATAEND) {
/* Rld may use space at the end of the main data */
/* segment. Thus we add that in. */
start = (word)DATAEND;
}
if (start < least_ha && end > least_ha) {
end = least_ha;
}
if (start < greatest_ha && end > greatest_ha) {
start = greatest_ha;
}
if (start >= least_ha && end <= greatest_ha) continue;
GC_add_roots_inner((char *)start, (char *)end, TRUE);
}
}
}
//
// parse_map_entry parses an entry from /proc/self/maps so we can
// locate all writable data segments that belong to shared libraries.
// The format of one of these entries and the fields we care about
// is as follows:
// XXXXXXXX-XXXXXXXX r-xp 00000000 30:05 260537 name of mapping...\n
// ^^^^^^^^ ^^^^^^^^ ^^^^ ^^
// start end prot maj_dev
// 0 9 18 32
//
// The parser is called with a pointer to the entry and the return value
// is either NULL or is advanced to the next entry(the byte after the
// trailing '\n'.)
//
#define OFFSET_MAP_START 0
#define OFFSET_MAP_END 9
#define OFFSET_MAP_PROT 18
#define OFFSET_MAP_MAJDEV 32
static char *parse_map_entry(char *buf_ptr, word *start, word *end,
char *prot_buf, unsigned int *maj_dev)
{
int i;
unsigned int val;
char *tok;
if (buf_ptr == NULL || *buf_ptr == '\0') {
return NULL;
}
memcpy(prot_buf, buf_ptr+OFFSET_MAP_PROT, 4); // do the protections first
prot_buf[4] = '\0';
if (prot_buf[1] == 'w') { // we can skip all of this if it's not writable
tok = buf_ptr;
buf_ptr[OFFSET_MAP_START+8] = '\0';
*start = strtoul(tok, NULL, 16);
tok = buf_ptr+OFFSET_MAP_END;
buf_ptr[OFFSET_MAP_END+8] = '\0';
*end = strtoul(tok, NULL, 16);
buf_ptr += OFFSET_MAP_MAJDEV;
tok = buf_ptr;
while (*buf_ptr != ':') buf_ptr++;
*buf_ptr++ = '\0';
*maj_dev = strtoul(tok, NULL, 16);
}
while (*buf_ptr && *buf_ptr++ != '\n');
return buf_ptr;
}
#else /* !USE_PROC_FOR_LIBRARIES */
/* Dynamic loading code for Linux running ELF. Somewhat tested on
* Linux/x86, untested but hopefully should work on Linux/Alpha.
* This code was derived from the Solaris/ELF support. Thanks to
* whatever kind soul wrote that. - Patrick Bridges */
#include <elf.h>
#if defined(NETBSD)
# include <sys/exec_elf.h>
#else
# include <elf.h>
#endif
#include <link.h>
/* Newer versions of Linux/Alpha and Linux/x86 define this macro. We
@@ -342,21 +503,26 @@ void GC_register_dynamic_libraries()
}
}
#endif
#endif /* !USE_PROC_FOR_LIBRARIES */
#if defined(IRIX5) || defined(USE_PROC_FOR_LIBRARIES)
#endif /* LINUX */
#if defined(IRIX5) || (defined(USE_PROC_FOR_LIBRARIES) && !defined(LINUX))
#include <sys/procfs.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <elf.h>
#include <errno.h>
#include <signal.h> /* Only for the following test. */
#ifndef _sigargs
# define IRIX6
#endif
extern void * GC_roots_present();
/* The type is a lie, since the real type doesn't make sense here, */
/* and we only test for NULL. */
extern ptr_t GC_scratch_last_end_ptr; /* End of GC_scratch_alloc arena */
/* We use /proc to track down all parts of the address space that are */
/* mapped by the process, and throw out regions we know we shouldn't */
@@ -413,7 +579,8 @@ void GC_register_dynamic_libraries()
if ((flags & (MA_BREAK | MA_STACK | MA_PHYS)) != 0) goto irrelevant;
if ((flags & (MA_READ | MA_WRITE)) != (MA_READ | MA_WRITE))
goto irrelevant;
/* The latter test is empirically useless. Other than the */
/* The latter test is empirically useless in very old Irix */
/* versions. Other than the */
/* main data and stack segments, everything appears to be */
/* mapped readable, writable, executable, and shared(!!). */
/* This makes no sense to me. - HB */
@@ -426,7 +593,11 @@ void GC_register_dynamic_libraries()
# endif /* MMAP_STACKS */
limit = start + addr_map[i].pr_size;
if (addr_map[i].pr_off == 0 && strncmp(start, ELFMAG, 4) == 0) {
/* The following seemed to be necessary for very old versions */
/* of Irix, but it has been reported to discard relevant */
/* segments under Irix 6.5. */
# ifndef IRIX6
if (addr_map[i].pr_off == 0 && strncmp(start, ELFMAG, 4) == 0) {
/* Discard text segments, i.e. 0-offset mappings against */
/* executable files which appear to have ELF headers. */
caddr_t arg;
@@ -453,7 +624,8 @@ void GC_register_dynamic_libraries()
goto irrelevant;
}
}
}
}
# endif /* !IRIX6 */
GC_add_roots_inner(start, limit, TRUE);
irrelevant: ;
}
@@ -465,7 +637,7 @@ void GC_register_dynamic_libraries()
# endif /* USE_PROC || IRIX5 */
# ifdef MSWIN32
# if defined(MSWIN32) || defined(MSWINCE)
# define WIN32_LEAN_AND_MEAN
# define NOSERVICE
@@ -474,86 +646,97 @@ void GC_register_dynamic_libraries()
/* We traverse the entire address space and register all segments */
/* that could possibly have been written to. */
DWORD GC_allocation_granularity;
extern GC_bool GC_is_heap_base (ptr_t p);
# ifdef WIN32_THREADS
extern void GC_get_next_stack(char *start, char **lo, char **hi);
# endif
void GC_cond_add_roots(char *base, char * limit)
{
char dummy;
char * stack_top
= (char *) ((word)(&dummy) & ~(GC_allocation_granularity-1));
if (base == limit) return;
# ifdef WIN32_THREADS
void GC_cond_add_roots(char *base, char * limit)
{
char * curr_base = base;
char * next_stack_lo;
char * next_stack_hi;
for(;;) {
GC_get_next_stack(curr_base, &next_stack_lo, &next_stack_hi);
if (next_stack_lo >= limit) break;
GC_add_roots_inner(curr_base, next_stack_lo, TRUE);
curr_base = next_stack_hi;
}
if (curr_base < limit) GC_add_roots_inner(curr_base, limit, TRUE);
char * curr_base = base;
char * next_stack_lo;
char * next_stack_hi;
if (base == limit) return;
for(;;) {
GC_get_next_stack(curr_base, &next_stack_lo, &next_stack_hi);
if (next_stack_lo >= limit) break;
GC_add_roots_inner(curr_base, next_stack_lo, TRUE);
curr_base = next_stack_hi;
}
if (curr_base < limit) GC_add_roots_inner(curr_base, limit, TRUE);
}
# else
if (limit > stack_top && base < GC_stackbottom) {
/* Part of the stack; ignore it. */
return;
}
GC_add_roots_inner(base, limit, TRUE);
# endif
}
# else
void GC_cond_add_roots(char *base, char * limit)
{
char dummy;
char * stack_top
= (char *) ((word)(&dummy) & ~(GC_sysinfo.dwAllocationGranularity-1));
if (base == limit) return;
if (limit > stack_top && base < GC_stackbottom) {
/* Part of the stack; ignore it. */
return;
}
GC_add_roots_inner(base, limit, TRUE);
}
# endif
# ifndef MSWINCE
extern GC_bool GC_win32s;
# endif
void GC_register_dynamic_libraries()
{
MEMORY_BASIC_INFORMATION buf;
SYSTEM_INFO sysinfo;
DWORD result;
DWORD protect;
LPVOID p;
char * base;
char * limit, * new_limit;
if (GC_win32s) return;
GetSystemInfo(&sysinfo);
base = limit = p = sysinfo.lpMinimumApplicationAddress;
GC_allocation_granularity = sysinfo.dwAllocationGranularity;
while (p < sysinfo.lpMaximumApplicationAddress) {
# ifdef MSWIN32
if (GC_win32s) return;
# endif
base = limit = p = GC_sysinfo.lpMinimumApplicationAddress;
# if defined(MSWINCE) && !defined(_WIN32_WCE_EMULATION)
/* Only the first 32 MB of address space belongs to the current process */
while (p < (LPVOID)0x02000000) {
result = VirtualQuery(p, &buf, sizeof(buf));
if (result != sizeof(buf)) {
ABORT("Weird VirtualQuery result");
}
new_limit = (char *)p + buf.RegionSize;
protect = buf.Protect;
if (buf.State == MEM_COMMIT
&& (protect == PAGE_EXECUTE_READWRITE
|| protect == PAGE_READWRITE)
&& !GC_is_heap_base(buf.AllocationBase)) {
if ((char *)p == limit) {
limit = new_limit;
} else {
GC_cond_add_roots(base, limit);
base = p;
limit = new_limit;
}
}
if (result == 0) {
/* Page is free; advance to the next possible allocation base */
new_limit = (char *)
(((DWORD) p + GC_sysinfo.dwAllocationGranularity)
& ~(GC_sysinfo.dwAllocationGranularity-1));
} else
# else
while (p < GC_sysinfo.lpMaximumApplicationAddress) {
result = VirtualQuery(p, &buf, sizeof(buf));
# endif
{
if (result != sizeof(buf)) {
ABORT("Weird VirtualQuery result");
}
new_limit = (char *)p + buf.RegionSize;
protect = buf.Protect;
if (buf.State == MEM_COMMIT
&& (protect == PAGE_EXECUTE_READWRITE
|| protect == PAGE_READWRITE)
&& !GC_is_heap_base(buf.AllocationBase)) {
if ((char *)p != limit) {
GC_cond_add_roots(base, limit);
base = p;
}
limit = new_limit;
}
}
if (p > (LPVOID)new_limit /* overflow */) break;
p = (LPVOID)new_limit;
}
GC_cond_add_roots(base, limit);
}
#endif /* MSWIN32 */
#endif /* MSWIN32 || MSWINCE */
#if defined(ALPHA) && defined(OSF1)
#include <loader.h>
@@ -658,7 +841,7 @@ void GC_register_dynamic_libraries()
}
#endif
#if defined(HP_PA)
#if defined(HPUX)
#include <errno.h>
#include <dl.h>
@@ -681,6 +864,11 @@ void GC_register_dynamic_libraries()
/* Check if this is the end of the list or if some error occured */
if (status != 0) {
# ifdef HPUX_THREADS
/* I've seen errno values of 0. The man page is not clear */
/* as to whether errno should get set on a -1 return. */
break;
# else
if (errno == EINVAL) {
break; /* Moved past end of shared library list --> finished */
} else {
@@ -691,6 +879,7 @@ void GC_register_dynamic_libraries()
}
ABORT("shl_get failed");
}
# endif
}
# ifdef VERBOSE
@@ -713,7 +902,7 @@ void GC_register_dynamic_libraries()
index++;
}
}
#endif /* HP_PA */
#endif /* HPUX */
#ifdef RS6000
#pragma alloca