upgrade to Boehm GC version 6.7

svn: r3634
This commit is contained in:
Matthew Flatt 2006-07-06 21:08:23 +00:00
parent 154329bf0e
commit ac267d077f
62 changed files with 6796 additions and 6458 deletions

View File

@ -8,13 +8,12 @@
11/22/94 pcb StripAddress the temporary memory handle for 24-bit mode.
11/30/94 pcb Tracking all memory usage so we can deallocate it all at once.
02/10/96 pcb Added routine to perform a final collection when unloading shared library.
02/10/96 pcb Added routine to perform a final collection when
unloading shared library.
by Patrick C. Beard.
PLTSCHEME: this file is substantially modified for MzScheme/MrEd.
*/
/* Boehm, November 17, 1995 11:50 am PST */
/* Boehm, February 15, 1996 2:55 pm PST */
#include <Resources.h>
#include <Memory.h>
@ -24,7 +23,7 @@
#include <string.h>
#include "gc.h"
#include "private/gc_priv.h"
#include "gc_priv.h"
// use 'CODE' resource 0 to get exact location of the beginning of global space.
@ -48,20 +47,6 @@ void* GC_MacGetDataStart()
return 0;
}
/* PLTSCHEME: Function for handling CW Pro 3 far data */
void* GC_MacGetDataEnd()
{
CodeZeroHandle code0 = (CodeZeroHandle)GetResource('CODE', 0);
if (code0) {
long aboveA5Size = (**code0).aboveA5;
ReleaseResource((Handle)code0);
return (LMGetCurrentA5() + aboveA5Size);
}
fprintf(stderr, "Couldn't load the jump table.");
exit(-1);
return 0;
}
/* track the use of temporary memory so it can be freed all at once. */
typedef struct TemporaryMemoryBlock TemporaryMemoryBlock, **TemporaryMemoryHandle;
@ -81,27 +66,7 @@ Ptr GC_MacTemporaryNewPtr(size_t size, Boolean clearMemory)
static Boolean firstTime = true;
OSErr result;
TemporaryMemoryHandle tempMemBlock;
Ptr tempPtr;
/* PLTSCHEME: IM requests that temp memory not be locked across
calls to GetNextEvent or WaitNextEvent. So, we'll use regular
pointers, but grab temp memory if we run out completely.
Also, we'll be nicer about not grabbing *all* of temp memory,
as this seems to bring down the whole system. */
if ((FreeMem() - size) >= 65536) { /* resort to tmp mem if local < some amount */
if (clearMemory)
tempPtr = NewPtrClear(size);
else
tempPtr = NewPtr(size);
if (tempPtr)
return tempPtr;
} else
tempPtr = NULL;
if ((TempFreeMem() - size) < 65536) {
/* Not much temp mem availabl, either. Give up. */
return NULL;
}
Ptr tempPtr = nil;
tempMemBlock = (TemporaryMemoryHandle)TempNewHandle(size + sizeof(TemporaryMemoryBlock), &result);
if (tempMemBlock && result == noErr) {
@ -115,36 +80,42 @@ Ptr GC_MacTemporaryNewPtr(size_t size, Boolean clearMemory)
theTemporaryMemory = tempMemBlock;
}
#if !defined(SHARED_LIBRARY_BUILD)
# if !defined(SHARED_LIBRARY_BUILD)
// install an exit routine to clean up the memory used at the end.
if (firstTime) {
atexit(&GC_MacFreeTemporaryMemory);
firstTime = false;
}
#endif
# endif
return tempPtr;
}
extern word GC_fo_entries;
static void perform_final_collection()
{
int i;
unsigned i;
word last_fo_entries = 0;
/* adjust the stack bottom, because CFM calls us from another stack location. */
/* adjust the stack bottom, because CFM calls us from another stack
location. */
GC_stackbottom = (ptr_t)&i;
/* try to collect everything in sight (from test.c). Is this safe? */
while (GC_collect_a_little()) ;
for (i = 0; i < 16; i++)
/* try to collect and finalize everything in sight */
for (i = 0; i < 2 || GC_fo_entries < last_fo_entries; i++) {
last_fo_entries = GC_fo_entries;
GC_gcollect();
}
}
void GC_MacFreeTemporaryMemory()
{
#if defined(SHARED_LIBRARY_BUILD)
/* collect all memory, and invoke all finalizers. */
# if defined(SHARED_LIBRARY_BUILD)
/* if possible, collect all memory, and invoke all finalizers. */
perform_final_collection();
#endif
# endif
if (theTemporaryMemory != NULL) {
long totalMemoryUsed = 0;
@ -157,9 +128,27 @@ void GC_MacFreeTemporaryMemory()
}
theTemporaryMemory = NULL;
#if !defined(SILENT) && !defined(SHARED_LIBRARY_BUILD)
fprintf(stdout, "[total memory used: %ld bytes.]\n", totalMemoryUsed);
# if !defined(SILENT) && !defined(SHARED_LIBRARY_BUILD)
fprintf(stdout, "[total memory used: %ld bytes.]\n",
totalMemoryUsed);
fprintf(stdout, "[total collections: %ld.]\n", GC_gc_no);
#endif
# endif
}
}
#if __option(far_data)
void* GC_MacGetDataEnd()
{
CodeZeroHandle code0 = (CodeZeroHandle)GetResource('CODE', 0);
if (code0) {
long aboveA5Size = (**code0).aboveA5;
ReleaseResource((Handle)code0);
return (LMGetCurrentA5() + aboveA5Size);
}
fprintf(stderr, "Couldn't load the jump table.");
exit(-1);
return 0;
}
#endif /* __option(far_data) */

View File

@ -45,7 +45,7 @@ asm_libgc_sources =
endif
libgc_la_SOURCES = allchblk.c alloc.c blacklst.c checksums.c dbg_mlc.c \
dyn_load.c finalize.c gc_dlopen.c gcj_mlc.c headers.c aix_irix_threads.c \
dyn_load.c finalize.c gc_dlopen.c gcj_mlc.c headers.c \
malloc.c mallocx.c mark.c mark_rts.c misc.c new_hblk.c \
obj_map.c os_dep.c pcr_interface.c ptr_chck.c real_malloc.c reclaim.c \
solaris_pthreads.c solaris_threads.c specific.c stubborn.c typd_mlc.c \
@ -53,9 +53,9 @@ backgraph.c win32_threads.c \
pthread_support.c pthread_stop_world.c darwin_stop_world.c \
$(asm_libgc_sources)
# Include THREADLIBS here to ensure that the correct versions of
# Include THREADDLLIBS here to ensure that the correct versions of
# linuxthread semaphore functions get linked:
libgc_la_LIBADD = @addobjs@ $(THREADLIBS) $(UNWINDLIBS)
libgc_la_LIBADD = @addobjs@ $(THREADDLLIBS) $(UNWINDLIBS)
libgc_la_DEPENDENCIES = @addobjs@
libgc_la_LDFLAGS = -version-info 1:2:0
@ -65,7 +65,7 @@ EXTRA_libgc_la_SOURCES = alpha_mach_dep.S \
sparc_sunos4_mach_dep.s ia64_save_regs_in_stack.s
libgccpp_la_SOURCES = gc_cpp.cc
libgccpp_la_LIBADD = $(THREADLIBS) $(UNWINDLIBS)
libgccpp_la_LIBADD = $(THREADDLLIBS) $(UNWINDLIBS)
libgccpp_la_LDFLAGS = -version-info 1:2:0
EXTRA_DIST += alpha_mach_dep.S mips_sgi_mach_dep.s sparc_mach_dep.S
@ -91,11 +91,11 @@ test_cpp.o: $(srcdir)/tests/test_cpp.cc
## are included in the distribution
# gctest_OBJECTS = test.o
gctest_SOURCES = tests/test.c
gctest_LDADD = ./libgc.la $(THREADLIBS) $(UNWINDLIBS) $(EXTRA_TEST_LIBS)
gctest_LDADD = ./libgc.la $(THREADDLLIBS) $(UNWINDLIBS) $(EXTRA_TEST_LIBS)
test_cpp_SOURCES = tests/test_cpp.cc
test_cpp_LDADD = ./libgc.la ./libgccpp.la $(THREADLIBS) $(UNWINDLIBS) $(EXTRA_TEST_LIBS)
test_cpp_LDADD = ./libgc.la ./libgccpp.la $(THREADDLLIBS) $(UNWINDLIBS) $(EXTRA_TEST_LIBS)
TESTS = gctest $(extra_checks)
TESTS = $(check_PROGRAMS)
## FIXME: relies on internal code generated by automake.
all_objs = @addobjs@ $(libgc_la_OBJECTS)
@ -105,10 +105,18 @@ include/gc_pthread_redirects.h include/gc_config_macros.h \
include/gc_mark.h @addincludes@
## FIXME: we shouldn't have to do this, but automake forces us to.
if COMPILER_XLC
## XLC neither requires nor tolerates the unnecessary assembler goop
ASM_CPP_OPTIONS =
else
## We use -Wp,-P to strip #line directives. Irix `as' chokes on
## these.
ASM_CPP_OPTIONS = -Wp,-P -x assembler-with-cpp
endif
.s.lo:
## We use -Wp,-P to strip #line directives. Irix `as' chokes on
## these.
$(LTCOMPILE) -Wp,-P -x assembler-with-cpp -c $<
$(LTCOMPILE) $(ASM_CPP_OPTIONS) -c $<
## We have our own definition of LTCOMPILE because we want to use our
## CFLAGS, not those passed in from the top level make.

View File

@ -36,7 +36,7 @@ CFLAGS= -O -I$(srcdir)/include -DATOMIC_UNCOLLECTABLE -DNO_SIGNALS -DNO_EXECUTE_
# -DGC_LINUX_THREADS -DPARALLEL_MARK -DTHREAD_LOCAL_ALLOC
# To build the parallel collector in a static library on HP/UX,
# add to the above:
# -DGC_HPUX_THREADS -DPARALLEL_MARK -DTHREAD_LOCAL_ALLOC -D_POSIX_C_SOURCE=199506L
# -DGC_HPUX_THREADS -DPARALLEL_MARK -DTHREAD_LOCAL_ALLOC -D_POSIX_C_SOURCE=199506L -mt
# To build the thread-safe collector on Tru64, add to the above:
# -pthread -DGC_OSF1_THREADS
@ -70,10 +70,11 @@ HOSTCFLAGS=$(CFLAGS)
# Also requires -D_REENTRANT or -D_POSIX_C_SOURCE=199506L. See README.hp.
# -DGC_LINUX_THREADS enables support for Xavier Leroy's Linux threads.
# see README.linux. -D_REENTRANT may also be required.
# -DGC_OSF1_THREADS enables support for Tru64 pthreads. Untested.
# -DGC_FREEBSD_THREADS enables support for FreeBSD pthreads. Untested.
# -DGC_OSF1_THREADS enables support for Tru64 pthreads.
# -DGC_FREEBSD_THREADS enables support for FreeBSD pthreads.
# Appeared to run into some underlying thread problems.
# -DGC_DARWIN_THREADS enables support for Mac OS X pthreads. Untested.
# -DGC_DARWIN_THREADS enables support for Mac OS X pthreads.
# -DGC_AIX_THREADS enables support for IBM AIX threads.
# -DGC_DGUX386_THREADS enables support for DB/UX on I386 threads.
# See README.DGUX386.
# -DGC_WIN32_THREADS enables support for win32 threads. That makes sense
@ -143,9 +144,9 @@ HOSTCFLAGS=$(CFLAGS)
# -DJAVA_FINALIZATION makes it somewhat safer to finalize objects out of
# order by specifying a nonstandard finalization mark procedure (see
# finalize.c). Objects reachable from finalizable objects will be marked
# in a sepearte postpass, and hence their memory won't be reclaimed.
# in a separate postpass, and hence their memory won't be reclaimed.
# Not recommended unless you are implementing a language that specifies
# these semantics. Since 5.0, determines only only the initial value
# these semantics. Since 5.0, determines only the initial value
# of GC_java_finalization variable.
# -DFINALIZE_ON_DEMAND causes finalizers to be run only in response
# to explicit GC_invoke_finalizers() calls.
@ -233,8 +234,8 @@ HOSTCFLAGS=$(CFLAGS)
# -DTHREAD_LOCAL_ALLOC defines GC_local_malloc(), GC_local_malloc_atomic()
# and GC_local_gcj_malloc(). Needed for gc_gcj.h interface. These allocate
# in a way that usually does not involve acquisition of a global lock.
# Currently requires -DGC_LINUX_THREADS, but should be easy to port to
# other pthreads environments. Recommended for multiprocessors.
# Currently works only on platforms such as Linux which use pthread_support.c.
# Recommended for multiprocessors.
# -DUSE_COMPILER_TLS causes thread local allocation to use compiler-supported
# "__thread" thread-local variables. This is the default in HP/UX. It
# may help performance on recent Linux installations. (It failed for
@ -276,6 +277,10 @@ HOSTCFLAGS=$(CFLAGS)
# -DPOINTER_SHIFT=n causes the collector to left shift candidate pointers
# by the indicated amount before trying to interpret them. Applied
# after POINTER_MASK. EXPERIMENTAL. See also the preceding macro.
# -DDARWIN_DONT_PARSE_STACK Causes the Darwin port to discover thread
# stack bounds in the same way as other pthread ports, without trying to
# walk the frames onthe stack. This is recommended only as a fallback
# for applications that don't support proper stack unwinding.
#
CXXFLAGS= $(CFLAGS)
@ -283,9 +288,9 @@ AR= ar
RANLIB= ranlib
OBJS= alloc.o reclaim.o allchblk.o misc.o mach_dep.o os_dep.o mark_rts.o headers.o mark.o obj_map.o blacklst.o finalize.o new_hblk.o dbg_mlc.o malloc.o stubborn.o checksums.o solaris_threads.o aix_irix_threads.o pthread_support.o pthread_stop_world.o darwin_stop_world.o typd_mlc.o ptr_chck.o mallocx.o solaris_pthreads.o gcj_mlc.o specific.o gc_dlopen.o backgraph.o win32_threads.o
OBJS= alloc.o reclaim.o allchblk.o misc.o mach_dep.o os_dep.o mark_rts.o headers.o mark.o obj_map.o blacklst.o finalize.o new_hblk.o dbg_mlc.o malloc.o stubborn.o checksums.o solaris_threads.o pthread_support.o pthread_stop_world.o darwin_stop_world.o typd_mlc.o ptr_chck.o mallocx.o solaris_pthreads.o gcj_mlc.o specific.o gc_dlopen.o backgraph.o win32_threads.o
CSRCS= reclaim.c allchblk.c misc.c alloc.c mach_dep.c os_dep.c mark_rts.c headers.c mark.c obj_map.c pcr_interface.c blacklst.c finalize.c new_hblk.c real_malloc.c dyn_load.c dbg_mlc.c malloc.c stubborn.c checksums.c solaris_threads.c aix_irix_threads.c pthread_support.c pthread_stop_world.c darwin_stop_world.c typd_mlc.c ptr_chck.c mallocx.c solaris_pthreads.c gcj_mlc.c specific.c gc_dlopen.c backgraph.c win32_threads.c
CSRCS= reclaim.c allchblk.c misc.c alloc.c mach_dep.c os_dep.c mark_rts.c headers.c mark.c obj_map.c pcr_interface.c blacklst.c finalize.c new_hblk.c real_malloc.c dyn_load.c dbg_mlc.c malloc.c stubborn.c checksums.c solaris_threads.c pthread_support.c pthread_stop_world.c darwin_stop_world.c typd_mlc.c ptr_chck.c mallocx.c solaris_pthreads.c gcj_mlc.c specific.c gc_dlopen.c backgraph.c win32_threads.c
CORD_SRCS= cord/cordbscs.c cord/cordxtra.c cord/cordprnt.c cord/de.c cord/cordtest.c include/cord.h include/ec.h include/private/cord_pos.h cord/de_win.c cord/de_win.h cord/de_cmds.h cord/de_win.ICO cord/de_win.RC

View File

@ -38,7 +38,7 @@ CFLAGS= $(BASEFLAGS) @PROFFLAGS@ $(OPTIONS) -DNO_EXECUTE_PERMISSION -DSILENT -DN
# -DGC_LINUX_THREADS -DPARALLEL_MARK -DTHREAD_LOCAL_ALLOC
# To build the parallel collector in a static library on HP/UX,
# add to the above:
# -DGC_HPUX_THREADS -DPARALLEL_MARK -DTHREAD_LOCAL_ALLOC -D_POSIX_C_SOURCE=199506L
# -DGC_HPUX_THREADS -DPARALLEL_MARK -DTHREAD_LOCAL_ALLOC -D_POSIX_C_SOURCE=199506L -mt
# To build the thread-safe collector on Tru64, add to the above:
# -pthread -DGC_OSF1_THREADS
@ -72,10 +72,11 @@ HOSTCFLAGS=$(BASEFLAGS)
# Also requires -D_REENTRANT or -D_POSIX_C_SOURCE=199506L. See README.hp.
# -DGC_LINUX_THREADS enables support for Xavier Leroy's Linux threads.
# see README.linux. -D_REENTRANT may also be required.
# -DGC_OSF1_THREADS enables support for Tru64 pthreads. Untested.
# -DGC_FREEBSD_THREADS enables support for FreeBSD pthreads. Untested.
# -DGC_OSF1_THREADS enables support for Tru64 pthreads.
# -DGC_FREEBSD_THREADS enables support for FreeBSD pthreads.
# Appeared to run into some underlying thread problems.
# -DGC_DARWIN_THREADS enables support for Mac OS X pthreads. Untested.
# -DGC_DARWIN_THREADS enables support for Mac OS X pthreads.
# -DGC_AIX_THREADS enables support for IBM AIX threads.
# -DGC_DGUX386_THREADS enables support for DB/UX on I386 threads.
# See README.DGUX386.
# -DGC_WIN32_THREADS enables support for win32 threads. That makes sense
@ -145,9 +146,9 @@ HOSTCFLAGS=$(BASEFLAGS)
# -DJAVA_FINALIZATION makes it somewhat safer to finalize objects out of
# order by specifying a nonstandard finalization mark procedure (see
# finalize.c). Objects reachable from finalizable objects will be marked
# in a sepearte postpass, and hence their memory won't be reclaimed.
# in a seperate postpass, and hence their memory won't be reclaimed.
# Not recommended unless you are implementing a language that specifies
# these semantics. Since 5.0, determines only only the initial value
# these semantics. Since 5.0, determines only the initial value
# of GC_java_finalization variable.
# -DFINALIZE_ON_DEMAND causes finalizers to be run only in response
# to explicit GC_invoke_finalizers() calls.
@ -235,8 +236,8 @@ HOSTCFLAGS=$(BASEFLAGS)
# -DTHREAD_LOCAL_ALLOC defines GC_local_malloc(), GC_local_malloc_atomic()
# and GC_local_gcj_malloc(). Needed for gc_gcj.h interface. These allocate
# in a way that usually does not involve acquisition of a global lock.
# Currently requires -DGC_LINUX_THREADS, but should be easy to port to
# other pthreads environments. Recommended for multiprocessors.
# Currently works only on platforms such as Linux which use pthread_support.c.
# Recommended for multiprocessors.
# -DUSE_COMPILER_TLS causes thread local allocation to use compiler-supported
# "__thread" thread-local variables. This is the default in HP/UX. It
# may help performance on recent Linux installations. (It failed for
@ -278,6 +279,10 @@ HOSTCFLAGS=$(BASEFLAGS)
# -DPOINTER_SHIFT=n causes the collector to left shift candidate pointers
# by the indicated amount before trying to interpret them. Applied
# after POINTER_MASK. EXPERIMENTAL. See also the preceding macro.
# -DDARWIN_DONT_PARSE_STACK Causes the Darwin port to discover thread
# stack bounds in the same way as other pthread ports, without trying to
# walk the frames onthe stack. This is recommended only as a fallback
# for applications that don't support proper stack unwinding.
#
CXXFLAGS= $(CFLAGS)
@ -286,9 +291,9 @@ ARFLAGS= @ARFLAGS@
RANLIB= @RANLIB@
OBJS= alloc.@LTO@ reclaim.@LTO@ allchblk.@LTO@ misc.@LTO@ mach_dep.@LTO@ os_dep.@LTO@ mark_rts.@LTO@ headers.@LTO@ mark.@LTO@ obj_map.@LTO@ blacklst.@LTO@ finalize.@LTO@ new_hblk.@LTO@ dbg_mlc.@LTO@ malloc.@LTO@ stubborn.@LTO@ checksums.@LTO@ solaris_threads.@LTO@ aix_irix_threads.@LTO@ pthread_support.@LTO@ pthread_stop_world.@LTO@ darwin_stop_world.@LTO@ typd_mlc.@LTO@ ptr_chck.@LTO@ mallocx.@LTO@ solaris_pthreads.@LTO@ gcj_mlc.@LTO@ specific.@LTO@ gc_dlopen.@LTO@ backgraph.@LTO@ win32_threads.@LTO@
OBJS= alloc.@LTO@ reclaim.@LTO@ allchblk.@LTO@ misc.@LTO@ mach_dep.@LTO@ os_dep.@LTO@ mark_rts.@LTO@ headers.@LTO@ mark.@LTO@ obj_map.@LTO@ blacklst.@LTO@ finalize.@LTO@ new_hblk.@LTO@ dbg_mlc.@LTO@ malloc.@LTO@ stubborn.@LTO@ checksums.@LTO@ solaris_threads.@LTO@ pthread_support.@LTO@ pthread_stop_world.@LTO@ darwin_stop_world.@LTO@ typd_mlc.@LTO@ ptr_chck.@LTO@ mallocx.@LTO@ solaris_pthreads.@LTO@ gcj_mlc.@LTO@ specific.@LTO@ gc_dlopen.@LTO@ backgraph.@LTO@ win32_threads.@LTO@
CSRCS= reclaim.c allchblk.c misc.c alloc.c mach_dep.c os_dep.c mark_rts.c headers.c mark.c obj_map.c pcr_interface.c blacklst.c finalize.c new_hblk.c real_malloc.c dyn_load.c dbg_mlc.c malloc.c stubborn.c checksums.c solaris_threads.c aix_irix_threads.c pthread_support.c pthread_stop_world.c darwin_stop_world.c typd_mlc.c ptr_chck.c mallocx.c solaris_pthreads.c gcj_mlc.c specific.c gc_dlopen.c backgraph.c win32_threads.c
CSRCS= reclaim.c allchblk.c misc.c alloc.c mach_dep.c os_dep.c mark_rts.c headers.c mark.c obj_map.c pcr_interface.c blacklst.c finalize.c new_hblk.c real_malloc.c dyn_load.c dbg_mlc.c malloc.c stubborn.c checksums.c solaris_threads.c pthread_support.c pthread_stop_world.c darwin_stop_world.c typd_mlc.c ptr_chck.c mallocx.c solaris_pthreads.c gcj_mlc.c specific.c gc_dlopen.c backgraph.c win32_threads.c
CORD_SRCS= cord/cordbscs.c cord/cordxtra.c cord/cordprnt.c cord/de.c cord/cordtest.c include/cord.h include/ec.h include/private/cord_pos.h cord/de_win.c cord/de_win.h cord/de_cmds.h cord/de_win.ICO cord/de_win.RC
@ -729,9 +734,6 @@ solaris_threads.@LTO@: $(srcdir)/solaris_threads.c
win32_threads.@LTO@: $(srcdir)/win32_threads.c
$(CC) $(CFLAGS) -c $(srcdir)/win32_threads.c
aix_irix_threads.@LTO@: $(srcdir)/aix_irix_threads.c
$(CC) $(CFLAGS) -c $(srcdir)/aix_irix_threads.c
pthread_support.@LTO@: $(srcdir)/pthread_support.c
$(CC) $(CFLAGS) -c $(srcdir)/pthread_support.c

File diff suppressed because it is too large Load Diff

View File

@ -1,688 +0,0 @@
/*
* Copyright (c) 1991-1995 by Xerox Corporation. All rights reserved.
* Copyright (c) 1996-1999 by Silicon Graphics. All rights reserved.
* Copyright (c) 1999-2003 by Hewlett-Packard Company. All rights reserved.
*
* THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
* OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
*
* Permission is hereby granted to use or copy this program
* for any purpose, provided the above notices are retained on all copies.
* Permission to modify the code and to distribute modified code is granted,
* provided the above notices are retained, and a notice that the code was
* modified is included with the above copyright notice.
*/
/*
* Support code for Irix (>=6.2) Pthreads and for AIX pthreads.
* This relies on properties
* not guaranteed by the Pthread standard. It may or may not be portable
* to other implementations.
*
* Note that there is a lot of code duplication between this file and
* (pthread_support.c, pthread_stop_world.c). They should be merged.
* Pthread_support.c should be directly usable.
*
* Please avoid adding new ports here; use the generic pthread support
* as a base instead.
*/
# if defined(GC_IRIX_THREADS) || defined(GC_AIX_THREADS)
# include "private/gc_priv.h"
# include <pthread.h>
# include <assert.h>
# include <semaphore.h>
# include <time.h>
# include <errno.h>
# include <unistd.h>
# include <sys/mman.h>
# include <sys/time.h>
#undef pthread_create
#undef pthread_sigmask
#undef pthread_join
#if defined(GC_IRIX_THREADS) && !defined(MUTEX_RECURSIVE_NP)
#define MUTEX_RECURSIVE_NP PTHREAD_MUTEX_RECURSIVE
#endif
void GC_thr_init();
#if 0
void GC_print_sig_mask()
{
sigset_t blocked;
int i;
if (pthread_sigmask(SIG_BLOCK, NULL, &blocked) != 0)
ABORT("pthread_sigmask");
GC_printf0("Blocked: ");
for (i = 1; i <= MAXSIG; i++) {
if (sigismember(&blocked, i)) { GC_printf1("%ld ",(long) i); }
}
GC_printf0("\n");
}
#endif
/* We use the allocation lock to protect thread-related data structures. */
/* The set of all known threads. We intercept thread creation and */
/* joins. We never actually create detached threads. We allocate all */
/* new thread stacks ourselves. These allow us to maintain this */
/* data structure. */
/* Protected by GC_thr_lock. */
/* Some of this should be declared volatile, but that's incosnsistent */
/* with some library routine declarations. */
typedef struct GC_Thread_Rep {
struct GC_Thread_Rep * next; /* More recently allocated threads */
/* with a given pthread id come */
/* first. (All but the first are */
/* guaranteed to be dead, but we may */
/* not yet have registered the join.) */
pthread_t id;
word stop;
# define NOT_STOPPED 0
# define PLEASE_STOP 1
# define STOPPED 2
word flags;
# define FINISHED 1 /* Thread has exited. */
# define DETACHED 2 /* Thread is intended to be detached. */
ptr_t stack_cold; /* cold end of the stack */
ptr_t stack_hot; /* Valid only when stopped. */
/* But must be within stack region at */
/* all times. */
void * status; /* Used only to avoid premature */
/* reclamation of any data it might */
/* reference. */
} * GC_thread;
GC_thread GC_lookup_thread(pthread_t id);
/*
* The only way to suspend threads given the pthread interface is to send
* signals. Unfortunately, this means we have to reserve
* a signal, and intercept client calls to change the signal mask.
*/
#if 0 /* DOB: 6.1 */
# if defined(GC_AIX_THREADS)
# define SIG_SUSPEND SIGUSR1
# else
# define SIG_SUSPEND (SIGRTMIN + 6)
# endif
#endif
pthread_mutex_t GC_suspend_lock = PTHREAD_MUTEX_INITIALIZER;
/* Number of threads stopped so far */
pthread_cond_t GC_suspend_ack_cv = PTHREAD_COND_INITIALIZER;
pthread_cond_t GC_continue_cv = PTHREAD_COND_INITIALIZER;
void GC_suspend_handler(int sig)
{
int dummy;
GC_thread me;
sigset_t all_sigs;
sigset_t old_sigs;
int i;
if (sig != SIG_SUSPEND) ABORT("Bad signal in suspend_handler");
me = GC_lookup_thread(pthread_self());
/* The lookup here is safe, since I'm doing this on behalf */
/* of a thread which holds the allocation lock in order */
/* to stop the world. Thus concurrent modification of the */
/* data structure is impossible. */
if (PLEASE_STOP != me -> stop) {
/* Misdirected signal. */
pthread_mutex_unlock(&GC_suspend_lock);
return;
}
pthread_mutex_lock(&GC_suspend_lock);
me -> stack_hot = (ptr_t)(&dummy);
me -> stop = STOPPED;
pthread_cond_signal(&GC_suspend_ack_cv);
pthread_cond_wait(&GC_continue_cv, &GC_suspend_lock);
pthread_mutex_unlock(&GC_suspend_lock);
/* GC_printf1("Continuing 0x%x\n", pthread_self()); */
}
GC_bool GC_thr_initialized = FALSE;
# define THREAD_TABLE_SZ 128 /* Must be power of 2 */
volatile GC_thread GC_threads[THREAD_TABLE_SZ];
void GC_push_thread_structures GC_PROTO((void))
{
GC_push_all((ptr_t)(GC_threads), (ptr_t)(GC_threads)+sizeof(GC_threads));
}
/* Add a thread to GC_threads. We assume it wasn't already there. */
/* Caller holds allocation lock. */
GC_thread GC_new_thread(pthread_t id)
{
int hv = ((word)id) % THREAD_TABLE_SZ;
GC_thread result;
static struct GC_Thread_Rep first_thread;
static GC_bool first_thread_used = FALSE;
GC_ASSERT(I_HOLD_LOCK());
if (!first_thread_used) {
result = &first_thread;
first_thread_used = TRUE;
/* Dont acquire allocation lock, since we may already hold it. */
} else {
result = (struct GC_Thread_Rep *)
GC_generic_malloc_inner(sizeof(struct GC_Thread_Rep), NORMAL);
}
if (result == 0) return(0);
result -> id = id;
result -> next = GC_threads[hv];
GC_threads[hv] = result;
/* result -> flags = 0; */
/* result -> stop = 0; */
return(result);
}
/* Delete a thread from GC_threads. We assume it is there. */
/* (The code intentionally traps if it wasn't.) */
/* Caller holds allocation lock. */
/* We explicitly pass in the GC_thread we're looking for, since */
/* if a thread has been joined, but we have not yet */
/* been notified, then there may be more than one thread */
/* in the table with the same pthread id. */
/* This is OK, but we need a way to delete a specific one. */
void GC_delete_gc_thread(pthread_t id, GC_thread gc_id)
{
int hv = ((word)id) % THREAD_TABLE_SZ;
register GC_thread p = GC_threads[hv];
register GC_thread prev = 0;
GC_ASSERT(I_HOLD_LOCK());
while (p != gc_id) {
prev = p;
p = p -> next;
}
if (prev == 0) {
GC_threads[hv] = p -> next;
} else {
prev -> next = p -> next;
}
}
/* Return a GC_thread corresponding to a given thread_t. */
/* Returns 0 if it's not there. */
/* Caller holds allocation lock or otherwise inhibits */
/* updates. */
/* If there is more than one thread with the given id we */
/* return the most recent one. */
GC_thread GC_lookup_thread(pthread_t id)
{
int hv = ((word)id) % THREAD_TABLE_SZ;
register GC_thread p = GC_threads[hv];
/* I either hold the lock, or i'm being called from the stop-the-world
* handler. */
#if defined(GC_AIX_THREADS)
GC_ASSERT(I_HOLD_LOCK()); /* no stop-the-world handler needed on AIX */
#endif
while (p != 0 && !pthread_equal(p -> id, id)) p = p -> next;
return(p);
}
#if defined(GC_AIX_THREADS)
void GC_stop_world()
{
pthread_t my_thread = pthread_self();
register int i;
register GC_thread p;
register int result;
struct timespec timeout;
GC_ASSERT(I_HOLD_LOCK());
for (i = 0; i < THREAD_TABLE_SZ; i++) {
for (p = GC_threads[i]; p != 0; p = p -> next) {
if (p -> id != my_thread) {
pthread_suspend_np(p->id);
}
}
}
/* GC_printf1("World stopped 0x%x\n", pthread_self()); */
}
void GC_start_world()
{
GC_thread p;
unsigned i;
pthread_t my_thread = pthread_self();
/* GC_printf0("World starting\n"); */
GC_ASSERT(I_HOLD_LOCK());
for (i = 0; i < THREAD_TABLE_SZ; i++) {
for (p = GC_threads[i]; p != 0; p = p -> next) {
if (p -> id != my_thread) {
pthread_continue_np(p->id);
}
}
}
}
#else /* GC_AIX_THREADS */
/* Caller holds allocation lock. */
void GC_stop_world()
{
pthread_t my_thread = pthread_self();
register int i;
register GC_thread p;
register int result;
struct timespec timeout;
GC_ASSERT(I_HOLD_LOCK());
for (i = 0; i < THREAD_TABLE_SZ; i++) {
for (p = GC_threads[i]; p != 0; p = p -> next) {
if (p -> id != my_thread) {
if (p -> flags & FINISHED) {
p -> stop = STOPPED;
continue;
}
p -> stop = PLEASE_STOP;
result = pthread_kill(p -> id, SIG_SUSPEND);
/* GC_printf1("Sent signal to 0x%x\n", p -> id); */
switch(result) {
case ESRCH:
/* Not really there anymore. Possible? */
p -> stop = STOPPED;
break;
case 0:
break;
default:
ABORT("pthread_kill failed");
}
}
}
}
pthread_mutex_lock(&GC_suspend_lock);
for (i = 0; i < THREAD_TABLE_SZ; i++) {
for (p = GC_threads[i]; p != 0; p = p -> next) {
while (p -> id != my_thread && p -> stop != STOPPED) {
clock_gettime(CLOCK_REALTIME, &timeout);
timeout.tv_nsec += 50000000; /* 50 msecs */
if (timeout.tv_nsec >= 1000000000) {
timeout.tv_nsec -= 1000000000;
++timeout.tv_sec;
}
result = pthread_cond_timedwait(&GC_suspend_ack_cv,
&GC_suspend_lock,
&timeout);
if (result == ETIMEDOUT) {
/* Signal was lost or misdirected. Try again. */
/* Duplicate signals should be benign. */
result = pthread_kill(p -> id, SIG_SUSPEND);
}
}
}
}
pthread_mutex_unlock(&GC_suspend_lock);
/* GC_printf1("World stopped 0x%x\n", pthread_self()); */
}
/* Caller holds allocation lock. */
void GC_start_world()
{
GC_thread p;
unsigned i;
/* GC_printf0("World starting\n"); */
GC_ASSERT(I_HOLD_LOCK());
for (i = 0; i < THREAD_TABLE_SZ; i++) {
for (p = GC_threads[i]; p != 0; p = p -> next) {
p -> stop = NOT_STOPPED;
}
}
pthread_mutex_lock(&GC_suspend_lock);
/* All other threads are at pthread_cond_wait in signal handler. */
/* Otherwise we couldn't have acquired the lock. */
pthread_mutex_unlock(&GC_suspend_lock);
pthread_cond_broadcast(&GC_continue_cv);
}
#endif /* GC_AIX_THREADS */
/* We hold allocation lock. Should do exactly the right thing if the */
/* world is stopped. Should not fail if it isn't. */
void GC_push_all_stacks()
{
register int i;
register GC_thread p;
register ptr_t hot, cold;
pthread_t me = pthread_self();
/* GC_init() should have been called before GC_push_all_stacks is
* invoked, and GC_init calls GC_thr_init(), which sets
* GC_thr_initialized. */
GC_ASSERT(GC_thr_initialized);
/* GC_printf1("Pushing stacks from thread 0x%x\n", me); */
GC_ASSERT(I_HOLD_LOCK());
for (i = 0; i < THREAD_TABLE_SZ; i++) {
for (p = GC_threads[i]; p != 0; p = p -> next) {
if (p -> flags & FINISHED) continue;
cold = p->stack_cold;
if (!cold) cold=GC_stackbottom; /* 0 indicates 'original stack' */
if (pthread_equal(p -> id, me)) {
hot = GC_approx_sp();
} else {
# ifdef GC_AIX_THREADS
/* AIX doesn't use signals to suspend, so we need to get an */
/* accurate hot stack pointer. */
/* See http://publib16.boulder.ibm.com/pseries/en_US/libs/basetrf1/pthread_getthrds_np.htm */
pthread_t id = p -> id;
struct __pthrdsinfo pinfo;
int regbuf[64];
int val = sizeof(regbuf);
int retval = pthread_getthrds_np(&id, PTHRDSINFO_QUERY_ALL, &pinfo,
sizeof(pinfo), regbuf, &val);
if (retval != 0) {
printf("ERROR: pthread_getthrds_np() failed in GC\n");
abort();
}
/* according to the AIX ABI,
"the lowest possible valid stack address is 288 bytes (144 + 144)
less than the current value of the stack pointer. Functions may
use this stack space as volatile storage which is not preserved
across function calls."
ftp://ftp.penguinppc64.org/pub/people/amodra/PPC-elf64abi.txt.gz
*/
hot = (ptr_t)(unsigned long)pinfo.__pi_ustk-288;
cold = (ptr_t)pinfo.__pi_stackend; /* more precise */
/* push the registers too, because they won't be on stack */
GC_push_all_eager((ptr_t)&pinfo.__pi_context,
(ptr_t)((&pinfo.__pi_context)+1));
GC_push_all_eager((ptr_t)regbuf, ((ptr_t)regbuf)+val);
# else
hot = p -> stack_hot;
# endif
}
# ifdef STACK_GROWS_UP
GC_push_all_stack(cold, hot);
# else
/* printf("thread 0x%x: hot=0x%08x cold=0x%08x\n", p -> id, hot, cold); */
GC_push_all_stack(hot, cold);
# endif
}
}
}
/* We hold the allocation lock. */
void GC_thr_init()
{
GC_thread t;
struct sigaction act;
if (GC_thr_initialized) return;
GC_ASSERT(I_HOLD_LOCK());
GC_thr_initialized = TRUE;
#ifndef GC_AIX_THREADS
(void) sigaction(SIG_SUSPEND, 0, &act);
if (act.sa_handler != SIG_DFL)
ABORT("Previously installed SIG_SUSPEND handler");
/* Install handler. */
act.sa_handler = GC_suspend_handler;
act.sa_flags = SA_RESTART;
(void) sigemptyset(&act.sa_mask);
if (0 != sigaction(SIG_SUSPEND, &act, 0))
ABORT("Failed to install SIG_SUSPEND handler");
#endif
/* Add the initial thread, so we can stop it. */
t = GC_new_thread(pthread_self());
/* use '0' to indicate GC_stackbottom, since GC_init() has not
* completed by the time we are called (from GC_init_inner()) */
t -> stack_cold = 0; /* the original stack. */
t -> stack_hot = (ptr_t)(&t);
t -> flags = DETACHED;
}
int GC_pthread_sigmask(int how, const sigset_t *set, sigset_t *oset)
{
sigset_t fudged_set;
#ifdef GC_AIX_THREADS
return(pthread_sigmask(how, set, oset));
#endif
if (set != NULL && (how == SIG_BLOCK || how == SIG_SETMASK)) {
fudged_set = *set;
sigdelset(&fudged_set, SIG_SUSPEND);
set = &fudged_set;
}
return(pthread_sigmask(how, set, oset));
}
struct start_info {
void *(*start_routine)(void *);
void *arg;
word flags;
pthread_mutex_t registeredlock;
pthread_cond_t registered;
int volatile registereddone;
};
void GC_thread_exit_proc(void *arg)
{
GC_thread me;
LOCK();
me = GC_lookup_thread(pthread_self());
me -> flags |= FINISHED;
/* reclaim DETACHED thread right away; otherwise wait until join() */
if (me -> flags & DETACHED) {
GC_delete_gc_thread(pthread_self(), me);
}
UNLOCK();
}
int GC_pthread_join(pthread_t thread, void **retval)
{
int result;
GC_thread thread_gc_id;
LOCK();
thread_gc_id = GC_lookup_thread(thread);
/* This is guaranteed to be the intended one, since the thread id */
/* cant have been recycled by pthreads. */
UNLOCK();
GC_ASSERT(!(thread_gc_id->flags & DETACHED));
result = pthread_join(thread, retval);
/* Some versions of the Irix pthreads library can erroneously */
/* return EINTR when the call succeeds. */
if (EINTR == result) result = 0;
GC_ASSERT(thread_gc_id->flags & FINISHED);
LOCK();
/* Here the pthread thread id may have been recycled. */
GC_delete_gc_thread(thread, thread_gc_id);
UNLOCK();
return result;
}
void * GC_start_routine(void * arg)
{
int dummy;
struct start_info * si = arg;
void * result;
GC_thread me;
pthread_t my_pthread;
void *(*start)(void *);
void *start_arg;
my_pthread = pthread_self();
/* If a GC occurs before the thread is registered, that GC will */
/* ignore this thread. That's fine, since it will block trying to */
/* acquire the allocation lock, and won't yet hold interesting */
/* pointers. */
LOCK();
/* We register the thread here instead of in the parent, so that */
/* we don't need to hold the allocation lock during pthread_create. */
/* Holding the allocation lock there would make REDIRECT_MALLOC */
/* impossible. It probably still doesn't work, but we're a little */
/* closer ... */
/* This unfortunately means that we have to be careful the parent */
/* doesn't try to do a pthread_join before we're registered. */
me = GC_new_thread(my_pthread);
me -> flags = si -> flags;
me -> stack_cold = (ptr_t) &dummy; /* this now the 'start of stack' */
me -> stack_hot = me->stack_cold;/* this field should always be sensible */
UNLOCK();
start = si -> start_routine;
start_arg = si -> arg;
pthread_mutex_lock(&(si->registeredlock));
si->registereddone = 1;
pthread_cond_signal(&(si->registered));
pthread_mutex_unlock(&(si->registeredlock));
/* si went away as soon as we did this unlock */
pthread_cleanup_push(GC_thread_exit_proc, 0);
result = (*start)(start_arg);
me -> status = result;
pthread_cleanup_pop(1);
/* This involves acquiring the lock, ensuring that we can't exit */
/* while a collection that thinks we're alive is trying to stop */
/* us. */
return(result);
}
int
GC_pthread_create(pthread_t *new_thread,
const pthread_attr_t *attr,
void *(*start_routine)(void *), void *arg)
{
int result;
GC_thread t;
int detachstate;
word my_flags = 0;
struct start_info * si;
/* This is otherwise saved only in an area mmapped by the thread */
/* library, which isn't visible to the collector. */
LOCK();
/* GC_INTERNAL_MALLOC implicitly calls GC_init() if required */
si = (struct start_info *)GC_INTERNAL_MALLOC(sizeof(struct start_info),
NORMAL);
GC_ASSERT(GC_thr_initialized); /* initialized by GC_init() */
UNLOCK();
if (0 == si) return(ENOMEM);
pthread_mutex_init(&(si->registeredlock), NULL);
pthread_cond_init(&(si->registered),NULL);
pthread_mutex_lock(&(si->registeredlock));
si -> start_routine = start_routine;
si -> arg = arg;
pthread_attr_getdetachstate(attr, &detachstate);
if (PTHREAD_CREATE_DETACHED == detachstate) my_flags |= DETACHED;
si -> flags = my_flags;
result = pthread_create(new_thread, attr, GC_start_routine, si);
/* Wait until child has been added to the thread table. */
/* This also ensures that we hold onto si until the child is done */
/* with it. Thus it doesn't matter whether it is otherwise */
/* visible to the collector. */
if (0 == result) {
si->registereddone = 0;
while (!si->registereddone)
pthread_cond_wait(&(si->registered), &(si->registeredlock));
}
pthread_mutex_unlock(&(si->registeredlock));
pthread_cond_destroy(&(si->registered));
pthread_mutex_destroy(&(si->registeredlock));
LOCK();
GC_INTERNAL_FREE(si);
UNLOCK();
return(result);
}
/* For now we use the pthreads locking primitives on HP/UX */
VOLATILE GC_bool GC_collecting = 0; /* A hint that we're in the collector and */
/* holding the allocation lock for an */
/* extended period. */
/* Reasonably fast spin locks. Basically the same implementation */
/* as STL alloc.h. */
#define SLEEP_THRESHOLD 3
volatile unsigned int GC_allocate_lock = 0;
#define GC_TRY_LOCK() !GC_test_and_set(&GC_allocate_lock)
#define GC_LOCK_TAKEN GC_allocate_lock
void GC_lock()
{
# define low_spin_max 30 /* spin cycles if we suspect uniprocessor */
# define high_spin_max 1000 /* spin cycles for multiprocessor */
static unsigned spin_max = low_spin_max;
unsigned my_spin_max;
static unsigned last_spins = 0;
unsigned my_last_spins;
volatile unsigned junk;
# define PAUSE junk *= junk; junk *= junk; junk *= junk; junk *= junk
int i;
if (GC_TRY_LOCK()) {
return;
}
junk = 0;
my_spin_max = spin_max;
my_last_spins = last_spins;
for (i = 0; i < my_spin_max; i++) {
if (GC_collecting) goto yield;
if (i < my_last_spins/2 || GC_LOCK_TAKEN) {
PAUSE;
continue;
}
if (GC_TRY_LOCK()) {
/*
* got it!
* Spinning worked. Thus we're probably not being scheduled
* against the other process with which we were contending.
* Thus it makes sense to spin longer the next time.
*/
last_spins = i;
spin_max = high_spin_max;
return;
}
}
/* We are probably being scheduled against the other process. Sleep. */
spin_max = low_spin_max;
yield:
for (i = 0;; ++i) {
if (GC_TRY_LOCK()) {
return;
}
if (i < SLEEP_THRESHOLD) {
sched_yield();
} else {
struct timespec ts;
if (i > 26) i = 26;
/* Don't wait for more than about 60msecs, even */
/* under extreme contention. */
ts.tv_sec = 0;
ts.tv_nsec = 1 << i;
nanosleep(&ts, 0);
}
}
}
# else /* !GC_IRIX_THREADS && !GC_AIX_THREADS */
#ifndef LINT
int GC_no_Irix_threads;
#endif
# endif /* IRIX_THREADS */

View File

@ -285,8 +285,8 @@ int n;
GET_HDR(hhdr -> hb_prev, phdr);
phdr -> hb_next = hhdr -> hb_next;
}
FREE_ASSERT(GC_free_bytes[index] >= hhdr -> hb_sz);
INCR_FREE_BYTES(index, - (signed_word)(hhdr -> hb_sz));
FREE_ASSERT(GC_free_bytes[index] >= 0);
if (0 != hhdr -> hb_next) {
hdr * nhdr;
GC_ASSERT(!IS_FORWARDING_ADDR_OR_NIL(NHDR(hhdr)));
@ -529,7 +529,7 @@ int index; /* Index of free list */
/* free blocks in GC_add_to_fl. */
# endif
# ifdef USE_MUNMAP
hhdr -> hb_last_reclaimed = GC_gc_no;
hhdr -> hb_last_reclaimed = (unsigned short)GC_gc_no;
# endif
hhdr -> hb_sz = h_size;
GC_add_to_fl(h, hhdr);
@ -590,8 +590,9 @@ int n;
GET_HDR(hbp, hhdr);
size_avail = hhdr->hb_sz;
if (size_avail < size_needed) continue;
if (!GC_use_entire_heap
&& size_avail != size_needed
if (size_avail != size_needed
&& !GC_use_entire_heap
&& !GC_dont_gc
&& USED_HEAP_SIZE >= GC_requested_heapsize
&& !TRUE_INCREMENTAL && GC_should_collect()) {
# ifdef USE_MUNMAP
@ -608,7 +609,8 @@ int n;
/* If we are deallocating lots of memory from */
/* finalizers, fail and collect sooner rather */
/* than later. */
if (GC_finalizer_mem_freed > (GC_heapsize >> 4)) {
if (WORDS_TO_BYTES(GC_finalizer_mem_freed)
> (GC_heapsize >> 4)) {
continue;
}
# endif /* !USE_MUNMAP */
@ -701,7 +703,7 @@ int n;
struct hblk * h;
struct hblk * prev = hhdr -> hb_prev;
GC_words_wasted += total_size;
GC_words_wasted += BYTES_TO_WORDS(total_size);
GC_large_free_bytes -= total_size;
GC_remove_from_fl(hhdr, n);
for (h = hbp; h < limit; h++) {
@ -794,7 +796,7 @@ signed_word size;
GC_remove_counts(hbp, (word)size);
hhdr->hb_sz = size;
# ifdef USE_MUNMAP
hhdr -> hb_last_reclaimed = GC_gc_no;
hhdr -> hb_last_reclaimed = (unsigned short)GC_gc_no;
# endif
/* Check for duplicate deallocation in the easy case */
@ -822,7 +824,7 @@ signed_word size;
GC_remove_from_fl(prevhdr, FL_UNKNOWN);
prevhdr -> hb_sz += hhdr -> hb_sz;
# ifdef USE_MUNMAP
prevhdr -> hb_last_reclaimed = GC_gc_no;
prevhdr -> hb_last_reclaimed = (unsigned short)GC_gc_no;
# endif
GC_remove_header(hbp);
hbp = prev;

View File

@ -92,6 +92,16 @@ char * GC_copyright[] =
# include "version.h"
#if defined(SAVE_CALL_CHAIN) && \
!(defined(REDIRECT_MALLOC) && defined(GC_HAVE_BUILTIN_BACKTRACE))
# define SAVE_CALL_CHAIN_IN_GC
/* This is only safe if the call chain save mechanism won't end up */
/* calling GC_malloc. The GNU C library documentation suggests */
/* that backtrace doesn't use malloc, but at least the initial */
/* call in some versions does seem to invoke the dynamic linker, */
/* which uses malloc. */
#endif
/* some more variables */
extern signed_word GC_mem_found; /* Number of reclaimed longwords */
@ -104,8 +114,6 @@ word GC_free_space_divisor = 4; /* PLTSCHEME: 3 -> 4 */
extern GC_bool GC_collection_in_progress();
/* Collection is in progress, or was abandoned. */
extern GC_bool GC_print_back_height;
int GC_never_stop_func GC_PROTO((void)) { return(0); }
unsigned long GC_time_limit = TIME_LIMIT;
@ -198,6 +206,7 @@ word GC_adj_words_allocd()
/* had been reallocated this round. Finalization is user */
/* visible progress. And if we don't count this, we have */
/* stability problems for programs that finalize all objects. */
if ((signed_word)(GC_words_wasted >> 3) < result)
result += GC_words_wasted;
/* This doesn't reflect useful work. But if there is lots of */
/* new fragmentation, the same is probably true of the heap, */
@ -223,6 +232,8 @@ void GC_clear_a_few_frames()
{
# define NWORDS 64
word frames[NWORDS];
/* Some compilers will warn that frames was set but never used. */
/* That's the whole idea ... */
register int i;
for (i = 0; i < NWORDS; i++) frames[i] = 0;
@ -295,7 +306,7 @@ void GC_maybe_gc()
# endif
if (GC_stopped_mark(GC_time_limit == GC_TIME_UNLIMITED?
GC_never_stop_func : GC_timeout_stop_func)) {
# ifdef SAVE_CALL_CHAIN
# ifdef SAVE_CALL_CHAIN_IN_GC
GC_save_callers(GC_last_stack);
# endif
GC_finish_collection();
@ -366,7 +377,7 @@ GC_stop_func stop_func;
}
GC_invalidate_mark_state(); /* Flush mark stack. */
GC_clear_marks();
# ifdef SAVE_CALL_CHAIN
# ifdef SAVE_CALL_CHAIN_IN_GC
GC_save_callers(GC_last_stack);
# endif
GC_is_full_gc = TRUE;
@ -400,7 +411,7 @@ GC_stop_func stop_func;
/*
* Perform n units of garbage collection work. A unit is intended to touch
* roughly GC_RATE pages. Every once in a while, we do more than that.
* This needa to be a fairly large number with our current incremental
* This needs to be a fairly large number with our current incremental
* GC strategy, since otherwise we allocate too much during GC, and the
* cleanup gets expensive.
*/
@ -424,7 +435,7 @@ int n;
for (i = GC_deficit; i < GC_RATE*n; i++) {
if (GC_mark_some((ptr_t)0)) {
/* Need to finish a collection */
# ifdef SAVE_CALL_CHAIN
# ifdef SAVE_CALL_CHAIN_IN_GC
GC_save_callers(GC_last_stack);
# endif
# ifdef PARALLEL_MARK
@ -940,7 +951,7 @@ word n;
# endif
expansion_slop = WORDS_TO_BYTES(min_words_allocd()) + 4*MAXHINCR*HBLKSIZE;
if (GC_last_heap_addr == 0 && !((word)space & SIGNB)
|| GC_last_heap_addr != 0 && GC_last_heap_addr < (ptr_t)space) {
|| (GC_last_heap_addr != 0 && GC_last_heap_addr < (ptr_t)space)) {
/* Assume the heap is growing up */
GC_greatest_plausible_heap_addr =
(GC_PTR)GC_max((ptr_t)GC_greatest_plausible_heap_addr,
@ -1006,7 +1017,7 @@ word needed_blocks;
GC_bool ignore_off_page;
{
if (!GC_incremental && !GC_dont_gc &&
(GC_dont_expand && GC_words_allocd > 0 || GC_should_collect())) {
((GC_dont_expand && GC_words_allocd > 0) || GC_should_collect())) {
GC_gcollect_inner();
} else {
word blocks_to_get = GC_heapsize/(HBLKSIZE*GC_free_space_divisor)
@ -1015,6 +1026,9 @@ GC_bool ignore_off_page;
if (blocks_to_get > MAXHINCR) {
word slop;
/* Get the minimum required to make it likely that we */
/* can satisfy the current request in the presence of black- */
/* listing. This will probably be more than MAXHINCR. */
if (ignore_off_page) {
slop = 4;
} else {

View File

@ -1,4 +1,3 @@
# $Id: alpha_mach_dep.S,v 1.1 2004/07/21 13:07:52 mflatt Exp $
.arch ev6
.text
@ -12,13 +11,13 @@ GC_push_regs:
.mask 0x04000000, 0
.frame $sp, 16, $26, 0
# $0 integer result
# $1-$8 temp regs - not preserved cross calls
# $9-$15 call saved regs
# $16-$21 argument regs - not preserved cross calls
# $22-$28 temp regs - not preserved cross calls
# $29 global pointer - not preserved cross calls
# $30 stack pointer
/* $0 integer result */
/* $1-$8 temp regs - not preserved cross calls */
/* $9-$15 call saved regs */
/* $16-$21 argument regs - not preserved cross calls */
/* $22-$28 temp regs - not preserved cross calls */
/* $29 global pointer - not preserved cross calls */
/* $30 stack pointer */
# define call_push(x) \
mov x, $16; \
@ -33,12 +32,12 @@ GC_push_regs:
call_push($14)
call_push($15)
# $f0-$f1 floating point results
# $f2-$f9 call saved regs
# $f10-$f30 temp regs - not preserved cross calls
/* $f0-$f1 floating point results */
/* $f2-$f9 call saved regs */
/* $f10-$f30 temp regs - not preserved cross calls */
# Use the most efficient transfer method for this hardware.
# Bit 1 detects the FIX extension, which includes ftoit.
/* Use the most efficient transfer method for this hardware. */
/* Bit 1 detects the FIX extension, which includes ftoit. */
amask 2, $0
bne $0, $use_stack

View File

@ -85,7 +85,7 @@ static back_edges * new_back_edges(void)
{
if (0 == back_edge_space) {
back_edge_space = (back_edges *)
sbrk(MAX_BACK_EDGE_STRUCTS*sizeof(back_edges));
GET_MEM(MAX_BACK_EDGE_STRUCTS*sizeof(back_edges));
}
if (0 != avail_back_edges) {
back_edges * result = avail_back_edges;
@ -113,17 +113,31 @@ static void deallocate_back_edges(back_edges *p)
/* Table of objects that are currently on the depth-first search */
/* stack. Only objects with in-degree one are in this table. */
/* Other objects are identified using HEIGHT_IN_PROGRESS. */
/* This data structure NEEDS IMPROVEMENT. */
#define MAX_IN_PROGRESS 10000
/* FIXME: This data structure NEEDS IMPROVEMENT. */
#define INITIAL_IN_PROGRESS 10000
static ptr_t * in_progress_space = 0;
static int n_in_progress = 0;
static size_t in_progress_size = 0;
static size_t n_in_progress = 0;
static void push_in_progress(ptr_t p)
{
if (n_in_progress >= in_progress_size)
if (in_progress_size == 0) {
in_progress_size = INITIAL_IN_PROGRESS;
in_progress_space = (ptr_t *)GET_MEM(in_progress_size * sizeof(ptr_t));
} else {
ptr_t * new_in_progress_space;
in_progress_size *= 2;
new_in_progress_space = (ptr_t *)
GET_MEM(in_progress_size * sizeof(ptr_t));
BCOPY(in_progress_space, new_in_progress_space,
n_in_progress * sizeof(ptr_t));
in_progress_space = new_in_progress_space;
/* FIXME: This just drops the old space. */
}
if (in_progress_space == 0)
in_progress_space = sbrk(MAX_IN_PROGRESS * sizeof(ptr_t));
if (n_in_progress == MAX_IN_PROGRESS)
ABORT("Exceeded MAX_IN_PROGRESS");
ABORT("MAKE_BACK_GRAPH: Out of in-progress space: "
"Huge linear data structure?");
in_progress_space[n_in_progress++] = p;
}
@ -318,7 +332,7 @@ static void add_back_edges(ptr_t p, word n_words, word gc_descr)
}
}
/* Rebuild the reprentation of the backward reachability graph. */
/* Rebuild the representation of the backward reachability graph. */
/* Does not examine mark bits. Can be called before GC. */
void GC_build_back_graph(void)
{
@ -424,15 +438,20 @@ static void update_max_height(ptr_t p, word n_words, word gc_descr)
}
}
word GC_max_max_height = 0;
void GC_traverse_back_graph(void)
{
static word max_max_height = 0;
GC_max_height = 0;
GC_apply_to_each_object(update_max_height);
}
void GC_print_back_graph_stats(void)
{
GC_printf2("Maximum backwards height of reachable objects at GC %lu is %ld\n",
(unsigned long) GC_gc_no, GC_max_height);
if (GC_max_height > max_max_height) {
max_max_height = GC_max_height;
if (GC_max_height > GC_max_max_height) {
GC_max_max_height = GC_max_height;
GC_printf0("The following unreachable object is last in a longest chain "
"of unreachable objects:\n");
GC_print_heap_obj(GC_deepest_obj);

File diff suppressed because it is too large Load Diff

View File

@ -17,12 +17,12 @@ dnl Process this file with autoconf to produce configure.
# Initialization
# ==============
AC_INIT(gc,6.3,Hans.Boehm@hp.com)
AC_INIT(gc,6.7,Hans.Boehm@hp.com)
## version must conform to [0-9]+[.][0-9]+(alpha[0-9]+)?
AC_CONFIG_SRCDIR(gcj_mlc.c)
AC_CANONICAL_TARGET
AC_PREREQ(2.53)
AC_REVISION($Revision: 1.3 $)
AC_REVISION($Revision: 1.2 $)
GC_SET_VERSION
AM_INIT_AUTOMAKE
@ -68,14 +68,15 @@ AC_ARG_ENABLE(cplusplus,
)
INCLUDES=-I${srcdir}/include
THREADLIBS=
THREADDLLIBS=
## Libraries needed to support dynamic loading and/or threads.
case "$THREADS" in
no | none | single)
THREADS=none
;;
posix | pthreads)
THREADS=posix
THREADLIBS=-lpthread
THREADDLLIBS=-lpthread
case "$host" in
x86-*-linux* | ia64-*-linux* | i586-*-linux* | i686-*-linux* | x86_64-*-linux* | alpha-*-linux*)
AC_DEFINE(GC_LINUX_THREADS)
@ -101,13 +102,20 @@ case "$THREADS" in
AC_DEFINE(PARALLEL_MARK)
fi
AC_DEFINE(THREAD_LOCAL_ALLOC)
THREADLIBS="-lpthread -lrt"
THREADDLLIBS="-lpthread -lrt"
;;
*-*-freebsd*)
AC_MSG_WARN("FreeBSD does not yet fully support threads with Boehm GC.")
AC_DEFINE(GC_FREEBSD_THREADS)
INCLUDES="$INCLUDES -pthread"
THREADLIBS=-pthread
THREADDLLIBS=-pthread
;;
*-*-netbsd*)
AC_MSG_WARN("Only on NetBSD 2.0 or later.")
AC_DEFINE(GC_NETBSD_THREADS)
AC_DEFINE(_REENTRANT)
AC_DEFINE(_PTHREADS)
THREADDLLIBS="-lpthread -lrt"
;;
*-*-solaris*)
AC_DEFINE(GC_SOLARIS_THREADS)
@ -135,7 +143,10 @@ case "$THREADS" in
# Measurements havent yet been done.
fi
INCLUDES="$INCLUDES -pthread"
THREADLIBS="-lpthread -lrt"
THREADDLLIBS="-lpthread -lrt"
;;
*)
AC_MSG_ERROR("Pthreads not supported by the GC on this platform.")
;;
esac
;;
@ -146,9 +157,9 @@ case "$THREADS" in
;;
dgux386)
THREADS=dgux386
AC_MSG_RESULT($THREADLIBS)
AC_MSG_RESULT($THREADDLLIBS)
# Use pthread GCC switch
THREADLIBS=-pthread
THREADDLLIBS=-pthread
if test "${enable_parallel_mark}" = yes; then
AC_DEFINE(PARALLEL_MARK)
fi
@ -160,7 +171,7 @@ case "$THREADS" in
;;
aix)
THREADS=posix
THREADLIBS=-lpthread
THREADDLLIBS=-lpthread
AC_DEFINE(GC_AIX_THREADS)
AC_DEFINE(_REENTRANT)
;;
@ -171,7 +182,7 @@ case "$THREADS" in
AC_MSG_ERROR($THREADS is an unknown thread package)
;;
esac
AC_SUBST(THREADLIBS)
AC_SUBST(THREADDLLIBS)
case "$host" in
powerpc-*-darwin*)
@ -180,12 +191,25 @@ case "$host" in
esac
AM_CONDITIONAL(POWERPC_DARWIN,test x$powerpc_darwin = xtrue)
AC_MSG_CHECKING(for xlc)
AC_TRY_COMPILE([],[
#ifndef __xlC__
# error
#endif
], [compiler_xlc=yes], [compiler_xlc=no])
AC_MSG_RESULT($compiler_xlc)
AM_CONDITIONAL(COMPILER_XLC,test $compiler_xlc = yes)
if test $compiler_xlc = yes -a "$powerpc_darwin" = true; then
# the darwin stack-frame-walking code is completely broken on xlc
AC_DEFINE(DARWIN_DONT_PARSE_STACK)
fi
# We never want libdl on darwin. It is a fake libdl that just ends up making
# dyld calls anyway
case "$host" in
*-*-darwin*) ;;
*)
AC_CHECK_LIB(dl, dlopen, EXTRA_TEST_LIBS="$EXTRA_TEST_LIBS -ldl")
AC_CHECK_LIB(dl, dlopen, THREADDLLIBS="$THREADDLLIBS -ldl")
;;
esac
@ -286,7 +310,7 @@ case "$host" in
machdep="sparc_mach_dep.lo"
AC_DEFINE(SUNOS53_SHARED_LIB)
;;
sparc-sun-solaris2.*)
sparc*-sun-solaris2.*)
machdep="sparc_mach_dep.lo"
;;
ia64-*-*)
@ -345,10 +369,10 @@ fi
dnl As of 4.13a2, the collector will not properly work on Solaris when
dnl built with gcc and -O. So we remove -O in the appropriate case.
dnl
dnl Not needed anymore on Solaris.
AC_MSG_CHECKING(whether Solaris gcc optimization fix is necessary)
case "$host" in
sparc-sun-solaris2*|*aix*)
*aix*)
if test "$GCC" = yes; then
AC_MSG_RESULT(yes)
new_CFLAGS=

View File

@ -59,7 +59,7 @@ static int extract_conv_spec(CORD_pos source, char *buf,
register int result = 0;
register int current_number = 0;
register int saw_period = 0;
register int saw_number;
register int saw_number = 0;
register int chars_so_far = 0;
register char current;
@ -243,7 +243,7 @@ int CORD_vsprintf(CORD * out, CORD format, va_list args)
char * str = va_arg(args, char *);
register char c;
while (c = *str++) {
while ((c = *str++)) {
CORD_ec_append(result, c);
}
goto done;
@ -320,7 +320,7 @@ int CORD_vsprintf(CORD * out, CORD format, va_list args)
if (buf != result[0].ec_bufptr) {
register char c;
while (c = *buf++) {
while ((c = *buf++)) {
CORD_ec_append(result, c);
}
} else {

View File

@ -221,7 +221,7 @@ void test_printf()
if (CORD_cmp(result, result2) != 0)ABORT("CORD_sprintf goofed 5");
}
main()
int main()
{
# ifdef THINK_C
printf("cordtest:\n");

View File

@ -1,5 +1,7 @@
#include "private/pthread_support.h"
/* This probably needs more porting work to ppc64. */
# if defined(GC_DARWIN_THREADS)
/* From "Inside Mac OS X - Mach-O Runtime Architecture" published by Apple
@ -12,23 +14,33 @@
Page 50: "If a leaf procedure's red zone usage would exceed 224 bytes, then
it must set up a stack frame just like routines that call other routines."
*/
#define PPC_RED_ZONE_SIZE 224
#ifdef POWERPC
# if CPP_WORDSZ == 32
# define PPC_RED_ZONE_SIZE 224
# elif CPP_WORDSZ == 64
# define PPC_RED_ZONE_SIZE 320
# endif
#endif
/* Not 64-bit clean. Wait until Apple defines their 64-bit ABI */
typedef struct StackFrame {
unsigned int savedSP;
unsigned int savedCR;
unsigned int savedLR;
unsigned int reserved[2];
unsigned int savedRTOC;
unsigned long savedSP;
unsigned long savedCR;
unsigned long savedLR;
unsigned long reserved[2];
unsigned long savedRTOC;
} StackFrame;
unsigned int FindTopOfStack(unsigned int stack_start) {
unsigned long FindTopOfStack(unsigned int stack_start) {
StackFrame *frame;
if (stack_start == 0) {
# ifdef POWERPC
# if CPP_WORDSZ == 32
__asm__ volatile("lwz %0,0(r1)" : "=r" (frame));
# else
__asm__ volatile("ld %0,0(r1)" : "=r" (frame));
# endif
# endif
} else {
frame = (StackFrame *)stack_start;
}
@ -37,7 +49,7 @@ unsigned int FindTopOfStack(unsigned int stack_start) {
/* GC_printf1("FindTopOfStack start at sp = %p\n", frame); */
# endif
do {
if (frame->savedSP == NULL) break;
if (frame->savedSP == 0) break;
/* if there are no more stack frames, stop */
frame = (StackFrame*)frame->savedSP;
@ -53,9 +65,108 @@ unsigned int FindTopOfStack(unsigned int stack_start) {
/* GC_printf1("FindTopOfStack finish at sp = %p\n", frame); */
# endif
return (unsigned int)frame;
return (unsigned long)frame;
}
#ifdef DARWIN_DONT_PARSE_STACK
void GC_push_all_stacks() {
int i;
kern_return_t r;
GC_thread p;
pthread_t me;
ptr_t lo, hi;
#if defined(POWERPC)
ppc_thread_state_t state;
#elif defined(I386)
i386_thread_state_t state;
#else
# error FIXME for non-x86 || ppc architectures
#endif
mach_msg_type_number_t thread_state_count = MACHINE_THREAD_STATE_COUNT;
me = pthread_self();
if (!GC_thr_initialized) GC_thr_init();
for(i=0;i<THREAD_TABLE_SZ;i++) {
for(p=GC_threads[i];p!=0;p=p->next) {
if(p -> flags & FINISHED) continue;
if(pthread_equal(p->id,me)) {
lo = GC_approx_sp();
} else {
/* Get the thread state (registers, etc) */
r = thread_get_state(
p->stop_info.mach_thread,
MACHINE_THREAD_STATE,
(natural_t*)&state,
&thread_state_count);
if(r != KERN_SUCCESS) ABORT("thread_get_state failed");
#if defined(I386)
lo = state.esp;
GC_push_one(state.eax);
GC_push_one(state.ebx);
GC_push_one(state.ecx);
GC_push_one(state.edx);
GC_push_one(state.edi);
GC_push_one(state.esi);
GC_push_one(state.ebp);
#elif defined(POWERPC)
lo = (void*)(state.r1 - PPC_RED_ZONE_SIZE);
GC_push_one(state.r0);
GC_push_one(state.r2);
GC_push_one(state.r3);
GC_push_one(state.r4);
GC_push_one(state.r5);
GC_push_one(state.r6);
GC_push_one(state.r7);
GC_push_one(state.r8);
GC_push_one(state.r9);
GC_push_one(state.r10);
GC_push_one(state.r11);
GC_push_one(state.r12);
GC_push_one(state.r13);
GC_push_one(state.r14);
GC_push_one(state.r15);
GC_push_one(state.r16);
GC_push_one(state.r17);
GC_push_one(state.r18);
GC_push_one(state.r19);
GC_push_one(state.r20);
GC_push_one(state.r21);
GC_push_one(state.r22);
GC_push_one(state.r23);
GC_push_one(state.r24);
GC_push_one(state.r25);
GC_push_one(state.r26);
GC_push_one(state.r27);
GC_push_one(state.r28);
GC_push_one(state.r29);
GC_push_one(state.r30);
GC_push_one(state.r31);
#else
# error FIXME for non-x86 || ppc architectures
#endif
} /* p != me */
if(p->flags & MAIN_THREAD)
hi = GC_stackbottom;
else
hi = p->stack_end;
#if DEBUG_THREADS
GC_printf3("Darwin: Stack for thread 0x%lx = [%lx,%lx)\n",
(unsigned long) p -> id,
(unsigned long) lo,
(unsigned long) hi
);
#endif
GC_push_all_stack(lo,hi);
} /* for(p=GC_threads[i]...) */
} /* for(i=0;i<THREAD_TABLE_SZ...) */
}
#else /* !DARWIN_DONT_PARSE_STACK; Use FindTopOfStack() */
void GC_push_all_stacks() {
int i;
kern_return_t r;
@ -75,8 +186,12 @@ void GC_push_all_stacks() {
lo = GC_approx_sp();
hi = (ptr_t)FindTopOfStack(0);
} else {
# ifdef POWERPC
# if defined(POWERPC)
# if CPP_WORDSZ == 32
ppc_thread_state_t info;
# else
ppc_thread_state64_t info;
# endif
mach_msg_type_number_t outCount = THREAD_STATE_MAX;
r = thread_get_state(thread, MACHINE_THREAD_STATE,
(natural_t *)&info, &outCount);
@ -154,7 +269,9 @@ void GC_push_all_stacks() {
# endif
GC_push_all_stack(lo, hi);
} /* for(p=GC_threads[i]...) */
vm_deallocate(current_task(), (vm_address_t)act_list, sizeof(thread_t) * listcount);
}
#endif /* !DARWIN_DONT_PARSE_STACK */
static mach_port_t GC_mach_handler_thread;
static int GC_use_mach_handler_thread = 0;
@ -296,6 +413,7 @@ void GC_stop_world()
changes = result;
prev_list = act_list;
prevcount = listcount;
vm_deallocate(current_task(), (vm_address_t)act_list, sizeof(thread_t) * listcount);
} while (changes);
@ -324,6 +442,8 @@ void GC_start_world()
kern_return_t kern_result;
thread_act_array_t act_list;
mach_msg_type_number_t listcount;
struct thread_basic_info info;
mach_msg_type_number_t outCount = THREAD_INFO_MAX;
# if DEBUG_THREADS
GC_printf0("World starting\n");
@ -350,8 +470,6 @@ void GC_start_world()
# endif
continue;
}
struct thread_basic_info info;
mach_msg_type_number_t outCount = THREAD_INFO_MAX;
kern_result = thread_info(thread, THREAD_BASIC_INFO,
(thread_info_t)&info, &outCount);
if(kern_result != KERN_SUCCESS) ABORT("thread_info failed");
@ -367,6 +485,7 @@ void GC_start_world()
}
}
}
vm_deallocate(current_task(), (vm_address_t)act_list, sizeof(thread_t) * listcount);
# if DEBUG_THREADS
GC_printf0("World started\n");
# endif

View File

@ -14,6 +14,8 @@
* modified is included with the above copyright notice.
*/
#include <errno.h>
#include <string.h>
#include "private/dbg_mlc.h"
void GC_default_print_heap_obj_proc();
@ -713,6 +715,26 @@ GC_PTR p;
return (GC_store_debug_info(result, (word)lb, s, (word)i));
}
# ifdef __STDC__
char *GC_debug_strdup(const char *str, GC_EXTRA_PARAMS)
#else
char *GC_debug_strdup(str, s, i)
char *str;
char *s;
int i;
#endif
{
char *copy;
if (str == NULL) return NULL;
copy = GC_debug_malloc_atomic(strlen(str) + 1, OPT_RA s, i);
if (copy == NULL) {
errno = ENOMEM;
return NULL;
}
strcpy(copy, str);
return copy;
}
# ifdef __STDC__
GC_PTR GC_debug_malloc_uncollectable(size_t lb, GC_EXTRA_PARAMS)
# else

View File

@ -1,8 +1,8 @@
# Makefile.in generated by automake 1.6.3 from Makefile.am.
# Makefile.in generated by automake 1.9.3 from Makefile.am.
# @configure_input@
# Copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002
# Free Software Foundation, Inc.
# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
# 2003, 2004 Free Software Foundation, Inc.
# This Makefile.in is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
# with or without modifications, as long as this notice is preserved.
@ -26,96 +26,174 @@
# modified is included with the above copyright notice.
#
# Modified by: Grzegorz Jakacki <jakacki at acm dot org>
SHELL = @SHELL@
srcdir = @srcdir@
top_srcdir = @top_srcdir@
VPATH = @srcdir@
prefix = @prefix@
exec_prefix = @exec_prefix@
bindir = @bindir@
sbindir = @sbindir@
libexecdir = @libexecdir@
datadir = @datadir@
sysconfdir = @sysconfdir@
sharedstatedir = @sharedstatedir@
localstatedir = @localstatedir@
libdir = @libdir@
infodir = @infodir@
mandir = @mandir@
includedir = @includedir@
oldincludedir = /usr/include
pkgdatadir = $(datadir)/@PACKAGE@
pkglibdir = $(libdir)/@PACKAGE@
pkgincludedir = $(includedir)/@PACKAGE@
top_builddir = ..
ACLOCAL = @ACLOCAL@
AUTOCONF = @AUTOCONF@
AUTOMAKE = @AUTOMAKE@
AUTOHEADER = @AUTOHEADER@
am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
INSTALL = @INSTALL@
INSTALL_PROGRAM = @INSTALL_PROGRAM@
INSTALL_DATA = @INSTALL_DATA@
install_sh_DATA = $(install_sh) -c -m 644
install_sh_PROGRAM = $(install_sh) -c
install_sh_SCRIPT = $(install_sh) -c
INSTALL_SCRIPT = @INSTALL_SCRIPT@
INSTALL_HEADER = $(INSTALL_DATA)
transform = @program_transform_name@
transform = $(program_transform_name)
NORMAL_INSTALL = :
PRE_INSTALL = :
POST_INSTALL = :
NORMAL_UNINSTALL = :
PRE_UNINSTALL = :
POST_UNINSTALL = :
host_alias = @host_alias@
build_triplet = @build@
host_triplet = @host@
EXEEXT = @EXEEXT@
OBJEXT = @OBJEXT@
PATH_SEPARATOR = @PATH_SEPARATOR@
target_triplet = @target@
subdir = doc
DIST_COMMON = README $(dist_pkgdata_DATA) $(srcdir)/Makefile.am \
$(srcdir)/Makefile.in
ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
am__aclocal_m4_deps = $(top_srcdir)/acinclude.m4 \
$(top_srcdir)/libtool.m4 $(top_srcdir)/configure.in
am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
$(ACLOCAL_M4)
mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs
CONFIG_CLEAN_FILES =
SOURCES =
DIST_SOURCES =
am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
am__vpath_adj = case $$p in \
$(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
*) f=$$p;; \
esac;
am__strip_dir = `echo $$p | sed -e 's|^.*/||'`;
am__installdirs = "$(DESTDIR)$(pkgdatadir)"
dist_pkgdataDATA_INSTALL = $(INSTALL_DATA)
DATA = $(dist_pkgdata_DATA)
DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
ACLOCAL = @ACLOCAL@
AMDEP_FALSE = @AMDEP_FALSE@
AMDEP_TRUE = @AMDEP_TRUE@
AMTAR = @AMTAR@
AR = @AR@
AS = @AS@
AUTOCONF = @AUTOCONF@
AUTOHEADER = @AUTOHEADER@
AUTOMAKE = @AUTOMAKE@
AWK = @AWK@
CC = @CC@
CCAS = @CCAS@
CCASFLAGS = @CCASFLAGS@
CCDEPMODE = @CCDEPMODE@
CFLAGS = @CFLAGS@
COMPILER_XLC_FALSE = @COMPILER_XLC_FALSE@
COMPILER_XLC_TRUE = @COMPILER_XLC_TRUE@
CPLUSPLUS_FALSE = @CPLUSPLUS_FALSE@
CPLUSPLUS_TRUE = @CPLUSPLUS_TRUE@
CPP = @CPP@
CPPFLAGS = @CPPFLAGS@
CXX = @CXX@
CXXDEPMODE = @CXXDEPMODE@
CXXFLAGS = @CXXFLAGS@
CXXINCLUDES = @CXXINCLUDES@
CYGPATH_W = @CYGPATH_W@
DEFS = @DEFS@
DEPDIR = @DEPDIR@
DLLTOOL = @DLLTOOL@
ECHO = @ECHO@
ECHO_C = @ECHO_C@
ECHO_N = @ECHO_N@
ECHO_T = @ECHO_T@
EGREP = @EGREP@
EXEEXT = @EXEEXT@
EXTRA_TEST_LIBS = @EXTRA_TEST_LIBS@
GC_CFLAGS = @GC_CFLAGS@
GC_VERSION = @GC_VERSION@
INCLUDES = @INCLUDES@
INSTALL_DATA = @INSTALL_DATA@
INSTALL_PROGRAM = @INSTALL_PROGRAM@
INSTALL_SCRIPT = @INSTALL_SCRIPT@
INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
LDFLAGS = @LDFLAGS@
LIBOBJS = @LIBOBJS@
LIBS = @LIBS@
LIBTOOL = @LIBTOOL@
LN_S = @LN_S@
LTLIBOBJS = @LTLIBOBJS@
MAINT = @MAINT@
MAINTAINER_MODE_FALSE = @MAINTAINER_MODE_FALSE@
MAINTAINER_MODE_TRUE = @MAINTAINER_MODE_TRUE@
MAKEINFO = @MAKEINFO@
MY_CFLAGS = @MY_CFLAGS@
OBJDUMP = @OBJDUMP@
OBJEXT = @OBJEXT@
PACKAGE = @PACKAGE@
PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
PACKAGE_NAME = @PACKAGE_NAME@
PACKAGE_STRING = @PACKAGE_STRING@
PACKAGE_TARNAME = @PACKAGE_TARNAME@
PACKAGE_VERSION = @PACKAGE_VERSION@
PATH_SEPARATOR = @PATH_SEPARATOR@
POWERPC_DARWIN_FALSE = @POWERPC_DARWIN_FALSE@
POWERPC_DARWIN_TRUE = @POWERPC_DARWIN_TRUE@
RANLIB = @RANLIB@
SET_MAKE = @SET_MAKE@
SHELL = @SHELL@
STRIP = @STRIP@
THREADLIBS = @THREADLIBS@
THREADDLLIBS = @THREADDLLIBS@
UNWINDLIBS = @UNWINDLIBS@
USE_LIBDIR_FALSE = @USE_LIBDIR_FALSE@
USE_LIBDIR_TRUE = @USE_LIBDIR_TRUE@
VERSION = @VERSION@
ac_ct_AR = @ac_ct_AR@
ac_ct_CC = @ac_ct_CC@
ac_ct_CXX = @ac_ct_CXX@
ac_ct_RANLIB = @ac_ct_RANLIB@
ac_ct_STRIP = @ac_ct_STRIP@
addincludes = @addincludes@
addlibs = @addlibs@
addobjs = @addobjs@
addtests = @addtests@
am__fastdepCC_FALSE = @am__fastdepCC_FALSE@
am__fastdepCC_TRUE = @am__fastdepCC_TRUE@
am__fastdepCXX_FALSE = @am__fastdepCXX_FALSE@
am__fastdepCXX_TRUE = @am__fastdepCXX_TRUE@
am__include = @am__include@
am__leading_dot = @am__leading_dot@
am__quote = @am__quote@
am__tar = @am__tar@
am__untar = @am__untar@
bindir = @bindir@
build = @build@
build_alias = @build_alias@
build_cpu = @build_cpu@
build_os = @build_os@
build_vendor = @build_vendor@
datadir = @datadir@
exec_prefix = @exec_prefix@
host = @host@
host_alias = @host_alias@
host_cpu = @host_cpu@
host_os = @host_os@
host_vendor = @host_vendor@
includedir = @includedir@
infodir = @infodir@
install_sh = @install_sh@
libdir = @libdir@
libexecdir = @libexecdir@
localstatedir = @localstatedir@
mandir = @mandir@
mkdir_p = @mkdir_p@
oldincludedir = @oldincludedir@
prefix = @prefix@
program_transform_name = @program_transform_name@
sbindir = @sbindir@
sharedstatedir = @sharedstatedir@
sysconfdir = @sysconfdir@
target = @target@
target_alias = @target_alias@
target_all = @target_all@
target_cpu = @target_cpu@
target_os = @target_os@
target_vendor = @target_vendor@
# installed documentation
#
@ -129,21 +207,38 @@ dist_pkgdata_DATA = barrett_diagram debugging.html gc.man \
tree.html leak.html gcinterface.html scale.html \
README.darwin simple_example.html
subdir = doc
mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs
CONFIG_CLEAN_FILES =
DIST_SOURCES =
DATA = $(dist_pkgdata_DATA)
DIST_COMMON = README $(dist_pkgdata_DATA) Makefile.am Makefile.in
all: all-am
.SUFFIXES:
$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4)
$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
@for dep in $?; do \
case '$(am__configure_deps)' in \
*$$dep*) \
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \
&& exit 0; \
exit 1;; \
esac; \
done; \
echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu doc/Makefile'; \
cd $(top_srcdir) && \
$(AUTOMAKE) --gnu doc/Makefile
Makefile: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.in $(top_builddir)/config.status
cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)
.PRECIOUS: Makefile
Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
@case '$?' in \
*config.status*) \
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
*) \
echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
esac;
$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
mostlyclean-libtool:
-rm -f *.lo
@ -154,39 +249,43 @@ clean-libtool:
distclean-libtool:
-rm -f libtool
uninstall-info-am:
dist_pkgdataDATA_INSTALL = $(INSTALL_DATA)
install-dist_pkgdataDATA: $(dist_pkgdata_DATA)
@$(NORMAL_INSTALL)
$(mkinstalldirs) $(DESTDIR)$(pkgdatadir)
test -z "$(pkgdatadir)" || $(mkdir_p) "$(DESTDIR)$(pkgdatadir)"
@list='$(dist_pkgdata_DATA)'; for p in $$list; do \
if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
f="`echo $$p | sed -e 's|^.*/||'`"; \
echo " $(dist_pkgdataDATA_INSTALL) $$d$$p $(DESTDIR)$(pkgdatadir)/$$f"; \
$(dist_pkgdataDATA_INSTALL) $$d$$p $(DESTDIR)$(pkgdatadir)/$$f; \
f=$(am__strip_dir) \
echo " $(dist_pkgdataDATA_INSTALL) '$$d$$p' '$(DESTDIR)$(pkgdatadir)/$$f'"; \
$(dist_pkgdataDATA_INSTALL) "$$d$$p" "$(DESTDIR)$(pkgdatadir)/$$f"; \
done
uninstall-dist_pkgdataDATA:
@$(NORMAL_UNINSTALL)
@list='$(dist_pkgdata_DATA)'; for p in $$list; do \
f="`echo $$p | sed -e 's|^.*/||'`"; \
echo " rm -f $(DESTDIR)$(pkgdatadir)/$$f"; \
rm -f $(DESTDIR)$(pkgdatadir)/$$f; \
f=$(am__strip_dir) \
echo " rm -f '$(DESTDIR)$(pkgdatadir)/$$f'"; \
rm -f "$(DESTDIR)$(pkgdatadir)/$$f"; \
done
tags: TAGS
TAGS:
DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
ctags: CTAGS
CTAGS:
top_distdir = ..
distdir = $(top_distdir)/$(PACKAGE)-$(VERSION)
distdir: $(DISTFILES)
@list='$(DISTFILES)'; for file in $$list; do \
@srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \
topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \
list='$(DISTFILES)'; for file in $$list; do \
case $$file in \
$(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \
$(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \
esac; \
if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \
if test "$$dir" != "$$file" && test "$$dir" != "."; then \
dir="/$$dir"; \
$(mkinstalldirs) "$(distdir)$$dir"; \
$(mkdir_p) "$(distdir)$$dir"; \
else \
dir=''; \
fi; \
@ -204,10 +303,10 @@ distdir: $(DISTFILES)
check-am: all-am
check: check-am
all-am: Makefile $(DATA)
installdirs:
$(mkinstalldirs) $(DESTDIR)$(pkgdatadir)
for dir in "$(DESTDIR)$(pkgdatadir)"; do \
test -z "$$dir" || $(mkdir_p) "$$dir"; \
done
install: install-am
install-exec: install-exec-am
install-data: install-data-am
@ -219,7 +318,7 @@ install-am: all-am
installcheck: installcheck-am
install-strip:
$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
INSTALL_STRIP_FLAG=-s \
install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
`test -z '$(STRIP)' || \
echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
mostlyclean-generic:
@ -227,7 +326,7 @@ mostlyclean-generic:
clean-generic:
distclean-generic:
-rm -f Makefile $(CONFIG_CLEAN_FILES)
-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
maintainer-clean-generic:
@echo "This command is intended for maintainers to use"
@ -237,13 +336,15 @@ clean: clean-am
clean-am: clean-generic clean-libtool mostlyclean-am
distclean: distclean-am
-rm -f Makefile
distclean-am: clean-am distclean-generic distclean-libtool
dvi: dvi-am
dvi-am:
html: html-am
info: info-am
info-am:
@ -259,24 +360,33 @@ install-man:
installcheck-am:
maintainer-clean: maintainer-clean-am
-rm -f Makefile
maintainer-clean-am: distclean-am maintainer-clean-generic
mostlyclean: mostlyclean-am
mostlyclean-am: mostlyclean-generic mostlyclean-libtool
pdf: pdf-am
pdf-am:
ps: ps-am
ps-am:
uninstall-am: uninstall-dist_pkgdataDATA uninstall-info-am
.PHONY: all all-am check check-am clean clean-generic clean-libtool \
distclean distclean-generic distclean-libtool distdir dvi \
dvi-am info info-am install install-am install-data \
install-data-am install-dist_pkgdataDATA install-exec \
install-exec-am install-info install-info-am install-man \
install-strip installcheck installcheck-am installdirs \
maintainer-clean maintainer-clean-generic mostlyclean \
mostlyclean-generic mostlyclean-libtool uninstall uninstall-am \
uninstall-dist_pkgdataDATA uninstall-info-am
dvi-am html html-am info info-am install install-am \
install-data install-data-am install-dist_pkgdataDATA \
install-exec install-exec-am install-info install-info-am \
install-man install-strip installcheck installcheck-am \
installdirs maintainer-clean maintainer-clean-generic \
mostlyclean mostlyclean-generic mostlyclean-libtool pdf pdf-am \
ps ps-am uninstall uninstall-am uninstall-dist_pkgdataDATA \
uninstall-info-am
# Tell versions [3.59,3.63) of GNU make to not export all variables.
# Otherwise a system limit (for SysV at least) may be exceeded.

View File

@ -28,7 +28,7 @@ are GPL'ed, but with an exception that should cover all uses in the
collector. (If you are concerned about such things, I recommend you look
at the notice in config.guess or ltmain.sh.)
This is version 6.3 of a conservative garbage collector for C and C++.
This is version 6.7 of a conservative garbage collector for C and C++.
You might find a more recent version of this at

View File

@ -2101,6 +2101,189 @@ Since gc6.3alpha6:
- Fix GC_task_self declaration in os_dep.c. (Thanks to Andrew Pinski.)
- Increase INITIAL_BUF_SZ in os_dep.c for Solaris /proc reads.
Since 6.3:
- Merge gcconfig.h changes from gcc tree.
- Unconditionally include gc_priv.h in solaris_pthreads.c, win32_threads.h,
aix_irix_threads.c, and solaris_threads.c to get thread definitions.
- Start marker threads in GC_thr_init, so that they get started even
if no other threads are ever started. (Oddly enough, the parallel
collector worked correctly, though not well, with no helper threads.)
- Go ahead and split large blocks in GC_allochblk_nth if GC_dont_gc
is set. (Thanks to Alexander Petrossian.)
- GC_PRINT_BACK_HEIGHT would deadlock with thread support.
- Let in_progress_space in backgraph.s grow dynamically.
- Fix README.solaris2. The GC_thr_init() hack doesn't work anymore.
- Convert GC_finalizer_mem_freed to bytes in allchblk.c.
- Add missing declaration for GC_generic_malloc_words_small_inner.
Without it, s390x breaks. (Thanks to Ulrich Weigand.)
- Applied several MacOSX patches to support older tool chains.
(Thanks to Stefan Ring.)
- Bug fix for NetBSD/amd64. (Thanks to Marc Recht.) Add NetBSD/sh3
support. (Thanks to Uchiyama Yasushi.)
- Fixed an uninitialized variable in cordprnt.c. (Thanks to gcc for
providing the warning.)
- Eliminated some, but not all, gcc -Wall warnings.
- Changed some old style casts to reinterpret_cast in new_gc_alloc.h.
(Thanks to Dan Grayson.)
- GC_extend_size_map shouldn't adjust for GC_all_interior_pointers if
GC_DONT_ADD_BYTE_AT_END is set.
- Changed some (long) casts to (word) in preparation for win64.
(Thanks to Peter Colson.)
- Changed "int stack_size" declaration in pthread_support.c to use
size_t. (Only mattered with GC_ASSERTIONS enabled.)
- Added CRIS (etrax) support. (Thanks to Simon Posnjak and
Hans-Peter Nilsson.)
- Removed GC_IGNORE_FB frame buffer recognition, and replaced
it with a check that the mapping type is MEM_IMAGE.
In theory, this should work much better, but it is a high
risk change for win32. (Thanks to Ashley Bone for the crucial
experimental data behind this, and to Rutger Ovidus for
some further experiments.)
- Fixed print_block_list to print the correct kind number for
STUBBORN. (Thanks to Rutger Ovidus.)
- GC_allochblk_nth incremented GC_words_wasted by bytes rather than
words.
- Consider GC_words_wasted in GC_adj_words_allocd only if it is within
reason. (A hack to avoid some extremely unlikely scenarios in which
we manage to allocate only "wasted" space. 7.0 has a better fix.)
- Changed PowerPC GC_clear implementation to use lwsync instead of
eieio, since the documentation recommends against eieio, and
it seems to be incorrect if the preceding memory op is a load.
- Fixed print_block_list to print the correct kind number for
STUBBORN. (Thanks to Rutger Ovidus.)
- Have configure.in generate an error if it is asked to support
pthreads, but doesn't know how to.
- Added Kazuhiro Inaoka's patch for Renesas M32R support.
- Have the GNU build mechanism link with -ldl. Rename THREADLIBS
to THREADDLLIBS to reflect this. (Thanks to Sven Verdoolaege.)
- Added Hannes Mehnert's patch for FreeBSD/SPARC support.
- Merged some FreeBSD specific patches to threadlibs.c and dyn_load.c.
(Thanks tp John Merryweather Cooper.)
- Define MPROTECT_VDB on MACOSX only if threads are being used, since the
dirty page tracking mechanism uses threads. (This avoids an undefined
reference to _GC_darwin_register_mach_handler_thread.)
- By popular demand, use __libc symbols only if we are built with
USE_LIBC_PRIVATES, which is off by default, and not otherwise documented.
- Ignore GC_enable_incremental() requests when KEEP_BACK_PTRS is set.
The GC itself will dirty lots of pages in this cases, probably making
it counterproductive on all platforms. And the DARWIN port crashes.
Since GC6.4:
- Integrated Paolo Molaro's patch to deal with EINTR in sem_wait.
- Make GC_approx_sp() write to dummy location to ensure that stack
is grown here, when sp looks reasonable, rather than later, when
it might look like a bad memory reference. (Problem was never
observed that I know of. But on rereading the code it seemed
dubious.)
- Separate out GC_with_callee_saves_pushed and sometimes call
it from GC_suspend_handler in pthread_stop_world.c. Callee-save
register values sometimes failed to get traced under HP/UX on
PA-RISC. Linux/IA64 had the same problem, though non-stacked
callee-save registers seem to be so rarely used there that nobody
ever noticed.
- Integrated an ancient Darwin powerpc_darwin_machine_dep.s patch
from Andreas Tobler, which I had lost.
- Fix compare_and_exchange implementation for gcc/IA64 to deal with
pickier compiler versions.
- Fixed Itanium 32-bit ABI support (HP/UX). In particular, the
compare_and_exchange implementation didn't consider that possibility.
- Undefine GC_pthread_detach in win32_threads.c. (Thanks to
Tagliapietra Tommaso.)
- Fixed inclusion of frame.h for NETBSD in os_dep.c.
- Applied Dan Bonachea's patch to use mmap on AIX.
- Several fixes to resurrect the Irix port on recent OS versions.
- Change ALPHA to use LINUX_STACKBOTTOM.
- Change SPARC64/LINUX to also use LINUX_STACKBOTTOM. Deal with potential
bad values of __libc_stack_end on that platform. (Thanks to David Miller.)
- Relax gctest to allow larger heap if ALIGN_DOUBLE isn't set.
(Unnecessary in 7.0)
- Force a define of __STDC__=0 for the IBM compiler on AIX, so that
we get prototypes. (Unnecessary in 7.0)
- GC_INIT definition for AIX and CYGWIN referred to DATASTART and DATAEND
which are only defined in private include files.
- Integrated some small gcconfig.h patches from Dan Bonachea. Also
relaxed assertion about FreeBSD stack size in pthread_support.c.
- Integrated Andrew Begel's darwin_stop_world.c patch for 64-bit
support. This may need additional work.
- Avoided potentially infinite recursion in GC_save_callers if
the system backtrace calls malloc. The workaround currently requires
__thread support if this code is used with threads.
- Avoided another similar infinite recursion by conditionally
invoking GC_save_callers in alloc.c. (Thanks to Matthias Andree
for helping to track down both of these.)
- Removed all traces of aix_irix_threads.c. AIX and Irix now use
pthread_support.c and pthread_stop_world.c. The old code appeared
to be unreliable for AIX, and was not regularly maintained.
- On Irix, ignore segments with MA_FETCHOP or MA_NOTCACHED attributed;
they're not always safe to read.
- Fixed a previously vacuous assertion (diagnosed by the SGI compiler)
in GC_remove_from_fl.
- Fix stack_size assertion in GC_pthread_create.
- Fix assertion in GC_steal_mark_stack.
Since 6.5
- Fix CPU count detection for Irix and FreeBSD. (Thanks to Dan Bonachea.)
- Integrate Dan Bonachea's patch for the IBM XLC compiler on Darwin.
- Integrated Andreas Tobler's FreeBSD/PowerPC patch.
- Don't access the GC thread structure from the restart handler. It's
unsafe, since the handler may run too late. (Thanks to Ben Maurer for
tracking this down.)
- Applied Christian Thalinger's patch to change comment syntax in
alpha_mach_dep.S.
- Added test for GC_no_dls in GC_dyld_image_add for DARWIN. (Thanks to
Juan Jose Garcia Ripoli).
- Use LINUX_STACKBOTTOM for Linux/SH and LINUX/ARM. (Thanks to Sugioka
Toshinobu and Christian Thalinger.)
- Rewrote GC_parse_map_entry. This assumed a fixed column layout of
/proc/self/maps on Linux. This ceased to be true about 2 years ago.
The old code is probably quite problemetic with -DREDIRECT_MALLOC. It
is also used by default for IA64, though I haven't seen actual failures
there.
- More consistently define HBLKSIZE to 4096 on 64 bit architectures with
4K pages. (Thanks to Andrew Haley.)
- With win32 threads, GC_stop_world needs to acquire GC_write_cs. (Thanks
to Ben Hutchings for the observation and patch.)
- Move up struct callinfo declaration to make gcc 4.0.2. happy.
Since 6.6:
- Add "int" to Solaris "end" and "etext" declaration in gc.h. Declared
the symbols with underscores and as arrays, since that's what's actually
used. Perhaps this could all just be removed? (Thanks to John Bowman.)
- Fixed ARM GC_test_and_set code. (Thanks to Kazu Hirata and Paul Brook.)
- Added casts for assignments to hb_last_reclaimed, which truncate the
value. Added a cast to GC_adj_words_allocd. Use GetModuleHandleA
when retrieving a handle to kernel32.dll under win32. (Thanks to the
Visual Prolog developers.)
- Added Tandem S-Series support. (Thanks to Craig McDaniel. A modified
version of his patch was applied, and hence breakage is probably not
his fault.)
- Remove spurious gc:: qualifier for operator delete[] in gc_cpp.h.
(Thanks to Hanno Boeck.)
- Changed a test for LINUX in config_macros.h to one for __linux__.
- Fix ppc 64 test_and_set code by removing it. (Thanks to Christian
Thalinger.)
- Add prototypes for GC_finalizer_notifier and GC_thr_init. (Thanks to
David Ayers.)
- Use ld instead of nonexistent ldz instruction in Darwin FindTopOfStack.
(Thanks to Andreas Tobler.)
- Add support for Darwin/X86. (Thanks to Geoff Norton and the Mono
developers.)
- Merge in some recent gcc fixes. Add ppc64 asm code. (Thanks to Bryce
McKinley and other gcj developers.)
- Scan MEM_PRIVATE sections under Windows ME and predecessors.
- Interior pointers with some largish offsets into large objects could
be ignored, if GC_all_interior_pointers was set. (Oddly this worked
correctly for stack references if it was not set. Otherwise it failed
for both stack and heap references.) Thanks to Andrew McKinlay for the
critical test case.
- Integrated Tatsuya Bizenn's NETBSD threads support, with some
minimally tested changes.
- Added GC_strdup and friends to make leak detection work correctly
for strdup clients. (Thanks to Jon Moore.) Fixed the existing strdup
with malloc redirection to handle a null malloc return correctly.
- Fix Makefile.am, so it handles exe extensions under Cygwin correctly
for gctest.
To do:
- The USE_MUNMAP code should really use a separate data structure
indexed by physical page to keep track of time since last use of

View File

@ -1,3 +1,16 @@
6.5 update:
I disabled incremental GC on Darwin in this version, since I couldn't
get gctest to pass when the GC was built as a dynamic library. Building
with -DMPROTECT_VDB (and threads) on the command line should get you
back to the old state. - HB
./configure --enable-cplusplus results in a "make check" failure, probably
because the ::delete override ends up in a separate dl, and Darwin dynamic
loader semantics appear to be such that this is not really visible to the
main program, unlike on ELF systems. Someone who understands dynamic
loading needs to lookat this. For now, gc_cpp.o needs to be linked
statically, if needed. - HB
Darwin/MacOSX Support - December 16, 2003
=========================================

View File

@ -115,6 +115,7 @@ GC_IGNORE_FB[=<n>] - (Win32 only.) Try to avoid treating a mapped
are never honored, eliminating this risk for most,
but not all, applications. This feature is likely to disappear
if/when we find a less disgusting "solution".
IN VERSION 6.4 AND LATER, THIS SHOULD BE UNNECESSARY.
The following turn on runtime flags that are also program settable. Checked
only during initialization. We expect that they will usually be set through

View File

@ -19,10 +19,10 @@ Linux threads. These should not be touched by the client program.
To use threads, you need to abide by the following requirements:
1) You need to use LinuxThreads (which are included in libc6).
1) You need to use LinuxThreads or NPTL (which are included in libc6).
The collector relies on some implementation details of the LinuxThreads
package. It is unlikely that this code will work on other
package. This code may not work on other
pthread implementations (in particular it will *not* work with
MIT pthreads).

View File

@ -43,9 +43,7 @@ can result in unpleasant heap growth. But it seems better than the
race/deadlock issues we had before.
If solaris_threads are used on an X86 processor with malloc redirected to
GC_malloc, it is necessary to call GC_thr_init explicitly before forking the
first thread. (This avoids a deadlock arising from calling GC_thr_init
with the allocation lock held.)
GC_malloc a deadlock is likely to result.
It appears that there is a problem in using gc_cpp.h in conjunction with
Solaris threads and Sun's C++ runtime. Apparently the overloaded new operator

View File

@ -34,6 +34,12 @@ after defining the appropriate <TT>GC_</tt><I>XXXX</i><TT>_THREADS</tt> macro.
The header file <TT>gc.h</tt> must be included
in files that use either GC or threads primitives, since threads primitives
will be redefined to cooperate with the GC on many platforms.
<P>
Thread users should also be aware that on many platforms objects reachable
only from thread-local variables may be prematurely reclaimed.
Thus objects pointed to by thread-local variables should also be pointed to
by a globally visible data structure. (This is viewed as a bug, but as
one that is exceedingly hard to fix without some libc hooks.)
<DL>
<DT> <B>void * GC_MALLOC(size_t <I>nbytes</i>)</b>
<DD>
@ -180,6 +186,11 @@ but are scanned for pointers to collectable objects.
They are allocated by <TT>GC_MALLOC_UNCOLLECTABLE</tt>, as described
above, and through some interfaces described below.
<P>
(On most platforms, the collector may not trace correctly from in-flight
exception objects. Thus objects thrown as exceptions should only
point to otherwise reachable memory. This is another bug whose
proper repair requires platform hooks.)
<P>
The easiest way to ensure that collectable objects are properly referenced
is to allocate only collectable objects. This requires that every
allocation go through one of the following interfaces, each one of

View File

@ -80,6 +80,11 @@
# define l_name lm_name
#endif
#if defined(NETBSD)
# include <machine/elf_machdep.h>
# define ELFSIZE ARCH_ELFSIZE
#endif
#if defined(LINUX) && defined(__ELF__) || defined(SCO_ELF) || \
(defined(FREEBSD) && defined(__ELF__)) || defined(DGUX) || \
(defined(NETBSD) && defined(__ELF__)) || defined(HURD)
@ -91,7 +96,14 @@
/* Newer versions of GNU/Linux define this macro. We
* define it similarly for any ELF systems that don't. */
# ifndef ElfW
# ifdef __NetBSD__
# if defined(FREEBSD)
# if __ELF_WORD_SIZE == 32
# define ElfW(type) Elf32_##type
# else
# define ElfW(type) Elf64_##type
# endif
# else
# ifdef NETBSD
# if ELFSIZE == 32
# define ElfW(type) Elf32_##type
# else
@ -105,6 +117,7 @@
# endif
# endif
# endif
# endif
#if defined(SUNOS5DL) && !defined(USE_PROC_FOR_LIBRARIES)
@ -480,7 +493,6 @@ static struct link_map *
GC_FirstDLOpenedLinkMap()
{
ElfW(Dyn) *dp;
struct r_debug *r;
static struct link_map *cachedResult = 0;
if( _DYNAMIC == 0) {
@ -489,6 +501,12 @@ GC_FirstDLOpenedLinkMap()
if( cachedResult == 0 ) {
int tag;
for( dp = _DYNAMIC; (tag = dp->d_tag) != 0; dp++ ) {
/* FIXME: The DT_DEBUG header is not mandated by the */
/* ELF spec. This code appears to be dependent on */
/* idiosynchracies of older GNU tool chains. If this code */
/* fails for you, the real problem is probably that it is */
/* being used at all. You should be getting the */
/* dl_iterate_phdr version. */
if( tag == DT_DEBUG ) {
struct link_map *lm
= ((struct r_debug *)(dp->d_un.d_ptr))->r_map;
@ -613,7 +631,8 @@ void GC_register_dynamic_libraries()
}
for (i = 0; i < needed_sz; i++) {
flags = addr_map[i].pr_mflags;
if ((flags & (MA_BREAK | MA_STACK | MA_PHYS)) != 0) goto irrelevant;
if ((flags & (MA_BREAK | MA_STACK | MA_PHYS
| MA_FETCHOP | MA_NOTCACHED)) != 0) goto irrelevant;
if ((flags & (MA_READ | MA_WRITE)) != (MA_READ | MA_WRITE))
goto irrelevant;
/* The latter test is empirically useless in very old Irix */
@ -735,6 +754,10 @@ void GC_register_dynamic_libraries()
# define HAVE_REGISTER_MAIN_STATIC_DATA
/* The frame buffer testing code is dead in this version. */
/* We leave it here temporarily in case the switch to just */
/* testing for MEM_IMAGE sections causes un expected */
/* problems. */
GC_bool GC_warn_fb = TRUE; /* Warn about traced likely */
/* graphics memory. */
GC_bool GC_disallow_ignore_fb = FALSE;
@ -749,25 +772,27 @@ void GC_register_dynamic_libraries()
/* Should [start, start+len) be treated as a frame buffer */
/* and ignored? */
/* Unfortunately, we currently have no real way to tell */
/* automatically, and rely largely on user input. */
/* FIXME: If we had more data on this phenomenon (e.g. */
/* is start aligned to a MB multiple?) we should be able to */
/* do better. */
/* Unfortunately, we currently are not quite sure how to tell */
/* this automatically, and rely largely on user input. */
/* We expect that any mapping with type MEM_MAPPED (which */
/* apparently excludes library data sections) can be safely */
/* ignored. But we're too completely remove this code in */
/* this version. */
/* Based on a very limited sample, it appears that: */
/* - Frame buffer mappings appear as mappings of length */
/* 2**n MB - 192K. (We guess the 192K can vary a bit.) */
/* - Have a stating address at best 64K aligned. */
/* I'd love more information about the mapping, since I */
/* can't reproduce the problem. */
static GC_bool is_frame_buffer(ptr_t start, size_t len)
/* - Frame buffer mappings appear as mappings of large */
/* length, usually a bit less than a power of two. */
/* - The definition of "a bit less" in the above cannot */
/* be made more precise. */
/* - Have a starting address at best 64K aligned. */
/* - Have type == MEM_MAPPED. */
static GC_bool is_frame_buffer(ptr_t start, size_t len, DWORD tp)
{
static GC_bool initialized = FALSE;
# define MB (1024*1024)
# define DEFAULT_FB_MB 15
# define MIN_FB_MB 3
if (GC_disallow_ignore_fb) return FALSE;
if (GC_disallow_ignore_fb || tp != MEM_MAPPED) return FALSE;
if (!initialized) {
char * ignore_fb_string = GETENV("GC_IGNORE_FB");
@ -819,6 +844,9 @@ void GC_register_dynamic_libraries()
}
# endif /* DEBUG_VIRTUALQUERY */
extern GC_bool GC_wnt; /* Is Windows NT derivative. */
/* Defined and set in os_dep.c. */
void GC_register_dynamic_libraries()
{
MEMORY_BASIC_INFORMATION buf;
@ -856,7 +884,16 @@ void GC_register_dynamic_libraries()
&& (protect == PAGE_EXECUTE_READWRITE
|| protect == PAGE_READWRITE)
&& !GC_is_heap_base(buf.AllocationBase)
&& !is_frame_buffer(p, buf.RegionSize)) {
/* This used to check for
* !is_frame_buffer(p, buf.RegionSize, buf.Type)
* instead of just checking for MEM_IMAGE.
* If something breaks, change it back. */
/* There is some evidence that we cannot always
* ignore MEM_PRIVATE sections under Windows ME
* and predecessors. Hence we now also check for
* that case. */
&& (buf.Type == MEM_IMAGE ||
!GC_wnt && buf.Type == MEM_PRIVATE)) {
# ifdef DEBUG_VIRTUALQUERY
GC_dump_meminfo(&buf);
# endif
@ -1112,6 +1149,7 @@ static const char *GC_dyld_name_for_hdr(struct mach_header *hdr) {
static void GC_dyld_image_add(struct mach_header* hdr, unsigned long slide) {
unsigned long start,end,i;
const struct section *sec;
if (GC_no_dls) return;
for(i=0;i<sizeof(GC_dyld_sections)/sizeof(GC_dyld_sections[0]);i++) {
sec = getsectbynamefromheader(
hdr,GC_dyld_sections[i].seg,GC_dyld_sections[i].sect);

View File

@ -210,7 +210,7 @@ register struct hblk * h;
result = alloc_hdr();
SET_HDR(h, result);
# ifdef USE_MUNMAP
result -> hb_last_reclaimed = GC_gc_no;
result -> hb_last_reclaimed = (unsigned short)GC_gc_no;
# endif
return(result);
}

View File

@ -1,8 +1,8 @@
# Makefile.in generated by automake 1.6.3 from Makefile.am.
# Makefile.in generated by automake 1.9.3 from Makefile.am.
# @configure_input@
# Copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002
# Free Software Foundation, Inc.
# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
# 2003, 2004 Free Software Foundation, Inc.
# This Makefile.in is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
# with or without modifications, as long as this notice is preserved.
@ -26,96 +26,176 @@
# modified is included with the above copyright notice.
#
# Modified by: Grzegorz Jakacki <jakacki at acm dot org>
SHELL = @SHELL@
srcdir = @srcdir@
top_srcdir = @top_srcdir@
VPATH = @srcdir@
prefix = @prefix@
exec_prefix = @exec_prefix@
bindir = @bindir@
sbindir = @sbindir@
libexecdir = @libexecdir@
datadir = @datadir@
sysconfdir = @sysconfdir@
sharedstatedir = @sharedstatedir@
localstatedir = @localstatedir@
libdir = @libdir@
infodir = @infodir@
mandir = @mandir@
includedir = @includedir@
oldincludedir = /usr/include
pkgdatadir = $(datadir)/@PACKAGE@
pkglibdir = $(libdir)/@PACKAGE@
pkgincludedir = $(includedir)/@PACKAGE@
top_builddir = ..
ACLOCAL = @ACLOCAL@
AUTOCONF = @AUTOCONF@
AUTOMAKE = @AUTOMAKE@
AUTOHEADER = @AUTOHEADER@
am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
INSTALL = @INSTALL@
INSTALL_PROGRAM = @INSTALL_PROGRAM@
INSTALL_DATA = @INSTALL_DATA@
install_sh_DATA = $(install_sh) -c -m 644
install_sh_PROGRAM = $(install_sh) -c
install_sh_SCRIPT = $(install_sh) -c
INSTALL_SCRIPT = @INSTALL_SCRIPT@
INSTALL_HEADER = $(INSTALL_DATA)
transform = @program_transform_name@
transform = $(program_transform_name)
NORMAL_INSTALL = :
PRE_INSTALL = :
POST_INSTALL = :
NORMAL_UNINSTALL = :
PRE_UNINSTALL = :
POST_UNINSTALL = :
host_alias = @host_alias@
build_triplet = @build@
host_triplet = @host@
EXEEXT = @EXEEXT@
OBJEXT = @OBJEXT@
PATH_SEPARATOR = @PATH_SEPARATOR@
target_triplet = @target@
subdir = include
DIST_COMMON = $(dist_noinst_HEADERS) $(pkginclude_HEADERS) \
$(srcdir)/Makefile.am $(srcdir)/Makefile.in
ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
am__aclocal_m4_deps = $(top_srcdir)/acinclude.m4 \
$(top_srcdir)/libtool.m4 $(top_srcdir)/configure.in
am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
$(ACLOCAL_M4)
mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs
CONFIG_CLEAN_FILES =
SOURCES =
DIST_SOURCES =
am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
am__vpath_adj = case $$p in \
$(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
*) f=$$p;; \
esac;
am__strip_dir = `echo $$p | sed -e 's|^.*/||'`;
am__installdirs = "$(DESTDIR)$(pkgincludedir)"
pkgincludeHEADERS_INSTALL = $(INSTALL_HEADER)
HEADERS = $(dist_noinst_HEADERS) $(pkginclude_HEADERS)
ETAGS = etags
CTAGS = ctags
DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
ACLOCAL = @ACLOCAL@
AMDEP_FALSE = @AMDEP_FALSE@
AMDEP_TRUE = @AMDEP_TRUE@
AMTAR = @AMTAR@
AR = @AR@
AS = @AS@
AUTOCONF = @AUTOCONF@
AUTOHEADER = @AUTOHEADER@
AUTOMAKE = @AUTOMAKE@
AWK = @AWK@
CC = @CC@
CCAS = @CCAS@
CCASFLAGS = @CCASFLAGS@
CCDEPMODE = @CCDEPMODE@
CFLAGS = @CFLAGS@
COMPILER_XLC_FALSE = @COMPILER_XLC_FALSE@
COMPILER_XLC_TRUE = @COMPILER_XLC_TRUE@
CPLUSPLUS_FALSE = @CPLUSPLUS_FALSE@
CPLUSPLUS_TRUE = @CPLUSPLUS_TRUE@
CPP = @CPP@
CPPFLAGS = @CPPFLAGS@
CXX = @CXX@
CXXDEPMODE = @CXXDEPMODE@
CXXFLAGS = @CXXFLAGS@
CXXINCLUDES = @CXXINCLUDES@
CYGPATH_W = @CYGPATH_W@
DEFS = @DEFS@
DEPDIR = @DEPDIR@
DLLTOOL = @DLLTOOL@
ECHO = @ECHO@
ECHO_C = @ECHO_C@
ECHO_N = @ECHO_N@
ECHO_T = @ECHO_T@
EGREP = @EGREP@
EXEEXT = @EXEEXT@
EXTRA_TEST_LIBS = @EXTRA_TEST_LIBS@
GC_CFLAGS = @GC_CFLAGS@
GC_VERSION = @GC_VERSION@
INCLUDES = @INCLUDES@
INSTALL_DATA = @INSTALL_DATA@
INSTALL_PROGRAM = @INSTALL_PROGRAM@
INSTALL_SCRIPT = @INSTALL_SCRIPT@
INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
LDFLAGS = @LDFLAGS@
LIBOBJS = @LIBOBJS@
LIBS = @LIBS@
LIBTOOL = @LIBTOOL@
LN_S = @LN_S@
LTLIBOBJS = @LTLIBOBJS@
MAINT = @MAINT@
MAINTAINER_MODE_FALSE = @MAINTAINER_MODE_FALSE@
MAINTAINER_MODE_TRUE = @MAINTAINER_MODE_TRUE@
MAKEINFO = @MAKEINFO@
MY_CFLAGS = @MY_CFLAGS@
OBJDUMP = @OBJDUMP@
OBJEXT = @OBJEXT@
PACKAGE = @PACKAGE@
PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
PACKAGE_NAME = @PACKAGE_NAME@
PACKAGE_STRING = @PACKAGE_STRING@
PACKAGE_TARNAME = @PACKAGE_TARNAME@
PACKAGE_VERSION = @PACKAGE_VERSION@
PATH_SEPARATOR = @PATH_SEPARATOR@
POWERPC_DARWIN_FALSE = @POWERPC_DARWIN_FALSE@
POWERPC_DARWIN_TRUE = @POWERPC_DARWIN_TRUE@
RANLIB = @RANLIB@
SET_MAKE = @SET_MAKE@
SHELL = @SHELL@
STRIP = @STRIP@
THREADLIBS = @THREADLIBS@
THREADDLLIBS = @THREADDLLIBS@
UNWINDLIBS = @UNWINDLIBS@
USE_LIBDIR_FALSE = @USE_LIBDIR_FALSE@
USE_LIBDIR_TRUE = @USE_LIBDIR_TRUE@
VERSION = @VERSION@
ac_ct_AR = @ac_ct_AR@
ac_ct_CC = @ac_ct_CC@
ac_ct_CXX = @ac_ct_CXX@
ac_ct_RANLIB = @ac_ct_RANLIB@
ac_ct_STRIP = @ac_ct_STRIP@
addincludes = @addincludes@
addlibs = @addlibs@
addobjs = @addobjs@
addtests = @addtests@
am__fastdepCC_FALSE = @am__fastdepCC_FALSE@
am__fastdepCC_TRUE = @am__fastdepCC_TRUE@
am__fastdepCXX_FALSE = @am__fastdepCXX_FALSE@
am__fastdepCXX_TRUE = @am__fastdepCXX_TRUE@
am__include = @am__include@
am__leading_dot = @am__leading_dot@
am__quote = @am__quote@
am__tar = @am__tar@
am__untar = @am__untar@
bindir = @bindir@
build = @build@
build_alias = @build_alias@
build_cpu = @build_cpu@
build_os = @build_os@
build_vendor = @build_vendor@
datadir = @datadir@
exec_prefix = @exec_prefix@
host = @host@
host_alias = @host_alias@
host_cpu = @host_cpu@
host_os = @host_os@
host_vendor = @host_vendor@
includedir = @includedir@
infodir = @infodir@
install_sh = @install_sh@
libdir = @libdir@
libexecdir = @libexecdir@
localstatedir = @localstatedir@
mandir = @mandir@
mkdir_p = @mkdir_p@
oldincludedir = @oldincludedir@
prefix = @prefix@
program_transform_name = @program_transform_name@
sbindir = @sbindir@
sharedstatedir = @sharedstatedir@
sysconfdir = @sysconfdir@
target = @target@
target_alias = @target_alias@
target_all = @target_all@
target_cpu = @target_cpu@
target_os = @target_os@
target_vendor = @target_vendor@
# installed headers
#
@ -139,22 +219,38 @@ dist_noinst_HEADERS = private/gc_hdrs.h \
private/darwin_semaphore.h private/darwin_stop_world.h \
cord.h ec.h javaxfc.h
subdir = include
mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs
CONFIG_CLEAN_FILES =
DIST_SOURCES =
HEADERS = $(dist_noinst_HEADERS) $(pkginclude_HEADERS)
DIST_COMMON = $(dist_noinst_HEADERS) $(pkginclude_HEADERS) Makefile.am \
Makefile.in
all: all-am
.SUFFIXES:
$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4)
$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
@for dep in $?; do \
case '$(am__configure_deps)' in \
*$$dep*) \
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \
&& exit 0; \
exit 1;; \
esac; \
done; \
echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu include/Makefile'; \
cd $(top_srcdir) && \
$(AUTOMAKE) --gnu include/Makefile
Makefile: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.in $(top_builddir)/config.status
cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)
.PRECIOUS: Makefile
Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
@case '$?' in \
*config.status*) \
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
*) \
echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
esac;
$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
mostlyclean-libtool:
-rm -f *.lo
@ -165,30 +261,24 @@ clean-libtool:
distclean-libtool:
-rm -f libtool
uninstall-info-am:
pkgincludeHEADERS_INSTALL = $(INSTALL_HEADER)
install-pkgincludeHEADERS: $(pkginclude_HEADERS)
@$(NORMAL_INSTALL)
$(mkinstalldirs) $(DESTDIR)$(pkgincludedir)
test -z "$(pkgincludedir)" || $(mkdir_p) "$(DESTDIR)$(pkgincludedir)"
@list='$(pkginclude_HEADERS)'; for p in $$list; do \
if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
f="`echo $$p | sed -e 's|^.*/||'`"; \
echo " $(pkgincludeHEADERS_INSTALL) $$d$$p $(DESTDIR)$(pkgincludedir)/$$f"; \
$(pkgincludeHEADERS_INSTALL) $$d$$p $(DESTDIR)$(pkgincludedir)/$$f; \
f=$(am__strip_dir) \
echo " $(pkgincludeHEADERS_INSTALL) '$$d$$p' '$(DESTDIR)$(pkgincludedir)/$$f'"; \
$(pkgincludeHEADERS_INSTALL) "$$d$$p" "$(DESTDIR)$(pkgincludedir)/$$f"; \
done
uninstall-pkgincludeHEADERS:
@$(NORMAL_UNINSTALL)
@list='$(pkginclude_HEADERS)'; for p in $$list; do \
f="`echo $$p | sed -e 's|^.*/||'`"; \
echo " rm -f $(DESTDIR)$(pkgincludedir)/$$f"; \
rm -f $(DESTDIR)$(pkgincludedir)/$$f; \
f=$(am__strip_dir) \
echo " rm -f '$(DESTDIR)$(pkgincludedir)/$$f'"; \
rm -f "$(DESTDIR)$(pkgincludedir)/$$f"; \
done
ETAGS = etags
ETAGSFLAGS =
tags: TAGS
ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
unique=`for i in $$list; do \
@ -197,6 +287,7 @@ ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
$(AWK) ' { files[$$0] = 1; } \
END { for (i in files) print i; }'`; \
mkid -fID $$unique
tags: TAGS
TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
$(TAGS_FILES) $(LISP)
@ -208,8 +299,24 @@ TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
done | \
$(AWK) ' { files[$$0] = 1; } \
END { for (i in files) print i; }'`; \
test -z "$(ETAGS_ARGS)$$tags$$unique" \
|| $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \
test -n "$$unique" || unique=$$empty_fix; \
$(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
$$tags $$unique; \
fi
ctags: CTAGS
CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
$(TAGS_FILES) $(LISP)
tags=; \
here=`pwd`; \
list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
unique=`for i in $$list; do \
if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
done | \
$(AWK) ' { files[$$0] = 1; } \
END { for (i in files) print i; }'`; \
test -z "$(CTAGS_ARGS)$$tags$$unique" \
|| $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
$$tags $$unique
GTAGS:
@ -218,20 +325,22 @@ GTAGS:
&& gtags -i $(GTAGS_ARGS) $$here
distclean-tags:
-rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH
DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
top_distdir = ..
distdir = $(top_distdir)/$(PACKAGE)-$(VERSION)
-rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
distdir: $(DISTFILES)
$(mkinstalldirs) $(distdir)/private
@list='$(DISTFILES)'; for file in $$list; do \
$(mkdir_p) $(distdir)/private
@srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \
topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \
list='$(DISTFILES)'; for file in $$list; do \
case $$file in \
$(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \
$(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \
esac; \
if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \
if test "$$dir" != "$$file" && test "$$dir" != "."; then \
dir="/$$dir"; \
$(mkinstalldirs) "$(distdir)$$dir"; \
$(mkdir_p) "$(distdir)$$dir"; \
else \
dir=''; \
fi; \
@ -249,10 +358,10 @@ distdir: $(DISTFILES)
check-am: all-am
check: check-am
all-am: Makefile $(HEADERS)
installdirs:
$(mkinstalldirs) $(DESTDIR)$(pkgincludedir)
for dir in "$(DESTDIR)$(pkgincludedir)"; do \
test -z "$$dir" || $(mkdir_p) "$$dir"; \
done
install: install-am
install-exec: install-exec-am
install-data: install-data-am
@ -264,7 +373,7 @@ install-am: all-am
installcheck: installcheck-am
install-strip:
$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
INSTALL_STRIP_FLAG=-s \
install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
`test -z '$(STRIP)' || \
echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
mostlyclean-generic:
@ -272,7 +381,7 @@ mostlyclean-generic:
clean-generic:
distclean-generic:
-rm -f Makefile $(CONFIG_CLEAN_FILES)
-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
maintainer-clean-generic:
@echo "This command is intended for maintainers to use"
@ -282,7 +391,7 @@ clean: clean-am
clean-am: clean-generic clean-libtool mostlyclean-am
distclean: distclean-am
-rm -f Makefile
distclean-am: clean-am distclean-generic distclean-libtool \
distclean-tags
@ -290,6 +399,8 @@ dvi: dvi-am
dvi-am:
html: html-am
info: info-am
info-am:
@ -305,25 +416,34 @@ install-man:
installcheck-am:
maintainer-clean: maintainer-clean-am
-rm -f Makefile
maintainer-clean-am: distclean-am maintainer-clean-generic
mostlyclean: mostlyclean-am
mostlyclean-am: mostlyclean-generic mostlyclean-libtool
pdf: pdf-am
pdf-am:
ps: ps-am
ps-am:
uninstall-am: uninstall-info-am uninstall-pkgincludeHEADERS
.PHONY: GTAGS all all-am check check-am clean clean-generic \
clean-libtool distclean distclean-generic distclean-libtool \
distclean-tags distdir dvi dvi-am info info-am install \
install-am install-data install-data-am install-exec \
install-exec-am install-info install-info-am install-man \
install-pkgincludeHEADERS install-strip installcheck \
installcheck-am installdirs maintainer-clean \
maintainer-clean-generic mostlyclean mostlyclean-generic \
mostlyclean-libtool tags uninstall uninstall-am \
uninstall-info-am uninstall-pkgincludeHEADERS
.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \
clean-libtool ctags distclean distclean-generic \
distclean-libtool distclean-tags distdir dvi dvi-am html \
html-am info info-am install install-am install-data \
install-data-am install-exec install-exec-am install-info \
install-info-am install-man install-pkgincludeHEADERS \
install-strip installcheck installcheck-am installdirs \
maintainer-clean maintainer-clean-generic mostlyclean \
mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
tags uninstall uninstall-am uninstall-info-am \
uninstall-pkgincludeHEADERS
# Tell versions [3.59,3.63) of GNU make to not export all variables.
# Otherwise a system limit (for SysV at least) may be exceeded.

View File

@ -32,7 +32,7 @@
# include "gc_config_macros.h"
# if defined(__STDC__) || defined(__cplusplus)
# if defined(__STDC__) || defined(__cplusplus) || defined(_AIX)
# define GC_PROTO(args) args
typedef void * GC_PTR;
# define GC_CONST const
@ -129,7 +129,7 @@ GC_API int GC_java_finalization;
/* ordered finalization. Default value is */
/* determined by JAVA_FINALIZATION macro. */
GC_API void (* GC_finalizer_notifier)();
GC_API void (* GC_finalizer_notifier) GC_PROTO((void));
/* Invoked by the collector when there are */
/* objects to be finalized. Invoked at most */
/* once per GC cycle. Never invoked unless */
@ -191,7 +191,7 @@ GC_API GC_word GC_free_space_divisor;
/* least N/GC_free_space_divisor bytes between */
/* collections, where N is the heap size plus */
/* a rough estimate of the root set size. */
/* Initially, GC_free_space_divisor = 4. */
/* Initially, GC_free_space_divisor = 3. */
/* Increasing its value will use less space */
/* but more collection time. Decreasing it */
/* will appreciably decrease collection time */
@ -267,6 +267,7 @@ GC_API void GC_init GC_PROTO((void));
*/
GC_API GC_PTR GC_malloc GC_PROTO((size_t size_in_bytes));
GC_API GC_PTR GC_malloc_atomic GC_PROTO((size_t size_in_bytes));
GC_API char *GC_strdup GC_PROTO((const char *str));
GC_API GC_PTR GC_malloc_uncollectable GC_PROTO((size_t size_in_bytes));
GC_API GC_PTR GC_malloc_stubborn GC_PROTO((size_t size_in_bytes));
@ -308,6 +309,9 @@ GC_API void GC_end_stubborn_change GC_PROTO((GC_PTR));
/* the base of the user object. */
/* Return 0 if displaced_pointer doesn't point to within a valid */
/* object. */
/* Note that a deallocated object in the garbage collected heap */
/* may be considered valid, even if it has been deallocated with */
/* GC_free. */
GC_API GC_PTR GC_base GC_PROTO((GC_PTR displaced_pointer));
/* Given a pointer to the base of an object, return its size in bytes. */
@ -520,6 +524,8 @@ GC_API GC_PTR GC_debug_malloc
GC_PROTO((size_t size_in_bytes, GC_EXTRA_PARAMS));
GC_API GC_PTR GC_debug_malloc_atomic
GC_PROTO((size_t size_in_bytes, GC_EXTRA_PARAMS));
GC_API char *GC_debug_strdup
GC_PROTO((const char *str, GC_EXTRA_PARAMS));
GC_API GC_PTR GC_debug_malloc_uncollectable
GC_PROTO((size_t size_in_bytes, GC_EXTRA_PARAMS));
GC_API GC_PTR GC_debug_malloc_stubborn
@ -554,6 +560,7 @@ GC_API GC_PTR GC_debug_realloc_replacement
# ifdef GC_DEBUG
# define GC_MALLOC(sz) GC_debug_malloc(sz, GC_EXTRAS)
# define GC_MALLOC_ATOMIC(sz) GC_debug_malloc_atomic(sz, GC_EXTRAS)
# define GC_STRDUP(s) GC_debug_strdup((s), GC_EXTRAS)
# define GC_MALLOC_UNCOLLECTABLE(sz) \
GC_debug_malloc_uncollectable(sz, GC_EXTRAS)
# define GC_MALLOC_IGNORE_OFF_PAGE(sz) \
@ -577,6 +584,7 @@ GC_API GC_PTR GC_debug_realloc_replacement
# else
# define GC_MALLOC(sz) GC_malloc(sz)
# define GC_MALLOC_ATOMIC(sz) GC_malloc_atomic(sz)
# define GC_STRDUP(s) GC_strdup(s)
# define GC_MALLOC_UNCOLLECTABLE(sz) GC_malloc_uncollectable(sz)
# define GC_MALLOC_IGNORE_OFF_PAGE(sz) \
GC_malloc_ignore_off_page(sz)
@ -855,7 +863,7 @@ GC_API GC_PTR GC_is_valid_displacement GC_PROTO((GC_PTR p));
/* Safer assignment of a pointer to a nonstack location. */
#ifdef GC_DEBUG
# ifdef __STDC__
# if defined(__STDC__) || defined(_AIX)
# define GC_PTR_STORE(p, q) \
(*(void **)GC_is_visible(p) = GC_is_valid_displacement(q))
# else
@ -896,7 +904,7 @@ GC_API void (*GC_is_visible_print_proc)
GC_PTR GC_malloc_many(size_t lb);
#define GC_NEXT(p) (*(GC_PTR *)(p)) /* Retrieve the next element */
/* in returned list. */
extern void GC_thr_init(); /* Needed for Solaris/X86 */
extern void GC_thr_init GC_PROTO((void));/* Needed for Solaris/X86 */
#endif /* THREADS && !SRC_M3 */
@ -947,17 +955,43 @@ extern void GC_thr_init(); /* Needed for Solaris/X86 */
* from the statically loaded program section.
* This circumvents a Solaris 2.X (X<=4) linker bug.
*/
/* PLTSCHEME: "extern" provided by Matthew.R.Wette@jpl.nasa.gov: */
extern void GC_noop(void *p, ...);
# define GC_INIT() { extern end, etext; \
GC_noop(&end, &etext); }
# ifdef __cplusplus
# define GC_INIT() { extern int _end[], _etext[]; \
extern "C" void GC_noop1(GC_word); \
GC_noop1((GC_word)_end); \
GC_noop1((GC_word)_etext); }
# else
# define GC_INIT() { extern int _end[], _etext[]; \
extern void GC_noop(); \
GC_noop(_end, _etext); }
# endif /* !__cplusplus */
#else
# if defined(__CYGWIN32__) && defined(GC_DLL) || defined (_AIX)
# if defined(__CYGWIN32__) || defined (_AIX)
/*
* Similarly gnu-win32 DLLs need explicit initialization from
* the main program, as does AIX.
*/
# define GC_INIT() { GC_add_roots(DATASTART, DATAEND); }
# ifdef __CYGWIN32__
extern int _data_start__[];
extern int _data_end__[];
extern int _bss_start__[];
extern int _bss_end__[];
# define GC_MAX(x,y) ((x) > (y) ? (x) : (y))
# define GC_MIN(x,y) ((x) < (y) ? (x) : (y))
# define GC_DATASTART ((GC_PTR) GC_MIN(_data_start__, _bss_start__))
# define GC_DATAEND ((GC_PTR) GC_MAX(_data_end__, _bss_end__))
# ifdef GC_DLL
# define GC_INIT() { GC_add_roots(GC_DATASTART, GC_DATAEND); }
# else
# define GC_INIT()
# endif
# endif
# if defined(_AIX)
extern int _data[], _end[];
# define GC_DATASTART ((GC_PTR)((ulong)_data))
# define GC_DATAEND ((GC_PTR)((ulong)_end))
# define GC_INIT() { GC_add_roots(GC_DATASTART, GC_DATAEND); }
# endif
# else
# if defined(__APPLE__) && defined(__MACH__) || defined(GC_WIN32_THREADS)
# define GC_INIT() { GC_init(); }

View File

@ -42,12 +42,17 @@
|| defined(GC_SOLARIS_PTHREADS) \
|| defined(GC_HPUX_THREADS) \
|| defined(GC_AIX_THREADS) \
|| defined(GC_LINUX_THREADS))
|| defined(GC_LINUX_THREADS) \
|| defined(GC_NETBSD_THREADS))
# define _REENTRANT
/* Better late than never. This fails if system headers that */
/* depend on this were previously included. */
#endif
#if !defined(_PTHREADS) && defined(GC_NETBSD_THREADS)
# define _PTHREADS
#endif
#if defined(GC_DGUX386_THREADS) && !defined(_POSIX4A_DRAFT10_SOURCE)
# define _POSIX4A_DRAFT10_SOURCE 1
#endif
@ -56,7 +61,7 @@
defined(GC_IRIX_THREADS) || defined(GC_LINUX_THREADS) || \
defined(GC_HPUX_THREADS) || defined(GC_OSF1_THREADS) || \
defined(GC_DGUX386_THREADS) || defined(GC_DARWIN_THREADS) || \
defined(GC_AIX_THREADS) || \
defined(GC_AIX_THREADS) || defined(GC_NETBSD_THREADS) || \
(defined(GC_WIN32_THREADS) && defined(__CYGWIN32__))
# define GC_PTHREADS
# endif
@ -66,7 +71,7 @@
# define GC_LINUX_THREADS
# define GC_PTHREADS
# endif
# if !defined(LINUX) && (defined(_PA_RISC1_1) || defined(_PA_RISC2_0) \
# if !defined(__linux__) && (defined(_PA_RISC1_1) || defined(_PA_RISC2_0) \
|| defined(hppa) || defined(__HPPA))
# define GC_HPUX_THREADS
# define GC_PTHREADS
@ -91,10 +96,18 @@
# define GC_FREEBSD_THREADS
# define GC_PTHREADS
# endif
# if !defined(GC_PTHREADS) && defined(__NetBSD__)
# define GC_NETBSD_THREADS
# define GC_PTHREADS
# endif
# if defined(DGUX) && (defined(i386) || defined(__i386__))
# define GC_DGUX386_THREADS
# define GC_PTHREADS
# endif
# if defined(_AIX)
# define GC_AIX_THREADS
# define GC_PTHREADS
# endif
#endif /* GC_THREADS */
#if defined(GC_THREADS) && !defined(GC_PTHREADS) && \

View File

@ -0,0 +1,164 @@
/*
* This should never be included directly. It is included only from gc.h.
* We separate it only to make gc.h more suitable as documentation.
*
* Some tests for old macros. These violate our namespace rules and will
* disappear shortly. Use the GC_ names.
*/
#if defined(SOLARIS_THREADS) || defined(_SOLARIS_THREADS)
# define GC_SOLARIS_THREADS
#endif
#if defined(_SOLARIS_PTHREADS)
# define GC_SOLARIS_PTHREADS
#endif
#if defined(IRIX_THREADS)
# define GC_IRIX_THREADS
#endif
#if defined(DGUX_THREADS)
# if !defined(GC_DGUX386_THREADS)
# define GC_DGUX386_THREADS
# endif
#endif
#if defined(AIX_THREADS)
# define GC_AIX_THREADS
#endif
#if defined(HPUX_THREADS)
# define GC_HPUX_THREADS
#endif
#if defined(OSF1_THREADS)
# define GC_OSF1_THREADS
#endif
#if defined(LINUX_THREADS)
# define GC_LINUX_THREADS
#endif
#if defined(WIN32_THREADS)
# define GC_WIN32_THREADS
#endif
#if defined(USE_LD_WRAP)
# define GC_USE_LD_WRAP
#endif
#if !defined(_REENTRANT) && (defined(GC_SOLARIS_THREADS) \
|| defined(GC_SOLARIS_PTHREADS) \
|| defined(GC_HPUX_THREADS) \
|| defined(GC_AIX_THREADS) \
|| defined(GC_LINUX_THREADS) \
|| defined(GC_NETBSD_THREADS))
# define _REENTRANT
/* Better late than never. This fails if system headers that */
/* depend on this were previously included. */
#endif
#if !defined(_PTHREADS) && defined(GC_NETBSD_THREADS)
# define _PTHREADS
#endif
#if defined(GC_DGUX386_THREADS) && !defined(_POSIX4A_DRAFT10_SOURCE)
# define _POSIX4A_DRAFT10_SOURCE 1
#endif
# if defined(GC_SOLARIS_PTHREADS) || defined(GC_FREEBSD_THREADS) || \
defined(GC_IRIX_THREADS) || defined(GC_LINUX_THREADS) || \
defined(GC_HPUX_THREADS) || defined(GC_OSF1_THREADS) || \
defined(GC_DGUX386_THREADS) || defined(GC_DARWIN_THREADS) || \
defined(GC_AIX_THREADS) || defined(GC_NETBSD_THREADS) || \
(defined(GC_WIN32_THREADS) && defined(__CYGWIN32__))
# define GC_PTHREADS
# endif
#if defined(GC_THREADS) && !defined(GC_PTHREADS)
# if defined(__linux__)
# define GC_LINUX_THREADS
# define GC_PTHREADS
# endif
# if !defined(__linux__) && (defined(_PA_RISC1_1) || defined(_PA_RISC2_0) \
|| defined(hppa) || defined(__HPPA))
# define GC_HPUX_THREADS
# define GC_PTHREADS
# endif
# if !defined(__linux__) && (defined(__alpha) || defined(__alpha__))
# define GC_OSF1_THREADS
# define GC_PTHREADS
# endif
# if defined(__mips) && !defined(__linux__)
# define GC_IRIX_THREADS
# define GC_PTHREADS
# endif
# if defined(__sparc) && !defined(__linux__)
# define GC_SOLARIS_PTHREADS
# define GC_PTHREADS
# endif
# if defined(__APPLE__) && defined(__MACH__) && defined(__ppc__)
# define GC_DARWIN_THREADS
# define GC_PTHREADS
# endif
# if !defined(GC_PTHREADS) && defined(__FreeBSD__)
# define GC_FREEBSD_THREADS
# define GC_PTHREADS
# endif
# if !defined(GC_PTHREADS) && defined(__NetBSD__)
# define GC_NETBSD_THREADS
# define GC_PTHREADS
# endif
# if defined(DGUX) && (defined(i386) || defined(__i386__))
# define GC_DGUX386_THREADS
# define GC_PTHREADS
# endif
# if defined(_AIX)
# define GC_AIX_THREADS
# define GC_PTHREADS
# endif
#endif /* GC_THREADS */
#if defined(GC_THREADS) && !defined(GC_PTHREADS) && \
(defined(_WIN32) || defined(_MSC_VER) || defined(__CYGWIN__) \
|| defined(__MINGW32__) || defined(__BORLANDC__) \
|| defined(_WIN32_WCE))
# define GC_WIN32_THREADS
#endif
#if defined(GC_SOLARIS_PTHREADS) && !defined(GC_SOLARIS_THREADS)
# define GC_SOLARIS_THREADS
#endif
# define __GC
# ifndef _WIN32_WCE
# include <stddef.h>
# else /* ! _WIN32_WCE */
/* Yet more kluges for WinCE */
# include <stdlib.h> /* size_t is defined here */
typedef long ptrdiff_t; /* ptrdiff_t is not defined */
# endif
#if defined(_DLL) && !defined(GC_NOT_DLL) && !defined(GC_DLL)
# define GC_DLL
#endif
#if defined(__MINGW32__) && defined(GC_DLL)
# ifdef GC_BUILD
# define GC_API __declspec(dllexport)
# else
# define GC_API __declspec(dllimport)
# endif
#endif
#if (defined(__DMC__) || defined(_MSC_VER)) && defined(GC_DLL)
# ifdef GC_BUILD
# define GC_API extern __declspec(dllexport)
# else
# define GC_API __declspec(dllimport)
# endif
#endif
#if defined(__WATCOMC__) && defined(GC_DLL)
# ifdef GC_BUILD
# define GC_API extern __declspec(dllexport)
# else
# define GC_API extern __declspec(dllimport)
# endif
#endif
#ifndef GC_API
#define GC_API extern
#endif

View File

@ -74,7 +74,7 @@ cycle, then that's considered a storage leak, and neither will be
collectable. See the interface gc.h for low-level facilities for
handling such cycles of objects with clean-up.
The collector cannot guarrantee that it will find all inaccessible
The collector cannot guarantee that it will find all inaccessible
objects. In practice, it finds almost all of them.
@ -180,7 +180,7 @@ class gc {public:
inline void* operator new[]( size_t size, void *p );
inline void operator delete[]( void* obj );
# ifdef GC_PLACEMENT_DELETE
inline void gc::operator delete[]( void*, void* );
inline void operator delete[]( void*, void* );
# endif
#endif /* GC_OPERATOR_NEW_ARRAY */
};

View File

@ -73,6 +73,9 @@
# define pthread_detach GC_pthread_detach
#ifndef GC_DARWIN_THREADS
# ifdef pthread_sigmask
# undef pthread_sigmask
# endif /* pthread_sigmask */
# define pthread_sigmask GC_pthread_sigmask
# define dlopen GC_dlopen
#endif

View File

@ -4,4 +4,6 @@
#define calloc(m,n) GC_MALLOC((m)*(n))
#define free(p) GC_FREE(p)
#define realloc(p,n) GC_REALLOC((p),(n))
#undef strdup
#define strdup(s) GC_STRDUP((s))
#define CHECK_LEAKS() GC_gcollect()

View File

@ -109,7 +109,7 @@ enum { GC_byte_alignment = 8 };
enum { GC_word_alignment = GC_byte_alignment/GC_bytes_per_word };
inline void * &GC_obj_link(void * p)
{ return *(void **)p; }
{ return *reinterpret_cast<void **>(p); }
// Compute a number of words >= n+1 bytes.
// The +1 allows for pointers one past the end.
@ -228,7 +228,7 @@ class single_client_gc_alloc_template {
} else {
flh = GC_objfreelist_ptr + nwords;
GC_obj_link(p) = *flh;
memset((char *)p + GC_bytes_per_word, 0,
memset(reinterpret_cast<char *>(p) + GC_bytes_per_word, 0,
GC_bytes_per_word * (nwords - 1));
*flh = p;
GC_aux::GC_mem_recently_freed += nwords;
@ -352,9 +352,9 @@ class simple_alloc<T, alloc> { \
public: \
static T *allocate(size_t n) \
{ return 0 == n? 0 : \
(T*) alloc::ptr_free_allocate(n * sizeof (T)); } \
reinterpret_cast<T*>(alloc::ptr_free_allocate(n * sizeof (T))); } \
static T *allocate(void) \
{ return (T*) alloc::ptr_free_allocate(sizeof (T)); } \
{ return reinterpret_cast<T*>(alloc::ptr_free_allocate(sizeof (T))); } \
static void deallocate(T *p, size_t n) \
{ if (0 != n) alloc::ptr_free_deallocate(p, n * sizeof (T)); } \
static void deallocate(T *p) \

View File

@ -108,7 +108,7 @@ extern hdr * GC_invalid_header; /* header for an imaginary block */
/* Analogous to GET_HDR, except that in the case of large objects, it */
/* Returns the header for the object beginning, and updates p. */
/* Returns &GC_bad_header instead of 0. All of this saves a branch */
/* Returns GC_invalid_header instead of 0. All of this saves a branch */
/* in the fast path. */
# define HC_GET_HDR(p, hhdr, source) \
{ \

View File

@ -174,7 +174,7 @@
}
# define GC_TEST_AND_SET_DEFINED
inline static void GC_clear(volatile unsigned int *addr) {
__asm__ __volatile__("eieio" : : : "memory");
__asm__ __volatile__("lwsync" : : : "memory");
*(addr) = 0;
}
# define GC_CLEAR_DEFINED
@ -219,18 +219,45 @@
# ifdef ARM32
inline static int GC_test_and_set(volatile unsigned int *addr) {
int oldval;
/* SWP on ARM is very similar to XCHG on x86. Doesn't lock the
* bus because there are no SMP ARM machines. If/when there are,
* this code will likely need to be updated. */
/* See linuxthreads/sysdeps/arm/pt-machine.h in glibc-2.1 */
__asm__ __volatile__("swp %0, %1, [%2]"
: "=r"(oldval)
: "r"(1), "r"(addr)
/* SWP on ARM is very similar to XCHG on x86. */
/* The first operand is the result, the second the value */
/* to be stored. Both registers must be different from addr. */
/* Make the address operand an early clobber output so it */
/* doesn't overlap with the other operands. The early clobber*/
/* on oldval is neccessary to prevent the compiler allocating */
/* them to the same register if they are both unused. */
__asm__ __volatile__("swp %0, %2, [%3]"
: "=&r"(oldval), "=&r"(addr)
: "r"(1), "1"(addr)
: "memory");
return oldval;
}
# define GC_TEST_AND_SET_DEFINED
# endif /* ARM32 */
# ifdef CRIS
inline static int GC_test_and_set(volatile unsigned int *addr) {
/* Ripped from linuxthreads/sysdeps/cris/pt-machine.h. */
/* Included with Hans-Peter Nilsson's permission. */
register unsigned long int ret;
/* Note the use of a dummy output of *addr to expose the write.
* The memory barrier is to stop *other* writes being moved past
* this code.
*/
__asm__ __volatile__("clearf\n"
"0:\n\t"
"movu.b [%2],%0\n\t"
"ax\n\t"
"move.b %3,[%2]\n\t"
"bwf 0b\n\t"
"clearf"
: "=&r" (ret), "=m" (*addr)
: "r" (addr), "r" ((int) 1), "m" (*addr)
: "memory");
return ret;
}
# define GC_TEST_AND_SET_DEFINED
# endif /* CRIS */
# ifdef S390
inline static int GC_test_and_set(volatile unsigned int *addr) {
int ret;
@ -274,6 +301,8 @@
# define GC_test_and_set(addr) test_and_set((void *)addr,1)
# endif
# else
# include <sgidefs.h>
# include <mutex.h>
# define GC_test_and_set(addr) __test_and_set32((void *)addr,1)
# define GC_clear(addr) __lock_release(addr);
# define GC_CLEAR_DEFINED
@ -346,7 +375,7 @@
# endif
# if defined(GC_PTHREADS) && !defined(GC_SOLARIS_THREADS) \
&& !defined(GC_IRIX_THREADS) && !defined(GC_WIN32_THREADS)
&& !defined(GC_WIN32_THREADS)
# define NO_THREAD (pthread_t)(-1)
# include <pthread.h>
# if defined(PARALLEL_MARK)
@ -393,6 +422,29 @@
# if defined(POWERPC)
# if !defined(GENERIC_COMPARE_AND_SWAP)
# if CPP_WORDSZ == 64
/* Returns TRUE if the comparison succeeded. */
inline static GC_bool GC_compare_and_exchange(volatile GC_word *addr,
GC_word old, GC_word new_val)
{
unsigned long result, dummy;
__asm__ __volatile__(
"1:\tldarx %0,0,%5\n"
"\tcmpd %0,%4\n"
"\tbne 2f\n"
"\tstdcx. %3,0,%2\n"
"\tbne- 1b\n"
"\tsync\n"
"\tli %1, 1\n"
"\tb 3f\n"
"2:\tli %1, 0\n"
"3:\t\n"
: "=&r" (dummy), "=r" (result), "=p" (addr)
: "r" (new_val), "r" (old), "2"(addr)
: "cr0","memory");
return (GC_bool) result;
}
# else
/* Returns TRUE if the comparison succeeded. */
inline static GC_bool GC_compare_and_exchange(volatile GC_word *addr,
GC_word old, GC_word new_val)
@ -414,6 +466,7 @@
: "cr0","memory");
return (GC_bool) result;
}
# endif
# endif /* !GENERIC_COMPARE_AND_SWAP */
inline static void GC_memory_barrier()
{
@ -427,9 +480,18 @@
GC_word old, GC_word new_val)
{
unsigned long oldval;
__asm__ __volatile__("mov ar.ccv=%4 ;; cmpxchg8.rel %0=%1,%2,ar.ccv"
: "=r"(oldval), "=m"(*addr)
: "r"(new_val), "1"(*addr), "r"(old) : "memory");
# if CPP_WORDSZ == 32
__asm__ __volatile__(
"addp4 %0=0,%1\n"
"mov ar.ccv=%3 ;; cmpxchg4.rel %0=[%0],%2,ar.ccv"
: "=&r"(oldval)
: "r"(addr), "r"(new_val), "r"(old) : "memory");
# else
__asm__ __volatile__(
"mov ar.ccv=%3 ;; cmpxchg8.rel %0=[%1],%2,ar.ccv"
: "=r"(oldval)
: "r"(addr), "r"(new_val), "r"(old) : "memory");
# endif
return (oldval == old);
}
# endif /* !GENERIC_COMPARE_AND_SWAP */
@ -593,33 +655,6 @@
extern pthread_t GC_mark_lock_holder;
# endif
# endif /* GC_PTHREADS with linux_threads.c implementation */
# if defined(GC_IRIX_THREADS)
# include <pthread.h>
/* This probably should never be included, but I can't test */
/* on Irix anymore. */
# include <mutex.h>
extern volatile unsigned int GC_allocate_lock;
/* This is not a mutex because mutexes that obey the (optional) */
/* POSIX scheduling rules are subject to convoys in high contention */
/* applications. This is basically a spin lock. */
extern pthread_t GC_lock_holder;
extern void GC_lock(void);
/* Allocation lock holder. Only set if acquired by client through */
/* GC_call_with_alloc_lock. */
# define SET_LOCK_HOLDER() GC_lock_holder = pthread_self()
# define NO_THREAD (pthread_t)(-1)
# define UNSET_LOCK_HOLDER() GC_lock_holder = NO_THREAD
# define I_HOLD_LOCK() (pthread_equal(GC_lock_holder, pthread_self()))
# define LOCK() { if (GC_test_and_set(&GC_allocate_lock)) GC_lock(); }
# define UNLOCK() GC_clear(&GC_allocate_lock);
extern VOLATILE GC_bool GC_collecting;
# define ENTER_GC() \
{ \
GC_collecting = 1; \
}
# define EXIT_GC() GC_collecting = 0;
# endif /* GC_IRIX_THREADS */
# if defined(GC_WIN32_THREADS)
# if defined(GC_PTHREADS)
# include <pthread.h>

View File

@ -248,7 +248,8 @@ exit_label: ; \
if (map_entry == OFFSET_TOO_BIG) { \
map_entry = displ % (hhdr -> hb_sz); \
displ -= map_entry; \
if (displ + (hhdr -> hb_sz) > BYTES_TO_WORDS(HBLKSIZE)) { \
if (displ + (hhdr -> hb_sz) > BYTES_TO_WORDS(HBLKSIZE) \
&& displ != 0) { \
GC_ADD_TO_BLACK_LIST_NORMAL((word)current, source); \
goto exit_label; \
} \

View File

@ -107,8 +107,7 @@ typedef char * ptr_t; /* A generic pointer to which we can add */
# define MAKE_HOTTER(x,y) (x) += (y)
# endif
/* PLTSCHEME: Always put GC_FAR as far data for Mac 68k */
#if defined(__MC68K__) || (defined(AMIGA) && defined(__SASC))
#if defined(AMIGA) && defined(__SASC)
# define GC_FAR __far
#else
# define GC_FAR
@ -259,17 +258,6 @@ typedef char * ptr_t; /* A generic pointer to which we can add */
/* */
/*********************************/
#ifdef SAVE_CALL_CHAIN
/* Fill in the pc and argument information for up to NFRAMES of my */
/* callers. Ignore my frame and my callers frame. */
struct callinfo;
void GC_save_callers GC_PROTO((struct callinfo info[NFRAMES]));
void GC_print_callers GC_PROTO((struct callinfo info[NFRAMES]));
#endif
#ifdef NEED_CALLINFO
struct callinfo {
word ci_pc; /* Caller, not callee, pc */
@ -283,6 +271,16 @@ void GC_print_callers GC_PROTO((struct callinfo info[NFRAMES]));
};
#endif
#ifdef SAVE_CALL_CHAIN
/* Fill in the pc and argument information for up to NFRAMES of my */
/* callers. Ignore my frame and my callers frame. */
void GC_save_callers GC_PROTO((struct callinfo info[NFRAMES]));
void GC_print_callers GC_PROTO((struct callinfo info[NFRAMES]));
#endif
/*********************************/
/* */
@ -757,17 +755,9 @@ struct hblk {
# ifdef LARGE_CONFIG
# define MAX_ROOT_SETS 4096
# else
# ifdef PCR
/* GCJ LOCAL: MAX_ROOT_SETS increased to permit more shared */
/* libraries to be loaded. */
# define MAX_ROOT_SETS 1024
# else
# if defined(MSWIN32) || defined(MSWINCE)
# define MAX_ROOT_SETS 1024
/* Under NT, we add only written pages, which can result */
/* in many small root sets. */
# else
# define MAX_ROOT_SETS 256
# endif
# endif
# endif
# define MAX_EXCLUSIONS (MAX_ROOT_SETS/4)
@ -1637,6 +1627,10 @@ ptr_t GC_generic_malloc_ignore_off_page GC_PROTO((size_t b, int k));
/* are ignored. */
ptr_t GC_generic_malloc_inner GC_PROTO((word lb, int k));
/* Ditto, but I already hold lock, etc. */
ptr_t GC_generic_malloc_words_small_inner GC_PROTO((word lw, int k));
/* Analogous to the above, but assumes */
/* a small object size, and bypasses */
/* MERGE_SIZES mechanism. */
ptr_t GC_generic_malloc_words_small GC_PROTO((size_t lw, int k));
/* As above, but size in units of words */
/* Bypasses MERGE_SIZES. Assumes */
@ -1722,7 +1716,7 @@ extern GC_bool GC_print_stats; /* Produce at least some logging output */
/* Set from environment variable. */
#ifndef NO_DEBUGGING
extern GC_bool GC_dump_regularly; /* Generate regular debugging dumps. */
extern GC_bool GC_dump_regularly; /* Generate regular debugging dumps. */
# define COND_DUMP if (GC_dump_regularly) GC_dump();
#else
# define COND_DUMP
@ -1730,6 +1724,13 @@ extern GC_bool GC_dump_regularly; /* Generate regular debugging dumps. */
#ifdef KEEP_BACK_PTRS
extern long GC_backtraces;
void GC_generate_random_backtrace_no_gc(void);
#endif
extern GC_bool GC_print_back_height;
#ifdef MAKE_BACK_GRAPH
void GC_print_back_graph_stats(void);
#endif
/* Macros used for collector internal allocation. */
@ -1817,6 +1818,17 @@ GC_API void GC_dump GC_PROTO((void));
# define GC_MARKED_FOR_FINALIZATION(dest)
#endif
/* Make arguments appear live to compiler */
# ifdef __WATCOMC__
void GC_noop(void*, ...);
# else
# ifdef __DMC__
GC_API void GC_noop(...);
# else
GC_API void GC_noop();
# endif
# endif
void GC_noop1 GC_PROTO((word));
/* Logging and diagnostic output: */

File diff suppressed because it is too large Load Diff

View File

@ -55,7 +55,7 @@
# endif
/* And one for FreeBSD: */
# if defined(__FreeBSD__)
# if defined(__FreeBSD__) && !defined(FREEBSD)
# define FREEBSD
# endif
@ -97,6 +97,10 @@
# define ARM32
# define mach_type_known
# endif
# if defined(NETBSD) && defined(__sh__)
# define SH
# define mach_type_known
# endif
# if defined(vax)
# define VAX
# ifdef ultrix
@ -115,8 +119,8 @@
# if defined(nec_ews) || defined(_nec_ews)
# define EWS4800
# endif
# if !defined(LINUX) && !defined(EWS4800)
# if defined(ultrix) || defined(__ultrix) || defined(__NetBSD__)
# if !defined(LINUX) && !defined(EWS4800) && !defined(NETBSD)
# if defined(ultrix) || defined(__ultrix)
# define ULTRIX
# else
# if defined(_SYSTYPE_SVR4) || defined(SYSTYPE_SVR4) \
@ -170,7 +174,7 @@
# define mach_type_known
# endif
# if defined(sparc) && defined(unix) && !defined(sun) && !defined(linux) \
&& !defined(__OpenBSD__) && !(__NetBSD__)
&& !defined(__OpenBSD__) && !defined(__NetBSD__) && !defined(__FreeBSD__)
# define SPARC
# define DRSNX
# define mach_type_known
@ -201,14 +205,16 @@
# if defined(_PA_RISC1_0) || defined(_PA_RISC1_1) || defined(_PA_RISC2_0) \
|| defined(hppa) || defined(__hppa__)
# define HP_PA
# ifndef LINUX
# if !defined(LINUX) && !defined(HPUX)
# define HPUX
# endif
# define mach_type_known
# endif
# if defined(__ia64) && defined(_HPUX_SOURCE)
# define IA64
# ifndef HPUX
# define HPUX
# endif
# define mach_type_known
# endif
# if defined(__BEOS__) && defined(_X86_)
@ -232,7 +238,18 @@
# define ARM32
# define mach_type_known
# endif
# if defined(LINUX) && (defined(powerpc) || defined(__powerpc__) || defined(powerpc64) || defined(__powerpc64__))
# if defined(LINUX) && defined(__cris__)
# ifndef CRIS
# define CRIS
# endif
# define mach_type_known
# endif
# if defined(LINUX) && (defined(powerpc) || defined(__powerpc__) || \
defined(powerpc64) || defined(__powerpc64__))
# define POWERPC
# define mach_type_known
# endif
# if defined(FREEBSD) && (defined(powerpc) || defined(__powerpc__))
# define POWERPC
# define mach_type_known
# endif
@ -252,6 +269,10 @@
# define SH
# define mach_type_known
# endif
# if defined(LINUX) && defined(__m32r__)
# define M32R
# define mach_type_known
# endif
# if defined(__alpha) || defined(__alpha__)
# define ALPHA
# if !defined(LINUX) && !defined(NETBSD) && !defined(OPENBSD) && !defined(FREEBSD)
@ -271,24 +292,22 @@
# define MACOS
# define mach_type_known
# endif
/* PLTSCHEME: added MPW_C */
# if (defined(__MWERKS__) || defined(MPW_C)) && defined(__powerc) && !defined(__MACH__)
# if defined(__MWERKS__) && defined(__powerc) && !defined(__MACH__)
# define POWERPC
# define MACOS
# define mach_type_known
# endif
# if defined(macosx) || \
defined(__APPLE__) && defined(__MACH__) && defined(__ppc__)
# if defined(macosx) || (defined(__APPLE__) && defined(__MACH__))
# define DARWIN
# if defined(__ppc__) || defined(__ppc64__)
# define POWERPC
# define mach_type_known
# endif
# if defined(__APPLE__) && defined(__MACH__) && defined(__i386__)
# define DARWIN
# if defined(__i386__)
# define I386
/* PLTSCHEME: support x86 Darwin... */
# define mach_type_known
# endif
# endif
# if defined(NeXT) && defined(mc68000)
# define M68K
# define NEXT
@ -316,6 +335,10 @@
# define X86_64
# define mach_type_known
# endif
# if defined(FREEBSD) && defined(__sparc__)
# define SPARC
# define mach_type_known
#endif
# if defined(bsdi) && (defined(i386) || defined(__i386__))
# define I386
# define BSDI
@ -426,6 +449,13 @@
# define mach_type_known
# endif
# endif
# if defined(__TANDEM)
/* Nonstop S-series */
/* FIXME: Should recognize Integrity series? */
# define MIPS
# define NONSTOP
# define mach_type_known
# endif
/* Feel free to add more clauses here */
@ -447,8 +477,8 @@
/* FREEBSD, THREE86BSD, MSWIN32, */
/* BSDI,SUNOS5, NEXT, other variants) */
/* NS32K ==> Encore Multimax */
/* MIPS ==> R2000 or R3000 */
/* (RISCOS, ULTRIX variants) */
/* MIPS ==> R2000 through R14K */
/* (many variants) */
/* VAX ==> DEC VAX */
/* (BSD, ULTRIX variants) */
/* RS6000 ==> IBM RS/6000 AIX3.X */
@ -476,17 +506,22 @@
/* POWERPC ==> IBM/Apple PowerPC */
/* (MACOS(<=9),DARWIN(incl.MACOSX),*/
/* LINUX, NETBSD, NOSYS variants) */
/* Handles 32 and 64-bit variants. */
/* AIX should be handled here, but */
/* that's called an RS6000. */
/* CRIS ==> Axis Etrax */
/* M32R ==> Renesas M32R */
/*
* For each architecture and OS, the following need to be defined:
*
* CPP_WORD_SZ is a simple integer constant representing the word size.
* CPP_WORDSZ is a simple integer constant representing the word size.
* in bits. We assume byte addressibility, where a byte has 8 bits.
* We also assume CPP_WORD_SZ is either 32 or 64.
* We also assume CPP_WORDSZ is either 32 or 64.
* (We care about the length of pointers, not hardware
* bus widths. Thus a 64 bit processor with a C compiler that uses
* 32 bit pointers should use CPP_WORD_SZ of 32, not 64. Default is 32.)
* 32 bit pointers should use CPP_WORDSZ of 32, not 64. Default is 32.)
*
* MACH_TYPE is a string representation of the machine type.
* OS_TYPE is analogous for the OS.
@ -507,6 +542,9 @@
* DATAEND, if not `end' where `end' is defined as ``extern int end[];''.
* RTH suggests gaining access to linker script synth'd values with
* this idiom instead of `&end' where `end' is defined as ``extern int end;'' .
* Otherwise, ``GCC will assume these are in .sdata/.sbss'' and it will, e.g.,
* cause failures on alpha*-*-* with ``-msmall-data or -fpic'' or mips-*-*
* without any special options.
*
* ALIGN_DOUBLE of GC_malloc should return blocks aligned to twice
* the pointer size.
@ -600,7 +638,8 @@
*/
# if defined(__GNUC__) && ((__GNUC__ >= 3) || \
(__GNUC__ == 2 && __GNUC_MINOR__ >= 8)) \
&& !defined(__INTEL_COMPILER)
&& !defined(__INTEL_COMPILER) \
&& !defined(__PATHCC__)
# define HAVE_BUILTIN_UNWIND_INIT
# endif
@ -707,12 +746,6 @@
# define GETPAGESIZE() 4096
# endif
# ifdef MACOS
/* PLTSCHEME: 4-byte alignment */
# ifdef USE_POWERPC_FOUR_BYTE_ALIGN
# define ALIGNMENT 4
# else
# define ALIGNMENT 2
# endif
# ifndef __LOWMEM__
# include <LowMem.h>
# endif
@ -730,7 +763,7 @@
# endif
# endif
# ifdef POWERPC
# if defined(POWERPC)
# define MACH_TYPE "POWERPC"
# ifdef MACOS
# define ALIGNMENT 2 /* Still necessary? Could it be 4? */
@ -743,12 +776,14 @@
# define DATAEND /* not needed */
# endif
# ifdef LINUX
# if (defined (powerpc64) || defined(__powerpc64__))
# if defined(__powerpc64__)
# define ALIGNMENT 8
# define CPP_WORDSZ 64
# ifndef HBLKSIZE
# define HBLKSIZE 4096
# endif
# else
# define ALIGNMENT 4 /* Guess. Can someone verify? */
/* This was 2, but that didn't sound right. */
# define ALIGNMENT 4
# endif
# define OS_TYPE "LINUX"
/* HEURISTIC1 has been reliably reported to fail for a 32-bit */
@ -760,7 +795,12 @@
# define DATAEND (_end)
# endif
# ifdef DARWIN
# ifdef __ppc64__
# define ALIGNMENT 8
# define CPP_WORDSZ 64
# else
# define ALIGNMENT 4
# endif
# define OS_TYPE "DARWIN"
# define DYNAMIC_LOADING
/* XXX: see get_end(3), get_etext() and get_end() should not be used.
@ -772,8 +812,10 @@
# define USE_MMAP_ANON
# define USE_ASM_PUSH_REGS
/* This is potentially buggy. It needs more testing. See the comments in
os_dep.c */
# define MPROTECT_VDB
os_dep.c. It relies on threads to track writes. */
# ifdef GC_DARWIN_THREADS
/* # define MPROTECT_VDB -- diabled for now. May work for some apps. */
# endif
# include <unistd.h>
# define GETPAGESIZE() getpagesize()
# if defined(USE_PPC_PREFETCH) && defined(__GNUC__)
@ -787,6 +829,22 @@
should be looked into some more */
# define NO_PTHREAD_TRYLOCK
# endif
# ifdef FREEBSD
# define ALIGNMENT 4
# define OS_TYPE "FREEBSD"
# ifndef GC_FREEBSD_THREADS
# define MPROTECT_VDB
# endif
# define SIG_SUSPEND SIGUSR1
# define SIG_THR_RESTART SIGUSR2
# define FREEBSD_STACKBOTTOM
# ifdef __ELF__
# define DYNAMIC_LOADING
# endif
extern char etext[];
extern char * GC_FreeBSDGetDataStart();
# define DATASTART GC_FreeBSDGetDataStart(0x1000, &etext)
# endif
# ifdef NETBSD
# define ALIGNMENT 4
# define OS_TYPE "NETBSD"
@ -922,12 +980,10 @@
extern ptr_t GC_SysVGetDataStart();
# ifdef __arch64__
# define DATASTART GC_SysVGetDataStart(0x100000, _etext)
/* libc_stack_end is not set reliably for sparc64 */
# define STACKBOTTOM ((ptr_t) 0x80000000000ULL)
# else
# define DATASTART GC_SysVGetDataStart(0x10000, _etext)
# define LINUX_STACKBOTTOM
# endif
# define LINUX_STACKBOTTOM
# endif
# ifdef OPENBSD
# define OS_TYPE "OPENBSD"
@ -946,6 +1002,23 @@
# define DATASTART ((ptr_t)(etext))
# endif
# endif
# ifdef FREEBSD
# define OS_TYPE "FREEBSD"
# define SIG_SUSPEND SIGUSR1
# define SIG_THR_RESTART SIGUSR2
# define FREEBSD_STACKBOTTOM
# ifdef __ELF__
# define DYNAMIC_LOADING
# endif
extern char etext[];
extern char edata[];
extern char end[];
# define NEED_FIND_LIMIT
# define DATASTART ((ptr_t)(&etext))
# define DATAEND (GC_find_limit (DATASTART, TRUE))
# define DATASTART2 ((ptr_t)(&edata))
# define DATAEND2 ((ptr_t)(&end))
# endif
# endif
# ifdef I386
@ -968,18 +1041,6 @@
# ifdef HAVE_BUILTIN_UNWIND_INIT
# define USE_GENERIC_PUSH_REGS
# endif
/* PLTSCHEME: I386 Darwin: */
# ifdef DARWIN
# define OS_TYPE "DARWIN"
# define DYNAMIC_LOADING
/* XXX: see get_end(3), get_etext() and get_end() should not be used.
These aren't used when dyld support is enabled (it is by default) */
# define DATASTART ((ptr_t) get_etext())
# define DATAEND ((ptr_t) get_end())
# define STACKBOTTOM ((ptr_t) 0xc0000000)
# define USE_MMAP
# define USE_MMAP_ANON
# endif
# ifdef SEQUENT
# define OS_TYPE "SEQUENT"
extern int etext[];
@ -1141,26 +1202,8 @@
# endif
# ifdef CYGWIN32
# define OS_TYPE "CYGWIN32"
extern int _data_start__[];
extern int _data_end__[];
extern int _bss_start__[];
extern int _bss_end__[];
/* For binutils 2.9.1, we have */
/* DATASTART = _data_start__ */
/* DATAEND = _bss_end__ */
/* whereas for some earlier versions it was */
/* DATASTART = _bss_start__ */
/* DATAEND = _data_end__ */
/* To get it right for both, we take the */
/* minumum/maximum of the two. */
# ifndef MAX
# define MAX(x,y) ((x) > (y) ? (x) : (y))
# endif
# ifndef MIN
# define MIN(x,y) ((x) < (y) ? (x) : (y))
# endif
# define DATASTART ((ptr_t) MIN(_data_start__, _bss_start__))
# define DATAEND ((ptr_t) MAX(_data_end__, _bss_end__))
# define DATASTART ((ptr_t)GC_DATASTART) /* From gc.h */
# define DATAEND ((ptr_t)GC_DATAEND)
# undef STACK_GRAN
# define STACK_GRAN 0x10000
# define HEURISTIC1
@ -1266,6 +1309,29 @@
/* # define MPROTECT_VDB Not quite working yet? */
# define DYNAMIC_LOADING
# endif
# ifdef DARWIN
# define OS_TYPE "DARWIN"
# define DARWIN_DONT_PARSE_STACK
# define DYNAMIC_LOADING
/* XXX: see get_end(3), get_etext() and get_end() should not be used.
These aren't used when dyld support is enabled (it is by default) */
# define DATASTART ((ptr_t) get_etext())
# define DATAEND ((ptr_t) get_end())
# define STACKBOTTOM ((ptr_t) 0xc0000000)
# define USE_MMAP
# define USE_MMAP_ANON
# define USE_ASM_PUSH_REGS
/* This is potentially buggy. It needs more testing. See the comments in
os_dep.c. It relies on threads to track writes. */
# ifdef GC_DARWIN_THREADS
/* # define MPROTECT_VDB -- disabled for now. May work for some apps. */
# endif
# include <unistd.h>
# define GETPAGESIZE() getpagesize()
/* There seems to be some issues with trylock hanging on darwin. This
should be looked into some more */
# define NO_PTHREAD_TRYLOCK
# endif /* DARWIN */
# endif
# ifdef NS32K
@ -1371,10 +1437,8 @@
# define DATAEND /* not needed */
# endif
# if defined(NETBSD)
/* This also checked for __MIPSEL__ . Why? NETBSD recognition */
/* should be handled at the top of the file. */
# define ALIGNMENT 4
# define OS_TYPE "NETBSD"
# define ALIGNMENT 4
# define HEURISTIC2
# define USE_GENERIC_PUSH_REGS
# ifdef __ELF__
@ -1387,6 +1451,16 @@
# define STACKBOTTOM ((ptr_t) 0x7ffff000)
# endif /* _ELF_ */
# endif
# if defined(NONSTOP)
# define CPP_WORDSZ 32
# define OS_TYPE "NONSTOP"
# define ALIGNMENT 4
# define DATASTART ((ptr_t) 0x08000000)
extern int _end[];
# define DATAEND (_end)
# define STACKBOTTOM ((ptr_t) 0x4fffffff)
# define USE_GENERIC_PUSH_REGS
# endif
# endif
# ifdef RS6000
@ -1406,6 +1480,8 @@
# define CPP_WORDSZ 32
# define STACKBOTTOM ((ptr_t)((ulong)&errno))
# endif
# define USE_MMAP
# define USE_MMAP_ANON
/* From AIX linker man page:
_text Specifies the first location of the program.
_etext Specifies the first location after the program.
@ -1562,7 +1638,7 @@
# endif
# ifdef LINUX
# define OS_TYPE "LINUX"
# define STACKBOTTOM ((ptr_t) 0x120000000)
# define LINUX_STACKBOTTOM
# ifdef __ELF__
# define SEARCH_FOR_DATA_START
# define DYNAMIC_LOADING
@ -1732,6 +1808,8 @@
# else
# define ALIGNMENT 8
# define CPP_WORDSZ 64
# endif
# ifndef HBLKSIZE
# define HBLKSIZE 4096
# endif
# ifdef LINUX
@ -1772,7 +1850,7 @@
# endif
# ifdef LINUX
# define OS_TYPE "LINUX"
# define HEURISTIC1
# define LINUX_STACKBOTTOM
# undef STACK_GRAN
# define STACK_GRAN 0x10000000
# define USE_GENERIC_PUSH_REGS
@ -1815,6 +1893,19 @@
# endif
#endif
# ifdef CRIS
# define MACH_TYPE "CRIS"
# define CPP_WORDSZ 32
# define ALIGNMENT 1
# define OS_TYPE "LINUX"
# define DYNAMIC_LOADING
# define LINUX_STACKBOTTOM
# define USE_GENERIC_PUSH_REGS
# define SEARCH_FOR_DATA_START
extern int _end[];
# define DATAEND (_end)
# endif
# ifdef SH
# define MACH_TYPE "SH"
# define ALIGNMENT 4
@ -1824,13 +1915,20 @@
# endif
# ifdef LINUX
# define OS_TYPE "LINUX"
# define STACKBOTTOM ((ptr_t) 0x7c000000)
# define LINUX_STACKBOTTOM
# define USE_GENERIC_PUSH_REGS
# define DYNAMIC_LOADING
# define SEARCH_FOR_DATA_START
extern int _end[];
# define DATAEND (_end)
# endif
# ifdef NETBSD
# define OS_TYPE "NETBSD"
# define HEURISTIC2
# define DATASTART GC_data_start
# define USE_GENERIC_PUSH_REGS
# define DYNAMIC_LOADING
# endif
# endif
# ifdef SH4
@ -1840,6 +1938,23 @@
# define DATAEND /* not needed */
# endif
# ifdef M32R
# define CPP_WORDSZ 32
# define MACH_TYPE "M32R"
# define ALIGNMENT 4
# ifdef LINUX
# define OS_TYPE "LINUX"
# define LINUX_STACKBOTTOM
# undef STACK_GRAN
# define STACK_GRAN 0x10000000
# define USE_GENERIC_PUSH_REGS
# define DYNAMIC_LOADING
# define SEARCH_FOR_DATA_START
extern int _end[];
# define DATAEND (_end)
# endif
# endif
# ifdef X86_64
# define MACH_TYPE "X86_64"
# define ALIGNMENT 8
@ -1953,6 +2068,11 @@
# define SUNOS5SIGS
# endif
# ifdef GC_NETBSD_THREADS
# define SIGRTMIN 33
# define SIGRTMAX 63
# endif
# if defined(SVR4) || defined(LINUX) || defined(IRIX5) || defined(HPUX) \
|| defined(OPENBSD) || defined(NETBSD) || defined(FREEBSD) \
|| defined(DGUX) || defined(BSD) || defined(SUNOS4) \
@ -2043,6 +2163,9 @@
# if defined(GC_LINUX_THREADS) && !defined(LINUX)
--> inconsistent configuration
# endif
# if defined(GC_NETBSD_THREADS) && !defined(NETBSD)
--> inconsistent configuration
# endif
# if defined(GC_SOLARIS_THREADS) && !defined(SUNOS5)
--> inconsistent configuration
# endif
@ -2062,8 +2185,9 @@
# define THREADS
# endif
# if defined(HP_PA) || defined(M88K) || defined(POWERPC) && !defined(DARWIN) \
|| defined(LINT) || defined(MSWINCE) || defined(ARM32) \
# if defined(HP_PA) || defined(M88K) \
|| defined(POWERPC) && !defined(DARWIN) \
|| defined(LINT) || defined(MSWINCE) || defined(ARM32) || defined(CRIS) \
|| (defined(I386) && defined(__LCC__))
/* Use setjmp based hack to mark from callee-save registers. */
/* The define should move to the individual platform */
@ -2175,7 +2299,7 @@
+ GC_page_size) \
+ GC_page_size-1)
# else
# if defined(NEXT) || defined(DOS4GW) || \
# if defined(NEXT) || defined(DOS4GW) || defined(NONSTOP) || \
(defined(AMIGA) && !defined(GC_AMIGA_FASTALLOC)) || \
(defined(SUNOS5) && !defined(USE_MMAP))
# define GET_MEM(bytes) HBLKPTR((size_t) \
@ -2204,7 +2328,7 @@
# else
# if defined(AMIGA) && defined(GC_AMIGA_FASTALLOC)
extern void *GC_amiga_get_mem(size_t size);
define GET_MEM(bytes) HBLKPTR((size_t) \
# define GET_MEM(bytes) HBLKPTR((size_t) \
GC_amiga_get_mem((size_t)bytes + GC_page_size) \
+ GC_page_size-1)
# else
@ -2220,4 +2344,10 @@
#endif /* GC_PRIVATE_H */
#if defined(_AIX) && !defined(__GNUC__) && !defined(__STDC__)
/* IBMs xlc compiler doesn't appear to follow the convention of */
/* defining __STDC__ to be zero in extended mode. */
# define __STDC__ 0
#endif
# endif /* GCCONFIG_H */

View File

@ -2,7 +2,6 @@
#define GC_PTHREAD_STOP_WORLD_H
struct thread_stop_info {
int signal;
word last_stop_count; /* GC_last_stop_count value when thread */
/* last successfully handled a suspend */
/* signal. */

View File

@ -4,7 +4,7 @@
# include "private/gc_priv.h"
# if defined(GC_PTHREADS) && !defined(GC_SOLARIS_THREADS) \
&& !defined(GC_IRIX_THREADS) && !defined(GC_WIN32_THREADS)
&& !defined(GC_WIN32_THREADS)
#if defined(GC_DARWIN_THREADS)
# include "private/darwin_stop_world.h"

View File

@ -27,6 +27,10 @@
# endif
# endif
#if defined(RS6000) || defined(POWERPC)
# include <ucontext.h>
#endif
#if defined(__MWERKS__) && !defined(POWERPC)
asm static void PushMacRegisters()
@ -400,19 +404,26 @@ void GC_push_regs()
}
#endif /* !USE_GENERIC_PUSH_REGS && !USE_ASM_PUSH_REGS */
#if defined(USE_GENERIC_PUSH_REGS)
void GC_generic_push_regs(cold_gc_frame)
ptr_t cold_gc_frame;
void GC_with_callee_saves_pushed(fn, arg)
void (*fn)();
ptr_t arg;
{
{
word dummy;
# if defined(USE_GENERIC_PUSH_REGS)
# ifdef HAVE_BUILTIN_UNWIND_INIT
/* This was suggested by Richard Henderson as the way to */
/* force callee-save registers and register windows onto */
/* the stack. */
__builtin_unwind_init();
# else /* !HAVE_BUILTIN_UNWIND_INIT */
# if defined(RS6000) || defined(POWERPC)
/* FIXME: RS6000 means AIX. */
/* This should probably be used in all Posix/non-gcc */
/* settings. We defer that change to minimize risk. */
ucontext_t ctxt;
getcontext(&ctxt);
# else
/* Generic code */
/* The idea is due to Parag Patel at HP. */
/* We're not sure whether he would like */
@ -426,7 +437,7 @@ ptr_t cold_gc_frame;
for (; (char *)i < lim; i++) {
*i = 0;
}
# if defined(POWERPC) || defined(MSWIN32) || defined(MSWINCE) \
# if defined(MSWIN32) || defined(MSWINCE) \
|| defined(UTS4) || defined(LINUX) || defined(EWS4800)
(void) setjmp(regs);
# else
@ -435,7 +446,17 @@ ptr_t cold_gc_frame;
/* SUSV3, setjmp() may or may not save signal mask. */
/* _setjmp won't, but is less portable. */
# endif
# endif /* !AIX ... */
# endif /* !HAVE_BUILTIN_UNWIND_INIT */
# else
# if defined(PTHREADS) && !defined(MSWIN32) /* !USE_GENERIC_PUSH_REGS */
/* We may still need this to save thread contexts. */
ucontext_t ctxt;
getcontext(&ctxt);
# else /* Shouldn't be needed */
ABORT("Unexpected call to GC_with_callee_saves_pushed");
# endif
# endif
# if (defined(SPARC) && !defined(HAVE_BUILTIN_UNWIND_INIT)) \
|| defined(IA64)
/* On a register window machine, we need to save register */
@ -452,12 +473,18 @@ ptr_t cold_gc_frame;
/* and later. */
}
# endif
GC_push_current_stack(cold_gc_frame);
fn(arg);
/* Strongly discourage the compiler from treating the above */
/* as a tail-call, since that would pop the register */
/* contents before we get a chance to look at them. */
GC_noop1((word)(&dummy));
}
}
#if defined(USE_GENERIC_PUSH_REGS)
void GC_generic_push_regs(cold_gc_frame)
ptr_t cold_gc_frame;
{
GC_with_callee_saves_pushed(GC_push_current_stack, cold_gc_frame);
}
#endif /* USE_GENERIC_PUSH_REGS */
@ -465,7 +492,7 @@ ptr_t cold_gc_frame;
/* the stack. Return sp. */
# ifdef SPARC
asm(" .seg \"text\"");
# if defined(SVR4) || defined(NETBSD)
# if defined(SVR4) || defined(NETBSD) || defined(FREEBSD)
asm(" .globl GC_save_regs_in_stack");
asm("GC_save_regs_in_stack:");
asm(" .type GC_save_regs_in_stack,#function");

View File

@ -15,6 +15,8 @@
/* Boehm, February 7, 1996 4:32 pm PST */
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include "private/gc_priv.h"
extern ptr_t GC_clear_stack(); /* in misc.c, behaves like identity */
@ -271,6 +273,26 @@ DCL_LOCK_STATE;
}
}
/* provide a version of strdup() that uses the collector to allocate the
copy of the string */
# ifdef __STDC__
char *GC_strdup(const char *s)
# else
char *GC_strdup(s)
char *s;
#endif
{
char *copy;
if (s == NULL) return NULL;
if ((copy = GC_malloc_atomic(strlen(s) + 1)) == NULL) {
errno = ENOMEM;
return NULL;
}
strcpy(copy, s);
return copy;
}
/* Allocate lb bytes of composite (pointerful) data */
# ifdef __STDC__
GC_PTR GC_malloc(size_t lb)
@ -370,6 +392,10 @@ DCL_LOCK_STATE;
{
size_t len = strlen(s) + 1;
char * result = ((char *)REDIRECT_MALLOC(len+1));
if (result == 0) {
errno = ENOMEM;
return 0;
}
BCOPY(s, result, len+1);
return result;
}

View File

@ -28,9 +28,6 @@ extern ptr_t GC_clear_stack(); /* in misc.c, behaves like identity */
void GC_extend_size_map(); /* in misc.c. */
GC_bool GC_alloc_reclaim_list(); /* in malloc.c */
/* PLTSCHEME: For MSVC /MD Compilation */
#ifndef USE_MSVC_MD_LIBRARY
/* Some externally visible but unadvertised variables to allow access to */
/* free lists from inlined allocators without including gc_priv.h */
/* or introducing dependencies on internal data structure layouts. */
@ -41,7 +38,6 @@ ptr_t * GC_CONST GC_uobjfreelist_ptr = GC_uobjfreelist;
ptr_t * GC_CONST GC_auobjfreelist_ptr = GC_auobjfreelist;
# endif
#endif /* PLTSCHEME: GC_MSVC_MD_LIBRARY */
GC_PTR GC_generic_or_special_malloc(lb,knd)
word lb;
@ -176,7 +172,8 @@ int obj_kind;
# endif /* REDIRECT_REALLOC */
/* The same thing, except caller does not hold allocation lock. */
/* Allocate memory such that only pointers to near the */
/* beginning of the object are considered. */
/* We avoid holding allocation lock while we clear memory. */
ptr_t GC_generic_malloc_ignore_off_page(lb, k)
register size_t lb;

View File

@ -25,7 +25,11 @@
/* We put this here to minimize the risk of inlining. */
/*VARARGS*/
void GC_noop(void *p, ...) {}
#ifdef __WATCOMC__
void GC_noop(void *p, ...) {}
#else
void GC_noop() {}
#endif
/* Single argument version, robust against whole program analysis. */
void GC_noop1(x)
@ -40,66 +44,30 @@ word x;
word GC_n_mark_procs = GC_RESERVED_MARK_PROCS;
/* PLTSCHEME: To work with MSVC /MD flag. Client must call GC_pre_init(). */
#ifdef USE_MSVC_MD_LIBRARY
# define INIT_FLD(x) 0
#else
# define INIT_FLD(x) x
#endif
/* Initialize GC_obj_kinds properly and standard free lists properly. */
/* This must be done statically since they may be accessed before */
/* GC_init is called. */
/* It's done here, since we need to deal with mark descriptors. */
struct obj_kind GC_obj_kinds[MAXOBJKINDS] = {
/* PTRFREE */ { INIT_FLD(&GC_aobjfreelist[0]), 0 /* filled in dynamically */,
/* PTRFREE */ { &GC_aobjfreelist[0], 0 /* filled in dynamically */,
0 | GC_DS_LENGTH, FALSE, FALSE },
/* NORMAL */ { INIT_FLD(&GC_objfreelist[0]), 0,
/* NORMAL */ { &GC_objfreelist[0], 0,
0 | GC_DS_LENGTH, /* Adjusted in GC_init_inner for EXTRA_BYTES */
TRUE /* add length to descr */, TRUE },
/* UNCOLLECTABLE */
{ INIT_FLD(&GC_uobjfreelist[0]), 0,
{ &GC_uobjfreelist[0], 0,
0 | GC_DS_LENGTH, TRUE /* add length to descr */, TRUE },
# ifdef ATOMIC_UNCOLLECTABLE
/* AUNCOLLECTABLE */
{ INIT_FLD(&GC_auobjfreelist[0]), 0,
{ &GC_auobjfreelist[0], 0,
0 | GC_DS_LENGTH, FALSE /* add length to descr */, FALSE },
# endif
# ifdef STUBBORN_ALLOC
/*STUBBORN*/ { INIT_FLD(&GC_sobjfreelist[0]), 0,
/*STUBBORN*/ { &GC_sobjfreelist[0], 0,
0 | GC_DS_LENGTH, TRUE /* add length to descr */, TRUE },
# endif
};
/* PLTSCHEME: explicit init proc */
#ifdef USE_MSVC_MD_LIBRARY
# ifdef __CYGWIN32__
# include <windows.h>
# endif
void GC_pre_init(void)
{
int i = 0;
GC_obj_kinds[i++].ok_freelist = &GC_aobjfreelist[0];
GC_obj_kinds[i++].ok_freelist = &GC_objfreelist[0];
GC_obj_kinds[i++].ok_freelist = &GC_uobjfreelist[0];
# ifdef ATOMIC_UNCOLLECTABLE
GC_obj_kinds[i++].ok_freelist = &GC_auobjfreelist[0];
# endif
# ifdef STUBBORN_ALLOC
GC_obj_kinds[i++].ok_freelist = &GC_sobjfreelist[0];
# endif
}
# ifdef MD_LIB_MAIN
BOOL WINAPI DllMain(HINSTANCE inst, ULONG reason, LPVOID reserved)
{
if (reason == DLL_PROCESS_ATTACH)
GC_pre_init();
return TRUE;
}
# endif
#endif
# ifdef ATOMIC_UNCOLLECTABLE
# ifdef STUBBORN_ALLOC
int GC_n_kinds = 5;
@ -901,9 +869,9 @@ mse * GC_steal_mark_stack(mse * low, mse * high, mse * local,
++top;
top -> mse_descr = descr;
top -> mse_start = p -> mse_start;
GC_ASSERT( top -> mse_descr & GC_DS_TAGS != GC_DS_LENGTH ||
top -> mse_descr < GC_greatest_plausible_heap_addr
- GC_least_plausible_heap_addr);
GC_ASSERT( (top -> mse_descr & GC_DS_TAGS) != GC_DS_LENGTH ||
top -> mse_descr < (ptr_t)GC_greatest_plausible_heap_addr
- (ptr_t)GC_least_plausible_heap_addr);
/* If this is a big object, count it as */
/* size/256 + 1 objects. */
++i;
@ -1493,8 +1461,8 @@ void GC_push_all_eager(bottom, top)
ptr_t bottom;
ptr_t top;
{
word * b = (word *)(((long) bottom + ALIGNMENT-1) & ~(ALIGNMENT-1));
word * t = (word *)(((long) top) & ~(ALIGNMENT-1));
word * b = (word *)(((word) bottom + ALIGNMENT-1) & ~(ALIGNMENT-1));
word * t = (word *)(((word) top) & ~(ALIGNMENT-1));
register word *p;
register word q;
register word *lim;
@ -1529,7 +1497,6 @@ ptr_t top;
ptr_t cold_gc_frame;
{
if (!NEED_FIXUP_POINTER && GC_all_interior_pointers) {
# define EAGER_BYTES 1024
/* Push the hot end of the stack eagerly, so that register values */
/* saved inside GC frames are marked before they disappear. */
/* The rest of the marking can be deferred until later. */

View File

@ -375,8 +375,11 @@ ptr_t p;
ptr_t GC_approx_sp()
{
word dummy;
VOLATILE word dummy;
dummy = 42; /* Force stack to grow if necessary. Otherwise the */
/* later accesses might cause the kernel to think we're */
/* doing something wrong. */
# ifdef _MSC_VER
# pragma warning(disable:4172)
# endif
@ -662,3 +665,4 @@ void GC_flush_mark_stack()
{
while (!GC_mark_stack_empty()) GC_mark_from_mark_stack();
}

View File

@ -34,6 +34,10 @@
# include <tchar.h>
#endif
#ifdef NONSTOP
# include <floss.h>
#endif
# ifdef THREADS
# ifdef PCR
# include "il/PCR_IL.h"
@ -246,7 +250,7 @@ void *arg2;
byte_sz = WORDS_TO_BYTES(word_sz);
if (GC_all_interior_pointers) {
/* We need one extra byte; don't fill in GC_size_map[byte_sz] */
byte_sz--;
byte_sz -= EXTRA_BYTES;
}
for (j = low_limit; j <= byte_sz; j++) GC_size_map[j] = word_sz;
@ -477,9 +481,10 @@ void GC_init()
#if defined(GC_WIN32_THREADS) && !defined(GC_PTHREADS)
if (!GC_is_initialized) {
BOOL (WINAPI *pfn) (LPCRITICAL_SECTION, DWORD) = NULL;
HMODULE hK32 = GetModuleHandle("kernel32.dll");
HMODULE hK32 = GetModuleHandleA("kernel32.dll");
if (hK32)
(FARPROC) pfn = GetProcAddress(hK32,
pfn = (BOOL (WINAPI *) (LPCRITICAL_SECTION, DWORD))
GetProcAddress (hK32,
"InitializeCriticalSectionAndSpinCount");
if (pfn)
pfn(&GC_allocate_ml, 4000);
@ -714,13 +719,6 @@ void GC_init_inner()
# endif
GC_ASSERT((signed_word)(-1) < (signed_word)0);
/* PLTSCHEME: In case we use near data for 68k Mac, this array is declared FAR */
#ifdef __MC68K__
GC_add_roots_inner((ptr_t)&GC_arrays,
(ptr_t)(((char *)&GC_arrays) + sizeof(GC_arrays)),
FALSE);
#endif
/* Add initial guess of root sets. Do this first, since sbrk(0) */
/* might be used. */
if (!GC_no_dls) /* PLTSCHEME: hack */
@ -813,7 +811,10 @@ void GC_init_inner()
void GC_enable_incremental GC_PROTO(())
{
# if !defined(SMALL_CONFIG)
# if !defined(SMALL_CONFIG) && !defined(KEEP_BACK_PTRS)
/* If we are keeping back pointers, the GC itself dirties all */
/* pages on which objects have been marked, making */
/* incremental GC pointless. */
if (!GC_find_leak) {
DCL_LOCK_STATE;
@ -1063,7 +1064,7 @@ void GC_abort(msg)
GC_CONST char * msg;
{
# if defined(MSWIN32)
//(void) MessageBoxA(NULL, msg, "Fatal error in gc", MB_ICONERROR|MB_OK);
(void) MessageBoxA(NULL, msg, "Fatal error in gc", MB_ICONERROR|MB_OK);
# else
GC_err_printf1("%s\n", msg);
# endif

View File

@ -4,7 +4,7 @@
# Created: 1993-05-16
# Public domain
# $Id: mkinstalldirs,v 1.2 2004/07/21 13:07:55 mflatt Exp $
# $Id: mkinstalldirs,v 1.13 1999/01/05 03:18:55 bje Exp $
errstatus=0
dirmode=""

View File

@ -60,6 +60,10 @@
# include <signal.h>
# endif
#if defined(LINUX) || defined(LINUX_STACKBOTTOM)
# include <ctype.h>
#endif
/* Blatantly OS dependent routines, except for those that are related */
/* to dynamic loading. */
@ -80,7 +84,7 @@
# define NEED_FIND_LIMIT
# endif
#if defined(FREEBSD) && defined(I386)
#if defined(FREEBSD) && (defined(I386) || defined(powerpc) || defined(__powerpc__))
# include <machine/trap.h>
# if !defined(PCR)
# define NEED_FIND_LIMIT
@ -245,30 +249,11 @@ word GC_apply_to_maps(word (*fn)(char *))
// XXXXXXXX-XXXXXXXX r-xp 00000000 30:05 260537 name of mapping...\n
// ^^^^^^^^ ^^^^^^^^ ^^^^ ^^
// start end prot maj_dev
// 0 9 18 32
//
// For 64 bit ABIs:
// 0 17 34 56
// Note that since about auguat 2003 kernels, the columns no longer have
// fixed offsets on 64-bit kernels. Hence we no longer rely on fixed offsets
// anywhere, which is safer anyway.
//
// 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'.)
//
#if CPP_WORDSZ == 32
# define OFFSET_MAP_START 0
# define OFFSET_MAP_END 9
# define OFFSET_MAP_PROT 18
# define OFFSET_MAP_MAJDEV 32
# define ADDR_WIDTH 8
#endif
#if CPP_WORDSZ == 64
# define OFFSET_MAP_START 0
# define OFFSET_MAP_END 17
# define OFFSET_MAP_PROT 34
# define OFFSET_MAP_MAJDEV 56
# define ADDR_WIDTH 16
#endif
/*
* Assign various fields of the first line in buf_ptr to *start, *end,
@ -277,37 +262,46 @@ word GC_apply_to_maps(word (*fn)(char *))
char *GC_parse_map_entry(char *buf_ptr, word *start, word *end,
char *prot_buf, unsigned int *maj_dev)
{
int i;
char *tok;
char *start_start, *end_start, *prot_start, *maj_dev_start;
char *p;
char *endp;
if (buf_ptr == NULL || *buf_ptr == '\0') {
return NULL;
}
memcpy(prot_buf, buf_ptr+OFFSET_MAP_PROT, 4);
/* do the protections first. */
p = buf_ptr;
while (isspace(*p)) ++p;
start_start = p;
GC_ASSERT(isxdigit(*start_start));
*start = strtoul(start_start, &endp, 16); p = endp;
GC_ASSERT(*p=='-');
++p;
end_start = p;
GC_ASSERT(isxdigit(*end_start));
*end = strtoul(end_start, &endp, 16); p = endp;
GC_ASSERT(isspace(*p));
while (isspace(*p)) ++p;
prot_start = p;
GC_ASSERT(*prot_start == 'r' || *prot_start == '-');
memcpy(prot_buf, prot_start, 4);
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+ADDR_WIDTH] = '\0';
*start = strtoul(tok, NULL, 16);
tok = buf_ptr+OFFSET_MAP_END;
buf_ptr[OFFSET_MAP_END+ADDR_WIDTH] = '\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);
if (prot_buf[1] == 'w') {/* we can skip the rest if it's not writable. */
/* Skip past protection field to offset field */
while (!isspace(*p)) ++p; while (isspace(*p)) ++p;
GC_ASSERT(isxdigit(*p));
/* Skip past offset field, which we ignore */
while (!isspace(*p)) ++p; while (isspace(*p)) ++p;
maj_dev_start = p;
GC_ASSERT(isxdigit(*maj_dev_start));
*maj_dev = strtoul(maj_dev_start, NULL, 16);
}
while (*buf_ptr && *buf_ptr++ != '\n');
while (*p && *p++ != '\n');
return buf_ptr;
return p;
}
#endif /* Need to parse /proc/self/maps. */
@ -706,7 +700,7 @@ ptr_t GC_get_stack_base()
# if defined(SUNOS5SIGS) || defined(IRIX5) || defined(OSF1) \
|| defined(HURD) || defined(NETBSD)
static struct sigaction old_segv_act;
# if defined(_sigargs) /* !Irix6.x */ || defined(HPUX) \
# if defined(IRIX5) || defined(HPUX) \
|| defined(HURD) || defined(NETBSD)
static struct sigaction old_bus_act;
# endif
@ -739,9 +733,11 @@ ptr_t GC_get_stack_base()
/* and setting a handler at the same time. */
(void) sigaction(SIGSEGV, 0, &old_segv_act);
(void) sigaction(SIGSEGV, &act, 0);
(void) sigaction(SIGBUS, 0, &old_bus_act);
(void) sigaction(SIGBUS, &act, 0);
# else
(void) sigaction(SIGSEGV, &act, &old_segv_act);
# if defined(IRIX5) && defined(_sigargs) /* Irix 5.x, not 6.x */ \
# if defined(IRIX5) \
|| defined(HPUX) || defined(HURD) || defined(NETBSD)
/* Under Irix 5.x or HP/UX, we may get SIGBUS. */
/* Pthreads doesn't exist under Irix 5.x, so we */
@ -780,7 +776,7 @@ ptr_t GC_get_stack_base()
# if defined(SUNOS5SIGS) || defined(IRIX5) \
|| defined(OSF1) || defined(HURD) || defined(NETBSD)
(void) sigaction(SIGSEGV, &old_segv_act, 0);
# if defined(IRIX5) && defined(_sigargs) /* Irix 5.x, not 6.x */ \
# if defined(IRIX5) \
|| defined(HPUX) || defined(HURD) || defined(NETBSD)
(void) sigaction(SIGBUS, &old_bus_act, 0);
# endif
@ -861,13 +857,14 @@ ptr_t GC_get_stack_base()
#include <sys/types.h>
#include <sys/stat.h>
#include <ctype.h>
# define STAT_SKIP 27 /* Number of fields preceding startstack */
/* field in /proc/self/stat */
#ifdef USE_LIBC_PRIVATES
# pragma weak __libc_stack_end
extern ptr_t __libc_stack_end;
#endif
# ifdef IA64
/* Try to read the backing store base from /proc/self/maps. */
@ -897,11 +894,14 @@ ptr_t GC_get_stack_base()
return GC_apply_to_maps(backing_store_base_from_maps);
}
# ifdef USE_LIBC_PRIVATES
# pragma weak __libc_ia64_register_backing_store_base
extern ptr_t __libc_ia64_register_backing_store_base;
# endif
ptr_t GC_get_register_stack_base(void)
{
# ifdef USE_LIBC_PRIVATES
if (0 != &__libc_ia64_register_backing_store_base
&& 0 != __libc_ia64_register_backing_store_base) {
/* Glibc 2.2.4 has a bug such that for dynamically linked */
@ -909,7 +909,8 @@ ptr_t GC_get_stack_base()
/* defined but uninitialized during constructor calls. */
/* Hence we check for both nonzero address and value. */
return __libc_ia64_register_backing_store_base;
} else {
}
# endif
word result = backing_store_base_from_proc();
if (0 == result) {
/* Use dumb heuristics. Works only for default configuration. */
@ -921,7 +922,6 @@ ptr_t GC_get_stack_base()
}
return (ptr_t)result;
}
}
# endif
ptr_t GC_linux_stack_base(void)
@ -943,6 +943,7 @@ ptr_t GC_get_stack_base()
/* since the correct value of __libc_stack_end never */
/* becomes visible to us. The second test works around */
/* this. */
# ifdef USE_LIBC_PRIVATES
if (0 != &__libc_stack_end && 0 != __libc_stack_end ) {
# ifdef IA64
/* Some versions of glibc set the address 16 bytes too */
@ -951,10 +952,20 @@ ptr_t GC_get_stack_base()
return __libc_stack_end + 0x10;
} /* Otherwise it's not safe to add 16 bytes and we fall */
/* back to using /proc. */
# else
# ifdef SPARC
/* Older versions of glibc for 64-bit Sparc do not set
* this variable correctly, it gets set to either zero
* or one.
*/
if (__libc_stack_end != (ptr_t) (unsigned long)0x1)
return __libc_stack_end;
# else
return __libc_stack_end;
# endif
# endif
}
# endif
f = open("/proc/self/stat", O_RDONLY);
if (f < 0 || STAT_READ(f, stat_buf, STAT_BUF_SIZE) < 2 * STAT_SKIP) {
ABORT("Couldn't read /proc/self/stat");
@ -1177,12 +1188,15 @@ void GC_register_data_segments()
/* This used to be set for gcc, to avoid dealing with */
/* the structured exception handling issues. But we now have */
/* assembly code to do that right. */
GC_bool GC_wnt = FALSE;
/* This is a Windows NT derivative, i.e. NT, W2K, XP or later. */
void GC_init_win32()
{
/* if we're running under win32s, assume that no DLLs will be loaded */
DWORD v = GetVersion();
GC_no_win32_dlls |= ((v & 0x80000000) && (v & 0xff) <= 3);
GC_wnt = !(v & 0x80000000);
GC_no_win32_dlls |= ((!GC_wnt) && (v & 0xff) <= 3);
}
/* Return the smallest address a such that VirtualQuery */
@ -1385,7 +1399,7 @@ int * etext_addr;
}
# endif
# if defined(FREEBSD) && defined(I386) && !defined(PCR)
# if defined(FREEBSD) && (defined(I386) || defined(powerpc) || defined(__powerpc__)) && !defined(PCR)
/* Its unclear whether this should be identical to the above, or */
/* whether it should apply to non-X86 architectures. */
/* For now we don't assume that there is always an empty page after */
@ -1494,7 +1508,7 @@ void GC_register_data_segments()
# if !defined(OS2) && !defined(PCR) && !defined(AMIGA) \
&& !defined(MSWIN32) && !defined(MSWINCE) \
&& !defined(MACOS) && !defined(DOS4GW)
&& !defined(MACOS) && !defined(DOS4GW) && !defined(NONSTOP)
# ifdef SUNOS4
extern caddr_t sbrk();
@ -1506,7 +1520,7 @@ void GC_register_data_segments()
# endif
# ifdef RS6000
# if 0 && defined(RS6000) /* We now use mmap */
/* The compiler seems to generate speculative reads one past the end of */
/* an allocated object. Hence we need to make sure that the page */
/* following the last heap page is also mapped. */
@ -1572,13 +1586,6 @@ ptr_t GC_unix_get_mem(bytes)
word bytes;
{
void *result;
/* PLTSCHEME: make sure HEAP_START and MAP_FAILED are defined: */
#if !defined(HEAP_START)
# define HEAP_START 0
#endif
#if !defined(MAP_FAILED)
# define MAP_FAILED ((void *)-1)
#endif
static ptr_t last_addr = HEAP_START;
# ifndef USE_MMAP_ANON
@ -1616,18 +1623,6 @@ word bytes;
ptr_t GC_unix_get_mem(bytes)
word bytes;
{
/* PLTSCHEME: The SunOS4 man page says not use to sbrk() with malloc().
Xt definitely breaks in SunOS 4.x if I use sbrk. */
#if defined(sun)
ptr_t mem;
mem = malloc(bytes + HBLKSIZE - 1);
if ((long)mem % HBLKSIZE)
return mem + (HBLKSIZE - ((long)mem % HBLKSIZE));
else
return mem;
#else /* PLTSCHEME: end malloc() */
ptr_t result;
# ifdef IRIX5
/* Bare sbrk isn't thread safe. Play by malloc rules. */
@ -1649,7 +1644,6 @@ word bytes;
__UNLOCK_MALLOC();
# endif
return(result);
#endif /* PLTSCHEME: close */
}
#endif /* Not USE_MMAP */
@ -1709,7 +1703,7 @@ word bytes;
/* This wastes a small amount of memory, and risks */
/* increased fragmentation. But better alternatives */
/* would require effort. */
/* PLTSCHEME: PAGE_READWRITE works better for MrEd (because I don't need execute?) */
/* PLTSCHEME: use more conservative PAGE_READWRITE */
result = (ptr_t) VirtualAlloc(NULL, bytes + 1,
MEM_COMMIT | MEM_RESERVE,
PAGE_READWRITE);
@ -2400,7 +2394,7 @@ SIG_PF GC_old_segv_handler; /* Also old MSWIN32 ACCESS_VIOLATION filter */
# endif
# ifdef FREEBSD
# define SIG_OK (sig == SIGBUS)
# define CODE_OK (code == BUS_PAGE_FAULT)
# define CODE_OK TRUE
# endif
# endif /* SUNOS4 || (FREEBSD && !SUNOS5SIGS) */
@ -2537,6 +2531,9 @@ SIG_PF GC_old_segv_handler; /* Also old MSWIN32 ACCESS_VIOLATION filter */
# else
# if defined(ARM32)
char * addr = (char *)sc.fault_address;
# else
# if defined(CRIS)
char * addr = (char *)sc.regs.csraddr;
# else
--> architecture not supported
# endif
@ -2546,6 +2543,7 @@ SIG_PF GC_old_segv_handler; /* Also old MSWIN32 ACCESS_VIOLATION filter */
# endif
# endif
# endif
# endif
# if defined(MSWIN32) || defined(MSWINCE)
char * addr = (char *) (exc_info -> ExceptionRecord
-> ExceptionInformation[1]);
@ -2961,8 +2959,7 @@ word len;
/* to the write-protected heap with a system call. */
/* This still serves as sample code if you do want to wrap system calls.*/
/* PLTSCHEME: no read() redefinition for MacOS X */
#if !defined(MSWIN32) && !defined(MSWINCE) && !defined(GC_USE_LD_WRAP) && !defined(DARWIN)
#if !defined(MSWIN32) && !defined(MSWINCE) && !defined(GC_USE_LD_WRAP)
/* Replacement for UNIX system call. */
/* Other calls that write to the heap should be handled similarly. */
/* Note that this doesn't work well for blocking reads: It will hold */
@ -3745,7 +3742,7 @@ static kern_return_t GC_forward_exception(
exception_behavior_t behavior;
thread_state_flavor_t flavor;
thread_state_data_t thread_state;
thread_state_t thread_state;
mach_msg_type_number_t thread_state_count = THREAD_STATE_MAX;
for(i=0;i<GC_old_exc_ports.count;i++)
@ -3806,13 +3803,23 @@ catch_exception_raise(
char *addr;
struct hblk *h;
int i;
#ifdef POWERPC
# if defined(POWERPC)
# if CPP_WORDSZ == 32
thread_state_flavor_t flavor = PPC_EXCEPTION_STATE;
mach_msg_type_number_t exc_state_count = PPC_EXCEPTION_STATE_COUNT;
ppc_exception_state_t exc_state;
#else
# error FIXME for non-ppc darwin
#endif
# else
thread_state_flavor_t flavor = PPC_EXCEPTION_STATE64;
mach_msg_type_number_t exc_state_count = PPC_EXCEPTION_STATE64_COUNT;
ppc_exception_state64_t exc_state;
# endif
# elif defined(I386)
thread_state_flavor_t flavor = i386_EXCEPTION_STATE;
mach_msg_type_number_t exc_state_count = i386_EXCEPTION_STATE_COUNT;
i386_exception_state_t exc_state;
# else
# error FIXME for non-ppc/x86 darwin
# endif
if(exception != EXC_BAD_ACCESS || code[0] != KERN_PROTECTION_FAILURE) {
@ -3841,7 +3848,13 @@ catch_exception_raise(
}
/* This is the address that caused the fault */
#if defined(POWERPC)
addr = (char*) exc_state.dar;
#elif defined (I386)
addr = (char*) exc_state.faultvaddr;
#else
# error FIXME for non POWERPC/I386
#endif
if((HDR(addr)) == 0) {
/* Ugh... just like the SIGBUS problem above, it seems we get a bogus
@ -3972,14 +3985,18 @@ kern_return_t catch_exception_raise_state_identity(
# if defined (DRSNX)
# include <sys/sparc/frame.h>
# else
# if defined(OPENBSD) || defined(NETBSD)
# if defined(OPENBSD)
# include <frame.h>
# else
# if defined(FREEBSD) || defined(NETBSD)
# include <machine/frame.h>
# else
# include <sys/frame.h>
# endif
# endif
# endif
# endif
# endif
# if NARGS > 6
--> We only know how to to get the first 6 arguments
# endif
@ -4004,6 +4021,16 @@ kern_return_t catch_exception_raise_state_identity(
#if NARGS == 0 && NFRAMES % 2 == 0 /* No padding */ \
&& defined(GC_HAVE_BUILTIN_BACKTRACE)
#ifdef REDIRECT_MALLOC
/* Deal with possible malloc calls in backtrace by omitting */
/* the infinitely recursing backtrace. */
# ifdef THREADS
__thread /* If your compiler doesn't understand this */
/* you could use something like pthread_getspecific. */
# endif
GC_in_save_callers = FALSE;
#endif
void GC_save_callers (info)
struct callinfo info[NFRAMES];
{
@ -4013,15 +4040,26 @@ struct callinfo info[NFRAMES];
/* We retrieve NFRAMES+1 pc values, but discard the first, since it */
/* points to our own frame. */
# ifdef REDIRECT_MALLOC
if (GC_in_save_callers) {
info[0].ci_pc = (word)(&GC_save_callers);
for (i = 1; i < NFRAMES; ++i) info[i].ci_pc = 0;
return;
}
GC_in_save_callers = TRUE;
# endif
GC_ASSERT(sizeof(struct callinfo) == sizeof(void *));
npcs = backtrace((void **)tmp_info, NFRAMES + IGNORE_FRAMES);
BCOPY(tmp_info+IGNORE_FRAMES, info, (npcs - IGNORE_FRAMES) * sizeof(void *));
for (i = npcs - IGNORE_FRAMES; i < NFRAMES; ++i) info[i].ci_pc = 0;
# ifdef REDIRECT_MALLOC
GC_in_save_callers = FALSE;
# endif
}
#else /* No builtin backtrace; do it ourselves */
#if (defined(OPENBSD) || defined(NETBSD)) && defined(SPARC)
#if (defined(OPENBSD) || defined(NETBSD) || defined(FREEBSD)) && defined(SPARC)
# define FR_SAVFP fr_fp
# define FR_SAVPC fr_pc
#else

View File

@ -1,10 +1,21 @@
#if defined(__ppc64__)
#define MODE_CHOICE(x, y) y
#else
#define MODE_CHOICE(x, y) x
#endif
#define lgu MODE_CHOICE(lwzu, ldu)
#define g_long MODE_CHOICE(long, quad) /* usage is ".g_long" */
#define LOG2_GPR_BYTES MODE_CHOICE(2,3) /* log2(GPR_BYTES) */
; GC_push_regs function. Under some optimization levels GCC will clobber
; some of the non-volatile registers before we get a chance to save them
; therefore, this can't be inline asm.
; therefore, this cannot be inline asm.
.text
.align 2
.align LOG2_GPR_BYTES
.globl _GC_push_regs
_GC_push_regs:
@ -64,7 +75,8 @@ _GC_push_regs:
; PIC stuff, generated by GCC
.data
.picsymbol_stub
.section __TEXT,__picsymbolstub1,symbol_stubs,pure_instructions,32
.align LOG2_GPR_BYTES
L_GC_push_one$stub:
.indirect_symbol _GC_push_one
mflr r0
@ -73,12 +85,11 @@ L0$_GC_push_one:
mflr r11
addis r11,r11,ha16(L_GC_push_one$lazy_ptr-L0$_GC_push_one)
mtlr r0
lwz r12,lo16(L_GC_push_one$lazy_ptr-L0$_GC_push_one)(r11)
lgu r12,lo16(L_GC_push_one$lazy_ptr-L0$_GC_push_one)(r11)
mtctr r12
addi r11,r11,lo16(L_GC_push_one$lazy_ptr-L0$_GC_push_one)
bctr
.data
.lazy_symbol_pointer
L_GC_push_one$lazy_ptr:
.indirect_symbol _GC_push_one
.long dyld_stub_binding_helper
.g_long dyld_stub_binding_helper

View File

@ -1,13 +1,17 @@
#include "private/pthread_support.h"
#if defined(GC_PTHREADS) && !defined(GC_SOLARIS_THREADS) \
&& !defined(GC_IRIX_THREADS) && !defined(GC_WIN32_THREADS) \
&& !defined(GC_DARWIN_THREADS) && !defined(GC_AIX_THREADS)
&& !defined(GC_WIN32_THREADS) && !defined(GC_DARWIN_THREADS)
#include <signal.h>
#include <semaphore.h>
#include <errno.h>
#include <unistd.h>
#include <sys/time.h>
#ifndef HPUX
# include <sys/select.h>
/* Doesn't exist on HP/UX 11.11. */
#endif
#if DEBUG_THREADS
@ -67,7 +71,22 @@ void GC_remove_allowed_signals(sigset_t *set)
static sigset_t suspend_handler_mask;
word GC_stop_count; /* Incremented at the beginning of GC_stop_world. */
volatile sig_atomic_t GC_stop_count;
/* Incremented at the beginning of GC_stop_world. */
volatile sig_atomic_t GC_world_is_stopped = FALSE;
/* FALSE ==> it is safe for threads to restart, i.e. */
/* they will see another suspend signal before they */
/* are expected to stop (unless they have voluntarily */
/* stopped). */
void GC_brief_async_signal_safe_sleep()
{
struct timeval tv;
tv.tv_sec = 0;
tv.tv_usec = 1000 * TIME_LIMIT / 2;
select(0, 0, 0, 0, &tv);
}
#ifdef GC_OSF1_THREADS
GC_bool GC_retry_signals = TRUE;
@ -88,7 +107,7 @@ word GC_stop_count; /* Incremented at the beginning of GC_stop_world. */
*/
#ifndef SIG_THR_RESTART
# if defined(GC_HPUX_THREADS) || defined(GC_OSF1_THREADS)
# if defined(GC_HPUX_THREADS) || defined(GC_OSF1_THREADS) || defined(GC_NETBSD_THREADS)
# ifdef _SIGRTMIN
# define SIG_THR_RESTART _SIGRTMIN + 5
# else
@ -101,8 +120,39 @@ word GC_stop_count; /* Incremented at the beginning of GC_stop_world. */
sem_t GC_suspend_ack_sem;
#ifdef GC_NETBSD_THREADS
# define GC_NETBSD_THREADS_WORKAROUND
/* It seems to be necessary to wait until threads have restarted. */
/* But it is unclear why that is the case. */
sem_t GC_restart_ack_sem;
#endif
void GC_suspend_handler_inner(ptr_t sig_arg);
#if defined(IA64) || defined(HP_PA)
extern void GC_with_callee_saves_pushed();
void GC_suspend_handler(int sig)
{
int old_errno = errno;
GC_with_callee_saves_pushed(GC_suspend_handler_inner, (ptr_t)(word)sig);
errno = old_errno;
}
#else
/* We believe that in all other cases the full context is already */
/* in the signal handler frame. */
void GC_suspend_handler(int sig)
{
int old_errno = errno;
GC_suspend_handler_inner((ptr_t)(word)sig);
errno = old_errno;
}
#endif
void GC_suspend_handler_inner(ptr_t sig_arg)
{
int sig = (int)(word)sig_arg;
int dummy;
pthread_t my_thread = pthread_self();
GC_thread me;
@ -152,16 +202,26 @@ void GC_suspend_handler(int sig)
/* this thread a SIG_THR_RESTART signal. */
/* SIG_THR_RESTART should be masked at this point. Thus there */
/* is no race. */
do {
me->stop_info.signal = 0;
/* We do not continue until we receive a SIG_THR_RESTART, */
/* but we do not take that as authoritative. (We may be */
/* accidentally restarted by one of the user signals we */
/* don't block.) After we receive the signal, we use a */
/* primitive and expensive mechanism to wait until it's */
/* really safe to proceed. Under normal circumstances, */
/* this code should not be executed. */
sigsuspend(&suspend_handler_mask); /* Wait for signal */
} while (me->stop_info.signal != SIG_THR_RESTART);
while (GC_world_is_stopped && GC_stop_count == my_stop_count) {
GC_brief_async_signal_safe_sleep();
# if DEBUG_THREADS
GC_err_printf0("Sleeping in signal handler");
# endif
}
/* If the RESTART signal gets lost, we can still lose. That should be */
/* less likely than losing the SUSPEND signal, since we don't do much */
/* between the sem_post and sigsuspend. */
/* We'd need more handshaking to work around that, since we don't want */
/* to accidentally leave a RESTART signal pending, thus causing us to */
/* continue prematurely in a future round. */
/* We'd need more handshaking to work around that. */
/* Simply dropping the sigsuspend call should be safe, but is unlikely */
/* to be efficient. */
#if DEBUG_THREADS
GC_printf1("Continuing 0x%lx\n", my_thread);
@ -171,20 +231,15 @@ void GC_suspend_handler(int sig)
void GC_restart_handler(int sig)
{
pthread_t my_thread = pthread_self();
GC_thread me;
if (sig != SIG_THR_RESTART) ABORT("Bad signal in suspend_handler");
/* Let the GC_suspend_handler() know that we got a SIG_THR_RESTART. */
/* The lookup here is safe, since I'm doing this on behalf */
/* of a thread which holds the allocation lock in order */
/* to stop the world. Thus concurrent modification of the */
/* data structure is impossible. */
me = GC_lookup_thread(my_thread);
me->stop_info.signal = SIG_THR_RESTART;
#ifdef GC_NETBSD_THREADS_WORKAROUND
sem_post(&GC_restart_ack_sem);
#endif
/*
** Note: even if we didn't do anything useful here,
** Note: even if we don't do anything useful here,
** it would still be necessary to have a signal handler,
** rather than ignoring the signals, otherwise
** the signals will not be delivered at all, and
@ -259,6 +314,8 @@ void GC_push_all_stacks()
(unsigned long) bs_lo, (unsigned long) bs_hi);
# endif
if (pthread_equal(p -> id, me)) {
/* FIXME: This may add an unbounded number of entries, */
/* and hence overflow the mark stack, which is bad. */
GC_push_all_eager(bs_lo, bs_hi);
} else {
GC_push_all_stack(bs_lo, bs_hi);
@ -337,6 +394,7 @@ void GC_stop_world()
/* We should have previously waited for it to become zero. */
# endif /* PARALLEL_MARK */
++GC_stop_count;
GC_world_is_stopped = TRUE;
n_live_threads = GC_suspend_all();
if (GC_retry_signals) {
@ -369,11 +427,13 @@ void GC_stop_world()
}
}
for (i = 0; i < n_live_threads; i++) {
if (0 != (code = sem_wait(&GC_suspend_ack_sem))) {
while (0 != (code = sem_wait(&GC_suspend_ack_sem))) {
if (errno != EINTR) {
GC_err_printf1("Sem_wait returned %ld\n", (unsigned long)code);
ABORT("sem_wait for handler failed");
}
}
}
# ifdef PARALLEL_MARK
GC_release_mark_lock();
# endif
@ -392,11 +452,15 @@ void GC_start_world()
register GC_thread p;
register int n_live_threads = 0;
register int result;
#ifdef GC_NETBSD_THREADS_WORKAROUND
int code;
#endif
# if DEBUG_THREADS
GC_printf0("World starting\n");
# endif
GC_world_is_stopped = FALSE;
for (i = 0; i < THREAD_TABLE_SZ; i++) {
for (p = GC_threads[i]; p != 0; p = p -> next) {
if (p -> id != my_thread) {
@ -406,7 +470,6 @@ void GC_start_world()
#if DEBUG_THREADS
GC_printf1("Sending restart signal to 0x%lx\n", p -> id);
#endif
result = pthread_kill(p -> id, SIG_THR_RESTART);
switch(result) {
case ESRCH:
@ -421,6 +484,14 @@ void GC_start_world()
}
}
}
#ifdef GC_NETBSD_THREADS_WORKAROUND
for (i = 0; i < n_live_threads; i++)
while (0 != (code = sem_wait(&GC_restart_ack_sem)))
if (errno != EINTR) {
GC_err_printf1("sem_wait() returned %ld\n", (unsigned long)code);
ABORT("sem_wait() for restart handler failed");
}
#endif
#if DEBUG_THREADS
GC_printf0("World started\n");
#endif
@ -431,6 +502,10 @@ void GC_stop_init() {
if (sem_init(&GC_suspend_ack_sem, 0, 0) != 0)
ABORT("sem_init failed");
#ifdef GC_NETBSD_THREADS_WORKAROUND
if (sem_init(&GC_restart_ack_sem, 0, 0) != 0)
ABORT("sem_init failed");
#endif
act.sa_flags = SA_RESTART;
if (sigfillset(&act.sa_mask) != 0) {

View File

@ -2,7 +2,7 @@
* Copyright (c) 1994 by Xerox Corporation. All rights reserved.
* Copyright (c) 1996 by Silicon Graphics. All rights reserved.
* Copyright (c) 1998 by Fergus Henderson. All rights reserved.
* Copyright (c) 2000-2001 by Hewlett-Packard Company. All rights reserved.
* Copyright (c) 2000-2004 by Hewlett-Packard Company. All rights reserved.
*
* THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
* OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
@ -50,8 +50,7 @@
# include "private/pthread_support.h"
# if defined(GC_PTHREADS) && !defined(GC_SOLARIS_THREADS) \
&& !defined(GC_IRIX_THREADS) && !defined(GC_WIN32_THREADS) \
&& !defined(GC_AIX_THREADS)
&& !defined(GC_WIN32_THREADS)
# if defined(GC_HPUX_THREADS) && !defined(USE_PTHREAD_SPECIFIC) \
&& !defined(USE_COMPILER_TLS)
@ -68,7 +67,9 @@
# endif
# if (defined(GC_DGUX386_THREADS) || defined(GC_OSF1_THREADS) || \
defined(GC_DARWIN_THREADS)) && !defined(USE_PTHREAD_SPECIFIC)
defined(GC_DARWIN_THREADS) || defined(GC_AIX_THREADS) || \
defined(GC_NETBSD_THREADS)) \
&& !defined(USE_PTHREAD_SPECIFIC)
# define USE_PTHREAD_SPECIFIC
# endif
@ -116,11 +117,14 @@
# include <semaphore.h>
#endif /* !GC_DARWIN_THREADS */
#if defined(GC_DARWIN_THREADS)
#if defined(GC_DARWIN_THREADS) || defined(GC_FREEBSD_THREADS)
# include <sys/sysctl.h>
#endif /* GC_DARWIN_THREADS */
#if defined(GC_NETBSD_THREADS)
# include <sys/param.h>
# include <sys/sysctl.h>
#endif /* GC_NETBSD_THREADS */
#if defined(GC_DGUX386_THREADS)
# include <sys/dg_sys_info.h>
@ -836,6 +840,18 @@ int GC_get_nprocs()
}
#endif /* GC_DGUX386_THREADS */
#if defined(GC_NETBSD_THREADS)
static int get_ncpu(void)
{
int mib[] = {CTL_HW,HW_NCPU};
int res;
size_t len = sizeof(res);
sysctl(mib, sizeof(mib)/sizeof(int), &res, &len, NULL, 0);
return res;
}
#endif /* GC_NETBSD_THREADS */
/* We hold the allocation lock. */
void GC_thr_init()
{
@ -873,14 +889,18 @@ void GC_thr_init()
# if defined(GC_HPUX_THREADS)
GC_nprocs = pthread_num_processors_np();
# endif
# if defined(GC_OSF1_THREADS)
# if defined(GC_OSF1_THREADS) || defined(GC_AIX_THREADS)
GC_nprocs = sysconf(_SC_NPROCESSORS_ONLN);
if (GC_nprocs <= 0) GC_nprocs = 1;
# endif
# if defined(GC_FREEBSD_THREADS)
GC_nprocs = 1;
# if defined(GC_IRIX_THREADS)
GC_nprocs = sysconf(_SC_NPROC_ONLN);
if (GC_nprocs <= 0) GC_nprocs = 1;
# endif
# if defined(GC_DARWIN_THREADS)
# if defined(GC_NETBSD_THREADS)
GC_nprocs = get_ncpu();
# endif
# if defined(GC_DARWIN_THREADS) || defined(GC_FREEBSD_THREADS)
int ncpus = 1;
size_t len = sizeof(ncpus);
sysctl((int[2]) {CTL_HW, HW_NCPU}, 2, &ncpus, &len, NULL, 0);
@ -927,6 +947,8 @@ void GC_thr_init()
/* Disable true incremental collection, but generational is OK. */
GC_time_limit = GC_TIME_UNLIMITED;
}
/* If we are using a parallel marker, actually start helper threads. */
if (GC_parallel) start_mark_threads();
# endif
}
@ -943,10 +965,6 @@ void GC_init_parallel()
/* GC_init() calls us back, so set flag first. */
if (!GC_is_initialized) GC_init();
/* If we are using a parallel marker, start the helper threads. */
# ifdef PARALLEL_MARK
if (GC_parallel) start_mark_threads();
# endif
/* Initialize thread local free lists if used. */
# if defined(THREAD_LOCAL_ALLOC) && !defined(DBG_HDRS_ALL)
LOCK();
@ -1222,7 +1240,7 @@ WRAP_FUNC(pthread_create)(pthread_t *new_thread,
if (!GC_thr_initialized) GC_thr_init();
# ifdef GC_ASSERTIONS
{
int stack_size;
size_t stack_size;
if (NULL == attr) {
pthread_attr_t my_attr;
pthread_attr_init(&my_attr);
@ -1230,7 +1248,13 @@ WRAP_FUNC(pthread_create)(pthread_t *new_thread,
} else {
pthread_attr_getstacksize(attr, &stack_size);
}
# ifdef PARALLEL_MARK
GC_ASSERT(stack_size >= (8*HBLKSIZE*sizeof(word)));
# else
/* FreeBSD-5.3/Alpha: default pthread stack is 64K, */
/* HBLKSIZE=8192, sizeof(word)=8 */
GC_ASSERT(stack_size >= 65536);
# endif
/* Our threads may need to do some work for the GC. */
/* Ridiculously small threads won't work, and they */
/* probably wouldn't work anyway. */

View File

@ -888,7 +888,7 @@ void GC_print_block_list()
{
struct Print_stats pstats;
GC_printf0("(kind(0=ptrfree,1=normal,2=unc.,3=stubborn):size_in_bytes, #_marks_set)\n");
GC_printf1("(kind(0=ptrfree,1=normal,2=unc.,%lu=stubborn):size_in_bytes, #_marks_set)\n", STUBBORN);
pstats.number_of_blocks = 0;
pstats.total_bytes = 0;
GC_apply_to_all_blocks(GC_print_block_descr, (word)&pstats);

View File

@ -16,9 +16,8 @@
* Modified by Peter C. for Solaris Posix Threads.
*/
# if defined(GC_SOLARIS_PTHREADS) || defined(GC_THREADS)
# include "private/gc_priv.h"
# endif
# if defined(GC_SOLARIS_PTHREADS)
# include <pthread.h>
# include <thread.h>

View File

@ -16,10 +16,7 @@
*/
/* Boehm, September 14, 1994 4:44 pm PDT */
# if defined(GC_SOLARIS_THREADS) || defined(GC_SOLARIS_PTHREADS) \
|| defined(GC_THREADS)
# include "private/gc_priv.h"
# endif
# if defined(GC_SOLARIS_THREADS) || defined(GC_SOLARIS_PTHREADS)
# include "private/solaris_threads.h"

View File

@ -11,9 +11,10 @@
* modified is included with the above copyright notice.
*/
#include "private/gc_priv.h" /* For GC_compare_and_exchange, GC_memory_barrier */
#if defined(GC_LINUX_THREADS)
#include "private/gc_priv.h" /* For GC_compare_and_exchange, GC_memory_barrier */
#include "private/specific.h"
static tse invalid_tse = {INVALID_QTID, 0, 0, INVALID_THREADID};

View File

@ -1367,6 +1367,10 @@ void check_heap_stats()
max_heap_sz = 11000000;
}
# endif
# ifndef ALIGN_DOUBLE
/* We end up needing more small object pages. */
max_heap_sz += 2000000;
# endif
# ifdef GC_DEBUG
max_heap_sz *= 2;
# ifdef SAVE_CALL_CHAIN

View File

@ -11,10 +11,21 @@ int main()
"-Wl,--wrap -Wl,pthread_sigmask -Wl,--wrap -Wl,sleep\n");
# endif
# if defined(GC_LINUX_THREADS) || defined(GC_IRIX_THREADS) \
|| defined(GC_FREEBSD_THREADS) || defined(GC_SOLARIS_PTHREADS) \
|| defined(GC_SOLARIS_PTHREADS) \
|| defined(GC_DARWIN_THREADS) || defined(GC_AIX_THREADS)
printf("-lpthread\n");
# endif
# if defined(GC_FREEBSD_THREADS)
# if (__FREEBSD_version >= 500000)
printf("-lpthread\n");
# else
printf("-pthread\n");
# endif
# endif
# if defined(GC_NETBSD_THREADS)
printf("-lpthread -lrt\n");
# endif
# if defined(GC_HPUX_THREADS) || defined(GC_OSF1_THREADS)
printf("-lpthread -lrt\n");
# endif

View File

@ -1,6 +1,6 @@
(define old-dir (current-directory))
(define new-dir "~/tmp/gc6.3")
(define new-dir "~/Desktop/gc6.7")
(define really-svn? #t)
(require (lib "file.ss")

View File

@ -2,7 +2,7 @@
/* Eventually this one may become unnecessary. For now we need */
/* it to keep the old-style build process working. */
#define GC_TMP_VERSION_MAJOR 6
#define GC_TMP_VERSION_MINOR 3
#define GC_TMP_VERSION_MINOR 7
#define GC_TMP_ALPHA_VERSION GC_NOT_ALPHA
#ifndef GC_NOT_ALPHA

View File

@ -1,6 +1,7 @@
#include "private/gc_priv.h"
#if defined(GC_WIN32_THREADS)
#include "private/gc_priv.h"
#include <windows.h>
#ifdef CYGWIN32
@ -10,6 +11,7 @@
# undef pthread_create
# undef pthread_sigmask
# undef pthread_join
# undef pthread_detach
# undef dlopen
# define DEBUG_CYGWIN_THREADS 0
@ -184,7 +186,7 @@ static void GC_delete_thread(DWORD thread_id) {
/* Must still be in_use, since nobody else can store our thread_id. */
i++) {}
if (i > my_max) {
WARN("Removing nonexisiting thread %ld\n", (GC_word)thread_id);
WARN("Removing nonexistent thread %ld\n", (GC_word)thread_id);
} else {
GC_delete_gc_thread(thread_table+i);
}
@ -231,6 +233,9 @@ void GC_push_thread_structures GC_PROTO((void))
# endif
}
/* Defined in misc.c */
extern CRITICAL_SECTION GC_write_cs;
void GC_stop_world()
{
DWORD thread_id = GetCurrentThreadId();
@ -239,6 +244,9 @@ void GC_stop_world()
if (!GC_thr_initialized) ABORT("GC_stop_world() called before GC_thr_init()");
GC_please_stop = TRUE;
# ifndef CYGWIN32
EnterCriticalSection(&GC_write_cs);
# endif /* !CYGWIN32 */
for (i = 0; i <= GC_get_max_thread_index(); i++)
if (thread_table[i].stack_base != 0
&& thread_table[i].id != thread_id) {
@ -269,6 +277,9 @@ void GC_stop_world()
# endif
thread_table[i].suspended = TRUE;
}
# ifndef CYGWIN32
LeaveCriticalSection(&GC_write_cs);
# endif /* !CYGWIN32 */
}
void GC_start_world()