Import GC 6.3alpha1.

* BCC_MAKEFILE: Merge with GC 6.3alpha1 release.
	* ChangeLog: Likewise.
	* Makefile.am: Likewise.
	* Makefile.direct: Likewise.
	* Makefile.dj: Likewise.
	* allchblk.c: Likewise.
	* alloc.c: Likewise.
	* backgraph.c: Likewise.
	* configure.host: Likewise.
	* configure.in: Likewise.
	* dbg_mlc.c: Likewise.
	* dyn_load.c: Likewise.
	* finalize.c: Likewise.
	* gc_cpp.cc: Likewise.
	* gc_dlopen.c: Likewise.
	* gcj_mlc.c: Likewise.
	* if_mach.c: Likewise.
	* mach_dep.c: Likewise.
	* malloc.c: Likewise.
	* mallocx.c: Likewise.
	* mark.c: Likewise.
	* mark_rts.c: Likewise.
	* misc.c: Likewise.
	* os_dep.c: Likewise.
	* ptr_chck.c: Likewise.
	* reclaim.c: Likewise.
	* solaris_pthreads.c: Likewise.
	* solaris_threads.c: Likewise.
	* sparc_mach_dep.S: Likewise.
	* threadlibs.c: Likewise.
	* typd_mlc.c: Likewise.
	* version.h: Likewise.
	* win32_threads.c: Likewise.
	* Mac_files/MacOS_Test_config.h: Likewise.
	* Mac_files/MacOS_config.h: Likewise.
	* cord/cordbscs.c: Likewise.
	* cord/cordprnt.c: Likewise.
	* cord/de_win.c: Likewise.
	* doc/README: Likewise.
	* doc/README.MacOSX: Likewise.
	* doc/README.changes: Likewise.
	* doc/README.environment: Likewise.
	* doc/README.ews4800: Likewise.
	* doc/README.linux: Likewise.
	* doc/README.macros: Likewise.
	* doc/README.win32: Likewise.
	* doc/debugging.html: Likewise.
	* doc/gcdescr.html: Likewise.
	* doc/tree.html: Likewise.
	* include/Makefile.in: Likewise.
	* include/gc.h: Likewise.
	* include/gc_cpp.h: Likewise.
	* include/gc_local_alloc.h: Likewise.
	* include/gc_mark.h: Likewise.
	* include/gc_pthread_redirects.h: Likewise.
	* include/gc_typed.h: Likewise.
	* include/new_gc_alloc.h: Likewise.
	* include/private/dbg_mlc.h: Likewise.
	* include/private/gc_hdrs.h: Likewise.
	* include/private/gc_locks.h: Likewise.
	* include/private/gc_pmark.h: Likewise.
	* include/private/gc_priv.h: Likewise.
	* include/private/gcconfig.h: Likewise.
	* include/private/solaris_threads.h: Likewise.
	* include/private/specific.h: Likewise.
	* tests/test.c: Likewise.
	* tests/test_cpp.cc: Likewise.

	* configure: Rebuild.
	* Makefile.in: Rebuild.

	* mips_sgi_mach_dep.s: Add.

	* alpha_mach_dep.s: Remove.
	* irix_threads.c: Remove.
	* linux_threads.c: Remove.
	* mips_sgi_mach_dep.S: Remove.
	* missing: Remove.
	* powerpc_macosx_mach_dep.s: Remove.
	* doc/Makefile.am: Remove.
	* doc/Makefile.in: Remove.

From-SVN: r69880
This commit is contained in:
Jeff Sturm 2003-07-28 04:18:23 +00:00 committed by Jeff Sturm
parent 1cb1de7ead
commit 30c3de1ffb
72 changed files with 5097 additions and 4953 deletions

View File

@ -1,29 +1,31 @@
# Makefile for Borland C++ 4.5 on NT
# For Borland 5.0, replace bc45 by bc5.
# Makefile for Borland C++ 5.5 on NT
# If you have the Borland assembler, remove "-DUSE_GENERIC"
#
bc= c:\bc45
bcbin= $(bc)\bin
bclib= $(bc)\lib
bc= c:\Borland\BCC55
bcbin= $(bc)\bin
bclib= $(bc)\lib
bcinclude= $(bc)\include
cc= $(bcbin)\bcc32
rc= $(bcbin)\brc32
lib= $(bcbin)\tlib
link= $(bcbin)\tlink32
cflags= -R -v -vi -H -H=gc.csm -I$(bcinclude);cord -L$(bclib) \
-w-pro -w-aus -w-par -w-ccc -w-rch -a4 -D__STDC__=0
gcinclude1 = $(bc)\gc6.2\include
gcinclude2 = $(bc)\gc6.2\cord
cc= $(bcbin)\bcc32
rc= $(bcbin)\brc32
lib= $(bcbin)\tlib
link= $(bcbin)\ilink32
cflags= -O2 -R -v- -vi -H -H=gc.csm -I$(bcinclude);$(gcinclude1);$(gcinclude2) -L$(bclib) \
-w-pro -w-aus -w-par -w-ccc -w-rch -a4 -D__STDC__=0
#defines= -DSILENT
defines= -DSMALL_CONFIG -DSILENT -DALL_INTERIOR_POINTERS -DUSE_GENERIC
defines= -DSMALL_CONFIG -DSILENT -DALL_INTERIOR_POINTERS -DUSE_GENERIC -DNO_GETENV -DJAVA_FINALIZATION -DGC_OPERATOR_NEW_ARRAY
.c.obj:
$(cc) @&&|
$(cdebug) $(cflags) $(cvars) $(defines) -o$* -c $*.c
$(cdebug) $(cflags) $(cvars) $(defines) -o$* -c $*.c
|
.cpp.obj:
$(cc) @&&|
$(cdebug) $(cflags) $(cvars) $(defines) -o$* -c $*.cpp
$(cdebug) $(cflags) $(cvars) $(defines) -o$* -c $*.cpp
|
.rc.res:
@ -39,31 +41,31 @@ OBJS= $(XXXOBJS:XXX=)
all: gctest.exe cord\de.exe test_cpp.exe
$(OBJS) test.obj: gc_priv.h gc_hdrs.h gc.h gcconfig.h MAKEFILE
$(OBJS) test.obj: include\private\gc_priv.h include\private\gc_hdrs.h include\gc.h include\private\gcconfig.h MAKEFILE
gc.lib: $(OBJS)
-del gc.lib
tlib $* @&&|
$(XXXOBJS:XXX=+)
del gc.lib
$(lib) $* @&&|
$(XXXOBJS:XXX=+)
|
gctest.exe: tests\test.obj gc.lib
$(cc) @&&|
$(cflags) -W -e$* tests\test.obj gc.lib
$(cflags) -W -e$* tests\test.obj gc.lib
|
cord\de.obj cord\de_win.obj: cord\cord.h cord\private\cord_pos.h cord\de_win.h \
cord\de.obj cord\de_win.obj: include\cord.h include\private\cord_pos.h cord\de_win.h \
cord\de_cmds.h
cord\de.exe: cord\cordbscs.obj cord\cordxtra.obj cord\de.obj cord\de_win.obj \
cord\de_win.res gc.lib
cord\de_win.res gc.lib
$(cc) @&&|
$(cflags) -W -e$* cord\cordbscs.obj cord\cordxtra.obj \
cord\de.obj cord\de_win.obj gc.lib
$(cflags) -W -e$* cord\cordbscs.obj cord\cordxtra.obj \
cord\de.obj cord\de_win.obj gc.lib
|
$(rc) cord\de_win.res cord\de.exe
gc_cpp.obj: gc_cpp.h gc.h
gc_cpp.obj: include\gc_cpp.h include\gc.h
gc_cpp.cpp: gc_cpp.cc
copy gc_cpp.cc gc_cpp.cpp
@ -71,12 +73,16 @@ gc_cpp.cpp: gc_cpp.cc
test_cpp.cpp: tests\test_cpp.cc
copy tests\test_cpp.cc test_cpp.cpp
test_cpp.exe: test_cpp.obj gc_cpp.h gc.h gc.lib
test_cpp.exe: test_cpp.obj include\gc_cpp.h include\gc.h gc.lib
$(cc) @&&|
$(cflags) -W -e$* test_cpp.obj gc.lib
$(cflags) -W -e$* test_cpp.obj gc.lib
|
scratch:
-del *.obj *.res *.exe *.csm cord\*.obj cord\*.res cord\*.exe cord\*.csm
clean:
del gc.lib
del *.obj
del tests\test.obj

View File

@ -1,3 +1,88 @@
2003-07-28 Jeff Sturm <jsturm@one-point.com>
Import GC 6.3alpha1.
* BCC_MAKEFILE: Merge with GC 6.3alpha1 release.
* ChangeLog: Likewise.
* Makefile.am: Likewise.
* Makefile.direct: Likewise.
* Makefile.dj: Likewise.
* allchblk.c: Likewise.
* alloc.c: Likewise.
* backgraph.c: Likewise.
* configure.host: Likewise.
* configure.in: Likewise.
* dbg_mlc.c: Likewise.
* dyn_load.c: Likewise.
* finalize.c: Likewise.
* gc_cpp.cc: Likewise.
* gc_dlopen.c: Likewise.
* gcj_mlc.c: Likewise.
* if_mach.c: Likewise.
* mach_dep.c: Likewise.
* malloc.c: Likewise.
* mallocx.c: Likewise.
* mark.c: Likewise.
* mark_rts.c: Likewise.
* misc.c: Likewise.
* os_dep.c: Likewise.
* ptr_chck.c: Likewise.
* reclaim.c: Likewise.
* solaris_pthreads.c: Likewise.
* solaris_threads.c: Likewise.
* sparc_mach_dep.S: Likewise.
* threadlibs.c: Likewise.
* typd_mlc.c: Likewise.
* version.h: Likewise.
* win32_threads.c: Likewise.
* Mac_files/MacOS_Test_config.h: Likewise.
* Mac_files/MacOS_config.h: Likewise.
* cord/cordbscs.c: Likewise.
* cord/cordprnt.c: Likewise.
* cord/de_win.c: Likewise.
* doc/README: Likewise.
* doc/README.MacOSX: Likewise.
* doc/README.changes: Likewise.
* doc/README.environment: Likewise.
* doc/README.ews4800: Likewise.
* doc/README.linux: Likewise.
* doc/README.macros: Likewise.
* doc/README.win32: Likewise.
* doc/debugging.html: Likewise.
* doc/gcdescr.html: Likewise.
* doc/tree.html: Likewise.
* include/Makefile.in: Likewise.
* include/gc.h: Likewise.
* include/gc_cpp.h: Likewise.
* include/gc_local_alloc.h: Likewise.
* include/gc_mark.h: Likewise.
* include/gc_pthread_redirects.h: Likewise.
* include/gc_typed.h: Likewise.
* include/new_gc_alloc.h: Likewise.
* include/private/dbg_mlc.h: Likewise.
* include/private/gc_hdrs.h: Likewise.
* include/private/gc_locks.h: Likewise.
* include/private/gc_pmark.h: Likewise.
* include/private/gc_priv.h: Likewise.
* include/private/gcconfig.h: Likewise.
* include/private/solaris_threads.h: Likewise.
* include/private/specific.h: Likewise.
* tests/test.c: Likewise.
* tests/test_cpp.cc: Likewise.
* configure: Rebuild.
* Makefile.in: Rebuild.
* mips_sgi_mach_dep.s: Add.
* alpha_mach_dep.s: Remove.
* irix_threads.c: Remove.
* linux_threads.c: Remove.
* mips_sgi_mach_dep.S: Remove.
* missing: Remove.
* powerpc_macosx_mach_dep.s: Remove.
* doc/Makefile.am: Remove.
* doc/Makefile.in: Remove.
2003-07-25 Roger Sayle <roger@eyesopen.com>
* configure.host: Only use +ESdbgasm when using the HPUX native

View File

@ -74,7 +74,7 @@
// implementations, and it sometimes has a significant performance
// impact. However, it is dangerous for many not-quite-ANSI C
// programs that call things like printf in asynchronous signal handlers.
// -DOPERATOR_NEW_ARRAY declares that the C++ compiler supports the
// -DGC_OPERATOR_NEW_ARRAY declares that the C++ compiler supports the
// new syntax "operator new[]" for allocating and deleting arrays.
// See gc_cpp.h for details. No effect on the C part of the collector.
// This is defined implicitly in a few environments.

View File

@ -72,7 +72,7 @@
// implementations, and it sometimes has a significant performance
// impact. However, it is dangerous for many not-quite-ANSI C
// programs that call things like printf in asynchronous signal handlers.
// -DOPERATOR_NEW_ARRAY declares that the C++ compiler supports the
// -DGC_OPERATOR_NEW_ARRAY declares that the C++ compiler supports the
// new syntax "operator new[]" for allocating and deleting arrays.
// See gc_cpp.h for details. No effect on the C part of the collector.
// This is defined implicitly in a few environments.
@ -86,4 +86,4 @@
// since some ports use malloc or calloc to obtain system memory.
// (Probably works for UNIX, and win32.)
// -DNO_DEBUG removes GC_dump and the debugging routines it calls.
// Reduces code size slightly at the expense of debuggability.
// Reduces code size slightly at the expense of debuggability.

View File

@ -18,15 +18,23 @@ MULTICLEAN = true
noinst_LTLIBRARIES = libgcjgc.la libgcjgc_convenience.la
if POWERPC_DARWIN
asm_libgc_sources = powerpc_darwin_mach_dep.s
else
asm_libgc_sources =
endif
GC_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 irix_threads.c \
linux_threads.c malloc.c mallocx.c mark.c mark_rts.c misc.c new_hblk.c \
dyn_load.c finalize.c gc_dlopen.c gcj_mlc.c headers.c aix_irix_threads.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 \
backgraph.c win32_threads.c
backgraph.c win32_threads.c \
pthread_support.c pthread_stop_world.c darwin_stop_world.c \
$(asm_libgc_sources)
EXTRA_GC_SOURCES = alpha_mach_dep.s \
mips_sgi_mach_dep.S mips_ultrix_mach_dep.s powerpc_macosx_mach_dep.s \
EXTRA_GC_SOURCES = alpha_mach_dep.S \
mips_sgi_mach_dep.s mips_ultrix_mach_dep.s powerpc_darwin_mach_dep.s \
rs6000_mach_dep.s sparc_mach_dep.S sparc_netbsd_mach_dep.s \
sparc_sunos4_mach_dep.s ia64_save_regs_in_stack.s
@ -63,7 +71,9 @@ TESTS = gctest
## FIXME: relies on internal code generated by automake.
all_objs = @addobjs@ $(libgcjgc_la_OBJECTS)
$(all_objs) : include/private/gcconfig.h include/private/gc_priv.h \
include/private/gc_hdrs.h include/gc.h include/gc_gcj.h include/gc_mark.h
include/private/gc_hdrs.h include/gc.h include/gc_gcj.h \
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.
.s.lo:

View File

@ -27,8 +27,11 @@ CFLAGS= -O -I$(srcdir)/include -DATOMIC_UNCOLLECTABLE -DNO_SIGNALS -DNO_EXECUTE_
# To build the parallel collector on Linux, add to the above:
# -DGC_LINUX_THREADS -DPARALLEL_MARK -DTHREAD_LOCAL_ALLOC
# To build the parallel collector n a static library on HP/UX, add to the above:
# To build the parallel collector in a static library on HP/UX,
# add to the above:
# -DGC_HPUX_THREADS -DPARALLEL_MARK -DTHREAD_LOCAL_ALLOC -DUSE_HPUX_TLS -D_POSIX_C_SOURCE=199506L
# To build the thread-safe collector on Tru64, add to the above:
# -pthread -DGC_OSF1_THREADS
# HOSTCC and HOSTCFLAGS are used to build executables that will be run as
# part of the build process, i.e. on the build machine. These will usually
@ -60,6 +63,16 @@ 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.
# Appeared to run into some underlying thread problems.
# -DGC_DARWIN_THREADS enables support for Mac OS X pthreads. Untested.
# -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
# for this Makefile only under Cygwin.
# -DGC_THREADS should set the appropriate one of the above macros.
# It assumes pthreads for Solaris.
# -DALL_INTERIOR_POINTERS allows all pointers to the interior
# of objects to be recognized. (See gc_priv.h for consequences.)
# Alternatively, GC_all_interior_pointers can be set at process
@ -93,13 +106,15 @@ HOSTCFLAGS=$(CFLAGS)
# See gc_cpp.h for details. No effect on the C part of the collector.
# This is defined implicitly in a few environments. Must also be defined
# by clients that use gc_cpp.h.
# -DREDIRECT_MALLOC=X causes malloc, realloc, and free to be
# defined as aliases for X, GC_realloc, and GC_free, respectively.
# -DREDIRECT_MALLOC=X causes malloc to be defined as alias for X.
# Unless the following macros are defined, realloc is also redirected
# to GC_realloc, and free is redirected to GC_free.
# Calloc and strdup are redefined in terms of the new malloc. X should
# be either GC_malloc or GC_malloc_uncollectable, or
# GC_debug_malloc_replacement. (The latter invokes GC_debug_malloc
# with dummy source location information, but still results in
# properly remembered call stacks on Linux/X86 and Solaris/SPARC.)
# properly remembered call stacks on Linux/X86 and Solaris/SPARC.
# It requires that the following two macros also be used.)
# The former is occasionally useful for working around leaks in code
# you don't want to (or can't) look at. It may not work for
# existing code, but it often does. Neither works on all platforms,
@ -111,6 +126,9 @@ HOSTCFLAGS=$(CFLAGS)
# The canonical use is -DREDIRECT_REALLOC=GC_debug_realloc_replacement,
# together with -DREDIRECT_MALLOC=GC_debug_malloc_replacement to
# generate leak reports with call stacks for both malloc and realloc.
# This also requires the following:
# -DREDIRECT_FREE=X causes free to be redirected to X. The
# canonical use is -DREDIRECT_FREE=GC_debug_free.
# -DIGNORE_FREE turns calls to free into a noop. Only useful with
# -DREDIRECT_MALLOC.
# -DNO_DEBUGGING removes GC_dump and the debugging routines it calls.
@ -197,8 +215,11 @@ HOSTCFLAGS=$(CFLAGS)
# 15% or so.
# -DUSE_3DNOW_PREFETCH causes the collector to issue AMD 3DNow style
# prefetch instructions. Same restrictions as USE_I686_PREFETCH.
# UNTESTED!!
# -DGC_USE_LD_WRAP in combination with the gld flags listed in README.linux
# Minimally tested. Didn't appear to be an obvious win on a K6-2/500.
# -DUSE_PPC_PREFETCH causes the collector to issue PowerPC style
# prefetch instructions. No effect except on PowerPC OS X platforms.
# Performance impact untested.
# -DGC_USE_LD_WRAP in combination with the old flags listed in README.linux
# causes the collector some system and pthread calls in a more transparent
# fashion than the usual macro-based approach. Requires GNU ld, and
# currently probably works only with Linux.
@ -226,6 +247,24 @@ HOSTCFLAGS=$(CFLAGS)
# -DSTUBBORN_ALLOC allows allocation of "hard to change" objects, and thus
# makes incremental collection easier. Was enabled by default until 6.0.
# Rarely used, to my knowledge.
# -DHANDLE_FORK attempts to make GC_malloc() work in a child process fork()ed
# from a multithreaded parent. Currently only supported by pthread_support.c.
# (Similar code should work on Solaris or Irix, but it hasn't been tried.)
# -DTEST_WITH_SYSTEM_MALLOC causes gctest to allocate (and leak) large chunks
# of memory with the standard system malloc. This will cause the root
# set and collected heap to grow significantly if malloced memory is
# somehow getting traced by the collector. This has no impact on the
# generated library; it only affects the test.
# -DPOINTER_MASK=0x... causes candidate pointers to be ANDed with the
# given mask before being considered. If either this or the following
# macro is defined, it will be assumed that all pointers stored in
# the heap need to be processed this way. Stack and register pointers
# will be considered both with and without processing.
# These macros are normally needed only to support systems that use
# high-order pointer tags. EXPERIMENTAL.
# -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.
#
CXXFLAGS= $(CFLAGS)
@ -233,15 +272,15 @@ 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 irix_threads.o linux_threads.o typd_mlc.o ptr_chck.o mallocx.o solaris_pthreads.o gcj_mlc.o specific.o gc_dlopen.o backgraph.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 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
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 irix_threads.c linux_threads.c typd_mlc.c ptr_chck.c mallocx.c solaris_pthreads.c gcj_mlc.c specific.c gc_dlopen.c backgraph.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 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
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
CORD_OBJS= cord/cordbscs.o cord/cordxtra.o cord/cordprnt.o
SRCS= $(CSRCS) mips_sgi_mach_dep.s rs6000_mach_dep.s alpha_mach_dep.s \
SRCS= $(CSRCS) mips_sgi_mach_dep.s rs6000_mach_dep.s alpha_mach_dep.S \
sparc_mach_dep.S include/gc.h include/gc_typed.h \
include/private/gc_hdrs.h include/private/gc_priv.h \
include/private/gcconfig.h include/private/gc_pmark.h \
@ -249,14 +288,17 @@ SRCS= $(CSRCS) mips_sgi_mach_dep.s rs6000_mach_dep.s alpha_mach_dep.s \
threadlibs.c if_mach.c if_not_there.c gc_cpp.cc include/gc_cpp.h \
gcname.c include/weakpointer.h include/private/gc_locks.h \
gcc_support.c mips_ultrix_mach_dep.s include/gc_alloc.h \
include/new_gc_alloc.h include/javaxfc.h sparc_sunos4_mach_dep.s \
sparc_netbsd_mach_dep.s \
include/new_gc_alloc.h include/gc_allocator.h \
include/javaxfc.h sparc_sunos4_mach_dep.s sparc_netbsd_mach_dep.s \
include/private/solaris_threads.h include/gc_backptr.h \
hpux_test_and_clear.s include/gc_gcj.h \
include/gc_local_alloc.h include/private/dbg_mlc.h \
include/private/specific.h powerpc_macosx_mach_dep.s \
include/private/specific.h powerpc_darwin_mach_dep.s \
include/leak_detector.h include/gc_amiga_redirects.h \
include/gc_pthread_redirects.h $(CORD_SRCS)
include/gc_pthread_redirects.h ia64_save_regs_in_stack.s \
include/gc_config_macros.h include/private/pthread_support.h \
include/private/pthread_stop_world.h include/private/darwin_semaphore.h \
include/private/darwin_stop_world.h $(CORD_SRCS)
DOC_FILES= README.QUICK doc/README.Mac doc/README.MacOSX doc/README.OS2 \
doc/README.amiga doc/README.cords doc/debugging.html \
@ -265,15 +307,19 @@ DOC_FILES= README.QUICK doc/README.Mac doc/README.MacOSX doc/README.OS2 \
doc/README.win32 doc/barrett_diagram doc/README \
doc/README.contributors doc/README.changes doc/gc.man \
doc/README.environment doc/tree.html doc/gcdescr.html \
doc/README.autoconf doc/README.macros doc/README.ews4800
doc/README.autoconf doc/README.macros doc/README.ews4800 \
doc/README.DGUX386 doc/README.arm.cross doc/leak.html \
doc/scale.html doc/gcinterface.html doc/README.darwin
TESTS= tests/test.c tests/test_cpp.cc tests/trace_test.c \
tests/leak_test.c tests/thread_leak_test.c
GNU_BUILD_FILES= configure.in Makefile.am configure acinclude.m4 \
libtool.m4 install-sh configure.host Makefile.in \
aclocal.m4 config.sub config.guess ltconfig \
ltmain.sh mkinstalldirs
ltconfig aclocal.m4 config.sub config.guess \
include/Makefile.am include/Makefile.in \
doc/Makefile.am doc/Makefile.in \
ltmain.sh mkinstalldirs depcomp missing
OTHER_MAKEFILES= OS2_MAKEFILE NT_MAKEFILE NT_THREADS_MAKEFILE gc.mak \
BCC_MAKEFILE EMX_MAKEFILE WCC_MAKEFILE Makefile.dj \
@ -285,7 +331,7 @@ OTHER_FILES= Makefile setjmp_t.c callprocs pc_excludes \
MacProjects.sit.hqx MacOS.c \
Mac_files/datastart.c Mac_files/dataend.c \
Mac_files/MacOS_config.h Mac_files/MacOS_Test_config.h \
add_gc_prefix.c gc_cpp.cpp win32_threads.c \
add_gc_prefix.c gc_cpp.cpp \
version.h AmigaOS.c \
$(TESTS) $(GNU_BUILD_FILES) $(OTHER_MAKEFILES)
@ -330,16 +376,16 @@ mach_dep.o $(SRCS)
$(OBJS) tests/test.o dyn_load.o dyn_load_sunos53.o: \
$(srcdir)/include/private/gc_priv.h \
$(srcdir)/include/private/gc_hdrs.h $(srcdir)/include/private/gc_locks.h \
$(srcdir)/include/gc.h \
$(srcdir)/include/gc.h $(srcdir)/include/gc_pthread_redirects.h \
$(srcdir)/include/private/gcconfig.h $(srcdir)/include/gc_typed.h \
Makefile
$(srcdir)/include/gc_config_macros.h Makefile
# The dependency on Makefile is needed. Changing
# options such as -DSILENT affects the size of GC_arrays,
# invalidating all .o files that rely on gc_priv.h
mark.o typd_mlc.o finalize.o ptr_chck.o: $(srcdir)/include/gc_mark.h $(srcdir)/include/private/gc_pmark.h
specific.o linux_threads.o: $(srcdir)/include/private/specific.h
specific.o pthread_support.o: $(srcdir)/include/private/specific.h
solaris_threads.o solaris_pthreads.o: $(srcdir)/include/private/solaris_threads.h
@ -434,17 +480,18 @@ liblinuxgc.so: $(OBJS) dyn_load.o
# gcc -shared -Wl,-soname=libgc.so.0 -o libgc.so.0 $(LIBOBJS) dyn_load.lo
# touch liblinuxgc.so
mach_dep.o: $(srcdir)/mach_dep.c $(srcdir)/mips_sgi_mach_dep.s $(srcdir)/mips_ultrix_mach_dep.s \
$(srcdir)/rs6000_mach_dep.s $(srcdir)/powerpc_macosx_mach_dep.s $(UTILS)
mach_dep.o: $(srcdir)/mach_dep.c $(srcdir)/mips_sgi_mach_dep.s \
$(srcdir)/mips_ultrix_mach_dep.s \
$(srcdir)/rs6000_mach_dep.s $(srcdir)/powerpc_darwin_mach_dep.s \
$(srcdir)/sparc_mach_dep.S $(srcdir)/sparc_sunos4_mach_dep.s \
$(srcdir)/ia64_save_regs_in_stack.s \
$(srcdir)/sparc_netbsd_mach_dep.s $(UTILS)
rm -f mach_dep.o
./if_mach MIPS IRIX5 $(AS) -o mach_dep.o $(srcdir)/mips_sgi_mach_dep.s
./if_mach MIPS IRIX5 $(CC) -c -o mach_dep.o $(srcdir)/mips_sgi_mach_dep.s
./if_mach MIPS RISCOS $(AS) -o mach_dep.o $(srcdir)/mips_ultrix_mach_dep.s
./if_mach MIPS ULTRIX $(AS) -o mach_dep.o $(srcdir)/mips_ultrix_mach_dep.s
./if_mach RS6000 "" $(AS) -o mach_dep.o $(srcdir)/rs6000_mach_dep.s
./if_mach POWERPC MACOSX $(AS) -o mach_dep.o $(srcdir)/powerpc_macosx_mach_dep.s
# ./if_mach ALPHA "" $(AS) -o mach_dep.o $(srcdir)/alpha_mach_dep.s
# alpha_mach_dep.s assumes that pointers are not saved in fp registers.
# Gcc on a 21264 can spill pointers to fp registers. Oops.
./if_mach POWERPC DARWIN $(AS) -o mach_dep.o $(srcdir)/powerpc_darwin_mach_dep.s
./if_mach ALPHA LINUX $(CC) -c -o mach_dep.o $(srcdir)/alpha_mach_dep.S
./if_mach SPARC SUNOS5 $(CC) -c -o mach_dep.o $(srcdir)/sparc_mach_dep.S
./if_mach SPARC SUNOS4 $(AS) -o mach_dep.o $(srcdir)/sparc_sunos4_mach_dep.s
./if_mach SPARC OPENBSD $(AS) -o mach_dep.o $(srcdir)/sparc_sunos4_mach_dep.s
@ -491,7 +538,7 @@ cord/de: $(srcdir)/cord/de.c cord/cordbscs.o cord/cordxtra.o gc.a $(UTILS)
./if_mach SPARC DRSNX $(CC) $(CFLAGS) -o cord/de $(srcdir)/cord/de.c cord/cordbscs.o cord/cordxtra.o gc.a $(CURSES) -lucb `./threadlibs`
./if_mach HP_PA HPUX $(CC) $(CFLAGS) -o cord/de $(srcdir)/cord/de.c cord/cordbscs.o cord/cordxtra.o gc.a $(CURSES) -ldld `./threadlibs`
./if_mach RS6000 "" $(CC) $(CFLAGS) -o cord/de $(srcdir)/cord/de.c cord/cordbscs.o cord/cordxtra.o gc.a -lcurses
./if_mach POWERPC MACOSX $(CC) $(CFLAGS) -o cord/de $(srcdir)/cord/de.c cord/cordbscs.o cord/cordxtra.o gc.a
./if_mach POWERPC DARWIN $(CC) $(CFLAGS) -o cord/de $(srcdir)/cord/de.c cord/cordbscs.o cord/cordxtra.o gc.a
./if_mach I386 LINUX $(CC) $(CFLAGS) -o cord/de $(srcdir)/cord/de.c cord/cordbscs.o cord/cordxtra.o gc.a -lcurses `./threadlibs`
./if_mach ALPHA LINUX $(CC) $(CFLAGS) -o cord/de $(srcdir)/cord/de.c cord/cordbscs.o cord/cordxtra.o gc.a -lcurses `./threadlibs`
./if_mach IA64 LINUX $(CC) $(CFLAGS) -o cord/de $(srcdir)/cord/de.c cord/cordbscs.o cord/cordxtra.o gc.a -lcurses `./threadlibs`
@ -510,7 +557,7 @@ if_not_there: $(srcdir)/if_not_there.c
clean:
rm -f gc.a *.o *.exe tests/*.o gctest gctest_dyn_link test_cpp \
setjmp_test mon.out gmon.out a.out core if_not_there if_mach \
threadlibs $(CORD_OBJS) cord/cordtest cord/de
threadlibs $(CORD_OBJS) cord/cordtest cord/de
-rm -f *~
gctest: tests/test.o gc.a $(UTILS)

View File

@ -152,7 +152,7 @@ CFLAGS= -O -I$(srcdir)/include -DATOMIC_UNCOLLECTABLE -DNO_SIGNALS -DALL_INTERIO
# currently probably works only with Linux.
CXXFLAGS= $(CFLAGS) -DOPERATOR_NEW_ARRAY
CXXFLAGS= $(CFLAGS) -DGC_OPERATOR_NEW_ARRAY
AR= ar
RANLIB= ranlib
@ -165,8 +165,8 @@ CORD_SRCS= cord/cordbscs.c cord/cordxtra.c cord/cordprnt.c cord/de.c cord/cordt
CORD_OBJS= cord/cordbscs.o cord/cordxtra.o cord/cordprnt.o
SRCS= $(CSRCS) mips_sgi_mach_dep.s rs6000_mach_dep.s alpha_mach_dep.s \
sparc_mach_dep.s include/gc.h include/gc_typed.h \
SRCS= $(CSRCS) mips_sgi_mach_dep.S rs6000_mach_dep.s alpha_mach_dep.S \
sparc_mach_dep.S include/gc.h include/gc_typed.h \
include/private/gc_hdrs.h include/private/gc_priv.h \
include/private/gcconfig.h include/private/gc_mark.h \
include/gc_inl.h include/gc_inline.h gc.man \
@ -177,7 +177,7 @@ SRCS= $(CSRCS) mips_sgi_mach_dep.s rs6000_mach_dep.s alpha_mach_dep.s \
include/private/solaris_threads.h include/gc_backptr.h \
hpux_test_and_clear.s include/gc_gcj.h \
include/gc_local_alloc.h include/private/dbg_mlc.h \
include/private/specific.h powerpc_macosx_mach_dep.s \
include/private/specific.h powerpc_darwin_mach_dep.s \
include/leak_detector.h $(CORD_SRCS)
OTHER_FILES= Makefile PCR-Makefile OS2_MAKEFILE NT_MAKEFILE BCC_MAKEFILE \
@ -284,16 +284,16 @@ liblinuxgc.so: $(OBJS) dyn_load.o
gcc -shared -o liblinuxgc.so $(OBJS) dyn_load.o -lo
ln liblinuxgc.so libgc.so
mach_dep.o: $(srcdir)/mach_dep.c $(srcdir)/mips_sgi_mach_dep.s $(srcdir)/mips_ultrix_mach_dep.s \
$(srcdir)/rs6000_mach_dep.s $(srcdir)/powerpc_macosx_mach_dep.s $(UTILS)
mach_dep.o: $(srcdir)/mach_dep.c $(srcdir)/mips_sgi_mach_dep.S $(srcdir)/mips_ultrix_mach_dep.s \
$(srcdir)/rs6000_mach_dep.s $(srcdir)/powerpc_darwin_mach_dep.s $(UTILS)
rm -f mach_dep.o
./if_mach MIPS IRIX5 $(AS) -o mach_dep.o $(srcdir)/mips_sgi_mach_dep.s
./if_mach MIPS IRIX5 $(AS) -o mach_dep.o $(srcdir)/mips_sgi_mach_dep.S
./if_mach MIPS RISCOS $(AS) -o mach_dep.o $(srcdir)/mips_ultrix_mach_dep.s
./if_mach MIPS ULTRIX $(AS) -o mach_dep.o $(srcdir)/mips_ultrix_mach_dep.s
./if_mach RS6000 "" $(AS) -o mach_dep.o $(srcdir)/rs6000_mach_dep.s
./if_mach POWERPC MACOSX $(AS) -o mach_dep.o $(srcdir)/powerpc_macosx_mach_dep.s
./if_mach ALPHA "" $(AS) -o mach_dep.o $(srcdir)/alpha_mach_dep.s
./if_mach SPARC SUNOS5 $(AS) -o mach_dep.o $(srcdir)/sparc_mach_dep.s
./if_mach POWERPC MACOSX $(AS) -o mach_dep.o $(srcdir)/powerpc_darwin_mach_dep.s
./if_mach ALPHA "" $(AS) -o mach_dep.o $(srcdir)/alpha_mach_dep.S
./if_mach SPARC SUNOS5 $(AS) -o mach_dep.o $(srcdir)/sparc_mach_dep.S
./if_mach SPARC SUNOS4 $(AS) -o mach_dep.o $(srcdir)/sparc_sunos4_mach_dep.s
./if_not_there mach_dep.o $(CC) -c $(SPECIALCFLAGS) $(srcdir)/mach_dep.c

View File

@ -1,6 +1,6 @@
# Makefile.in generated automatically by automake 1.4 from Makefile.am
# Makefile.in generated automatically by automake 1.4-p5 from Makefile.am
# Copyright (C) 1994, 1995-8, 1999 Free Software Foundation, Inc.
# Copyright (C) 1994, 1995-8, 1999, 2001 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.
@ -66,9 +66,11 @@ target_triplet = @target@
AR = @AR@
AS = @AS@
CC = @CC@
CFLAGS = @CFLAGS@
CPP = @CPP@
CXX = @CXX@
CXXCPP = @CXXCPP@
CXXFLAGS = @CXXFLAGS@
CXXINCLUDES = @CXXINCLUDES@
DLLTOOL = @DLLTOOL@
EXEEXT = @EXEEXT@
@ -89,7 +91,10 @@ RANLIB = @RANLIB@
STRIP = @STRIP@
THREADLIBS = @THREADLIBS@
VERSION = @VERSION@
addincludes = @addincludes@
addlibs = @addlibs@
addobjs = @addobjs@
addtests = @addtests@
gc_basedir = @gc_basedir@
mkinstalldirs = @mkinstalldirs@
target_all = @target_all@
@ -109,17 +114,21 @@ MULTIDO = true
MULTICLEAN = true
noinst_LTLIBRARIES = libgcjgc.la libgcjgc_convenience.la
@POWERPC_DARWIN_TRUE@asm_libgc_sources = @POWERPC_DARWIN_TRUE@powerpc_darwin_mach_dep.s
@POWERPC_DARWIN_FALSE@asm_libgc_sources =
GC_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 irix_threads.c \
linux_threads.c malloc.c mallocx.c mark.c mark_rts.c misc.c new_hblk.c \
dyn_load.c finalize.c gc_dlopen.c gcj_mlc.c headers.c aix_irix_threads.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 \
backgraph.c win32_threads.c
backgraph.c win32_threads.c \
pthread_support.c pthread_stop_world.c darwin_stop_world.c \
$(asm_libgc_sources)
EXTRA_GC_SOURCES = alpha_mach_dep.s \
mips_sgi_mach_dep.S mips_ultrix_mach_dep.s powerpc_macosx_mach_dep.s \
EXTRA_GC_SOURCES = alpha_mach_dep.S \
mips_sgi_mach_dep.s mips_ultrix_mach_dep.s powerpc_darwin_mach_dep.s \
rs6000_mach_dep.s sparc_mach_dep.S sparc_netbsd_mach_dep.s \
sparc_sunos4_mach_dep.s ia64_save_regs_in_stack.s
@ -213,24 +222,53 @@ DEFS = @DEFS@ -I. -I$(srcdir)
CPPFLAGS = @CPPFLAGS@
LDFLAGS = @LDFLAGS@
LIBS = @LIBS@
libgcjgc_la_OBJECTS = allchblk.lo alloc.lo blacklst.lo checksums.lo \
dbg_mlc.lo dyn_load.lo finalize.lo gc_dlopen.lo gcj_mlc.lo headers.lo \
irix_threads.lo linux_threads.lo malloc.lo mallocx.lo mark.lo \
mark_rts.lo misc.lo new_hblk.lo obj_map.lo os_dep.lo pcr_interface.lo \
ptr_chck.lo real_malloc.lo reclaim.lo solaris_pthreads.lo \
solaris_threads.lo specific.lo stubborn.lo typd_mlc.lo backgraph.lo \
win32_threads.lo
@POWERPC_DARWIN_FALSE@libgcjgc_la_OBJECTS = allchblk.lo alloc.lo \
@POWERPC_DARWIN_FALSE@blacklst.lo checksums.lo dbg_mlc.lo dyn_load.lo \
@POWERPC_DARWIN_FALSE@finalize.lo gc_dlopen.lo gcj_mlc.lo headers.lo \
@POWERPC_DARWIN_FALSE@aix_irix_threads.lo malloc.lo mallocx.lo mark.lo \
@POWERPC_DARWIN_FALSE@mark_rts.lo misc.lo new_hblk.lo obj_map.lo \
@POWERPC_DARWIN_FALSE@os_dep.lo pcr_interface.lo ptr_chck.lo \
@POWERPC_DARWIN_FALSE@real_malloc.lo reclaim.lo solaris_pthreads.lo \
@POWERPC_DARWIN_FALSE@solaris_threads.lo specific.lo stubborn.lo \
@POWERPC_DARWIN_FALSE@typd_mlc.lo backgraph.lo win32_threads.lo \
@POWERPC_DARWIN_FALSE@pthread_support.lo pthread_stop_world.lo \
@POWERPC_DARWIN_FALSE@darwin_stop_world.lo
@POWERPC_DARWIN_TRUE@libgcjgc_la_OBJECTS = allchblk.lo alloc.lo \
@POWERPC_DARWIN_TRUE@blacklst.lo checksums.lo dbg_mlc.lo dyn_load.lo \
@POWERPC_DARWIN_TRUE@finalize.lo gc_dlopen.lo gcj_mlc.lo headers.lo \
@POWERPC_DARWIN_TRUE@aix_irix_threads.lo malloc.lo mallocx.lo mark.lo \
@POWERPC_DARWIN_TRUE@mark_rts.lo misc.lo new_hblk.lo obj_map.lo \
@POWERPC_DARWIN_TRUE@os_dep.lo pcr_interface.lo ptr_chck.lo \
@POWERPC_DARWIN_TRUE@real_malloc.lo reclaim.lo solaris_pthreads.lo \
@POWERPC_DARWIN_TRUE@solaris_threads.lo specific.lo stubborn.lo \
@POWERPC_DARWIN_TRUE@typd_mlc.lo backgraph.lo win32_threads.lo \
@POWERPC_DARWIN_TRUE@pthread_support.lo pthread_stop_world.lo \
@POWERPC_DARWIN_TRUE@darwin_stop_world.lo powerpc_darwin_mach_dep.lo
libgcjgc_convenience_la_LDFLAGS =
libgcjgc_convenience_la_OBJECTS = allchblk.lo alloc.lo blacklst.lo \
checksums.lo dbg_mlc.lo dyn_load.lo finalize.lo gc_dlopen.lo gcj_mlc.lo \
headers.lo irix_threads.lo linux_threads.lo malloc.lo mallocx.lo \
mark.lo mark_rts.lo misc.lo new_hblk.lo obj_map.lo os_dep.lo \
pcr_interface.lo ptr_chck.lo real_malloc.lo reclaim.lo \
solaris_pthreads.lo solaris_threads.lo specific.lo stubborn.lo \
typd_mlc.lo backgraph.lo win32_threads.lo
@POWERPC_DARWIN_FALSE@libgcjgc_convenience_la_OBJECTS = allchblk.lo \
@POWERPC_DARWIN_FALSE@alloc.lo blacklst.lo checksums.lo dbg_mlc.lo \
@POWERPC_DARWIN_FALSE@dyn_load.lo finalize.lo gc_dlopen.lo gcj_mlc.lo \
@POWERPC_DARWIN_FALSE@headers.lo aix_irix_threads.lo malloc.lo \
@POWERPC_DARWIN_FALSE@mallocx.lo mark.lo mark_rts.lo misc.lo \
@POWERPC_DARWIN_FALSE@new_hblk.lo obj_map.lo os_dep.lo pcr_interface.lo \
@POWERPC_DARWIN_FALSE@ptr_chck.lo real_malloc.lo reclaim.lo \
@POWERPC_DARWIN_FALSE@solaris_pthreads.lo solaris_threads.lo \
@POWERPC_DARWIN_FALSE@specific.lo stubborn.lo typd_mlc.lo backgraph.lo \
@POWERPC_DARWIN_FALSE@win32_threads.lo pthread_support.lo \
@POWERPC_DARWIN_FALSE@pthread_stop_world.lo darwin_stop_world.lo
@POWERPC_DARWIN_TRUE@libgcjgc_convenience_la_OBJECTS = allchblk.lo \
@POWERPC_DARWIN_TRUE@alloc.lo blacklst.lo checksums.lo dbg_mlc.lo \
@POWERPC_DARWIN_TRUE@dyn_load.lo finalize.lo gc_dlopen.lo gcj_mlc.lo \
@POWERPC_DARWIN_TRUE@headers.lo aix_irix_threads.lo malloc.lo \
@POWERPC_DARWIN_TRUE@mallocx.lo mark.lo mark_rts.lo misc.lo new_hblk.lo \
@POWERPC_DARWIN_TRUE@obj_map.lo os_dep.lo pcr_interface.lo ptr_chck.lo \
@POWERPC_DARWIN_TRUE@real_malloc.lo reclaim.lo solaris_pthreads.lo \
@POWERPC_DARWIN_TRUE@solaris_threads.lo specific.lo stubborn.lo \
@POWERPC_DARWIN_TRUE@typd_mlc.lo backgraph.lo win32_threads.lo \
@POWERPC_DARWIN_TRUE@pthread_support.lo pthread_stop_world.lo \
@POWERPC_DARWIN_TRUE@darwin_stop_world.lo powerpc_darwin_mach_dep.lo
check_PROGRAMS = gctest$(EXEEXT)
gctest_DEPENDENCIES = ./libgcjgc.la
CFLAGS = @CFLAGS@
COMPILE = $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
CCLD = $(CC)
DIST_COMMON = ChangeLog Makefile.am Makefile.in acinclude.m4 aclocal.m4 \
@ -368,7 +406,7 @@ maintainer-clean-recursive:
dot_seen=no; \
rev=''; list='$(SUBDIRS)'; for subdir in $$list; do \
rev="$$subdir $$rev"; \
test "$$subdir" = "." && dot_seen=yes; \
test "$$subdir" != "." || dot_seen=yes; \
done; \
test "$$dot_seen" = "no" && rev=". $$rev"; \
target=`echo $@ | sed s/-recursive//`; \
@ -598,7 +636,9 @@ mostlyclean distclean maintainer-clean
test.o: tests/test.c
$(COMPILE) -c $(srcdir)/tests/test.c
$(all_objs) : include/private/gcconfig.h include/private/gc_priv.h \
include/private/gc_hdrs.h include/gc.h include/gc_gcj.h include/gc_mark.h
include/private/gc_hdrs.h include/gc.h include/gc_gcj.h \
include/gc_pthread_redirects.h include/gc_config_macros.h \
include/gc_mark.h @addincludes@
.s.lo:
$(LTCOMPILE) -Wp,-P -x assembler-with-cpp -c $<

View File

@ -47,12 +47,16 @@ GC_bool GC_use_entire_heap = 0;
struct hblk * GC_hblkfreelist[N_HBLK_FLS+1] = { 0 };
#ifndef USE_MUNMAP
word GC_free_bytes[N_HBLK_FLS+1] = { 0 };
/* Number of free bytes on each list. */
/* Is bytes + the number of free bytes on lists n .. N_HBLK_FLS */
/* > GC_max_large_allocd_bytes? */
GC_bool GC_enough_large_bytes_left(bytes,n)
# ifdef __GNUC__
__inline__
# endif
static GC_bool GC_enough_large_bytes_left(bytes,n)
word bytes;
int n;
{
@ -583,11 +587,11 @@ int n;
if (!GC_use_entire_heap
&& size_avail != size_needed
&& USED_HEAP_SIZE >= GC_requested_heapsize
&& !GC_incremental && GC_should_collect()) {
&& !TRUE_INCREMENTAL && GC_should_collect()) {
# ifdef USE_MUNMAP
continue;
# else
/* If we enough large blocks left to cover any */
/* If we have enough large blocks left to cover any */
/* previous request for large blocks, we go ahead */
/* and split. Assuming a steady state, that should */
/* be safe. It means that we can use the full */
@ -595,6 +599,12 @@ int n;
if (!GC_enough_large_bytes_left(GC_large_allocd_bytes, n)) {
continue;
}
/* If we are deallocating lots of memory from */
/* finalizers, fail and collect sooner rather */
/* than later. */
if (GC_finalizer_mem_freed > (GC_heapsize >> 4)) {
continue;
}
# endif /* !USE_MUNMAP */
}
/* If the next heap block is obviously better, go on. */

View File

@ -72,6 +72,13 @@ int GC_full_freq = 19; /* Every 20th collection is a full */
GC_bool GC_need_full_gc = FALSE;
/* Need full GC do to heap growth. */
#ifdef THREADS
GC_bool GC_world_stopped = FALSE;
# define IF_THREADS(x) x
#else
# define IF_THREADS(x)
#endif
word GC_used_heap_size_after_full = 0;
char * GC_copyright[] =
@ -160,7 +167,7 @@ static word min_words_allocd()
+ (GC_large_free_bytes >> 2)
/* use a bit more of large empty heap */
+ total_root_size);
if (GC_incremental) {
if (TRUE_INCREMENTAL) {
return scan_size / (2 * GC_free_space_divisor);
} else {
return scan_size / GC_free_space_divisor;
@ -182,7 +189,8 @@ word GC_adj_words_allocd()
/* managed object should not alter result, assuming the client */
/* is playing by the rules. */
result = (signed_word)GC_words_allocd
- (signed_word)GC_mem_freed - expl_managed;
- (signed_word)GC_mem_freed
+ (signed_word)GC_finalizer_mem_freed - expl_managed;
if (result > (signed_word)GC_words_allocd) {
result = GC_words_allocd;
/* probably client bug or unfortunate scheduling */
@ -250,7 +258,6 @@ void GC_maybe_gc()
if (GC_should_collect()) {
if (!GC_incremental) {
GC_notify_full_gc();
GC_gcollect_inner();
n_partial_gcs = 0;
return;
@ -302,10 +309,14 @@ void GC_maybe_gc()
/*
* Stop the world garbage collection. Assumes lock held, signals disabled.
* If stop_func is not GC_never_stop_func, then abort if stop_func returns TRUE.
* Return TRUE if we successfully completed the collection.
*/
GC_bool GC_try_to_collect_inner(stop_func)
GC_stop_func stop_func;
{
# ifdef CONDPRINT
CLOCK_TYPE start_time, current_time;
# endif
if (GC_dont_gc) return FALSE;
if (GC_incremental && GC_collection_in_progress()) {
# ifdef CONDPRINT
@ -320,8 +331,10 @@ GC_stop_func stop_func;
GC_collect_a_little_inner(1);
}
}
if (stop_func == GC_never_stop_func) GC_notify_full_gc();
# ifdef CONDPRINT
if (GC_print_stats) {
if (GC_print_stats) GET_TIME(start_time);
GC_printf2(
"Initiating full world-stop collection %lu after %ld allocd bytes\n",
(unsigned long) GC_gc_no+1,
@ -360,6 +373,13 @@ GC_stop_func stop_func;
return(FALSE);
}
GC_finish_collection();
# if defined(CONDPRINT)
if (GC_print_stats) {
GET_TIME(current_time);
GC_printf1("Complete collection took %lu msecs\n",
MS_TIME_DIFF(current_time,start_time));
}
# endif
return(TRUE);
}
@ -430,6 +450,7 @@ int GC_collect_a_little GC_PROTO(())
result = (int)GC_collection_in_progress();
UNLOCK();
ENABLE_SIGNALS();
if (!result && GC_debugging_started) GC_print_all_smashed();
return(result);
}
@ -448,16 +469,17 @@ GC_stop_func stop_func;
CLOCK_TYPE start_time, current_time;
# endif
# if defined(REGISTER_LIBRARIES_EARLY)
GC_cond_register_dynamic_libraries();
# endif
STOP_WORLD();
# ifdef PRINTTIMES
GET_TIME(start_time);
# endif
# if defined(CONDPRINT) && !defined(PRINTTIMES)
if (GC_print_stats) GET_TIME(start_time);
# endif
# if defined(REGISTER_LIBRARIES_EARLY)
GC_cond_register_dynamic_libraries();
# endif
STOP_WORLD();
IF_THREADS(GC_world_stopped = TRUE);
# ifdef CONDPRINT
if (GC_print_stats) {
GC_printf1("--> Marking for collection %lu ",
@ -488,6 +510,7 @@ GC_stop_func stop_func;
}
# endif
GC_deficit = i; /* Give the mutator a chance. */
IF_THREADS(GC_world_stopped = FALSE);
START_WORLD();
return(FALSE);
}
@ -521,6 +544,8 @@ GC_stop_func stop_func;
(*GC_check_heap)();
}
IF_THREADS(GC_world_stopped = FALSE);
START_WORLD();
# ifdef PRINTTIMES
GET_TIME(current_time);
GC_printf1("World-stopped marking took %lu msecs\n",
@ -534,7 +559,6 @@ GC_stop_func stop_func;
}
# endif
# endif
START_WORLD();
return(TRUE);
}
@ -611,6 +635,7 @@ void GC_finish_collection()
GC_print_address_map();
}
# endif
COND_DUMP;
if (GC_find_leak) {
/* Mark all objects on the free list. All objects should be */
/* marked when we're done. */
@ -707,6 +732,7 @@ void GC_finish_collection()
GC_words_allocd = 0;
GC_words_wasted = 0;
GC_mem_freed = 0;
GC_finalizer_mem_freed = 0;
# ifdef USE_MUNMAP
GC_unmap_old();
@ -730,6 +756,7 @@ void GC_finish_collection()
int result;
DCL_LOCK_STATE;
if (GC_debugging_started) GC_print_all_smashed();
GC_INVOKE_FINALIZERS();
DISABLE_SIGNALS();
LOCK();
@ -741,14 +768,17 @@ void GC_finish_collection()
EXIT_GC();
UNLOCK();
ENABLE_SIGNALS();
if(result) GC_INVOKE_FINALIZERS();
if(result) {
if (GC_debugging_started) GC_print_all_smashed();
GC_INVOKE_FINALIZERS();
}
return(result);
}
void GC_gcollect GC_PROTO(())
{
GC_notify_full_gc();
(void)GC_try_to_collect(GC_never_stop_func);
if (GC_have_errors) GC_print_all_errors();
}
word GC_n_heap_sects = 0; /* Number of sections currently in heap. */
@ -950,7 +980,6 @@ GC_bool ignore_off_page;
{
if (!GC_incremental && !GC_dont_gc &&
(GC_dont_expand && GC_words_allocd > 0 || GC_should_collect())) {
GC_notify_full_gc();
GC_gcollect_inner();
} else {
word blocks_to_get = GC_heapsize/(HBLKSIZE*GC_free_space_divisor)
@ -975,7 +1004,6 @@ GC_bool ignore_off_page;
&& !GC_expand_hp_inner(needed_blocks)) {
if (GC_fail_count++ < GC_max_retries) {
WARN("Out of Memory! Trying to continue ...\n", 0);
GC_notify_full_gc();
GC_gcollect_inner();
} else {
# if !defined(AMIGA) || !defined(GC_AMIGA_FASTALLOC)
@ -1005,29 +1033,38 @@ ptr_t GC_allocobj(sz, kind)
word sz;
int kind;
{
register ptr_t * flh = &(GC_obj_kinds[kind].ok_freelist[sz]);
ptr_t * flh = &(GC_obj_kinds[kind].ok_freelist[sz]);
GC_bool tried_minor = FALSE;
if (sz == 0) return(0);
while (*flh == 0) {
ENTER_GC();
/* Do our share of marking work */
if(GC_incremental && !GC_dont_gc) GC_collect_a_little_inner(1);
if(TRUE_INCREMENTAL) GC_collect_a_little_inner(1);
/* Sweep blocks for objects of this size */
GC_continue_reclaim(sz, kind);
GC_continue_reclaim(sz, kind);
EXIT_GC();
if (*flh == 0) {
GC_new_hblk(sz, kind);
}
if (*flh == 0) {
ENTER_GC();
if (!GC_collect_or_expand((word)1,FALSE)) {
if (GC_incremental && GC_time_limit == GC_TIME_UNLIMITED
&& ! tried_minor ) {
GC_collect_a_little_inner(1);
tried_minor = TRUE;
} else {
if (!GC_collect_or_expand((word)1,FALSE)) {
EXIT_GC();
return(0);
}
}
EXIT_GC();
}
}
/* Successful allocation; reset failure count. */
GC_fail_count = 0;
return(*flh);
}

View File

@ -1,86 +0,0 @@
.arch ev6
.text
.align 4
.globl GC_push_regs
.ent GC_push_regs 2
GC_push_regs:
ldgp $gp, 0($27)
lda $sp, -16($sp)
stq $26, 0($sp)
.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
# define call_push(x) \
mov x, $16; \
jsr $26, GC_push_one; \
ldgp $gp, 0($26)
call_push($9)
call_push($10)
call_push($11)
call_push($12)
call_push($13)
call_push($14)
call_push($15)
# $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.
amask 2, $0
bne $0, $use_stack
#undef call_push
#define call_push(x) \
ftoit x, $16; \
jsr $26, GC_push_one; \
ldgp $gp, 0($26)
call_push($f2)
call_push($f3)
call_push($f4)
call_push($f5)
call_push($f6)
call_push($f7)
call_push($f8)
call_push($f9)
ldq $26, 0($sp)
lda $sp, 16($sp)
ret $31, ($26), 1
.align 4
$use_stack:
#undef call_push
#define call_push(x) \
stt x, 8($sp); \
ldq $16, 8($sp); \
jsr $26, GC_push_one; \
ldgp $gp, 0($26)
call_push($f2)
call_push($f3)
call_push($f4)
call_push($f5)
call_push($f6)
call_push($f7)
call_push($f8)
call_push($f9)
ldq $26, 0($sp)
lda $sp, 16($sp)
ret $31, ($26), 1
.end GC_push_regs

575
boehm-gc/configure vendored

File diff suppressed because it is too large Load Diff

View File

@ -14,22 +14,28 @@
# host The configuration host
# host_cpu The configuration host CPU
# target_optspace --enable-target-optspace ("yes", "no", "")
# GCC should be "yes" if using gcc
# It sets the following shell variables:
# gc_cflags Special CFLAGS to use when building
gc_cflags=""
# We should set -fexceptions if we are using gcc and might be used
# inside something like gcj. This is the zeroth approximation:
case "$host" in
*-*-linux* )
gc_cflags=-fexceptions
;;
hppa*-*-hpux* )
if test $GCC != "yes" ; then
gc_cflags=+ESdbgasm
fi
;;
esac
if test :"$GCC": = :yes: ; then
gc_cflags="${gc_cflags} -fexceptions"
else
case "$host" in
hppa*-*-hpux* )
if test :$GCC: != :"yes": ; then
gc_cflags="${gc_flags} +ESdbgasm"
fi
# :TODO: actaully we should check using Autoconf if
# the compiler supports this option.
;;
esac
fi
case "${target_optspace}:${host}" in
yes:*)
@ -48,7 +54,7 @@ esac
case "${host}" in
mips-tx39-*|mipstx39-unknown-*)
boehm_gc_cflags="${boehm_gc_cflags} -G 0"
gc_cflags="${gc_cflags} -G 0"
;;
*)
;;

View File

@ -73,10 +73,10 @@ case "$THREADS" in
THREADS=posix
THREADLIBS=-lpthread
case "$host" in
x86-*-linux* | ia64-*-linux* | i586-*-linux* | i686-*-linux* | x86_64-*-linux* )
x86-*-linux* | ia64-*-linux* | i586-*-linux* | i686-*-linux* | x86_64-*-linux* | alpha-*-linux*)
AC_DEFINE(GC_LINUX_THREADS)
AC_DEFINE(_REENTRANT)
if test "${enable_parallel_mark}"; then
if test "${enable_parallel_mark}" = yes; then
AC_DEFINE(PARALLEL_MARK)
fi
AC_DEFINE(THREAD_LOCAL_ALLOC)
@ -85,6 +85,10 @@ case "$THREADS" in
AC_DEFINE(GC_LINUX_THREADS)
AC_DEFINE(_REENTRANT)
;;
*-*-aix*)
AC_DEFINE(GC_AIX_THREADS)
AC_DEFINE(_REENTRANT)
;;
*-*-hpux*)
AC_MSG_WARN("Only HP/UX 11 threads are supported.")
AC_DEFINE(GC_HPUX_THREADS)
@ -109,16 +113,52 @@ case "$THREADS" in
AC_DEFINE(GC_IRIX_THREADS)
;;
*-*-cygwin*)
THREADLIBS=
AC_DEFINE(GC_WIN32_THREADS)
;;
*-*-darwin*)
AC_DEFINE(GC_DARWIN_THREADS)
AC_DEFINE(THREAD_LOCAL_ALLOC)
if test "${enable_parallel_mark}" = yes; then
AC_DEFINE(PARALLEL_MARK)
fi
;;
*-*-osf*)
AC_DEFINE(GC_OSF1_THREADS)
if test "${enable_parallel_mark}" = yes; then
AC_DEFINE(PARALLEL_MARK)
AC_DEFINE(THREAD_LOCAL_ALLOC)
# May want to enable it in other cases, too.
# Measurements havent yet been done.
fi
INCLUDES="$INCLUDES -pthread"
THREADLIBS="-lpthread -lrt"
;;
esac
;;
win32)
AC_DEFINE(GC_WIN32_THREADS)
dnl Wine getenv may not return NULL for missing entry
AC_DEFINE(NO_GETENV)
if test $enable_shared = yes; then
AC_DEFINE(GC_DLL)
;;
dgux386)
THREADS=dgux386
AC_MSG_RESULT($THREADLIBS)
# Use pthread GCC switch
THREADLIBS=-pthread
if test "${enable_parallel_mark}" = yes; then
AC_DEFINE(PARALLEL_MARK)
fi
AC_DEFINE(THREAD_LOCAL_ALLOC)
AC_DEFINE(GC_DGUX386_THREADS)
AC_DEFINE(DGUX_THREADS)
# Enable _POSIX4A_DRAFT10_SOURCE with flag -pthread
INCLUDES="-pthread $INCLUDES"
;;
aix)
THREADS=posix
THREADLIBS=-lpthread
AC_DEFINE(GC_AIX_THREADS)
AC_DEFINE(_REENTRANT)
;;
decosf1 | irix | mach | os2 | solaris | dce | vxworks)
AC_MSG_ERROR(thread package $THREADS not yet supported)
@ -129,7 +169,22 @@ case "$THREADS" in
esac
AC_SUBST(THREADLIBS)
AC_CHECK_LIB(dl, dlopen, EXTRA_TEST_LIBS="$EXTRA_TEST_LIBS -ldl")
case "$host" in
powerpc-*-darwin*)
powerpc_darwin=true
;;
esac
AM_CONDITIONAL(POWERPC_DARWIN,test x$powerpc_darwin = xtrue)
# 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")
;;
esac
AC_SUBST(EXTRA_TEST_LIBS)
target_all=libgcjgc.la
@ -147,6 +202,9 @@ TARGET_ECOS="$with_ecos"
)
addobjs=
addlibs=
addincludes=
addtests=
CXXINCLUDES=
case "$TARGET_ECOS" in
no)
@ -157,21 +215,46 @@ case "$TARGET_ECOS" in
addobjs="$addobjs ecos.lo"
;;
esac
if test "${enable_cplusplus}" = yes; then
addincludes="$addincludes include/gc_cpp.h include/gc_allocator.h"
addtests="$addtests test_cpp"
fi
AM_CONDITIONAL(CPLUSPLUS, test "${enable_cplusplus}" = yes)
AC_SUBST(CXX)
AC_SUBST(INCLUDES)
AC_SUBST(CXXINCLUDES)
# Configuration of shared libraries
#
AC_MSG_CHECKING(whether to build shared libraries)
AC_ENABLE_SHARED
case "$host" in
alpha-*-openbsd*)
enable_shared=no
AC_MSG_RESULT(no)
;;
*)
AC_MSG_RESULT(yes)
;;
esac
# Configuration of machine-dependent code
#
AC_MSG_CHECKING(which machine-dependent code should be used)
machdep=
case "$host" in
alpha*-*-openbsd*)
machdep="alpha_mach_dep.lo"
if test x"${ac_cv_lib_dl_dlopen}" != xyes ; then
AC_MSG_WARN(OpenBSD/Alpha without dlopen(). Shared library support is disabled)
AM_DISABLE_SHARED
fi
;;
alpha*-*-*)
alpha*-*-linux*)
machdep="alpha_mach_dep.lo"
;;
i?86-*-solaris2.[[89]]*)
@ -185,12 +268,17 @@ case "$host" in
mips-dec-ultrix*)
machdep="mips_ultrix_mach-dep.lo"
;;
mips*-*-linux*)
mips-nec-sysv*|mips-unknown-sysv*)
;;
mips*-*-linux*)
;;
mips-*-*)
machdep="mips_sgi_mach_dep.lo"
AC_DEFINE(NO_EXECUTE_PERMISSION)
;;
sparc-*-netbsd*)
machdep="sparc_netbsd_mach_dep.lo"
;;
sparc-sun-solaris2.3*)
machdep="sparc_mach_dep.lo"
AC_DEFINE(SUNOS53_SHARED_LIB)
@ -203,16 +291,65 @@ case "$host" in
;;
esac
if test x"$machdep" = x; then
AC_MSG_RESULT($machdep)
machdep="mach_dep.lo"
fi
addobjs="$addobjs $machdep"
AC_SUBST(addobjs)
AC_SUBST(addincludes)
AC_SUBST(addlibs)
AC_SUBST(addtests)
AC_PROG_LIBTOOL
#
# Check for AViiON Machines running DGUX
#
AC_MSG_CHECKING(if host is AViiON running DGUX)
ac_is_dgux=no
AC_CHECK_HEADER(sys/dg_sys_info.h,
[ac_is_dgux=yes;])
AC_MSG_RESULT($ac_is_dgux)
## :GOTCHA: we do not check anything but sys/dg_sys_info.h
if test $ac_is_dgux = yes; then
if test "$enable_full_debug" = "yes"; then
CFLAGS="-g -mstandard -DDGUX -D_DGUX_SOURCE -Di386 -mno-legend -O2"
CXXFLAGS="-g -mstandard -DDGUX -D_DGUX_SOURCE -Di386 -mno-legend -O2"
else
CFLAGS="-DDGUX -D_DGUX_SOURCE -Di386 -mno-legend -O2"
CXXFLAGS="-DDGUX -D_DGUX_SOURCE -Di386 -mno-legend -O2"
fi
AC_SUBST(CFLAGS)
AC_SUBST(CXXFLAGS)
fi
dnl We use these options to decide which functions to include.
AC_ARG_WITH(target-subdir,
[ --with-target-subdir=SUBDIR
configuring with a cross compiler])
AC_ARG_WITH(cross-host,
[ --with-cross-host=HOST configuring with a cross compiler])
# automake wants to see AC_EXEEXT. But we don't need it. And having
# it is actually a problem, because the compiler we're passed can't
# necessarily do a full link. So we fool automake here.
if false; then
# autoconf 2.50 runs AC_EXEEXT by default, and the macro expands
# to nothing, so nothing would remain between `then' and `fi' if it
# were not for the `:' below.
:
AC_EXEEXT
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
AC_MSG_CHECKING(whether Solaris gcc optimization fix is necessary)
case "$host" in
sparc-sun-solaris2*)
sparc-sun-solaris2*|*aix*)
if test "$GCC" = yes; then
AC_MSG_RESULT(yes)
new_CFLAGS=
for i in $CFLAGS; do
case "$i" in
@ -224,8 +361,11 @@ case "$host" in
esac
done
CFLAGS="$new_CFLAGS"
else
AC_MSG_RESULT(no)
fi
;;
*) AC_MSG_RESULT(no) ;;
esac
dnl We need to override the top-level CFLAGS. This is how we do it.
@ -267,6 +407,9 @@ AC_ARG_ENABLE(full-debug,
AC_MSG_WARN("Client must not use -fomit-frame-pointer.")
AC_DEFINE(SAVE_CALL_COUNT, 8)
;;
i[3456]86-*-dgux*)
AC_DEFINE(MAKE_BACK_GRAPH)
;;
esac ]
fi)

View File

@ -219,7 +219,7 @@ CORD CORD_cat_char_star(CORD x, const char * y, size_t leny)
result->len = result_len;
result->left = x;
result->right = y;
if (depth > MAX_DEPTH) {
if (depth >= MAX_DEPTH) {
return(CORD_balance((CORD)result));
} else {
return((CORD) result);
@ -260,7 +260,11 @@ CORD CORD_cat(CORD x, CORD y)
result->len = result_len;
result->left = x;
result->right = y;
return((CORD) result);
if (depth >= MAX_DEPTH) {
return(CORD_balance((CORD)result));
} else {
return((CORD) result);
}
}
}

View File

@ -233,7 +233,7 @@ int CORD_vsprintf(CORD * out, CORD format, va_list args)
if (width == NONE && prec == NONE) {
register char c;
c = va_arg(args, int);
c = (char)va_arg(args, int);
CORD_ec_append(result, c);
goto done;
}
@ -255,12 +255,18 @@ int CORD_vsprintf(CORD * out, CORD format, va_list args)
/* Use standard sprintf to perform conversion */
{
register char * buf;
va_list vsprintf_args = args;
/* The above does not appear to be sanctioned */
/* by the ANSI C standard. */
va_list vsprintf_args;
int max_size = 0;
int res;
# ifdef __va_copy
__va_copy(vsprintf_args, args);
# else
# if defined(__GNUC__) /* and probably in other cases */
va_copy(vsprintf_args, args);
# else
vsprintf_args = args;
# endif
# endif
if (width == VARIABLE) width = va_arg(args, int);
if (prec == VARIABLE) prec = va_arg(args, int);
if (width != NONE) max_size = width;

View File

@ -249,7 +249,7 @@ LRESULT CALLBACK WndProc (HWND hwnd, UINT message,
case IDM_HELPABOUT:
if( DialogBox( hInstance, "ABOUTBOX",
hwnd, lpfnAboutBox ) );
hwnd, lpfnAboutBox ) )
InvalidateRect( hwnd, NULL, TRUE );
return( 0 );
case IDM_HELPCONTENTS:

View File

@ -60,7 +60,7 @@ ptr_t p;
# include <stdlib.h>
# if defined(LINUX) || defined(SUNOS4) || defined(SUNOS5) \
|| defined(HPUX) || defined(IRIX) || defined(OSF1)
|| defined(HPUX) || defined(IRIX5) || defined(OSF1)
# define RANDOM() random()
# else
# define RANDOM() (long)rand()
@ -228,6 +228,8 @@ ptr_t p;
#endif /* KEEP_BACK_PTRS */
# define CROSSES_HBLK(p, sz) \
(((word)(p + sizeof(oh) + sz - 1) ^ (word)p) >= HBLKSIZE)
/* Store debugging info into p. Return displaced pointer. */
/* Assumes we don't hold allocation lock. */
ptr_t GC_store_debug_info(p, sz, string, integer)
@ -243,6 +245,8 @@ word integer;
/* But that's expensive. And this way things should only appear */
/* inconsistent while we're in the handler. */
LOCK();
GC_ASSERT(GC_size(p) >= sizeof(oh) + sz);
GC_ASSERT(!(SMALL_OBJ(sz) && CROSSES_HBLK(p, sz)));
# ifdef KEEP_BACK_PTRS
((oh *)p) -> oh_back_ptr = HIDE_BACK_PTR(NOT_MARKED);
# endif
@ -275,6 +279,8 @@ word integer;
/* There is some argument that we should disable signals here. */
/* But that's expensive. And this way things should only appear */
/* inconsistent while we're in the handler. */
GC_ASSERT(GC_size(p) >= sizeof(oh) + sz);
GC_ASSERT(!(SMALL_OBJ(sz) && CROSSES_HBLK(p, sz)));
# ifdef KEEP_BACK_PTRS
((oh *)p) -> oh_back_ptr = HIDE_BACK_PTR(NOT_MARKED);
# endif
@ -324,10 +330,11 @@ ptr_t p;
{
register oh * ohdr = (oh *)GC_base(p);
GC_ASSERT(!I_HOLD_LOCK());
GC_err_printf1("0x%lx (", ((unsigned long)ohdr + sizeof(oh)));
GC_err_puts(ohdr -> oh_string);
# ifdef SHORT_DBG_HDRS
GC_err_printf1(":%ld, sz=%ld)\n", (unsigned long)(ohdr -> oh_int));
GC_err_printf1(":%ld)\n", (unsigned long)(ohdr -> oh_int));
# else
GC_err_printf2(":%ld, sz=%ld)\n", (unsigned long)(ohdr -> oh_int),
(unsigned long)(ohdr -> oh_sz));
@ -342,6 +349,7 @@ ptr_t p;
ptr_t p;
# endif
{
GC_ASSERT(!I_HOLD_LOCK());
if (GC_HAS_DEBUG_INFO(p)) {
GC_print_obj(p);
} else {
@ -355,6 +363,7 @@ ptr_t p, clobbered_addr;
{
register oh * ohdr = (oh *)GC_base(p);
GC_ASSERT(!I_HOLD_LOCK());
GC_err_printf2("0x%lx in object at 0x%lx(", (unsigned long)clobbered_addr,
(unsigned long)p);
if (clobbered_addr <= (ptr_t)(&(ohdr -> oh_sz))
@ -376,14 +385,18 @@ ptr_t p, clobbered_addr;
void GC_check_heap_proc GC_PROTO((void));
void GC_print_all_smashed_proc GC_PROTO((void));
void GC_do_nothing() {}
void GC_start_debugging()
{
# ifndef SHORT_DBG_HDRS
GC_check_heap = GC_check_heap_proc;
GC_print_all_smashed = GC_print_all_smashed_proc;
# else
GC_check_heap = GC_do_nothing;
GC_print_all_smashed = GC_do_nothing;
# endif
GC_print_heap_obj = GC_debug_print_heap_obj_proc;
GC_debugging_started = TRUE;
@ -429,6 +442,62 @@ void GC_start_debugging()
return (GC_store_debug_info(result, (word)lb, s, (word)i));
}
# ifdef __STDC__
GC_PTR GC_debug_malloc_ignore_off_page(size_t lb, GC_EXTRA_PARAMS)
# else
GC_PTR GC_debug_malloc_ignore_off_page(lb, s, i)
size_t lb;
char * s;
int i;
# ifdef GC_ADD_CALLER
--> GC_ADD_CALLER not implemented for K&R C
# endif
# endif
{
GC_PTR result = GC_malloc_ignore_off_page(lb + DEBUG_BYTES);
if (result == 0) {
GC_err_printf1("GC_debug_malloc_ignore_off_page(%ld) returning NIL (",
(unsigned long) lb);
GC_err_puts(s);
GC_err_printf1(":%ld)\n", (unsigned long)i);
return(0);
}
if (!GC_debugging_started) {
GC_start_debugging();
}
ADD_CALL_CHAIN(result, ra);
return (GC_store_debug_info(result, (word)lb, s, (word)i));
}
# ifdef __STDC__
GC_PTR GC_debug_malloc_atomic_ignore_off_page(size_t lb, GC_EXTRA_PARAMS)
# else
GC_PTR GC_debug_malloc_atomic_ignore_off_page(lb, s, i)
size_t lb;
char * s;
int i;
# ifdef GC_ADD_CALLER
--> GC_ADD_CALLER not implemented for K&R C
# endif
# endif
{
GC_PTR result = GC_malloc_atomic_ignore_off_page(lb + DEBUG_BYTES);
if (result == 0) {
GC_err_printf1("GC_debug_malloc_atomic_ignore_off_page(%ld)"
" returning NIL (", (unsigned long) lb);
GC_err_puts(s);
GC_err_printf1(":%ld)\n", (unsigned long)i);
return(0);
}
if (!GC_debugging_started) {
GC_start_debugging();
}
ADD_CALL_CHAIN(result, ra);
return (GC_store_debug_info(result, (word)lb, s, (word)i));
}
# ifdef DBG_HDRS_ALL
/*
* An allocation function for internal use.
@ -447,7 +516,7 @@ void GC_start_debugging()
(unsigned long) lb);
return(0);
}
ADD_CALL_CHAIN(result, ra);
ADD_CALL_CHAIN(result, GC_RETURN_ADDR);
return (GC_store_debug_info_inner(result, (word)lb, "INTERNAL", (word)0));
}
@ -461,7 +530,7 @@ void GC_start_debugging()
(unsigned long) lb);
return(0);
}
ADD_CALL_CHAIN(result, ra);
ADD_CALL_CHAIN(result, GC_RETURN_ADDR);
return (GC_store_debug_info_inner(result, (word)lb, "INTERNAL", (word)0));
}
# endif
@ -592,7 +661,7 @@ GC_PTR p;
int i;
# endif
{
GC_PTR result = GC_malloc_uncollectable(lb + DEBUG_BYTES);
GC_PTR result = GC_malloc_uncollectable(lb + UNCOLLECTABLE_DEBUG_BYTES);
if (result == 0) {
GC_err_printf1("GC_debug_malloc_uncollectable(%ld) returning NIL (",
@ -618,7 +687,8 @@ GC_PTR p;
int i;
# endif
{
GC_PTR result = GC_malloc_atomic_uncollectable(lb + DEBUG_BYTES);
GC_PTR result =
GC_malloc_atomic_uncollectable(lb + UNCOLLECTABLE_DEBUG_BYTES);
if (result == 0) {
GC_err_printf1(
@ -774,6 +844,45 @@ void GC_debug_free_inner(GC_PTR p)
}
#ifndef SHORT_DBG_HDRS
/* List of smashed objects. We defer printing these, since we can't */
/* always print them nicely with the allocation lock held. */
/* We put them here instead of in GC_arrays, since it may be useful to */
/* be able to look at them with the debugger. */
#define MAX_SMASHED 20
ptr_t GC_smashed[MAX_SMASHED];
unsigned GC_n_smashed = 0;
# if defined(__STDC__) || defined(__cplusplus)
void GC_add_smashed(ptr_t smashed)
# else
void GC_add_smashed(smashed)
ptr_t smashed;
#endif
{
GC_ASSERT(GC_is_marked(GC_base(smashed)));
GC_smashed[GC_n_smashed] = smashed;
if (GC_n_smashed < MAX_SMASHED - 1) ++GC_n_smashed;
/* In case of overflow, we keep the first MAX_SMASHED-1 */
/* entries plus the last one. */
GC_have_errors = TRUE;
}
/* Print all objects on the list. Clear the list. */
void GC_print_all_smashed_proc ()
{
unsigned i;
GC_ASSERT(!I_HOLD_LOCK());
if (GC_n_smashed == 0) return;
GC_err_printf0("GC_check_heap_block: found smashed heap objects:\n");
for (i = 0; i < GC_n_smashed; ++i) {
GC_print_smashed_obj(GC_base(GC_smashed[i]), GC_smashed[i]);
GC_smashed[i] = 0;
}
GC_n_smashed = 0;
}
/* Check all marked objects in the given block for validity */
/*ARGSUSED*/
# if defined(__STDC__) || defined(__cplusplus)
@ -802,11 +911,7 @@ void GC_debug_free_inner(GC_PTR p)
&& GC_HAS_DEBUG_INFO((ptr_t)p)) {
ptr_t clobbered = GC_check_annotated_obj((oh *)p);
if (clobbered != 0) {
GC_err_printf0(
"GC_check_heap_block: found smashed location at ");
GC_print_smashed_obj((ptr_t)p, clobbered);
}
if (clobbered != 0) GC_add_smashed(clobbered);
}
word_no += sz;
p += sz;
@ -819,9 +924,11 @@ void GC_debug_free_inner(GC_PTR p)
void GC_check_heap_proc()
{
# ifndef SMALL_CONFIG
if (sizeof(oh) & (2 * sizeof(word) - 1) != 0) {
ABORT("Alignment problem: object header has inappropriate size\n");
}
# ifdef ALIGN_DOUBLE
GC_STATIC_ASSERT((sizeof(oh) & (2 * sizeof(word) - 1)) == 0);
# else
GC_STATIC_ASSERT((sizeof(oh) & (sizeof(word) - 1)) == 0);
# endif
# endif
GC_apply_to_all_blocks(GC_check_heap_block, (word)0);
}
@ -842,12 +949,12 @@ struct closure {
# endif
{
struct closure * result =
# ifdef DBG_HDRS_ALL
(struct closure *) GC_debug_malloc(sizeof (struct closure),
GC_EXTRAS);
# else
(struct closure *) GC_malloc(sizeof (struct closure));
# endif
# ifdef DBG_HDRS_ALL
(struct closure *) GC_debug_malloc(sizeof (struct closure),
GC_EXTRAS);
# else
(struct closure *) GC_malloc(sizeof (struct closure));
# endif
result -> cl_fn = fn;
result -> cl_data = data;
@ -908,7 +1015,7 @@ GC_PTR *ocd;
ptr_t base = GC_base(obj);
if (0 == base || (ptr_t)obj - base != sizeof(oh)) {
GC_err_printf1(
"GC_register_finalizer called with non-base-pointer 0x%lx\n",
"GC_debug_register_finalizer called with non-base-pointer 0x%lx\n",
obj);
}
if (0 == fn) {
@ -940,7 +1047,7 @@ GC_PTR *ocd;
ptr_t base = GC_base(obj);
if (0 == base || (ptr_t)obj - base != sizeof(oh)) {
GC_err_printf1(
"GC_register_finalizer_no_order called with non-base-pointer 0x%lx\n",
"GC_debug_register_finalizer_no_order called with non-base-pointer 0x%lx\n",
obj);
}
if (0 == fn) {
@ -973,7 +1080,7 @@ GC_PTR *ocd;
ptr_t base = GC_base(obj);
if (0 == base || (ptr_t)obj - base != sizeof(oh)) {
GC_err_printf1(
"GC_register_finalizer_ignore_self called with non-base-pointer 0x%lx\n",
"GC_debug_register_finalizer_ignore_self called with non-base-pointer 0x%lx\n",
obj);
}
if (0 == fn) {

View File

@ -1,27 +0,0 @@
#
#
# 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.
#
# Modified by: Grzegorz Jakacki <jakacki at acm dot org>
## Process this file with automake to produce Makefile.in.
# installed documentation
#
dist_pkgdata_DATA = barrett_diagram debugging.html gc.man \
gcdescr.html README README.amiga README.arm.cross \
README.autoconf README.changes README.contributors \
README.cords README.DGUX386 README.dj README.environment \
README.ews4800 README.hp README.linux README.Mac \
README.MacOSX README.macros README.OS2 README.rs6000 \
README.sgi README.solaris2 README.uts README.win32 \
tree.html leak.html gcinterface.html scale.html \
README.darwin

View File

@ -1,282 +0,0 @@
# Makefile.in generated by automake 1.6.3 from Makefile.am.
# @configure_input@
# Copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002
# 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.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
# PARTICULAR PURPOSE.
@SET_MAKE@
#
#
# 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.
#
# 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@
NORMAL_INSTALL = :
PRE_INSTALL = :
POST_INSTALL = :
NORMAL_UNINSTALL = :
PRE_UNINSTALL = :
POST_UNINSTALL = :
host_alias = @host_alias@
host_triplet = @host@
EXEEXT = @EXEEXT@
OBJEXT = @OBJEXT@
PATH_SEPARATOR = @PATH_SEPARATOR@
AMTAR = @AMTAR@
AR = @AR@
AS = @AS@
AWK = @AWK@
CC = @CC@
CCAS = @CCAS@
CCASFLAGS = @CCASFLAGS@
CFLAGS = @CFLAGS@
CXX = @CXX@
CXXFLAGS = @CXXFLAGS@
CXXINCLUDES = @CXXINCLUDES@
DEPDIR = @DEPDIR@
DLLTOOL = @DLLTOOL@
ECHO = @ECHO@
EXTRA_TEST_LIBS = @EXTRA_TEST_LIBS@
GC_CFLAGS = @GC_CFLAGS@
GC_VERSION = @GC_VERSION@
INCLUDES = @INCLUDES@
INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
LIBTOOL = @LIBTOOL@
LN_S = @LN_S@
MAINT = @MAINT@
MY_CFLAGS = @MY_CFLAGS@
OBJDUMP = @OBJDUMP@
PACKAGE = @PACKAGE@
RANLIB = @RANLIB@
STRIP = @STRIP@
THREADLIBS = @THREADLIBS@
VERSION = @VERSION@
addincludes = @addincludes@
addlibs = @addlibs@
addobjs = @addobjs@
addtests = @addtests@
am__include = @am__include@
am__quote = @am__quote@
install_sh = @install_sh@
target_all = @target_all@
# installed documentation
#
dist_pkgdata_DATA = barrett_diagram debugging.html gc.man \
gcdescr.html README README.amiga README.arm.cross \
README.autoconf README.changes README.contributors \
README.cords README.DGUX386 README.dj README.environment \
README.ews4800 README.hp README.linux README.Mac \
README.MacOSX README.macros README.OS2 README.rs6000 \
README.sgi README.solaris2 README.uts README.win32 \
tree.html leak.html gcinterface.html scale.html \
README.darwin
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)
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)
mostlyclean-libtool:
-rm -f *.lo
clean-libtool:
-rm -rf .libs _libs
distclean-libtool:
-rm -f libtool
uninstall-info-am:
dist_pkgdataDATA_INSTALL = $(INSTALL_DATA)
install-dist_pkgdataDATA: $(dist_pkgdata_DATA)
@$(NORMAL_INSTALL)
$(mkinstalldirs) $(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; \
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; \
done
tags: TAGS
TAGS:
DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
top_distdir = ..
distdir = $(top_distdir)/$(PACKAGE)-$(VERSION)
distdir: $(DISTFILES)
@list='$(DISTFILES)'; for file in $$list; do \
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"; \
else \
dir=''; \
fi; \
if test -d $$d/$$file; then \
if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \
fi; \
cp -pR $$d/$$file $(distdir)$$dir || exit 1; \
else \
test -f $(distdir)/$$file \
|| cp -p $$d/$$file $(distdir)/$$file \
|| exit 1; \
fi; \
done
check-am: all-am
check: check-am
all-am: Makefile $(DATA)
installdirs:
$(mkinstalldirs) $(DESTDIR)$(pkgdatadir)
install: install-am
install-exec: install-exec-am
install-data: install-data-am
uninstall: uninstall-am
install-am: all-am
@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
installcheck: installcheck-am
install-strip:
$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
INSTALL_STRIP_FLAG=-s \
`test -z '$(STRIP)' || \
echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
mostlyclean-generic:
clean-generic:
distclean-generic:
-rm -f Makefile $(CONFIG_CLEAN_FILES)
maintainer-clean-generic:
@echo "This command is intended for maintainers to use"
@echo "it deletes files that may require special tools to rebuild."
clean: clean-am
clean-am: clean-generic clean-libtool mostlyclean-am
distclean: distclean-am
distclean-am: clean-am distclean-generic distclean-libtool
dvi: dvi-am
dvi-am:
info: info-am
info-am:
install-data-am: install-dist_pkgdataDATA
install-exec-am:
install-info: install-info-am
install-man:
installcheck-am:
maintainer-clean: maintainer-clean-am
maintainer-clean-am: distclean-am maintainer-clean-generic
mostlyclean: mostlyclean-am
mostlyclean-am: mostlyclean-generic mostlyclean-libtool
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
# 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.
.NOEXPORT:

View File

@ -1,7 +1,7 @@
Copyright (c) 1988, 1989 Hans-J. Boehm, Alan J. Demers
Copyright (c) 1991-1996 by Xerox Corporation. All rights reserved.
Copyright (c) 1996-1999 by Silicon Graphics. All rights reserved.
Copyright (c) 1999-2001 by Hewlett-Packard Company. All rights reserved.
Copyright (c) 1999-2003 by Hewlett-Packard Company. All rights reserved.
The file linux_threads.c is also
Copyright (c) 1998 by Fergus Henderson. All rights reserved.
@ -9,8 +9,9 @@ Copyright (c) 1998 by Fergus Henderson. All rights reserved.
The files Makefile.am, and configure.in are
Copyright (c) 2001 by Red Hat Inc. All rights reserved.
The files config.guess and a few others are copyrighted by the Free
Software Foundation.
Several files supporting GNU-style builds are copyrighted by the Free
Software Foundation, and carry a different license from that given
below.
THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
@ -27,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.1alpha3 of a conservative garbage collector for C and C++.
This is version 6.3alpha1 of a conservative garbage collector for C and C++.
You might find a more recent version of this at
@ -228,10 +229,12 @@ and several of those are compatible with the collector.
or equivalent is supplied. Many of these have separate README.system
files.
Dynamic libraries are completely supported only under SunOS
Dynamic libraries are completely supported only under SunOS/Solaris,
(and even that support is not functional on the last Sun 3 release),
Linux, IRIX 5&6, HP-PA, Win32 (not Win32S) and OSF/1 on DEC AXP machines.
On other machines we recommend that you do one of the following:
Linux, FreeBSD, NetBSD, IRIX 5&6, HP/UX, Win32 (not Win32S) and OSF/1
on DEC AXP machines plus perhaps a few others listed near the top
of dyn_load.c. On other machines we recommend that you do one of
the following:
1) Add dynamic library support (and send us the code).
2) Use static versions of the libraries.
@ -245,6 +248,8 @@ On other machines we recommend that you do one of the following:
In all cases we assume that pointer alignment is consistent with that
enforced by the standard C compilers. If you use a nonstandard compiler
you may have to adjust the alignment parameters defined in gc_priv.h.
Note that this may also be an issue with packed records/structs, if those
enforce less alignment for pointers.
A port to a machine that is not byte addressed, or does not use 32 bit
or 64 bit addresses will require a major effort. A port to plain MSDOS

View File

@ -1,27 +1 @@
While the GC should work on MacOS X Server, MacOS X and Darwin, I only tested
it on MacOS X Server.
I've added a PPC assembly version of GC_push_regs(), thus the setjmp() hack is
no longer necessary. Incremental collection is supported via mprotect/signal.
The current solution isn't really optimal because the signal handler must decode
the faulting PPC machine instruction in order to find the correct heap address.
Further, it must poke around in the register state which the kernel saved away
in some obscure register state structure before it calls the signal handler -
needless to say the layout of this structure is no where documented.
Threads and dynamic libraries are not yet supported (adding dynamic library
support via the low-level dyld API shouldn't be that hard).
The original MacOS X port was brought to you by Andrew Stone.
June, 1 2000
Dietmar Planitzer
dave.pl@ping.at
Note from Andrew Begel:
One more fix to enable gc.a to link successfully into a shared library for
MacOS X. You have to add -fno-common to the CFLAGS in the Makefile. MacOSX
disallows common symbols in anything that eventually finds its way into a
shared library. (I don't completely understand why, but -fno-common seems to
work and doesn't mess up the garbage collector's functionality).
See README.darwin for the latest Darwin/MacOSX information.

View File

@ -1469,8 +1469,439 @@ Since 6.1 alpha2:
- Caused the Solaris and Irix thread creation primitives to call
GC_init_inner().
Since 6.1alpha3:
- Fixed typo in sparc_mach_dep.S, preventing the 64-bit version from
building. Increased 64-bit heap size limit in test.c slightly, since
a functional SPARC collector seems to slightly exceed the old limits.
(Thanks again to Jeff Sturm.)
- Use NPRGREG in solaris_threads.c, thus printing all registers if things
go wrong.
- Added GC_MARKERS environment variable to allow use of a single marker
thread on an MP without confusing the lock implementation.
- Collect much less aggressively in incremental mode with GC_TIME_UNLIMITED.
This is really a purely generational mode, and we can afford to
postpone the collection until the heap is (nearly) full.
- Remove read() wrapper for MPROTECT_VDB. It was causing more harm than
good. It is often no longer needed if system calls avoid writing to
pointerfull heap objects.
- Fix MACOSX test in gcconfig.h. (Thanks to John Clements.)
- Change GC_test_and_set so that it consistently has one argument.
Add spaces to ::: in powerpc assembly code in gc_locks.h.
(Thanks to Ryan Murray.)
- Fixed a formatting error in dbg_mlc.c. Added prototype to GC_abort()
declaration. (Thanks to Michael Smith.)
- Removed "source" argument to GC_find_start(). Eliminate GC_FIND_START().
- Added win32 recognition code in configure.in. Changed some of the
dllimport/export defines in gc.h. (Thanks to Adam Megacz.)
- GC_malloc_many didn't set hb_last_reclaimed when it called
GC_reclaim_generic. (I'm not sure this matters much, but ...)
- Allocating uncollectable objects with debug information sometimes
allocated objects that were one byte too small, since uncollectable
objects don't have the extra byte added at the end. (Thanks to
Wink Saville for pointing this out.)
- Added a bit more assertion checking to make sure that gcj objects
on free lists never have a nonzero second word.
- Replaced BCC_MAKEFILE with an up-to-date one. (Thanks to
Andre Leiradella.)
- Upgraded libtool, cinfigure.in and some related files to hopefully
support NetBSD/SPARC. (Thanks to Adrian Bunk.) Unfortunately,
libtool 1.4.2 seemed to be buggy due to missing quotes in several
"test" invocations. Fixed those in the ltmain.sh script.
- Some win32-specific patches, including the introduction of
GC_CreateThread. (Thanks to Adam Megacz.)
- Merged in gcj changes from Anthony Green to support embedded systems.
- Tried to consistently rename preprocessed assembly files with a capital
.S extension.
- Use alpha_mach_dep.S on ALPHA again. It doesn't really matter, but this
makes our distribution consistent with the gcc one, avoiding future merge
problems.
- Move GET_MEM definition into gcconfig.h. Include gcconfig.h slightly
later in gc_priv.h to avoid forward references to ptr_t.
- Add some testing of local allocation to test.c.
- Change definition of INVALID_QTID in specific.h. The -1 value was used
inconsistently, and too likely to collide with a valid stack address.
Some general clean-up of specific.[ch]. Added assertions. (Thanks
to Michael Smith for tracking down an intermittent bug to this
general area. I'm not sure it has been squashed yet, however.)
- On Pthread systems it was not safe to call GC_malloc() between fork()
and exec(). According to the applicable standards, it doesn't appear
to be safe to call malloc() or many other libc functions either, thus
it's not clear this is fixable. Added experimental support for
-DHANDLE_FORK in linux_threads.c which tries to support it. It may
succeed if libc does the right thing. I'm not sure whether it does.
(Thanks to Kenneth Schalk for pointing out this issue.)
- Documented thread local allocation primitives to require an
explicit GC_init call. GC_init_parallel is no longer declared to
be a constructor function, since that isn't portable and often
seems to lead to initialization order problems.
- Changed gc_cpp.cc and gc_cpp.h in one more attempt to make them
compatible with Visual C++ 6. (Thanks to Wink Saville for the
patch.)
- Some more patches for Linux on HP PA-RISC.
- Added include/gc_allocator.h. It implements (hopefully) standard
conforming (as opposed to SGI-style) allocators that allocate
collectable (gc_allocator) or GC-traceable, but not collectable
(traceable_allocator) objects. This borrows heavily from libstc++,
which borrows heavily from the SGI implementation, this part of
which was written by Matt Austern. Changed test_cpp.cc to very
minimally test this.
- On Linux/X86, retry mmap with a different start argument. That should
allow the collector to use more (closer to 3GB) of the address space.
(Thanks to Jeffrey Mark Siskind for tracking this down.)
- Force 64 bit alignment with GCJ support. (Reflects Bryce McKinley's
patch to the gcc tree.)
- Refined the choice of sa_handler vs. sa_sigaction in GC_dirty_init
to accomodate some glibc5 systems. (Thanks to Dan Fandrich for the
patch.)
- Compensated for the fact that current versions of glibc set
__libc_stack_end incorrectly on Linux/IA64 while initialization code
is running. This could cause the collector to miss 16 bytes of
the memory stack if GC_malloc or friends where called before main().
- Mostly integrated Takis Psarogiannakopoulos' port to DG/UX Inix 86.
This will probably take another iteration to work, since his
patch conflicted with the libtool upgrade.
- Added README.arm.cross containing some information about cross-
compiling to an ARM processor from Margaret Fleck.
Since 6.1alpha4:
- Added GC_finalizer_mem_freed, and changed some of the code that
decided on heap expansion to look at it. Memory explicitly
deallocated by finalizers essentially needs to be counted as reclaimed
by the GC. Otherwise there are cases in which the heap can grow
unboundedly. (Thanks to Mark Reichert for the test case.)
- Integrated Adam Megacz patches to not scan dynamic libraries if
we are compiling with gcc on win32. Otherwise we need structured
exception handling to deal with asynchronously unmapped root
segments, and gcc doesn't directly support that.
- Integrated Anthony Green's patch to support Wine.
- GC_OPERATOR_NEW_ARRAY was misspelled OPERATOR_NEW_ARRAY in several
places, including gc_cpp.cc. (Thanks to Wink Saville for pointing
this out.)
- Integrated Loren James Rittle's Alpha FreeBSD patches. In
response to Richard Henderson's suggestion, these also
changed the declarations of symbols like _end on many platforms to
that they wouldn't mistakenly be declared as short data symbols.
- Integrated changes from the Debian distribution. (Thanks to Ryan Murray
for pointing these out.) Fix C++ comments in POWERPC port. Add ARM32
incremental GC support. Get rid of USE_GENERIC_PUSH_REGS for alpha/Linux,
this time for real. Use va_copy to get rid of cord printf problems
(finally).
- Close file descriptor used to count cpus. Thanks to Jeff Sturm for
pointing out the omission.
- Don't just drop gcj free lists in GC_start_reclaim, since that can
eventually cause the marker to see a bogus mark descriptor in the
dropped objects. The usual symptom was a very intermittent segmentation
fault in the marker. This mattered only if one of the GC_gcj_malloc
variants was used. (Thanks to Michael Smith, Jeff Sturm, Bryce
McKinley and Tom Tromey for helping to track this down.)
- Fixed Linux and Solaris/64 SPARC configuration. (Thanks to David Miller,
Jeff Sturm, Tom Tromey, and Christian Joensson.)
- Fixed a typo in strdup definition. (Thanks to Gerard A Allan.)
- Changed Makefile.direct to invoke $(CC) to assemble alpha_mach_dep.S.
This is needed on Linux. I'm not sure whether it's better or worse
on Tru64.
- Changed gc_cpp.h once more to declare operator new and friends only in
a Microsoft environment. This may need further fine tuning. (Thanks to
Johannes Schmidt for pointing out that the older code breaks on gcc3.0.4.)
- Don't ever override strdup if it's already macro defined. (Thanks to
Adnan Ali for pointing out the problem.)
- Changed gc_cpp.h yet again to also overload placement new. Due to the
C++ overloading rules, the other overloaded new operations otherwise hide
placement new, which causes many STL uses to break. (Thanks to Reza
Shahidi for reporting this, and to Matt Austern for proposing a fix.)
- Integrated cygwin pthreads support from Dan Bonachea.
- Turn on DYNAMIC_LOADING for NetBSD. (Thanks to Krister Walfridsson.)
- Changed printing code to print more complete GC times.
- Applied Mark Mitchell's Irix patch to correct some bitrot.
- Clarified which object-printing routines in dbg_mlc.c should hold
the allocation lock. Restructured the code to allow reasonable object
printing with -DREDIRECT_MALLOC.
- Fix the Linux mmap code to always start with 0x1000 as the initial hint.
Minor patches for 64-bit AIX, particularly to STACKBOTTOM.
(Thanks again to Jeffrey Mark Siskind.)
- Renamed "SUSPENDED" flag for Solaris threads support to avoid a conflict
with a system header. (Thanks to Philp Brown.)
- Cause win32_threads.c to handle an out of range stack pointer correctly,
though currently with a warning. (Thanks to Jonathan Clark for
observing that win32 applications may temporarily use the stack
pointer for other purposes, and suggesting a fix. Unfortunately, it's
not clear that there is a complete solution to this problem.)
Since 6.1alpha5:
- Added GC_MAXIMUM_HEAP_SIZE environment variable.
- Fix configure.in for MIPS/LINUX. (Thanks to H.J. Lu.)
- Double page hash table size for -DLARGE_CONFIG.
- Integrated Bo Thorsen's X86-64 support.
- STACKBOTTOM definition for LINUX/MIPS was partially changed back.
(Thanks to H.J. Lu and Hiroshi Kawashima for resolving this.)
- Replaced all occurrences of LINUX_DATA_START in gcconfig.h with
SEARCH_FOR_DATA_START. It doesn't hurt to falll back to a search.
And __data_start doesn't seem to get defined correctly of the GC
library is loaded with LD_PRELOAD, e.g. for leak detection.
- If the GC_find_leak environment variable is set, do a
atexit(GC_gcollect) to give us at least one chance to detect leaks.
This may report some very benign leaks, but ...
- Addeded REDIRECT_FREE. It's necessary if we want leak detection with
LD_PRELOAD.
- Defer printing of leaked objects, as for smashed objects.
- Fixed process and descriptor leak in GC_print_callers. Try for
line number even if we got function name.)
- Ported parallel GC support and thread local allocation to Alpha.
Not yet well-tested.
- Added GC_DUMP_REGULARLY and added finalization statistics to GC_dump().
- Fixed Makefile.am to mention alpha_mach_dep.S instead of the defunct
alpha_mach_dep.s. (Thanks to Fergus Henderson.)
- Incorporated a change to new_gc_alloc.h, suggested by Johannes Schmidt,
which should make it work with gcc3.1. (I would still like to encourage
use of gc_allocator.h instead.)
- Use alpha_mach_dep.S only on Linux. (It's not clear that this is
optimal, but it otherwise didn't build on Tru64. Thanks to Fergus
Henderson.)
- Added ifdef to guard free() in os_dep.c. Otherwise we get a
compilation error on Irix. (Thanks to Dai Sato.)
- Added an experimental version of GC_memalign to mallocx.c. This can't
always work, since we don't handle alignment requests in the hblk-level
allocator, and we can't handle arbitrary pointer displacements unless
GC_all_interior_pointers is enabled. But it should work for alignment
requests up to HBLKSIZE. This is not yet documented in the standard
places.
- Finally debugged the OSF1/Tru64 thread support. This needs more testing,
since I needed to add a somewhat unconvincing workaround for signal
delivery issues that I don't yet completely understand. But it does
pass my tests, even in parallel GC mode. Incremental GC support is
disabled if thread support is enabled, due to the signal issues.
- Eliminated name-space-incorrect definition of _cdecl from gc_cpp.h.
- Added GC_debug_malloc_replacement and GC_debug_realloc_replacement
declarations to gc.h. On IA64, this is required for REDIRECT_MALLOC
to work correctly with these.
- Fixed Linux USE_PROC_FOR_LIBRARIES to work with a 64-bit /proc format.
Since 6.1:
- Guard the test for GC_DUMP_REGULARLY in misc.c with
"#ifndef NO_DEBUGGING". Otherwise it fails to build with NO_DEBUGGING
defined. (Thanks to Manuel Serrano.)
- Message about retrying suspend signals was incorrectly generated even when
flag was not set.
- Cleaned up MACOSX/NEXT root registration code. There was apparently a
separate ifdef case in GC_register_data_segments() for no reason.
- Removed MPROTECT_VDB for MACOSX port, based on one negative report.
- Arrange for gc.h and friends to be correctly installed with GNU-style
"make install".
- Enable the GNU-style build facility include C++ support in the library
with --enable-cplusplus. (Thanks to Thomas Maier for some of the patch.)
- Mark from GC_thread_key in linux_threads.c, in case that's allocated
from the garbage collected heap, as it is with our own thread-specific
storage implementation. (Thanks to Jeff Sturm.)
- Mark all free list header blocks if they are heap allocated. This avoids
some unnecessary tracing. And it remains correct if we clear the
root set. (Thanks to Jeff Sturm for identifying the bug.)
- Improved S390/Linux support. Add S390/Linux 64-bit support. (Thanks
to Ulrich Weigand.)
- Corrected the spelling of GC_{M,C}ALLOC_EXPLICTLY_TYPED to
GC_{M,C}ALLOC_EXPLICITLY_TYPED in gc_typed.h. This is technically
an interface change. Based on the fact that nobody reported this,
I suspect/hope there were no clients.
- Cleaned up gc_typed.h so that (1) it adds an extern "C" declaration
when appropriate, (2) doesn't generate references to undefined internal
macros, and (3) allows easier manual construction of descriptors.
- Close the file descriptor used by GC_print_address_map().
- Set the "close-on-exec" bit for various file descriptors maintained
for the collector's internal use.
- Added a hack to find memory segments owned by the system allocator
under win32. Based on my tests, this tends to eventually find all
segments, though it may take a while. There appear to be cleaner,
but slower solutions under NT/XP. But they rely on an API that's
unsupported under 9X.
- Changed Linux PowerPC stack finding to LINUX_STACKBOTTOM. (Thanks
to Akira Tagoh for pointing out that HEURISTIC1 doesn't work on
64-bit kernels.)
- Added GC_set_free_space_divisor to avoid some Windows dll issues.
- Added FIXUP_POINTER, POINTER_SHIFT, POINTER_MASK to allow preprocessing
of candidate pointers for tagging, etc.
- Always lock around GC_notify_full_gc(). Simplified code for
invoking GC_notify_full_gc().
- Changed the way DATASTART is defined on FreeBSD to be robust against
an unmapped page after etext. (Thanks to Hironori Sakamoto for
tracking down the intermittent failure.)
- Made GC_enable() and GC_disable() official. Deprecated direct update
of GC_dont_gc. Changed GC_gcollect to be a noop when garbage collection
is disabled.
- Call GC_register_dynamic_libraries before stopping the world on Linux,
in order to avoid a potential deadlock due to the dl_iterate_phdr lock.
- Introduced a more general mechanism for platform-dependent code to
decide whether the main data segment should be handled separately
from dynamic libraries, or registered by GC_register_dynamic_libraries.
The latter is more reliable and easier on Linux with dl_iterate_phdr.
Since 6.2alpha1:
- Fixed the completely broken FreeBSD code in 6.2alpha1. (Thanks to
Hironori Sakamoto for the patch.)
- Changed IRIX reference in dbg_mlc.c to IRIX5. (Thanks to Marcus Herbert.)
- Attempted to work around the problems with .S filenames and the SGI
compiler. (Reported by several people. Untested.)
- Worked around an HP/UX make issue with the GNU-style build process.
- Fixed the --enable-cplusplus build machinery to allow builds without
a C++ compiler. (That was always the intent ...)
- Changed the debugging allocation macros to explicitly pass the return
address for Linux and XXXBSD on hardware for which we can't get stack
traces. Use __builtin_return_address(0) to generate it when possible.
Some of the configuration work was cleaned up (good) and moved to gc.h
(bad, but necessary). This should make leak detection more useful
on a number of platforms. (Thanks to Fabian Thylman for the suggestion.)
- Fixed compilation problems in dbg_mlc.c with GC_ADD_CALLER.
- Bumped revision number for dynamic library.
Since 6.2alpha2:
- Don't include execinfo.h in os_dep.c when it's not needed, and may not exist.
Since 6.2alpha3:
- Use LINUX_STACKBOTTOM for >= glibc2.2 on Linux/MIPS. (See Debian bug
# 177204)
- Integrated Jeff Sturm and Jesse Rosenstock's MACOSX threads patches.
- Integrated Grzegorz Jakacki's substantial GNU build patch. "Make dist"
should now work for the GNU build process. Documentation files
are installed under share/gc.
- Tweaked gc_cpp.h to again support the Borland compiler. (Thanks to
Rene Girard for pointing out the problems.)
- Updated BCC_MAKEFILE (thanks to Rene Girard).
- Added GC_ASSERT check for minimum thread stack size.
- Added --enable-gc-assertions.
- Added some web documentation to the distribution. Updated it in the
process.
- Separate gc_conf_macros.h from gc.h.
- Added generic GC_THREADS client-defined macro to set the appropriate
GC_XXX_THREADS internal macro. (gc_config_macros.h.)
- Add debugging versions of _ignore_off_page allocation primitves.
- Moved declarations of GC_make_closure and GC_debug_invoke_finalizer
from gc.h to gc_priv.h.
- Reset GC_fail_count even if only a small allocation succeeds.
- Integrated Brian Alliet's patch for dynamic library support on Darwin.
- gc_cpp.h's gc_cleanup destructor called GC_REGISTER_FINALIZER_IGNORE_SELF
when it should have called the lower case version, since it was
explicitly computing a base pointer.
Since 6.2alpha4:
- GC_invoke_finalizers could, under rare conditions, set
GC_finalizer_mem_freed to an essentially random value. This could
possibly cause unbounded heap growth for long-running applications
under some conditions. (The bug was introduced in 6.1alpha5, and
is not in gcc3.3. Thanks to Ben Hutchings for finding it.)
- Attempted to sanitize the various DLL macros. GC_USE_DLL disappeared.
GC_DLL is used instead. All internal tests are now on GC_DLL.
README.macros is now more precise about the intended meaning.
- Include DllMain in the multithreaded win32 version only if the
collector is actually built as a dll. (Thanks to Mohan Embar for
a version of the patch.)
- Hide the cygwin threadAttach/Detach functions. They were violating our
namespace rules.
- Fixed an assertion in GC_check_heap_proc. Added GC_STATIC_ASSERT.
(Thanks again to Ben Hutchings.)
- Removed some obsolete definitions for Linux/PowerPC in gcconfig.h.
- CORD_cat was not rebalancing unbalanced trees in some cases, violating
a CORD invariant. Also tweaked the rebalancing rule for
CORD_cat_char_star. (Thanks to Alexandr Petrosian for the bug report
and patch.)
- Added hand-coded structured exception handling support to mark.c.
This should enable support of dynamic libraries under win32 with
gcc-compiled code. (Thanks to Ranjit Mathew for the patch.)
Turned on dynamic library scanning for win32/gcc.
- Removed some remnants of read wrapping. (Thanks to Kenneth Schalk.)
GC_USE_LD_WRAP ws probably broken in recent versions.
- The build could fail on some platforms since gcconfig.h could include
declarations mentioning ptr_t, which was not defined, e.g. when if_mach
was built. (Thanks to Yann Dirson for pointing this out.) Also
cleaned up tests for GC_PRIVATE_H in gcconfig.h a bit.
- The GC_LOOP_ON_ABORT environment variable interfered with incremental
collection, since the write fault handler was erroneously overridden.
Handlers are now set up in the correct order.
- It used to be possible to call GC_mark_thread_local_free_lists() while
the world was not stopped during an incremental GC. This was not safe.
Fortunately, it was also unnecessary. Added GC_world_stopped flag
to avoid it. (This caused occasional crashes in GC_set_fl_marks
with thread local allocation and incremental GC. This probably happened
primarily on old, slow multiprocessors.)
- Allowed overriding of MAX_THREADS in win32_threads.c from the build
command line. (Patch from Yannis Bres.)
- Taught the IA64/linux code to determine the register backing store base from
/proc/self/maps after checking the __libc symbol, but before guessing.
(__libc symbols are on the endangered list, and the guess is likely to not
always be right for 2.6 kernels.) Restructured the code to read and parse
/proc/self/maps so it only exists in one place (all platforms).
- The -DUSE_PROC_FOR_LIBRARIES code was broken on Linux. It claimed that it
also registered the main data segment, but didn't actually do so. (I don't
think anyone actually uses this configuration, but ...)
- Made another attempt to get --enablecplusplus to do the right thing.
Since there are unavoidable problems with C programs linking against a
dynamic library that includes C++ code, I separated out the c++ code into
libgccpp.
Since 6.2alpha5:
- There was extra underscore in the name of GC_save_registers_in_stack
for NetBSD/SPARC. (Thanks to Jaap Boender for the patch.)
- Integrated Brian Alliet's patch for Darwin. This restructured the
linuxthreads/pthreads support to separate generic pthreads support
from more the system-dependent thread-stopping code. I believe this
should make it easier to eliminate the code duplication between
pthreads platforms in the future. The patch included some other
code cleanups.
- Integrated Dan Bonachea's patch to support AIX threads. This required
substantial manual integration, mostly due to conflicts with other
recent threads changes. It may take another iteration to
get it to work.
- Removed HPUX/PA-RISC support from aix_irix_threads.c. It wasn't used
anyway and it cluttered up the code. And anything we can do to migrate
towards generic pthreads support is a good thing.
- Added a more explicit test for tracing of function arguments to test.c.
(Thanks to Dan Grayson.)
- Added Akira Tagoh's PowerPC64 patch.
- Fixed some bit rot in the Cygwin port. (Thanks to Dan Bonachea for
pointing it out.) Gc.h now includes just windows.h, not winbase.h.
- Declared GC_save_regs_in_stack() in gc_priv.h. Remove other declarations.
- Changed --enable-cplusplus to use automake consitionals. The old way
confused libtool. "Make install" didn't work correctly for the old version.
Previously --enable-cplusplus was broken on cygwin.
- Changed the C version of GC_push_regs to fail at compile time if it is
generated with an empty body. This seems to have been the cause of one
or two subtle failures on unusual platforms. Those failures should
now occur at build time and be easily fixable.
Since 6.2alpha6:
- Integrated a second round of Irix/AIX patches from Dan Bonachea.
Renamed mips_sgi_mach_dep.S back to mips_sgi_mach_dep.s, since it requires
the Irix assembler to do the C preprocessing; gcc -E doesn't work.
- Fixed Makefile.direct for DARWIN. (Thanks to Manuel Serrano.)
- There was a race between GC_pthread_detach and thread exit that could
result in a thread structure being deallocated by GC_pthread_detach
eventhough it was still needed by the thread exit code. (Thanks to
Dick Porter for the small test case that allowed this to be debugged.)
- Fixed version parsing for non-alpha versions in acinclude.m4 and
version checking in version.h.
Since 6.2:
- Integrated some NetBSD patches forwarded to me by Marc Recht. These
were already in the NetBSD package.
- GC_pthread_create waited for the semaphore even if pthread_create failed.
Thanks to Dick Porter for the pthread_support.c patch. Applied the
analogous fix for aix_irix_threads.c.
- Added Rainer Orth's Tru64 fixes.
- The check for exceeding the thread table size in win32 threadDetach
was incorrect. (Thanks to Alexandr Petrosian for the patch.)
- Applied Andrew Begel's patch to correct some reentrancy issues
with dynamic loading on Darwin.
- GC_CreateThread() was neglecting to duplicate the thread handle in
the table. (Thanks to Tum Nguyen for the patch.)
- Pass +ESdbgasm only on PA-RISC machines with vendor compiler.
(Thanks to Roger Sayle for the patch.)
- Applied more AIX threads patches from Scott Ananian.
To do:
- A dynamic libgc.so references dlopen unconditionally, but doesn't link
against libdl.
- GC_proc_fd for Solaris is not correctly updated in response to a
fork() call. Thus incremental collection in the child won't work
correctly. (Thanks to Ben Cottrell for pointing this out.)
- --enable-redirect-malloc is mostly untested and known not to work
on some platforms.
- There seem to be outstanding issues on Solaris/X86, possibly with
finding the data segment starting address. Information/patches would
be appreciated.
@ -1488,7 +1919,4 @@ To do:
- Incremental collector should handle large objects better. Currently,
it looks like the whole object is treated as dirty if any part of it
is.
- Cord/cordprnt.c doesn't build on a few platforms (notably PowerPC), since
we make some unwarranted assumptions about how varargs are handled. This
currently makes the cord-aware versions of printf unusable on some platforms.
Fixing this is unfortunately not trivial.

View File

@ -5,6 +5,8 @@ platforms.
GC_INITIAL_HEAP_SIZE=<bytes> - Initial heap size in bytes. May speed up
process start-up.
GC_MAXIMUM_HEAP_SIZE=<bytes> - Maximum collected heap size.
GC_LOOP_ON_ABORT - Causes the collector abort routine to enter a tight loop.
This may make it easier to debug, such a process, especially
for multithreaded platforms that don't produce usable core
@ -19,6 +21,11 @@ GC_PRINT_STATS - Turn on as much logging as is easily feasible without
by setting GC_quiet. On by default if the collector
was built without -DSILENT.
GC_DUMP_REGULARLY - Generate a GC debugging dump GC_dump() on startup
and during every collection. Very verbose. Useful
if you have a bug to report, but please include only the
last complete dump.
GC_PRINT_ADDRESS_MAP - Linux only. Dump /proc/self/maps, i.e. various address
maps for the process, to stderr on every GC. Useful for
mapping root addresses to source for deciphering leak
@ -27,7 +34,14 @@ GC_PRINT_ADDRESS_MAP - Linux only. Dump /proc/self/maps, i.e. various address
GC_NPROCS=<n> - Linux w/threads only. Explicitly sets the number of processors
that the GC should expect to use. Note that setting this to 1
when multiple processors are available will preserve
correctness, but may lead to really horrible performance.
correctness, but may lead to really horrible performance,
since the lock implementation will immediately yield without
first spinning.
GC_MARKERS=<n> - Linux w/threads and parallel marker only. Set the number
of marker threads. This is normaly set to the number of
processors. It is safer to adjust GC_MARKERS than GC_NPROCS,
since GC_MARKERS has no impact on the lock implementation.
GC_NO_BLACKLIST_WARNING - Prevents the collector from issuing
warnings about allocations of very large blocks.
@ -62,6 +76,20 @@ GC_PRINT_BACK_HEIGHT - Print max length of chain through unreachable objects
of Conservative Garbage Collectors", POPL 2001, or
http://lib.hpl.hp.com/techpubs/2001/HPL-2001-251.html .
GC_RETRY_SIGNALS, GC_NO_RETRY_SIGNALS - Try to compensate for lost
thread suspend signals in linux_threads.c. On by
default for GC_OSF1_THREADS, off otherwise. Note
that this does not work around a possible loss of
thread restart signals. This seems to be necessary for
some versions of Tru64. Since we've previously seen
similar issues on some other operating systems, it
was turned into a runtime flag to enable last-minute
work-arounds.
The following turn on runtime flags that are also program settable. Checked
only during initialization. We expect that they will usually be set through
other means, but this may help with debugging and testing:
GC_ENABLE_INCREMENTAL - Turn on incremental collection at startup. Note that,
depending on platform and collector configuration, this
may involve write protecting pieces of the heap to
@ -71,22 +99,20 @@ GC_ENABLE_INCREMENTAL - Turn on incremental collection at startup. Note that,
Use with caution.
GC_PAUSE_TIME_TARGET - Set the desired garbage collector pause time in msecs.
This only has an effect if incremental collection is enabled.
If a collection requires appreciably more time than this,
the client will be restarted, and the collector will need
to do additional work to compensate. The special value
"999999" indicates that pause time is unlimited, and the
incremental collector will behave completely like a
simple generational collector. If the collector is
configured for parallel marking, and run on a multiprocessor,
incremental collection should only be used with unlimited
pause time.
This only has an effect if incremental collection is
enabled. If a collection requires appreciably more time
than this, the client will be restarted, and the collector
will need to do additional work to compensate. The
special value "999999" indicates that pause time is
unlimited, and the incremental collector will behave
completely like a simple generational collector. If
the collector is configured for parallel marking, and
run on a multiprocessor, incremental collection should
only be used with unlimited pause time.
The following turn on runtime flags that are also program settable. Checked
only during initialization. We expect that they will usually be set through
other means, but this may help with debugging and testing:
GC_FIND_LEAK - Turns on GC_find_leak and thus leak detection.
GC_FIND_LEAK - Turns on GC_find_leak and thus leak detection. Forces a
collection at program termination to detect leaks that would
otherwise occur after the last GC.
GC_ALL_INTERIOR_POINTERS - Turns on GC_all_interior_pointers and thus interior
pointer recognition.

View File

@ -1,21 +1,18 @@
See README.alpha for Linux on DEC AXP info.
This file applies mostly to Linux/Intel IA32. Ports to Linux on an M68K
and PowerPC are also integrated. They should behave similarly, except that
the PowerPC port lacks incremental GC support, and it is unknown to what
extent the Linux threads code is functional. See below for M68K specific
notes.
This file applies mostly to Linux/Intel IA32. Ports to Linux on an M68K, IA64,
SPARC, MIPS, Alpha and PowerPC are also integrated. They should behave
similarly, except that the PowerPC port lacks incremental GC support, and
it is unknown to what extent the Linux threads code is functional.
See below for M68K specific notes.
Incremental GC is supported on Intel IA32 and M68K.
Incremental GC is generally supported.
Dynamic libraries are supported on an ELF system. A static executable
should be linked with the gcc option "-Wl,-defsym,_DYNAMIC=0".
The collector appears to work with Linux threads. We have seen
intermittent hangs in sem_wait. So far we have been unable to reproduce
these unless the process was being debugged or traced. Thus it's
possible that the only real issue is that the debugger loses
signals on rare occasions.
The collector appears to work reliably with Linux threads, but beware
of older versions of glibc and gdb.
The garbage collector uses SIGPWR and SIGXCPU if it is used with
Linux threads. These should not be touched by the client program.

View File

@ -21,6 +21,13 @@ registrations are ignored, but not terribly quickly.)
pointers. And the VirtualQuery call has different semantics under
the two systems, and under different versions of win32s.)
Win32 applications compiled with some flavor of gcc currently behave
like win32s applications, in that dynamic library data segments are
not scanned. (Gcc does not directly support Microsoft's "structured
exception handling". It turns out that use of this feature is
unavoidable if you scan arbitrary memory segments obtained from
VirtualQuery.)
The collector test program "gctest" is linked as a GUI application,
but does not open any windows. Its output appears in the file
"gc.log". It may be started from the file manager. The hour glass
@ -50,13 +57,20 @@ This appears to cause problems under Windows NT and Windows 2000 (but
not Windows 95/98) if the memory is later passed to CreateDIBitmap.
To work around this problem, build the collector with -DUSE_GLOBAL_ALLOC.
This is currently incompatible with -DUSE_MUNMAP. (Thanks to Jonathan
Clark for tracking this down.)
Clark for tracking this down. There's some chance this may be fixed
in 6.1alpha4, since we now separate heap sections with an unused page.)
For Microsoft development tools, rename NT_MAKEFILE as
MAKEFILE. (Make sure that the CPU environment variable is defined
to be i386.) In order to use the gc_cpp.h C++ interface, all
client code should include gc_cpp.h.
If you would prefer a VC++.NET project file, ask boehm@acm.org. One has
been contributed, but it seems to contain some absolute paths etc., so
it can presumably only be a starting point, and is not in the standard
distribution. It is unclear (to me, Hans Boehm) whether it is feasible to
change that.
Clients may need to define GC_NOT_DLL before including gc.h, if the
collector was built as a static library (as it normally is in the
absence of thread support).
@ -64,7 +78,7 @@ absence of thread support).
For GNU-win32, use the regular makefile, possibly after uncommenting
the line "include Makefile.DLLs". The latter should be necessary only
if you want to package the collector as a DLL. The GNU-win32 port is
believed to work only for b18, not b19, probably dues to linker changes
believed to work only for b18, not b19, probably due to linker changes
in b19. This is probably fixable with a different definition of
DATASTART and DATAEND in gcconfig.h.
@ -147,7 +161,7 @@ To compile the collector and testing programs use the command:
All programs using gc should be compiled with 4-byte alignment.
For further explanations on this see comments about Borland.
If gc compiled as dll, the macro ``GC_DLL'' should be defined before
If the gc is compiled as dll, the macro ``GC_DLL'' should be defined before
including "gc.h" (for example, with -DGC_DLL compiler option). It's
important, otherwise resulting programs will not run.

View File

@ -248,8 +248,12 @@ The <TT>hb_last_reclaimed</tt> field will identify the collection number
during which its block was last swept.
<LI> Verify that the offending object still has its correct contents at
this point.
The call <TT>GC_is_marked(p)</tt> from the debugger to verify that the
object has not been marked, and is about to be reclaimed.
Then call <TT>GC_is_marked(p)</tt> from the debugger to verify that the
object has not been marked, and is about to be reclaimed. Note that
<TT>GC_is_marked(p)</tt> expects the real address of an object (the
address of the debug header if there is one), and thus it may
be more appropriate to call <TT>GC_is_marked(GC_base(p))</tt>
instead.
<LI> Determine a path from a root, i.e. static variable, stack, or
register variable,
to the reclaimed object. Call <TT>GC_is_marked(q)</tt> for each object

View File

@ -55,9 +55,10 @@
!defined(MSWIN32) && !defined(MSWINCE) && \
!(defined(ALPHA) && defined(OSF1)) && \
!defined(HPUX) && !(defined(LINUX) && defined(__ELF__)) && \
!defined(RS6000) && !defined(SCO_ELF) && \
!defined(RS6000) && !defined(SCO_ELF) && !defined(DGUX) && \
!(defined(FREEBSD) && defined(__ELF__)) && \
!(defined(NETBSD) && defined(__ELF__)) && !defined(HURD)
!(defined(NETBSD) && defined(__ELF__)) && !defined(HURD) && \
!defined(DARWIN)
--> We only know how to find data segments of dynamic libraries for the
--> above. Additional SVR4 variants might not be too
--> hard to add.
@ -80,7 +81,7 @@
#endif
#if defined(LINUX) && defined(__ELF__) || defined(SCO_ELF) || \
(defined(FREEBSD) && defined(__ELF__)) || \
(defined(FREEBSD) && defined(__ELF__)) || defined(DGUX) || \
(defined(NETBSD) && defined(__ELF__)) || defined(HURD)
# include <stddef.h>
# include <elf.h>
@ -264,7 +265,7 @@ void GC_register_dynamic_libraries()
# endif /* SUNOS */
#if defined(LINUX) && defined(__ELF__) || defined(SCO_ELF) || \
(defined(FREEBSD) && defined(__ELF__)) || \
(defined(FREEBSD) && defined(__ELF__)) || defined(DGUX) || \
(defined(NETBSD) && defined(__ELF__)) || defined(HURD)
@ -282,56 +283,23 @@ extern ssize_t GC_repeat_read(int fd, char *buf, size_t count);
/* Repeatedly read until buffer is filled, or EOF is encountered */
/* Defined in os_dep.c. */
static char *parse_map_entry(char *buf_ptr, word *start, word *end,
char *prot_buf, unsigned int *maj_dev);
char *GC_parse_map_entry(char *buf_ptr, word *start, word *end,
char *prot_buf, unsigned int *maj_dev);
word GC_apply_to_maps(word (*fn)(char *));
/* From os_dep.c */
void GC_register_dynamic_libraries()
word GC_register_map_entries(char *maps)
{
int f;
int result;
char prot_buf[5];
int maps_size;
char maps_temp[32768];
char *maps_buf;
char *buf_ptr;
char *buf_ptr = maps;
int count;
word start, end;
unsigned int maj_dev, min_dev;
unsigned int maj_dev;
word least_ha, greatest_ha;
unsigned i;
word datastart = (word)(DATASTART);
/* Read /proc/self/maps */
/* Note that we may not allocate, and thus can't use stdio. */
f = open("/proc/self/maps", O_RDONLY);
if (-1 == f) ABORT("Couldn't open /proc/self/maps");
/* stat() doesn't work for /proc/self/maps, so we have to
read it to find out how large it is... */
maps_size = 0;
do {
result = GC_repeat_read(f, maps_temp, sizeof(maps_temp));
if (result <= 0) ABORT("Couldn't read /proc/self/maps");
maps_size += result;
} while (result == sizeof(maps_temp));
if (maps_size > sizeof(maps_temp)) {
/* If larger than our buffer, close and re-read it. */
close(f);
f = open("/proc/self/maps", O_RDONLY);
if (-1 == f) ABORT("Couldn't open /proc/self/maps");
maps_buf = alloca(maps_size);
if (NULL == maps_buf) ABORT("/proc/self/maps alloca failed");
result = GC_repeat_read(f, maps_buf, maps_size);
if (result <= 0) ABORT("Couldn't read /proc/self/maps");
} else {
/* Otherwise use the fixed size buffer */
maps_buf = maps_temp;
}
close(f);
maps_buf[result] = '\0';
buf_ptr = maps_buf;
/* Compute heap bounds. Should be done by add_to_heap? */
/* Compute heap bounds. FIXME: Should be done by add_to_heap? */
least_ha = (word)(-1);
greatest_ha = 0;
for (i = 0; i < GC_n_heap_sects; ++i) {
@ -342,11 +310,10 @@ void GC_register_dynamic_libraries()
}
if (greatest_ha < (word)GC_scratch_last_end_ptr)
greatest_ha = (word)GC_scratch_last_end_ptr;
for (;;) {
buf_ptr = parse_map_entry(buf_ptr, &start, &end, prot_buf, &maj_dev);
if (buf_ptr == NULL) return;
buf_ptr = GC_parse_map_entry(buf_ptr, &start, &end, prot_buf, &maj_dev);
if (buf_ptr == NULL) return 1;
if (prot_buf[1] == 'w') {
/* This is a writable mapping. Add it to */
/* the root set unless it is already otherwise */
@ -358,16 +325,7 @@ void GC_register_dynamic_libraries()
# ifdef THREADS
if (GC_segment_is_thread_stack(start, end)) continue;
# endif
/* The rest of this assumes that there is no mapping */
/* spanning the beginning of the data segment, or extending */
/* beyond the entire heap at both ends. */
/* Empirically these assumptions hold. */
if (start < (word)DATAEND && end > (word)DATAEND) {
/* Rld may use space at the end of the main data */
/* segment. Thus we add that in. */
start = (word)DATAEND;
}
/* We no longer exclude the main data segment. */
if (start < least_ha && end > least_ha) {
end = least_ha;
}
@ -377,7 +335,14 @@ void GC_register_dynamic_libraries()
if (start >= least_ha && end <= greatest_ha) continue;
GC_add_roots_inner((char *)start, (char *)end, TRUE);
}
}
}
return 1;
}
void GC_register_dynamic_libraries()
{
if (!GC_apply_to_maps(GC_register_map_entries))
ABORT("Failed to read /proc for library registration.");
}
/* We now take care of the main data segment ourselves: */
@ -387,60 +352,6 @@ GC_bool GC_register_main_static_data()
}
# define HAVE_REGISTER_MAIN_STATIC_DATA
//
// parse_map_entry parses an entry from /proc/self/maps so we can
// locate all writable data segments that belong to shared libraries.
// The format of one of these entries and the fields we care about
// is as follows:
// XXXXXXXX-XXXXXXXX r-xp 00000000 30:05 260537 name of mapping...\n
// ^^^^^^^^ ^^^^^^^^ ^^^^ ^^
// start end prot maj_dev
// 0 9 18 32
//
// The parser is called with a pointer to the entry and the return value
// is either NULL or is advanced to the next entry(the byte after the
// trailing '\n'.)
//
#define OFFSET_MAP_START 0
#define OFFSET_MAP_END 9
#define OFFSET_MAP_PROT 18
#define OFFSET_MAP_MAJDEV 32
static char *parse_map_entry(char *buf_ptr, word *start, word *end,
char *prot_buf, unsigned int *maj_dev)
{
int i;
unsigned int val;
char *tok;
if (buf_ptr == NULL || *buf_ptr == '\0') {
return NULL;
}
memcpy(prot_buf, buf_ptr+OFFSET_MAP_PROT, 4); // do the protections first
prot_buf[4] = '\0';
if (prot_buf[1] == 'w') { // we can skip all of this if it's not writable
tok = buf_ptr;
buf_ptr[OFFSET_MAP_START+8] = '\0';
*start = strtoul(tok, NULL, 16);
tok = buf_ptr+OFFSET_MAP_END;
buf_ptr[OFFSET_MAP_END+8] = '\0';
*end = strtoul(tok, NULL, 16);
buf_ptr += OFFSET_MAP_MAJDEV;
tok = buf_ptr;
while (*buf_ptr != ':') buf_ptr++;
*buf_ptr++ = '\0';
*maj_dev = strtoul(tok, NULL, 16);
}
while (*buf_ptr && *buf_ptr++ != '\n');
return buf_ptr;
}
#endif /* USE_PROC_FOR_LIBRARIES */
@ -508,6 +419,7 @@ GC_bool GC_register_dynamic_libraries_dl_iterate_phdr()
GC_add_roots_inner(DATASTART2, (char *)(DATAEND2), TRUE);
# endif
}
return TRUE;
} else {
return FALSE;
@ -534,6 +446,16 @@ GC_bool GC_register_main_static_data()
#if defined(NETBSD)
# include <sys/exec_elf.h>
/* for compatibility with 1.4.x */
# ifndef DT_DEBUG
# define DT_DEBUG 21
# endif
# ifndef PT_LOAD
# define PT_LOAD 1
# endif
# ifndef PF_W
# define PF_W 2
# endif
#else
# include <elf.h>
#endif
@ -1048,7 +970,7 @@ void GC_register_dynamic_libraries()
len = ldi->ldinfo_next;
GC_add_roots_inner(
ldi->ldinfo_dataorg,
(unsigned long)ldi->ldinfo_dataorg
(ptr_t)(unsigned long)ldi->ldinfo_dataorg
+ ldi->ldinfo_datasize,
TRUE);
ldi = len ? (struct ld_info *)((char *)ldi + len) : 0;
@ -1056,7 +978,133 @@ void GC_register_dynamic_libraries()
}
#endif /* RS6000 */
#ifdef DARWIN
#include <mach-o/dyld.h>
#include <mach-o/getsect.h>
/*#define DARWIN_DEBUG*/
const static struct {
const char *seg;
const char *sect;
} GC_dyld_sections[] = {
{ SEG_DATA, SECT_DATA },
{ SEG_DATA, SECT_BSS },
{ SEG_DATA, SECT_COMMON }
};
#ifdef DARWIN_DEBUG
static const char *GC_dyld_name_for_hdr(struct mach_header *hdr) {
unsigned long i,c;
c = _dyld_image_count();
for(i=0;i<c;i++) if(_dyld_get_image_header(i) == hdr)
return _dyld_get_image_name(i);
return NULL;
}
#endif
/* This should never be called by a thread holding the lock */
static void GC_dyld_image_add(struct mach_header* hdr, unsigned long slide) {
unsigned long start,end,i;
const struct section *sec;
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);
if(sec == NULL || sec->size == 0) continue;
start = slide + sec->addr;
end = start + sec->size;
# ifdef DARWIN_DEBUG
GC_printf4("Adding section at %p-%p (%lu bytes) from image %s\n",
start,end,sec->size,GC_dyld_name_for_hdr(hdr));
# endif
GC_add_roots((char*)start,(char*)end);
}
# ifdef DARWIN_DEBUG
GC_print_static_roots();
# endif
}
/* This should never be called by a thread holding the lock */
static void GC_dyld_image_remove(struct mach_header* hdr, unsigned long slide) {
unsigned long start,end,i;
const struct section *sec;
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);
if(sec == NULL || sec->size == 0) continue;
start = slide + sec->addr;
end = start + sec->size;
# ifdef DARWIN_DEBUG
GC_printf4("Removing section at %p-%p (%lu bytes) from image %s\n",
start,end,sec->size,GC_dyld_name_for_hdr(hdr));
# endif
GC_remove_roots((char*)start,(char*)end);
}
# ifdef DARWIN_DEBUG
GC_print_static_roots();
# endif
}
void GC_register_dynamic_libraries() {
/* Currently does nothing. The callbacks are setup by GC_init_dyld()
The dyld library takes it from there. */
}
/* The _dyld_* functions have an internal lock so no _dyld functions
can be called while the world is stopped without the risk of a deadlock.
Because of this we MUST setup callbacks BEFORE we ever stop the world.
This should be called BEFORE any thread in created and WITHOUT the
allocation lock held. */
void GC_init_dyld() {
static GC_bool initialized = FALSE;
char *bind_fully_env = NULL;
if(initialized) return;
# ifdef DARWIN_DEBUG
GC_printf0("Registering dyld callbacks...\n");
# endif
/* Apple's Documentation:
When you call _dyld_register_func_for_add_image, the dynamic linker runtime
calls the specified callback (func) once for each of the images that is
currently loaded into the program. When a new image is added to the program,
your callback is called again with the mach_header for the new image, and the
virtual memory slide amount of the new image.
This WILL properly register already linked libraries and libraries
linked in the future
*/
_dyld_register_func_for_add_image(GC_dyld_image_add);
_dyld_register_func_for_remove_image(GC_dyld_image_remove);
/* Set this early to avoid reentrancy issues. */
initialized = TRUE;
bind_fully_env = getenv("DYLD_BIND_AT_LAUNCH");
if (bind_fully_env == NULL) {
# ifdef DARWIN_DEBUG
GC_printf0("Forcing full bind of GC code...\n");
# endif
if(!_dyld_bind_fully_image_containing_address((unsigned long*)GC_malloc))
GC_abort("_dyld_bind_fully_image_containing_address failed");
}
}
#define HAVE_REGISTER_MAIN_STATIC_DATA
GC_bool GC_register_main_static_data()
{
/* Already done through dyld callbacks */
return FALSE;
}
#endif /* DARWIN */
#else /* !DYNAMIC_LOADING */

View File

@ -207,7 +207,8 @@ signed_word * log_size_ptr;
UNLOCK();
ENABLE_SIGNALS();
# endif
new_dl = GC_oom_fn(sizeof(struct disappearing_link));
new_dl = (struct disappearing_link *)
GC_oom_fn(sizeof(struct disappearing_link));
if (0 == new_dl) {
GC_finalization_failures++;
return(0);
@ -433,7 +434,8 @@ finalization_mark_proc * mp;
UNLOCK();
ENABLE_SIGNALS();
# endif
new_fo = GC_oom_fn(sizeof(struct finalizable_object));
new_fo = (struct finalizable_object *)
GC_oom_fn(sizeof(struct finalizable_object));
if (0 == new_fo) {
GC_finalization_failures++;
return;
@ -759,8 +761,9 @@ int GC_should_invoke_finalizers GC_PROTO((void))
/* Should be called without allocation lock. */
int GC_invoke_finalizers()
{
register struct finalizable_object * curr_fo;
register int count = 0;
struct finalizable_object * curr_fo;
int count = 0;
word mem_freed_before;
DCL_LOCK_STATE;
while (GC_finalize_now != 0) {
@ -768,6 +771,9 @@ int GC_invoke_finalizers()
DISABLE_SIGNALS();
LOCK();
# endif
if (count == 0) {
mem_freed_before = GC_mem_freed;
}
curr_fo = GC_finalize_now;
# ifdef THREADS
if (curr_fo != 0) GC_finalize_now = fo_next(curr_fo);
@ -789,6 +795,11 @@ int GC_invoke_finalizers()
GC_free((GC_PTR)curr_fo);
# endif
}
if (count != 0 && mem_freed_before != GC_mem_freed) {
LOCK();
GC_finalizer_mem_freed += (GC_mem_freed - mem_freed_before);
UNLOCK();
}
return count;
}
@ -801,7 +812,9 @@ void GC_notify_or_invoke_finalizers GC_PROTO((void))
if (GC_finalize_now == 0) return;
if (!GC_finalize_on_demand) {
(void) GC_invoke_finalizers();
GC_ASSERT(GC_finalize_now == 0);
# ifndef THREADS
GC_ASSERT(GC_finalize_now == 0);
# endif /* Otherwise GC can run concurrently and add more */
return;
}
if (GC_finalizer_notifier != (void (*) GC_PROTO((void)))0
@ -839,3 +852,17 @@ void GC_notify_or_invoke_finalizers GC_PROTO((void))
return(result);
}
#if !defined(NO_DEBUGGING)
void GC_print_finalization_stats()
{
struct finalizable_object *fo = GC_finalize_now;
size_t ready = 0;
GC_printf2("%lu finalization table entries; %lu disappearing links\n",
GC_fo_entries, GC_dl_entries);
for (; 0 != fo; fo = fo_next(fo)) ++ready;
GC_printf1("%lu objects are eligible for immediate finalization\n", ready);
}
#endif /* NO_DEBUGGING */

View File

@ -26,15 +26,13 @@ Authors: John R. Ellis and Jesse Hull
#include "gc_cpp.h"
#ifndef _MSC_VER
/* In the Visual C++ case, we moved this into the header. */
void* operator new( size_t size ) {
return GC_MALLOC_UNCOLLECTABLE( size );}
void operator delete( void* obj ) {
GC_FREE( obj );}
#ifdef OPERATOR_NEW_ARRAY
#ifdef GC_OPERATOR_NEW_ARRAY
void* operator new[]( size_t size ) {
return GC_MALLOC_UNCOLLECTABLE( size );}
@ -42,8 +40,22 @@ void* operator new[]( size_t size ) {
void operator delete[]( void* obj ) {
GC_FREE( obj );}
#endif /* OPERATOR_NEW_ARRAY */
#endif /* GC_OPERATOR_NEW_ARRAY */
#ifdef _MSC_VER
// This new operator is used by VC++ in case of Debug builds !
void* operator new( size_t size,
int ,//nBlockUse,
const char * szFileName,
int nLine )
{
#ifndef GC_DEBUG
return GC_malloc_uncollectable( size );
#else
return GC_debug_malloc_uncollectable(size, szFileName, nLine);
#endif
}
#endif /* _MSC_VER */

View File

@ -19,12 +19,14 @@
/*
* This used to be in dyn_load.c. It was extracted into a separate file
* to avoid having to link against libdl.{a,so} if the client doesn't call
* dlopen. -HB
* dlopen. Of course this fails if the collector is in a dynamic
* library. -HB
*/
#include "private/gc_priv.h"
# if defined(GC_PTHREADS) || defined(GC_SOLARIS_THREADS)
# if (defined(GC_PTHREADS) && !defined(GC_DARWIN_THREADS)) \
|| defined(GC_SOLARIS_THREADS)
# if defined(dlopen) && !defined(GC_USE_LD_WRAP)
/* To support various threads pkgs, gc.h interposes on dlopen by */
@ -44,19 +46,14 @@
/* calls in either a multithreaded environment, or if the library */
/* initialization code allocates substantial amounts of GC'ed memory. */
/* But I don't know of a better solution. */
/* This can still deadlock if the client explicitly starts a GC */
/* during the dlopen. He shouldn't do that. */
static GC_bool disable_gc_for_dlopen()
static void disable_gc_for_dlopen()
{
GC_bool result;
LOCK();
result = GC_dont_gc;
while (GC_incremental && GC_collection_in_progress()) {
GC_collect_a_little_inner(1000);
}
GC_dont_gc = TRUE;
++GC_dont_gc;
UNLOCK();
return(result);
}
/* Redefine dlopen to guarantee mutual exclusion with */
@ -74,10 +71,9 @@
#endif
{
void * result;
GC_bool dont_gc_save;
# ifndef USE_PROC_FOR_LIBRARIES
dont_gc_save = disable_gc_for_dlopen();
disable_gc_for_dlopen();
# endif
# ifdef GC_USE_LD_WRAP
result = (void *)__real_dlopen(path, mode);
@ -85,7 +81,7 @@
result = dlopen(path, mode);
# endif
# ifndef USE_PROC_FOR_LIBRARIES
GC_dont_gc = dont_gc_save;
GC_enable(); /* undoes disable_gc_for_dlopen */
# endif
return(result);
}

View File

@ -157,6 +157,7 @@ DCL_LOCK_STATE;
GC_words_allocd += lw;
}
*(void **)op = ptr_to_struct_containing_descr;
GC_ASSERT(((void **)op)[1] == 0);
UNLOCK();
} else {
LOCK();

View File

@ -14,7 +14,7 @@ char ** envp;
if (strcmp(MACH_TYPE, argv[1]) != 0) return(0);
if (strcmp(OS_TYPE, "") != 0 && strcmp(argv[2], "") != 0
&& strcmp(OS_TYPE, argv[2]) != 0) return(0);
printf("^^^^Starting command^^^^\n");
fprintf(stderr, "^^^^Starting command^^^^\n");
fflush(stdout);
execvp(argv[3], argv+3);
perror("Couldn't execute");

View File

@ -1,6 +1,6 @@
# Makefile.in generated automatically by automake 1.4 from Makefile.am
# Makefile.in generated automatically by automake 1.4-p5 from Makefile.am
# Copyright (C) 1994, 1995-8, 1999 Free Software Foundation, Inc.
# Copyright (C) 1994, 1995-8, 1999, 2001 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.
@ -66,9 +66,11 @@ target_triplet = @target@
AR = @AR@
AS = @AS@
CC = @CC@
CFLAGS = @CFLAGS@
CPP = @CPP@
CXX = @CXX@
CXXCPP = @CXXCPP@
CXXFLAGS = @CXXFLAGS@
CXXINCLUDES = @CXXINCLUDES@
DLLTOOL = @DLLTOOL@
EXEEXT = @EXEEXT@
@ -89,10 +91,15 @@ RANLIB = @RANLIB@
STRIP = @STRIP@
THREADLIBS = @THREADLIBS@
VERSION = @VERSION@
addincludes = @addincludes@
addlibs = @addlibs@
addobjs = @addobjs@
addtests = @addtests@
gc_basedir = @gc_basedir@
mkinstalldirs = @mkinstalldirs@
target_all = @target_all@
toolexecdir = @toolexecdir@
toolexeclibdir = @toolexeclibdir@
AUTOMAKE_OPTIONS = foreign

View File

@ -30,91 +30,7 @@
# define _GC_H
/*
* 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(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_LINUX_THREADS))
# define _REENTRANT
/* Better late than never. This fails if system headers that */
/* depend on this were previously included. */
#endif
#if defined(GC_SOLARIS_PTHREADS) && !defined(GC_SOLARIS_THREADS)
# define GC_SOLARIS_THREADS
#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)
# define GC_PTHREADS
# endif
# define __GC
# include <stddef.h>
# ifdef _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(__MINGW32__) &&defined(_DLL) && !defined(GC_NOT_DLL)
# ifdef GC_BUILD
# define GC_API __declspec(dllexport)
# else
# define GC_API __declspec(dllimport)
# endif
#endif
#if (defined(__DMC__) || defined(_MSC_VER)) \
&& (defined(_DLL) && !defined(GC_NOT_DLL) \
|| 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
# include "gc_config_macros.h"
# if defined(__STDC__) || defined(__cplusplus)
# define GC_PROTO(args) args
@ -154,7 +70,7 @@ GC_API int GC_parallel; /* GC is parallelized for performance on */
/* Env variable GC_NPROC is set to > 1, or */
/* GC_NPROC is not set and this is an MP. */
/* If GC_parallel is set, incremental */
/* collection is aonly partially functional, */
/* collection is only partially functional, */
/* and may not be desirable. */
@ -215,8 +131,14 @@ GC_API void (* GC_finalizer_notifier)();
/* thread, which will call GC_invoke_finalizers */
/* in response. */
GC_API int GC_dont_gc; /* Dont collect unless explicitly requested, e.g. */
/* because it's not safe. */
GC_API int GC_dont_gc; /* != 0 ==> Dont collect. In versions 6.2a1+, */
/* this overrides explicit GC_gcollect() calls. */
/* Used as a counter, so that nested enabling */
/* and disabling work correctly. Should */
/* normally be updated with GC_enable() and */
/* GC_disable() calls. */
/* Direct assignment to GC_dont_gc is */
/* deprecated. */
GC_API int GC_dont_expand;
/* Dont expand heap unless explicitly requested */
@ -316,9 +238,18 @@ GC_API unsigned long GC_time_limit;
/* enabled. */
# define GC_TIME_UNLIMITED 999999
/* Setting GC_time_limit to this value */
/* will disable the "pause time exceeded */
/* will disable the "pause time exceeded"*/
/* tests. */
/* Public procedures */
/* Initialize the collector. This is only required when using thread-local
* allocation, since unlike the regular allocation routines, GC_local_malloc
* is not self-initializing. If you use GC_local_malloc you should arrange
* to call this somehow (e.g. from a constructor) before doing any allocation.
*/
GC_API void GC_init GC_PROTO((void));
/*
* general purpose allocation routines, with roughly malloc calling conv.
* The atomic versions promise that no relevant pointers are contained
@ -419,17 +350,21 @@ GC_API void GC_clear_roots GC_PROTO((void));
GC_API void GC_add_roots GC_PROTO((char * low_address,
char * high_address_plus_1));
/* Remove a root segment. Wizards only. */
GC_API void GC_remove_roots GC_PROTO((char * low_address,
char * high_address_plus_1));
/* Add a displacement to the set of those considered valid by the */
/* collector. GC_register_displacement(n) means that if p was returned */
/* by GC_malloc, then (char *)p + n will be considered to be a valid */
/* pointer to n. N must be small and less than the size of p. */
/* pointer to p. N must be small and less than the size of p. */
/* (All pointers to the interior of objects from the stack are */
/* considered valid in any case. This applies to heap objects and */
/* static data.) */
/* Preferably, this should be called before any other GC procedures. */
/* Calling it later adds to the probability of excess memory */
/* retention. */
/* This is a no-op if the collector was compiled with recognition of */
/* This is a no-op if the collector has recognition of */
/* arbitrary interior pointers enabled, which is now the default. */
GC_API void GC_register_displacement GC_PROTO((GC_word n));
@ -464,9 +399,18 @@ GC_API size_t GC_get_free_bytes GC_PROTO((void));
GC_API size_t GC_get_bytes_since_gc GC_PROTO((void));
/* Return the total number of bytes allocated in this process. */
/* Never decreases. */
/* Never decreases, except due to wrapping. */
GC_API size_t GC_get_total_bytes GC_PROTO((void));
/* Disable garbage collection. Even GC_gcollect calls will be */
/* ineffective. */
GC_API void GC_disable GC_PROTO((void));
/* Reenable garbage collection. GC_disable() and GC_enable() calls */
/* nest. Garbage collection is enabled if the number of calls to both */
/* both functions is equal. */
GC_API void GC_enable GC_PROTO((void));
/* Enable incremental/generational collection. */
/* Not advisable unless dirty bits are */
/* available or most heap objects are */
@ -474,7 +418,11 @@ GC_API size_t GC_get_total_bytes GC_PROTO((void));
/* Don't use in leak finding mode. */
/* Ignored if GC_dont_gc is true. */
/* Only the generational piece of this is */
/* functional if GC_parallel is TRUE. */
/* functional if GC_parallel is TRUE */
/* or if GC_time_limit is GC_TIME_UNLIMITED. */
/* Causes GC_local_gcj_malloc() to revert to */
/* locked allocation. Must be called */
/* before any GC_local_gcj_malloc() calls. */
GC_API void GC_enable_incremental GC_PROTO((void));
/* Does incremental mode write-protect pages? Returns zero or */
@ -518,6 +466,42 @@ GC_API GC_PTR GC_malloc_atomic_ignore_off_page GC_PROTO((size_t lb));
# define GC_RETURN_ADDR (GC_word)__return_address
#endif
#ifdef __linux__
# include <features.h>
# if (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 1 || __GLIBC__ > 2) \
&& !defined(__ia64__)
# define GC_HAVE_BUILTIN_BACKTRACE
# define GC_CAN_SAVE_CALL_STACKS
# endif
# if defined(__i386__) || defined(__x86_64__)
# define GC_CAN_SAVE_CALL_STACKS
# endif
#endif
#if defined(__sparc__)
# define GC_CAN_SAVE_CALL_STACKS
#endif
/* If we're on an a platform on which we can't save call stacks, but */
/* gcc is normally used, we go ahead and define GC_ADD_CALLER. */
/* We make this decision independent of whether gcc is actually being */
/* used, in order to keep the interface consistent, and allow mixing */
/* of compilers. */
/* This may also be desirable if it is possible but expensive to */
/* retrieve the call chain. */
#if (defined(__linux__) || defined(__NetBSD__) || defined(__OpenBSD__) \
|| defined(__FreeBSD__)) & !defined(GC_CAN_SAVE_CALL_STACKS)
# define GC_ADD_CALLER
# if __GNUC__ >= 3 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 95)
/* gcc knows how to retrieve return address, but we don't know */
/* how to generate call stacks. */
# define GC_RETURN_ADDR (GC_word)__builtin_return_address(0)
# else
/* Just pass 0 for gcc compatibility. */
# define GC_RETURN_ADDR 0
# endif
#endif
#ifdef GC_ADD_CALLER
# define GC_EXTRAS GC_RETURN_ADDR, __FILE__, __LINE__
# define GC_EXTRA_PARAMS GC_word ra, GC_CONST char * s, int i
@ -536,18 +520,42 @@ 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
GC_PROTO((size_t size_in_bytes, GC_EXTRA_PARAMS));
GC_API GC_PTR GC_debug_malloc_ignore_off_page
GC_PROTO((size_t size_in_bytes, GC_EXTRA_PARAMS));
GC_API GC_PTR GC_debug_malloc_atomic_ignore_off_page
GC_PROTO((size_t size_in_bytes, GC_EXTRA_PARAMS));
GC_API void GC_debug_free GC_PROTO((GC_PTR object_addr));
GC_API GC_PTR GC_debug_realloc
GC_PROTO((GC_PTR old_object, size_t new_size_in_bytes,
GC_EXTRA_PARAMS));
GC_API void GC_debug_change_stubborn GC_PROTO((GC_PTR));
GC_API void GC_debug_end_stubborn_change GC_PROTO((GC_PTR));
/* Routines that allocate objects with debug information (like the */
/* above), but just fill in dummy file and line number information. */
/* Thus they can serve as drop-in malloc/realloc replacements. This */
/* can be useful for two reasons: */
/* 1) It allows the collector to be built with DBG_HDRS_ALL defined */
/* even if some allocation calls come from 3rd party libraries */
/* that can't be recompiled. */
/* 2) On some platforms, the file and line information is redundant, */
/* since it can be reconstructed from a stack trace. On such */
/* platforms it may be more convenient not to recompile, e.g. for */
/* leak detection. This can be accomplished by instructing the */
/* linker to replace malloc/realloc with these. */
GC_API GC_PTR GC_debug_malloc_replacement GC_PROTO((size_t size_in_bytes));
GC_API GC_PTR GC_debug_realloc_replacement
GC_PROTO((GC_PTR object_addr, size_t size_in_bytes));
# 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_MALLOC_UNCOLLECTABLE(sz) GC_debug_malloc_uncollectable(sz, \
GC_EXTRAS)
# define GC_MALLOC_UNCOLLECTABLE(sz) \
GC_debug_malloc_uncollectable(sz, GC_EXTRAS)
# define GC_MALLOC_IGNORE_OFF_PAGE(sz) \
GC_debug_malloc_ignore_off_page(sz, GC_EXTRAS)
# define GC_MALLOC_ATOMIC_IGNORE_OFF_PAGE(sz) \
GC_debug_malloc_atomic_ignore_off_page(sz, GC_EXTRAS)
# define GC_REALLOC(old, sz) GC_debug_realloc(old, sz, GC_EXTRAS)
# define GC_FREE(p) GC_debug_free(p)
# define GC_REGISTER_FINALIZER(p, f, d, of, od) \
@ -566,6 +574,10 @@ GC_API void GC_debug_end_stubborn_change GC_PROTO((GC_PTR));
# define GC_MALLOC(sz) GC_malloc(sz)
# define GC_MALLOC_ATOMIC(sz) GC_malloc_atomic(sz)
# define GC_MALLOC_UNCOLLECTABLE(sz) GC_malloc_uncollectable(sz)
# define GC_MALLOC_IGNORE_OFF_PAGE(sz) \
GC_malloc_ignore_off_page(sz)
# define GC_MALLOC_ATOMIC_IGNORE_OFF_PAGE(sz) \
GC_malloc_atomic_ignore_off_page(sz)
# define GC_REALLOC(old, sz) GC_realloc(old, sz)
# define GC_FREE(p) GC_free(p)
# define GC_REGISTER_FINALIZER(p, f, d, of, od) \
@ -644,7 +656,8 @@ GC_API void GC_debug_register_finalizer
/* itself. There is a stylistic argument that this is wrong, */
/* but it's unavoidable for C++, since the compiler may */
/* silently introduce these. It's also benign in that specific */
/* case. */
/* case. And it helps if finalizable objects are split to */
/* avoid cycles. */
/* Note that cd will still be viewed as accessible, even if it */
/* refers to the object itself. */
GC_API void GC_register_finalizer_ignore_self
@ -717,11 +730,6 @@ GC_API int GC_unregister_disappearing_link GC_PROTO((GC_PTR * /* link */));
/* Undoes a registration by either of the above two */
/* routines. */
/* Auxiliary fns to make finalization work correctly with displaced */
/* pointers introduced by the debugging allocators. */
GC_API GC_PTR GC_make_closure GC_PROTO((GC_finalization_proc fn, GC_PTR data));
GC_API void GC_debug_invoke_finalizer GC_PROTO((GC_PTR obj, GC_PTR data));
/* Returns !=0 if GC_invoke_finalizers has something to do. */
GC_API int GC_should_invoke_finalizers GC_PROTO((void));
@ -738,6 +746,10 @@ GC_API int GC_invoke_finalizers GC_PROTO((void));
typedef void (*GC_warn_proc) GC_PROTO((char *msg, GC_word arg));
GC_API GC_warn_proc GC_set_warn_proc GC_PROTO((GC_warn_proc p));
/* Returns old warning procedure. */
GC_API GC_word GC_set_free_space_divisor GC_PROTO((GC_word value));
/* Set free_space_divisor. See above for definition. */
/* Returns old value. */
/* The following is intended to be used by a higher level */
/* (e.g. Java-like) finalization facility. It is expected */
@ -873,14 +885,17 @@ extern void GC_thr_init(); /* Needed for Solaris/X86 */
#endif /* THREADS && !SRC_M3 */
#if defined(GC_WIN32_THREADS)
#if defined(GC_WIN32_THREADS) && !defined(__CYGWIN32__) && !defined(__CYGWIN__)
# include <windows.h>
/*
* All threads must be created using GC_CreateThread, so that they will be
* recorded in the thread table.
* recorded in the thread table. For backwards compatibility, this is not
* technically true if the GC is built as a dynamic library, since it can
* and does then use DllMain to keep track of thread creations. But new code
* should be built to call GC_CreateThread.
*/
HANDLE WINAPI GC_CreateThread(
GC_API HANDLE GC_CreateThread(
LPSECURITY_ATTRIBUTES lpThreadAttributes,
DWORD dwStackSize, LPTHREAD_START_ROUTINE lpStartAddress,
LPVOID lpParameter, DWORD dwCreationFlags, LPDWORD lpThreadId );
@ -902,7 +917,7 @@ extern void GC_thr_init(); /* Needed for Solaris/X86 */
# endif
# endif /* defined(_WIN32_WCE) */
#endif /* defined(GC_WIN32_THREADS) */
#endif /* defined(GC_WIN32_THREADS) && !cygwin */
/*
* If you are planning on putting
@ -914,13 +929,18 @@ extern void GC_thr_init(); /* Needed for Solaris/X86 */
# define GC_INIT() { extern end, etext; \
GC_noop(&end, &etext); }
#else
# if (defined(__CYGWIN32__) && defined(GC_USE_DLL)) || defined (_AIX)
# if defined(__CYGWIN32__) && defined(GC_DLL) || defined (_AIX)
/*
* Similarly gnu-win32 DLLs need explicit initialization
* Similarly gnu-win32 DLLs need explicit initialization from
* the main program, as does AIX.
*/
# define GC_INIT() { GC_add_roots(DATASTART, DATAEND); }
# else
# if defined(__APPLE__) && defined(__MACH__)
# define GC_INIT() { GC_init(); }
# else
# define GC_INIT()
# endif
# endif
#endif

View File

@ -134,7 +134,9 @@ by UseGC. GC is an alias for UseGC, unless GC_NAME_CONFLICT is defined.
#include "gc.h"
#ifndef THINK_CPLUS
#define _cdecl
# define GC_cdecl
#else
# define GC_cdecl _cdecl
#endif
#if ! defined( GC_NO_OPERATOR_NEW_ARRAY ) \
@ -159,12 +161,22 @@ enum GCPlacement {UseGC,
class gc {public:
inline void* operator new( size_t size );
inline void* operator new( size_t size, GCPlacement gcp );
inline void* operator new( size_t size, void *p );
/* Must be redefined here, since the other overloadings */
/* hide the global definition. */
inline void operator delete( void* obj );
# ifndef __BORLANDC__ /* Confuses the Borland compiler. */
inline void operator delete( void*, void* );
# endif
#ifdef GC_OPERATOR_NEW_ARRAY
inline void* operator new[]( size_t size );
inline void* operator new[]( size_t size, GCPlacement gcp );
inline void* operator new[]( size_t size, void *p );
inline void operator delete[]( void* obj );
# ifndef __BORLANDC__
inline void gc::operator delete[]( void*, void* );
# endif
#endif /* GC_OPERATOR_NEW_ARRAY */
};
/*
@ -176,7 +188,7 @@ class gc_cleanup: virtual public gc {public:
inline gc_cleanup();
inline virtual ~gc_cleanup();
private:
inline static void _cdecl cleanup( void* obj, void* clientData );};
inline static void GC_cdecl cleanup( void* obj, void* clientData );};
/*
Instances of classes derived from "gc_cleanup" will be allocated
in the collected heap by default. When the collector discovers an
@ -211,7 +223,6 @@ inline void* operator new(
classes derived from "gc_cleanup" or containing members derived
from "gc_cleanup". */
#ifdef GC_OPERATOR_NEW_ARRAY
#ifdef _MSC_VER
/** This ensures that the system default operator new[] doesn't get
@ -220,42 +231,24 @@ inline void* operator new(
* There seems to be really redirect new in this environment without
* including this everywhere.
*/
inline void *operator new[]( size_t size )
{
return GC_MALLOC_UNCOLLECTABLE( size );
}
void *operator new[]( size_t size );
void operator delete[](void* obj);
inline void operator delete[](void* obj)
{
GC_FREE(obj);
};
void* operator new( size_t size);
inline void* operator new( size_t size)
{
return GC_MALLOC_UNCOLLECTABLE( size);
};
void operator delete(void* obj);
inline void operator delete(void* obj)
{
GC_FREE(obj);
};
// This new operator is used by VC++ in case of Debug builds !
inline void* operator new( size_t size,
// This new operator is used by VC++ in case of Debug builds !
void* operator new( size_t size,
int ,//nBlockUse,
const char * szFileName,
int nLine
) {
# ifndef GC_DEBUG
return GC_malloc_uncollectable( size );
# else
return GC_debug_malloc_uncollectable(size, szFileName, nLine);
# endif
}
int nLine );
#endif /* _MSC_VER */
#ifdef GC_OPERATOR_NEW_ARRAY
inline void* operator new[](
size_t size,
GCPlacement gcp,
@ -283,9 +276,15 @@ inline void* gc::operator new( size_t size, GCPlacement gcp ) {
else
return GC_MALLOC_UNCOLLECTABLE( size );}
inline void* gc::operator new( size_t size, void *p ) {
return p;}
inline void gc::operator delete( void* obj ) {
GC_FREE( obj );}
#ifndef __BORLANDC__
inline void gc::operator delete( void*, void* ) {}
#endif
#ifdef GC_OPERATOR_NEW_ARRAY
@ -295,14 +294,21 @@ inline void* gc::operator new[]( size_t size ) {
inline void* gc::operator new[]( size_t size, GCPlacement gcp ) {
return gc::operator new( size, gcp );}
inline void* gc::operator new[]( size_t size, void *p ) {
return p;}
inline void gc::operator delete[]( void* obj ) {
gc::operator delete( obj );}
#ifndef __BORLANDC__
inline void gc::operator delete[]( void*, void* ) {}
#endif
#endif /* GC_OPERATOR_NEW_ARRAY */
inline gc_cleanup::~gc_cleanup() {
GC_REGISTER_FINALIZER_IGNORE_SELF( GC_base(this), 0, 0, 0, 0 );}
GC_register_finalizer_ignore_self( GC_base(this), 0, 0, 0, 0 );}
inline void gc_cleanup::cleanup( void* obj, void* displ ) {
((gc_cleanup*) ((char*) obj + (ptrdiff_t) displ))->~gc_cleanup();}

View File

@ -33,6 +33,9 @@
* -DTHREAD_LOCAL_ALLOC, which is currently supported only on Linux.
*
* The debugging allocators use standard, not thread-local allocation.
*
* These routines normally require an explicit call to GC_init(), though
* that may be done from a constructor function.
*/
#ifndef GC_LOCAL_ALLOC_H

View File

@ -129,7 +129,9 @@ extern GC_PTR GC_greatest_plausible_heap_addr;
/* be reserved for exceptional cases. That will ensure that */
/* performance of this call is not extremely performance critical. */
/* (Otherwise we would need to inline GC_mark_and_push completely, */
/* which would tie the client code to a fixed colllector version.) */
/* which would tie the client code to a fixed collector version.) */
/* Note that mark procedures should explicitly call FIXUP_POINTER() */
/* if required. */
struct GC_ms_entry *GC_mark_and_push
GC_PROTO((GC_PTR obj,
struct GC_ms_entry * mark_stack_ptr,

View File

@ -52,15 +52,30 @@
int GC_pthread_create(pthread_t *new_thread,
const pthread_attr_t *attr,
void *(*start_routine)(void *), void *arg);
#ifndef GC_DARWIN_THREADS
int GC_pthread_sigmask(int how, const sigset_t *set, sigset_t *oset);
#endif
int GC_pthread_join(pthread_t thread, void **retval);
int GC_pthread_detach(pthread_t thread);
#if defined(GC_OSF1_THREADS) \
&& defined(_PTHREAD_USE_MANGLED_NAMES_) && !defined(_PTHREAD_USE_PTDNAM_)
/* Unless the compiler supports #pragma extern_prefix, the Tru64 UNIX
<pthread.h> redefines some POSIX thread functions to use mangled names.
If so, undef them before redefining. */
# undef pthread_create
# undef pthread_join
# undef pthread_detach
#endif
# define pthread_create GC_pthread_create
# define pthread_sigmask GC_pthread_sigmask
# define pthread_join GC_pthread_join
# define pthread_detach GC_pthread_detach
#ifndef GC_DARWIN_THREADS
# define pthread_sigmask GC_pthread_sigmask
# define dlopen GC_dlopen
#endif
#endif /* GC_xxxxx_THREADS */

View File

@ -29,14 +29,21 @@
# include "gc.h"
# endif
#ifdef __cplusplus
extern "C" {
#endif
typedef GC_word * GC_bitmap;
/* The least significant bit of the first word is one if */
/* the first word in the object may be a pointer. */
# define GC_WORDSZ (8*sizeof(GC_word))
# define GC_get_bit(bm, index) \
(((bm)[divWORDSZ(index)] >> modWORDSZ(index)) & 1)
(((bm)[index/GC_WORDSZ] >> (index%GC_WORDSZ)) & 1)
# define GC_set_bit(bm, index) \
(bm)[divWORDSZ(index)] |= (word)1 << modWORDSZ(index)
(bm)[index/GC_WORDSZ] |= ((GC_word)1 << (index%GC_WORDSZ))
# define GC_WORD_OFFSET(t, f) (offsetof(t,f)/sizeof(GC_word))
# define GC_WORD_LEN(t) (sizeof(t)/ sizeof(GC_word))
# define GC_BITMAP_SIZE(t) ((GC_WORD_LEN(t) + GC_WORDSZ-1)/GC_WORDSZ)
typedef GC_word GC_descr;
@ -57,6 +64,16 @@ GC_API GC_descr GC_make_descriptor GC_PROTO((GC_bitmap bm, size_t len));
/* is intended to be called once per type, not once */
/* per allocation. */
/* It is possible to generate a descriptor for a C type T with */
/* word aligned pointer fields f1, f2, ... as follows: */
/* */
/* GC_descr T_descr; */
/* GC_word T_bitmap[GC_BITMAP_SIZE(T)] = {0}; */
/* GC_set_bit(T_bitmap, GC_WORD_OFFSET(T,f1)); */
/* GC_set_bit(T_bitmap, GC_WORD_OFFSET(T,f2)); */
/* ... */
/* T_descr = GC_make_descriptor(T_bitmap, GC_WORD_LEN(T)); */
GC_API GC_PTR GC_malloc_explicitly_typed
GC_PROTO((size_t size_in_bytes, GC_descr d));
/* Allocate an object whose layout is described by d. */
@ -79,15 +96,18 @@ GC_API GC_PTR GC_calloc_explicitly_typed
/* Returned object is cleared. */
#ifdef GC_DEBUG
# define GC_MALLOC_EXPLICTLY_TYPED(bytes, d) GC_MALLOC(bytes)
# define GC_CALLOC_EXPLICTLY_TYPED(n, bytes, d) GC_MALLOC(n*bytes)
# define GC_MALLOC_EXPLICITLY_TYPED(bytes, d) GC_MALLOC(bytes)
# define GC_CALLOC_EXPLICITLY_TYPED(n, bytes, d) GC_MALLOC(n*bytes)
#else
# define GC_MALLOC_EXPLICTLY_TYPED(bytes, d) \
# define GC_MALLOC_EXPLICITLY_TYPED(bytes, d) \
GC_malloc_explicitly_typed(bytes, d)
# define GC_CALLOC_EXPLICTLY_TYPED(n, bytes, d) \
# define GC_CALLOC_EXPLICITLY_TYPED(n, bytes, d) \
GC_calloc_explicitly_typed(n, bytes, d)
#endif /* !GC_DEBUG */
#ifdef __cplusplus
} /* matches extern "C" */
#endif
#endif /* _GC_TYPED_H */

View File

@ -64,6 +64,14 @@
#endif
#endif
/* A hack to deal with gcc 3.1. If you are using gcc3.1 and later, */
/* you should probably really use gc_allocator.h instead. */
#if defined (__GNUC__) && \
(__GNUC > 3 || (__GNUC__ == 3 && (__GNUC_MINOR__ >= 1)))
# define simple_alloc __simple_alloc
#endif
#define GC_ALLOC_H

View File

@ -115,16 +115,24 @@ typedef struct {
#ifdef SHORT_DBG_HDRS
# define DEBUG_BYTES (sizeof (oh))
# define UNCOLLECTABLE_DEBUG_BYTES DEBUG_BYTES
#else
/* Add space for END_FLAG, but use any extra space that was already */
/* added to catch off-the-end pointers. */
# define DEBUG_BYTES (sizeof (oh) + sizeof (word) - EXTRA_BYTES)
/* For uncollectable objects, the extra byte is not added. */
# define UNCOLLECTABLE_DEBUG_BYTES (sizeof (oh) + sizeof (word))
# define DEBUG_BYTES (UNCOLLECTABLE_DEBUG_BYTES - EXTRA_BYTES)
#endif
#define USR_PTR_FROM_BASE(p) ((ptr_t)(p) + sizeof(oh))
/* Round bytes to words without adding extra byte at end. */
#define SIMPLE_ROUNDED_UP_WORDS(n) BYTES_TO_WORDS((n) + WORDS_TO_BYTES(1) - 1)
/* ADD_CALL_CHAIN stores a (partial) call chain into an object */
/* header. It may be called with or without the allocation */
/* lock. */
/* PRINT_CALL_CHAIN prints the call chain stored in an object */
/* to stderr. It requires that we do not hold the lock. */
#ifdef SAVE_CALL_CHAIN
# define ADD_CALL_CHAIN(base, ra) GC_save_callers(((oh *)(base)) -> oh_ci)
# define PRINT_CALL_CHAIN(base) GC_print_callers(((oh *)(base)) -> oh_ci)

View File

@ -70,7 +70,7 @@ extern hdr * GC_invalid_header; /* header for an imaginary block */
#define ADVANCE(p, hhdr, source) \
{ \
hdr * new_hdr = GC_invalid_header; \
p = GC_FIND_START(p, hhdr, &new_hdr, (word)source); \
p = GC_find_start(p, hhdr, &new_hdr); \
hhdr = new_hdr; \
}

View File

@ -141,23 +141,24 @@
# if defined(POWERPC)
inline static int GC_test_and_set(volatile unsigned int *addr) {
int oldval;
int temp = 1; // locked value
int temp = 1; /* locked value */
__asm__ __volatile__(
"1:\tlwarx %0,0,%3\n" // load and reserve
"\tcmpwi %0, 0\n" // if load is
"\tbne 2f\n" // non-zero, return already set
"\tstwcx. %2,0,%1\n" // else store conditional
"\tbne- 1b\n" // retry if lost reservation
"2:\t\n" // oldval is zero if we set
"1:\tlwarx %0,0,%3\n" /* load and reserve */
"\tcmpwi %0, 0\n" /* if load is */
"\tbne 2f\n" /* non-zero, return already set */
"\tstwcx. %2,0,%1\n" /* else store conditional */
"\tbne- 1b\n" /* retry if lost reservation */
"\tsync\n" /* import barrier */
"2:\t\n" /* oldval is zero if we set */
: "=&r"(oldval), "=p"(addr)
: "r"(temp), "1"(addr)
: "memory");
return (int)oldval;
: "cr0","memory");
return oldval;
}
# define GC_TEST_AND_SET_DEFINED
inline static void GC_clear(volatile unsigned int *addr) {
__asm__ __volatile__("eieio" ::: "memory");
__asm__ __volatile__("eieio" : : : "memory");
*(addr) = 0;
}
# define GC_CLEAR_DEFINED
@ -174,12 +175,18 @@
" bne %2,2f\n"
" xor %0,%3,%0\n"
" stl_c %0,%1\n"
# ifdef __ELF__
" beq %0,3f\n"
# else
" beq %0,1b\n"
# endif
" mb\n"
"2:\n"
# ifdef __ELF__
".section .text2,\"ax\"\n"
"3: br 1b\n"
".previous"
# endif
:"=&r" (temp), "=m" (*addr), "=&r" (oldvalue)
:"Ir" (1), "m" (*addr)
:"memory");
@ -187,8 +194,11 @@
return oldvalue;
}
# define GC_TEST_AND_SET_DEFINED
/* Should probably also define GC_clear, since it needs */
/* a memory barrier ?? */
inline static void GC_clear(volatile unsigned int *addr) {
__asm__ __volatile__("mb" : : : "memory");
*(addr) = 0;
}
# define GC_CLEAR_DEFINED
# endif /* ALPHA */
# ifdef ARM32
inline static int GC_test_and_set(volatile unsigned int *addr) {
@ -206,22 +216,30 @@
# define GC_TEST_AND_SET_DEFINED
# endif /* ARM32 */
# ifdef S390
inline static int GC_test_and_set(volatile unsigned int *addr) {
int ret;
__asm__ __volatile__ (
" l %0,0(%2)\n"
"0: cs %0,%1,0(%2)\n"
" jl 0b"
: "=&d" (ret)
: "d" (1), "a" (addr)
: "cc", "memory");
return ret;
}
inline static int GC_test_and_set(volatile unsigned int *addr) {
int ret;
__asm__ __volatile__ (
" l %0,0(%2)\n"
"0: cs %0,%1,0(%2)\n"
" jl 0b"
: "=&d" (ret)
: "d" (1), "a" (addr)
: "cc", "memory");
return ret;
}
# endif
# endif /* __GNUC__ */
# if (defined(ALPHA) && !defined(__GNUC__))
# define GC_test_and_set(addr) __cxx_test_and_set_atomic(addr, 1)
# ifndef OSF1
--> We currently assume that if gcc is not used, we are
--> running under Tru64.
# endif
# include <machine/builtins.h>
# include <c_asm.h>
# define GC_test_and_set(addr) __ATOMIC_EXCH_LONG(addr, 1)
# define GC_TEST_AND_SET_DEFINED
# define GC_clear(addr) { asm("mb"); *(volatile unsigned *)addr = 0; }
# define GC_CLEAR_DEFINED
# endif
# if defined(MSWIN32)
# define GC_test_and_set(addr) InterlockedExchange((LPLONG)addr,1)
@ -234,14 +252,51 @@
# define GC_TEST_AND_SET_DEFINED
# elif __mips < 3 || !(defined (_ABIN32) || defined(_ABI64)) \
|| !defined(_COMPILER_VERSION) || _COMPILER_VERSION < 700
# define GC_test_and_set(addr) test_and_set(addr, 1)
# ifdef __GNUC__
# define GC_test_and_set(addr) _test_and_set((void *)addr,1)
# else
# define GC_test_and_set(addr) test_and_set((void *)addr,1)
# endif
# else
# define GC_test_and_set(addr) __test_and_set(addr,1)
# define GC_test_and_set(addr) __test_and_set32((void *)addr,1)
# define GC_clear(addr) __lock_release(addr);
# define GC_CLEAR_DEFINED
# endif
# define GC_TEST_AND_SET_DEFINED
# endif /* MIPS */
# if defined(_AIX)
# include <sys/atomic_op.h>
# if (defined(_POWER) || defined(_POWERPC))
# if defined(__GNUC__)
inline static void GC_memsync() {
__asm__ __volatile__ ("sync" : : : "memory");
}
# else
# ifndef inline
# define inline __inline
# endif
# pragma mc_func GC_memsync { \
"7c0004ac" /* sync (same opcode used for dcs)*/ \
}
# endif
# else
# error dont know how to memsync
# endif
inline static int GC_test_and_set(volatile unsigned int * addr) {
int oldvalue = 0;
if (compare_and_swap((void *)addr, &oldvalue, 1)) {
GC_memsync();
return 0;
} else return 1;
}
# define GC_TEST_AND_SET_DEFINED
inline static void GC_clear(volatile unsigned int *addr) {
GC_memsync();
*(addr) = 0;
}
# define GC_CLEAR_DEFINED
# endif
# if 0 /* defined(HP_PA) */
/* The official recommendation seems to be to not use ldcw from */
/* user mode. Since multithreaded incremental collection doesn't */
@ -275,7 +330,7 @@
# endif
# if defined(GC_PTHREADS) && !defined(GC_SOLARIS_THREADS) \
&& !defined(GC_IRIX_THREADS)
&& !defined(GC_IRIX_THREADS) && !defined(GC_WIN32_THREADS)
# define NO_THREAD (pthread_t)(-1)
# include <pthread.h>
# if defined(PARALLEL_MARK)
@ -306,12 +361,12 @@
{
char result;
__asm__ __volatile__("lock; cmpxchgl %2, %0; setz %1"
: "=m"(*(addr)), "=r"(result)
: "r" (new_val), "0"(*(addr)), "a"(old) : "memory");
: "+m"(*(addr)), "=r"(result)
: "r" (new_val), "a"(old) : "memory");
return (GC_bool) result;
}
# endif /* !GENERIC_COMPARE_AND_SWAP */
inline static void GC_memory_write_barrier()
inline static void GC_memory_barrier()
{
/* We believe the processor ensures at least processor */
/* consistent ordering. Thus a compiler barrier */
@ -319,6 +374,37 @@
__asm__ __volatile__("" : : : "memory");
}
# endif /* I386 */
# if defined(POWERPC)
# if !defined(GENERIC_COMPARE_AND_SWAP)
/* 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)
{
int result, dummy;
__asm__ __volatile__(
"1:\tlwarx %0,0,%5\n"
"\tcmpw %0,%4\n"
"\tbne 2f\n"
"\tstwcx. %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;
}
# endif /* !GENERIC_COMPARE_AND_SWAP */
inline static void GC_memory_barrier()
{
__asm__ __volatile__("sync" : : : "memory");
}
# endif /* POWERPC */
# if defined(IA64)
# if !defined(GENERIC_COMPARE_AND_SWAP)
inline static GC_bool GC_compare_and_exchange(volatile GC_word *addr,
@ -330,31 +416,71 @@
# endif /* !GENERIC_COMPARE_AND_SWAP */
# if 0
/* Shouldn't be needed; we use volatile stores instead. */
inline static void GC_memory_write_barrier()
inline static void GC_memory_barrier()
{
__sync_synchronize ();
}
# endif /* 0 */
# endif /* IA64 */
# if defined(ALPHA)
# if !defined(GENERIC_COMPARE_AND_SWAP)
# if defined(__GNUC__)
inline static GC_bool GC_compare_and_exchange(volatile GC_word *addr,
GC_word old, GC_word new_val)
{
unsigned long was_equal;
unsigned long temp;
__asm__ __volatile__(
"1: ldq_l %0,%1\n"
" cmpeq %0,%4,%2\n"
" mov %3,%0\n"
" beq %2,2f\n"
" stq_c %0,%1\n"
" beq %0,1b\n"
"2:\n"
" mb\n"
:"=&r" (temp), "=m" (*addr), "=&r" (was_equal)
: "r" (new_val), "Ir" (old)
:"memory");
return was_equal;
}
# else /* !__GNUC__ */
inline static GC_bool GC_compare_and_exchange(volatile GC_word *addr,
GC_word old, GC_word new_val)
{
return __CMP_STORE_QUAD(addr, old, new_val, addr);
}
# endif /* !__GNUC__ */
# endif /* !GENERIC_COMPARE_AND_SWAP */
# ifdef __GNUC__
inline static void GC_memory_barrier()
{
__asm__ __volatile__("mb" : : : "memory");
}
# else
# define GC_memory_barrier() asm("mb")
# endif /* !__GNUC__ */
# endif /* ALPHA */
# if defined(S390)
# if !defined(GENERIC_COMPARE_AND_SWAP)
inline static GC_bool GC_compare_and_exchange(volatile C_word *addr,
GC_word old, GC_word new_val)
{
int retval;
__asm__ __volatile__ (
# ifndef __s390x__
" cs %1,%2,0(%3)\n"
# else
" csg %1,%2,0(%3)\n"
# endif
" ipm %0\n"
" srl %0,28\n"
: "=&d" (retval), "+d" (old)
: "d" (new_val), "a" (addr)
: "cc", "memory");
return retval == 0;
}
inline static GC_bool GC_compare_and_exchange(volatile C_word *addr,
GC_word old, GC_word new_val)
{
int retval;
__asm__ __volatile__ (
# ifndef __s390x__
" cs %1,%2,0(%3)\n"
# else
" csg %1,%2,0(%3)\n"
# endif
" ipm %0\n"
" srl %0,28\n"
: "=&d" (retval), "+d" (old)
: "d" (new_val), "a" (addr)
: "cc", "memory");
return retval == 0;
}
# endif
# endif
# if !defined(GENERIC_COMPARE_AND_SWAP)
@ -427,8 +553,12 @@
{ GC_ASSERT(I_HOLD_LOCK()); UNSET_LOCK_HOLDER(); \
pthread_mutex_unlock(&GC_allocate_ml); }
# else /* !GC_ASSERTIONS */
# if defined(NO_PTHREAD_TRYLOCK)
# define LOCK() GC_lock();
# else /* !defined(NO_PTHREAD_TRYLOCK) */
# define LOCK() \
{ if (0 != pthread_mutex_trylock(&GC_allocate_ml)) GC_lock(); }
# endif
# define UNLOCK() pthread_mutex_unlock(&GC_allocate_ml)
# endif /* !GC_ASSERTIONS */
# endif /* USE_PTHREAD_LOCKS */
@ -450,7 +580,7 @@
/* on Irix anymore. */
# include <mutex.h>
extern unsigned long GC_allocate_lock;
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. */
@ -471,11 +601,18 @@
}
# define EXIT_GC() GC_collecting = 0;
# endif /* GC_IRIX_THREADS */
# ifdef GC_WIN32_THREADS
# include <windows.h>
GC_API CRITICAL_SECTION GC_allocate_ml;
# define LOCK() EnterCriticalSection(&GC_allocate_ml);
# define UNLOCK() LeaveCriticalSection(&GC_allocate_ml);
# if defined(GC_WIN32_THREADS)
# if defined(GC_PTHREADS)
# include <pthread.h>
extern pthread_mutex_t GC_allocate_ml;
# define LOCK() pthread_mutex_lock(&GC_allocate_ml)
# define UNLOCK() pthread_mutex_unlock(&GC_allocate_ml)
# else
# include <windows.h>
GC_API CRITICAL_SECTION GC_allocate_ml;
# define LOCK() EnterCriticalSection(&GC_allocate_ml);
# define UNLOCK() LeaveCriticalSection(&GC_allocate_ml);
# endif
# endif
# ifndef SET_LOCK_HOLDER
# define SET_LOCK_HOLDER()

View File

@ -137,7 +137,7 @@ extern mse * GC_mark_stack;
#ifdef __STDC__
# ifdef PRINT_BLACK_LIST
ptr_t GC_find_start(ptr_t current, hdr *hhdr, hdr **new_hdr_p,
ptr_t source);
word source);
# else
ptr_t GC_find_start(ptr_t current, hdr *hhdr, hdr **new_hdr_p);
# endif
@ -145,7 +145,7 @@ extern mse * GC_mark_stack;
ptr_t GC_find_start();
#endif
mse *GC_signal_mark_stack_overflow(mse *msp);
mse * GC_signal_mark_stack_overflow GC_PROTO((mse *msp));
# ifdef GATHERSTATS
# define ADD_TO_ATOMIC(sz) GC_atomic_in_use += (sz)
@ -174,14 +174,6 @@ mse *GC_signal_mark_stack_overflow(mse *msp);
} \
}
#ifdef PRINT_BLACK_LIST
# define GC_FIND_START(current, hhdr, new_hdr_p, source) \
GC_find_start(current, hhdr, new_hdr_p, source)
#else
# define GC_FIND_START(current, hhdr, new_hdr_p, source) \
GC_find_start(current, hhdr, new_hdr_p)
#endif
/* Push the contents of current onto the mark stack if it is a valid */
/* ptr to a currently unmarked object. Mark it. */
/* If we assumed a standard-conforming compiler, we could probably */
@ -195,8 +187,7 @@ mse *GC_signal_mark_stack_overflow(mse *msp);
GET_HDR(my_current, my_hhdr); \
if (IS_FORWARDING_ADDR_OR_NIL(my_hhdr)) { \
hdr * new_hdr = GC_invalid_header; \
my_current = GC_FIND_START(my_current, my_hhdr, \
&new_hdr, (word)source); \
my_current = GC_find_start(my_current, my_hhdr, &new_hdr); \
my_hhdr = new_hdr; \
} \
PUSH_CONTENTS_HDR(my_current, mark_stack_top, mark_stack_limit, \
@ -290,21 +281,39 @@ exit_label: ; \
/*
* Push a single value onto mark stack. Mark from the object pointed to by p.
* Invoke FIXUP_POINTER(p) before any further processing.
* P is considered valid even if it is an interior pointer.
* Previously marked objects are not pushed. Hence we make progress even
* if the mark stack overflows.
*/
# define GC_PUSH_ONE_STACK(p, source) \
if ((ptr_t)(p) >= (ptr_t)GC_least_plausible_heap_addr \
# if NEED_FIXUP_POINTER
/* Try both the raw version and the fixed up one. */
# define GC_PUSH_ONE_STACK(p, source) \
if ((ptr_t)(p) >= (ptr_t)GC_least_plausible_heap_addr \
&& (ptr_t)(p) < (ptr_t)GC_greatest_plausible_heap_addr) { \
PUSH_ONE_CHECKED_STACK(p, source); \
}
} \
FIXUP_POINTER(p); \
if ((ptr_t)(p) >= (ptr_t)GC_least_plausible_heap_addr \
&& (ptr_t)(p) < (ptr_t)GC_greatest_plausible_heap_addr) { \
PUSH_ONE_CHECKED_STACK(p, source); \
}
# else /* !NEED_FIXUP_POINTER */
# define GC_PUSH_ONE_STACK(p, source) \
if ((ptr_t)(p) >= (ptr_t)GC_least_plausible_heap_addr \
&& (ptr_t)(p) < (ptr_t)GC_greatest_plausible_heap_addr) { \
PUSH_ONE_CHECKED_STACK(p, source); \
}
# endif
/*
* As above, but interior pointer recognition as for
* normal for heap pointers.
*/
# define GC_PUSH_ONE_HEAP(p,source) \
FIXUP_POINTER(p); \
if ((ptr_t)(p) >= (ptr_t)GC_least_plausible_heap_addr \
&& (ptr_t)(p) < (ptr_t)GC_greatest_plausible_heap_addr) { \
GC_mark_stack_top = GC_mark_and_push( \

View File

@ -30,14 +30,20 @@
# define BSD_TIME
#endif
#ifdef DGUX
# include <sys/types.h>
# include <sys/time.h>
# include <sys/resource.h>
#endif /* DGUX */
#ifdef BSD_TIME
# include <sys/types.h>
# include <sys/time.h>
# include <sys/resource.h>
#endif /* BSD_TIME */
# ifndef GC_H
# include "gc.h"
# ifndef _GC_H
# include "../gc.h"
# endif
# ifndef GC_MARK_H
@ -206,11 +212,10 @@ typedef char * ptr_t; /* A generic pointer to which we can add */
#endif
#if defined(GC_GCJ_SUPPORT) && ALIGNMENT < 8 && !defined(ALIGN_DOUBLE)
/* GCJ's Hashtable synchronization code requires 64-bit alignment. */
/* GCJ's Hashtable synchronization code requires 64-bit alignment. */
# define ALIGN_DOUBLE
#endif
/* ALIGN_DOUBLE requires MERGE_SIZES at present. */
# if defined(ALIGN_DOUBLE) && !defined(MERGE_SIZES)
# define MERGE_SIZES
@ -347,7 +352,8 @@ void GC_print_callers GC_PROTO((struct callinfo info[NFRAMES]));
# include <string.h>
# define BCOPY_EXISTS
# endif
# if defined(MACOSX)
# if defined(DARWIN)
# include <string.h>
# define BCOPY_EXISTS
# endif
@ -360,68 +366,6 @@ void GC_print_callers GC_PROTO((struct callinfo info[NFRAMES]));
# define BZERO(x,n) bzero((char *)(x),(int)(n))
# endif
/* HBLKSIZE aligned allocation. 0 is taken to mean failure */
/* space is assumed to be cleared. */
/* In the case os USE_MMAP, the argument must also be a */
/* physical page size. */
/* GET_MEM is currently not assumed to retrieve 0 filled space, */
/* though we should perhaps take advantage of the case in which */
/* does. */
struct hblk; /* See below. */
# ifdef PCR
char * real_malloc();
# define GET_MEM(bytes) HBLKPTR(real_malloc((size_t)bytes + GC_page_size) \
+ GC_page_size-1)
# else
# ifdef OS2
void * os2_alloc(size_t bytes);
# define GET_MEM(bytes) HBLKPTR((ptr_t)os2_alloc((size_t)bytes \
+ GC_page_size) \
+ GC_page_size-1)
# else
# if defined(NEXT) || defined(MACOSX) || defined(DOS4GW) || \
(defined(AMIGA) && !defined(GC_AMIGA_FASTALLOC)) || \
(defined(SUNOS5) && !defined(USE_MMAP))
# define GET_MEM(bytes) HBLKPTR((size_t) \
calloc(1, (size_t)bytes + GC_page_size) \
+ GC_page_size-1)
# else
# ifdef MSWIN32
extern ptr_t GC_win32_get_mem();
# define GET_MEM(bytes) (struct hblk *)GC_win32_get_mem(bytes)
# else
# ifdef MACOS
# if defined(USE_TEMPORARY_MEMORY)
extern Ptr GC_MacTemporaryNewPtr(size_t size,
Boolean clearMemory);
# define GET_MEM(bytes) HBLKPTR( \
GC_MacTemporaryNewPtr(bytes + GC_page_size, true) \
+ GC_page_size-1)
# else
# define GET_MEM(bytes) HBLKPTR( \
NewPtrClear(bytes + GC_page_size) + GC_page_size-1)
# endif
# else
# ifdef MSWINCE
extern ptr_t GC_wince_get_mem();
# define GET_MEM(bytes) (struct hblk *)GC_wince_get_mem(bytes)
# else
# if defined(AMIGA) && defined(GC_AMIGA_FASTALLOC)
extern void *GC_amiga_get_mem(size_t size);
define GET_MEM(bytes) HBLKPTR((size_t) \
GC_amiga_get_mem((size_t)bytes + GC_page_size) \
+ GC_page_size-1)
# else
extern ptr_t GC_unix_get_mem();
# define GET_MEM(bytes) (struct hblk *)GC_unix_get_mem(bytes)
# endif
# endif
# endif
# endif
# endif
# endif
# endif
/* Delay any interrupts or signals that may abort this thread. Data */
/* structures are in a consistent state outside this pair of calls. */
/* ANSI C allows both to be empty (though the standard isn't very */
@ -486,7 +430,7 @@ struct hblk; /* See below. */
# ifdef SMALL_CONFIG
# define ABORT(msg) abort();
# else
GC_API void GC_abort();
GC_API void GC_abort GC_PROTO((GC_CONST char * msg));
# define ABORT(msg) GC_abort(msg);
# endif
# endif
@ -646,9 +590,10 @@ extern GC_warn_proc GC_current_warn_proc;
*/
# ifdef LARGE_CONFIG
# define LOG_PHT_ENTRIES 19 /* Collisions likely at 512K blocks, */
/* which is >= 2GB. Each table takes */
/* 64KB. */
# define LOG_PHT_ENTRIES 20 /* Collisions likely at 1M blocks, */
/* which is >= 4GB. Each table takes */
/* 128KB, some of which may never be */
/* touched. */
# else
# ifdef SMALL_CONFIG
# define LOG_PHT_ENTRIES 14 /* Collisions are likely if heap grows */
@ -656,7 +601,7 @@ extern GC_warn_proc GC_current_warn_proc;
/* Each hash table occupies 2K bytes. */
# else /* default "medium" configuration */
# define LOG_PHT_ENTRIES 16 /* Collisions are likely if heap grows */
/* to more than 16K hblks >= 256MB. */
/* to more than 64K hblks >= 256MB. */
/* Each hash table occupies 8K bytes. */
# endif
# endif
@ -897,6 +842,10 @@ struct _GC_arrays {
word _mem_freed;
/* Number of explicitly deallocated words of memory */
/* since last collection. */
word _finalizer_mem_freed;
/* Words of memory explicitly deallocated while */
/* finalizers were running. Used to approximate mem. */
/* explicitly deallocated by finalizers. */
ptr_t _scratch_end_ptr;
ptr_t _scratch_last_end_ptr;
/* Used by headers.c, and can easily appear to point to */
@ -957,7 +906,7 @@ struct _GC_arrays {
/* OFFSET_TOO_BIG if the value j would be too */
/* large to fit in the entry. (Note that the */
/* size of these entries matters, both for */
/* space consumption and for cache utilization. */
/* space consumption and for cache utilization.) */
# define OFFSET_TOO_BIG 0xfe
# define OBJ_INVALID 0xff
# define MAP_ENTRY(map, bytes) (map)[bytes]
@ -1067,6 +1016,7 @@ GC_API GC_FAR struct _GC_arrays GC_arrays;
# define GC_words_finalized GC_arrays._words_finalized
# define GC_non_gc_bytes_at_gc GC_arrays._non_gc_bytes_at_gc
# define GC_mem_freed GC_arrays._mem_freed
# define GC_finalizer_mem_freed GC_arrays._finalizer_mem_freed
# define GC_scratch_end_ptr GC_arrays._scratch_end_ptr
# define GC_scratch_last_end_ptr GC_arrays._scratch_last_end_ptr
# define GC_mark_procs GC_arrays._mark_procs
@ -1201,17 +1151,19 @@ extern struct hblk * GC_hblkfreelist[];
/* header structure associated with */
/* block. */
extern GC_bool GC_is_initialized; /* GC_init() has been run. */
extern GC_bool GC_objects_are_marked; /* There are marked objects in */
/* the heap. */
#ifndef SMALL_CONFIG
extern GC_bool GC_incremental;
/* Using incremental/generational collection. */
# define TRUE_INCREMENTAL \
(GC_incremental && GC_time_limit != GC_TIME_UNLIMITED)
/* True incremental, not just generational, mode */
#else
# define GC_incremental FALSE
/* Hopefully allow optimizer to remove some code. */
# define TRUE_INCREMENTAL FALSE
#endif
extern GC_bool GC_dirty_maintained;
@ -1229,6 +1181,10 @@ extern long GC_large_alloc_warn_interval;
extern long GC_large_alloc_warn_suppressed;
/* Number of warnings suppressed so far. */
#ifdef THREADS
extern GC_bool GC_world_stopped;
#endif
/* Operations */
# ifndef abs
# define abs(x) ((x) < 0? (-(x)) : (x))
@ -1402,6 +1358,11 @@ extern void (*GC_start_call_back) GC_PROTO((void));
void GC_generic_push_regs GC_PROTO((ptr_t cold_gc_frame));
# else
void GC_push_regs GC_PROTO((void));
# endif
# if defined(SPARC) || defined(IA64)
/* Cause all stacked registers to be saved in memory. Return a */
/* pointer to the top of the corresponding memory stack. */
word GC_save_regs_in_stack GC_PROTO((void));
# endif
/* Push register contents onto mark stack. */
/* If NURSERY is defined, the default push */
@ -1452,6 +1413,7 @@ void GC_set_fl_marks GC_PROTO((ptr_t p));
/* Set all mark bits associated with */
/* a free list. */
void GC_add_roots_inner GC_PROTO((char * b, char * e, GC_bool tmp));
void GC_remove_roots_inner GC_PROTO((char * b, char * e));
GC_bool GC_is_static_root GC_PROTO((ptr_t p));
/* Is the address p in one of the registered static */
/* root sections? */
@ -1462,11 +1424,10 @@ GC_bool GC_is_tmp_root GC_PROTO((ptr_t p));
# endif
void GC_register_dynamic_libraries GC_PROTO((void));
/* Add dynamic library data sections to the root set. */
GC_bool GC_register_main_static_data GC_PROTO((void));
/* We need to register the main data segment. Returns */
/* TRUE unless this is done implicitly as part of */
/* dynamic library registration. */
/* We need to register the main data segment. Returns */
/* TRUE unless this is done implicitly as part of */
/* dynamic library registration. */
/* Machine dependent startup routines */
ptr_t GC_get_stack_base GC_PROTO((void)); /* Cold end of stack */
@ -1624,6 +1585,8 @@ GC_bool GC_collect_or_expand GC_PROTO(( \
/* until the blocks are available or */
/* until it fails by returning FALSE. */
extern GC_bool GC_is_initialized; /* GC_init() has been run. */
#if defined(MSWIN32) || defined(MSWINCE)
void GC_deinit GC_PROTO((void));
/* Free any resources allocated by */
@ -1665,6 +1628,8 @@ ptr_t GC_allocobj GC_PROTO((word sz, int kind));
/* Make the indicated */
/* free list nonempty, and return its */
/* head. */
void GC_free_inner(GC_PTR p);
void GC_init_headers GC_PROTO((void));
struct hblkhdr * GC_install_header GC_PROTO((struct hblk *h));
@ -1694,6 +1659,12 @@ void GC_notify_or_invoke_finalizers GC_PROTO((void));
/* Call *GC_finalizer_notifier if there are */
/* finalizers to be run, and we haven't called */
/* this procedure yet this GC cycle. */
GC_API GC_PTR GC_make_closure GC_PROTO((GC_finalization_proc fn, GC_PTR data));
GC_API void GC_debug_invoke_finalizer GC_PROTO((GC_PTR obj, GC_PTR data));
/* Auxiliary fns to make finalization work */
/* correctly with displaced pointers introduced */
/* by the debugging allocators. */
void GC_add_to_heap GC_PROTO((struct hblk *p, word bytes));
/* Add a HBLKSIZE aligned chunk to the heap. */
@ -1704,16 +1675,36 @@ void GC_print_obj GC_PROTO((ptr_t p));
/* description of the object to stderr. */
extern void (*GC_check_heap) GC_PROTO((void));
/* Check that all objects in the heap with */
/* debugging info are intact. Print */
/* descriptions of any that are not. */
/* debugging info are intact. */
/* Add any that are not to GC_smashed list. */
extern void (*GC_print_all_smashed) GC_PROTO((void));
/* Print GC_smashed if it's not empty. */
/* Clear GC_smashed list. */
extern void GC_print_all_errors GC_PROTO((void));
/* Print smashed and leaked objects, if any. */
/* Clear the lists of such objects. */
extern void (*GC_print_heap_obj) GC_PROTO((ptr_t p));
/* If possible print s followed by a more */
/* detailed description of the object */
/* referred to by p. */
#if defined(LINUX) && defined(__ELF__) && !defined(SMALL_CONFIG)
void GC_print_address_map GC_PROTO((void));
/* Print an address map of the process. */
#endif
extern GC_bool GC_have_errors; /* We saw a smashed or leaked object. */
/* Call error printing routine */
/* occasionally. */
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. */
# define COND_DUMP if (GC_dump_regularly) GC_dump();
#else
# define COND_DUMP
#endif
/* Macros used for collector internal allocation. */
/* These assume the collector lock is held. */
#ifdef DBG_HDRS_ALL
@ -1785,6 +1776,7 @@ void GC_print_block_list GC_PROTO((void));
void GC_print_hblkfreelist GC_PROTO((void));
void GC_print_heap_sects GC_PROTO((void));
void GC_print_static_roots GC_PROTO((void));
void GC_print_finalization_stats GC_PROTO((void));
void GC_dump GC_PROTO((void));
#ifdef KEEP_BACK_PTRS
@ -1866,6 +1858,16 @@ void GC_err_puts GC_PROTO((GC_CONST char *s));
# define GC_ASSERT(expr)
# endif
/* Check a compile time assertion at compile time. The error */
/* message for failure is a bit baroque, but ... */
#if defined(mips) && !defined(__GNUC__)
/* DOB: MIPSPro C gets an internal error taking the sizeof an array type.
This code works correctly (ugliness is to avoid "unused var" warnings) */
# define GC_STATIC_ASSERT(expr) do { if (0) { char j[(expr)? 1 : -1]; j[0]='\0'; j[0]=j[0]; } } while(0)
#else
# define GC_STATIC_ASSERT(expr) sizeof(char[(expr)? 1 : -1])
#endif
# if defined(PARALLEL_MARK) || defined(THREAD_LOCAL_ALLOC)
/* We need additional synchronization facilities from the thread */
/* support. We believe these are less performance critical */
@ -1911,7 +1913,7 @@ void GC_err_puts GC_PROTO((GC_CONST char *s));
/* in Linux glibc, but it's not exported.) Thus we continue to use */
/* the same hard-coded signals we've always used. */
# if !defined(SIG_SUSPEND)
# if defined(GC_LINUX_THREADS)
# if defined(GC_LINUX_THREADS) || defined(GC_DGUX386_THREADS)
# if defined(SPARC) && !defined(SIGPWR)
/* SPARC/Linux doesn't properly define SIGPWR in <signal.h>.
* It is aliased to SIGLOST in asm/signal.h, though. */

View File

@ -13,11 +13,25 @@
* provided the above notices are retained, and a notice that the code was
* modified is included with the above copyright notice.
*/
/*
* This header is private to the gc. It is almost always included from
* gc_priv.h. However it is possible to include it by itself if just the
* configuration macros are needed. In that
* case, a few declarations relying on types declared in gc_priv.h will be
* omitted.
*/
#ifndef GCCONFIG_H
# define GCCONFIG_H
# ifndef GC_PRIVATE_H
/* Fake ptr_t declaration, just to avoid compilation errors. */
/* This avoids many instances if "ifndef GC_PRIVATE_H" below. */
typedef struct GC_undefined_struct * ptr_t;
# endif
/* Machine dependent parameters. Some tuning parameters can be found */
/* near the top of gc_private.h. */
@ -25,7 +39,9 @@
/* First a unified test for Linux: */
# if defined(linux) || defined(__linux__)
# ifndef LINUX
# define LINUX
# endif
# endif
/* And one for NetBSD: */
@ -44,9 +60,9 @@
# endif
/* Determine the machine type: */
# if defined(__arm__) || defined(__thumb__)
# if defined(__XSCALE__)
# define ARM32
# if !defined(LINUX) && !defined(NETBSD)
# if !defined(LINUX)
# define NOSYS
# define mach_type_known
# endif
@ -69,7 +85,7 @@
# define SPARC
# define mach_type_known
# endif
# if defined(NETBSD) && defined(m68k)
# if defined(NETBSD) && (defined(m68k) || defined(__m68k__))
# define M68K
# define mach_type_known
# endif
@ -77,7 +93,7 @@
# define POWERPC
# define mach_type_known
# endif
# if defined(NETBSD) && defined(__arm__)
# if defined(NETBSD) && (defined(__arm32__) || defined(__arm__))
# define ARM32
# define mach_type_known
# endif
@ -90,6 +106,10 @@
# endif
# define mach_type_known
# endif
# if defined(__NetBSD__) && defined(__vax__)
# define VAX
# define mach_type_known
# endif
# if defined(mips) || defined(__mips) || defined(_mips)
# define MIPS
# if defined(nec_ews) || defined(_nec_ews)
@ -109,6 +129,13 @@
# endif /* !LINUX */
# define mach_type_known
# endif
# if defined(DGUX) && (defined(i386) || defined(__i386__))
# define I386
# ifndef _USING_DGUX
# define _USING_DGUX
# endif
# define mach_type_known
# endif
# if defined(sequent) && (defined(i386) || defined(__i386__))
# define I386
# define SEQUENT
@ -198,7 +225,11 @@
# define IA64
# define mach_type_known
# endif
# if defined(LINUX) && (defined(powerpc) || defined(__powerpc__))
# if defined(LINUX) && defined(__arm__)
# define ARM32
# define mach_type_known
# endif
# if defined(LINUX) && (defined(powerpc) || defined(__powerpc__) || defined(powerpc64) || defined(__powerpc64__))
# define POWERPC
# define mach_type_known
# endif
@ -237,19 +268,19 @@
# define MACOS
# define mach_type_known
# endif
# if defined(__MWERKS__) && defined(__powerc)
# 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__)
# define MACOSX
# define DARWIN
# define POWERPC
# define mach_type_known
# endif
# if defined(__APPLE__) && defined(__MACH__) && defined(__i386__)
# define MACOSX
# define DARWIN
# define I386
--> Not really supported, but at least we recognize it.
# endif
@ -291,7 +322,7 @@
# define CX_UX
# define mach_type_known
# endif
# if defined(DGUX)
# if defined(DGUX) && defined(m88k)
# define M88K
/* DGUX defined */
# define mach_type_known
@ -419,17 +450,18 @@
/* (CX_UX and DGUX) */
/* S370 ==> 370-like machine */
/* running Amdahl UTS4 */
/* S390 ==> 390-like machine */
/* running LINUX */
/* S390 ==> 390-like machine */
/* running LINUX */
/* ARM32 ==> Intel StrongARM */
/* IA64 ==> Intel IPF */
/* (e.g. Itanium) */
/* (LINUX and HPUX) */
/* IA64_32 ==> IA64 w/32 bit ABI */
/* (HPUX) */
/* SH ==> Hitachi SuperH */
/* (LINUX & MSWINCE) */
/* X86_64 ==> AMD x86-64 */
/* POWERPC ==> IBM/Apple PowerPC */
/* (MACOS(<=9),DARWIN(incl.MACOSX),*/
/* LINUX, NETBSD, NOSYS variants) */
/*
@ -450,7 +482,12 @@
* defining it to be 1 will always work, but perform poorly.
*
* DATASTART is the beginning of the data segment.
* On UNIX systems, the collector will scan the area between DATASTART
* On some platforms SEARCH_FOR_DATA_START is defined.
* SEARCH_FOR_DATASTART will cause GC_data_start to
* be set to an address determined by accessing data backwards from _end
* until an unmapped page is found. DATASTART will be defined to be
* GC_data_start.
* On UNIX-like systems, the collector will scan the area between DATASTART
* and DATAEND for root pointers.
*
* DATAEND, if not `end' where `end' is defined as ``extern int end[];''.
@ -470,8 +507,13 @@
* 1) define STACK_GROWS_UP if the stack grows toward higher addresses, and
* 2) define exactly one of
* STACKBOTTOM (should be defined to be an expression)
* LINUX_STACKBOTTOM
* HEURISTIC1
* HEURISTIC2
* If STACKBOTTOM is defined, then it's value will be used directly as the
* stack base. If LINUX_STACKBOTTOM is defined, then it will be determined
* with a method appropriate for most Linux systems. Currently we look
* first for __libc_stack_end, and if that fails read it from /proc.
* If either of the last two macros are defined, then STACKBOTTOM is computed
* during collector startup using one of the following two heuristics:
* HEURISTIC1: Take an address inside GC_init's frame, and round it up to
@ -536,6 +578,9 @@
* An architecture may also define CLEAR_DOUBLE(x) to be a fast way to
* clear the two words at GC_malloc-aligned address x. By default,
* word stores of 0 are used instead.
*
* HEAP_START may be defined as the initial address hint for mmap-based
* allocation.
*/
/* If we are using a recent version of gcc, we can use __builtin_unwind_init()
@ -560,18 +605,25 @@
# ifdef NETBSD
# define OS_TYPE "NETBSD"
# define HEURISTIC2
extern char etext[];
# define DATASTART ((ptr_t)(etext))
# ifdef __ELF__
# define DATASTART GC_data_start
# define DYNAMIC_LOADING
# else
extern char etext[];
# define DATASTART ((ptr_t)(etext))
# endif
# endif
# ifdef LINUX
# define OS_TYPE "LINUX"
# define STACKBOTTOM ((ptr_t)0xf0000000)
# define USE_GENERIC_PUSH_REGS
/* We never got around to the assembly version. */
/* # define MPROTECT_VDB - Reported to not work 9/17/01 */
# ifdef __ELF__
# define DYNAMIC_LOADING
# include <features.h>
# if defined(__GLIBC__)&& __GLIBC__>=2
# define LINUX_DATA_START
# define SEARCH_FOR_DATA_START
# else /* !GLIBC2 */
extern char **__environ;
# define DATASTART ((ptr_t)(&__environ))
@ -666,26 +718,49 @@
# define DATAEND /* not needed */
# endif
# ifdef LINUX
# define ALIGNMENT 4 /* Guess. Can someone verify? */
# if (defined (powerpc64) || defined(__powerpc64__))
# define ALIGNMENT 8
# define CPP_WORDSZ 64
# else
# define ALIGNMENT 4 /* Guess. Can someone verify? */
/* This was 2, but that didn't sound right. */
# endif
# define OS_TYPE "LINUX"
# define DYNAMIC_LOADING
/* HEURISTIC1 has been reliably reported to fail for a 32-bit */
/* executable on a 64 bit kernel. */
# define LINUX_STACKBOTTOM
/* Stack usually starts at 0x80000000 */
# define LINUX_DATA_START
# define DYNAMIC_LOADING
# define SEARCH_FOR_DATA_START
extern int _end[];
# define DATAEND (_end)
# endif
# ifdef MACOSX
/* There are reasons to suspect this may not be reliable. */
# ifdef DARWIN
# define ALIGNMENT 4
# define OS_TYPE "MACOSX"
# 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 DATAEND /* not needed */
# undef MPROTECT_VDB
# 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 */
# define MPROTECT_VDB
# include <unistd.h>
# define GETPAGESIZE() getpagesize()
# if defined(USE_PPC_PREFETCH) && defined(__GNUC__)
/* The performance impact of prefetches is untested */
# define PREFETCH(x) \
__asm__ __volatile__ ("dcbt 0,%0" : : "r" ((const void *) (x)))
# define PREFETCH_FOR_WRITE(x) \
__asm__ __volatile__ ("dcbtst 0,%0" : : "r" ((const void *) (x)))
# endif
/* There seems to be some issues with trylock hanging on darwin. This
should be looked into some more */
# define NO_PTHREAD_TRYLOCK
# endif
# ifdef NETBSD
# define ALIGNMENT 4
@ -746,8 +821,8 @@
# define OS_TYPE "SUNOS5"
extern int _etext[];
extern int _end[];
extern char * GC_SysVGetDataStart();
# define DATASTART (ptr_t)GC_SysVGetDataStart(0x10000, _etext)
extern ptr_t GC_SysVGetDataStart();
# define DATASTART GC_SysVGetDataStart(0x10000, _etext)
# define DATAEND (_end)
# if !defined(USE_MMAP) && defined(REDIRECT_MALLOC)
# define USE_MMAP
@ -801,9 +876,9 @@
# endif
# ifdef DRSNX
# define OS_TYPE "DRSNX"
extern char * GC_SysVGetDataStart();
extern ptr_t GC_SysVGetDataStart();
extern int etext[];
# define DATASTART (ptr_t)GC_SysVGetDataStart(0x10000, etext)
# define DATASTART GC_SysVGetDataStart(0x10000, etext)
# define MPROTECT_VDB
# define STACKBOTTOM ((ptr_t) 0xdfff0000)
# define DYNAMIC_LOADING
@ -819,13 +894,14 @@
extern int _etext[];
# define DATAEND (_end)
# define SVR4
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) 0x80000000000)
# define DATASTART (ptr_t)GC_SysVGetDataStart(0x100000, _etext)
# define STACKBOTTOM ((ptr_t) 0x80000000000ULL)
# else
# define LINUX_STACKBOTTOM
# define DATASTART (ptr_t)GC_SysVGetDataStart(0x10000, _etext)
# define DATASTART GC_SysVGetDataStart(0x10000, _etext)
# define LINUX_STACKBOTTOM
# endif
# endif
# ifdef OPENBSD
@ -876,7 +952,7 @@
# ifdef SUNOS5
# define OS_TYPE "SUNOS5"
extern int _etext[], _end[];
extern char * GC_SysVGetDataStart();
extern ptr_t GC_SysVGetDataStart();
# define DATASTART GC_SysVGetDataStart(0x1000, _etext)
# define DATAEND (_end)
/* # define STACKBOTTOM ((ptr_t)(_start)) worked through 2.7, */
@ -921,6 +997,28 @@
# define DYNAMIC_LOADING
# define ELF_CLASS ELFCLASS32
# endif
# ifdef DGUX
# define OS_TYPE "DGUX"
extern int _etext, _end;
extern ptr_t GC_SysVGetDataStart();
# define DATASTART GC_SysVGetDataStart(0x1000, &_etext)
# define DATAEND (&_end)
# define STACK_GROWS_DOWN
# define HEURISTIC2
# include <unistd.h>
# define GETPAGESIZE() sysconf(_SC_PAGESIZE)
# define DYNAMIC_LOADING
# ifndef USE_MMAP
# define USE_MMAP
# endif /* USE_MMAP */
# define MAP_FAILED (void *) -1
# ifdef USE_MMAP
# define HEAP_START (ptr_t)0x40000000
# else /* USE_MMAP */
# define HEAP_START DATAEND
# endif /* USE_MMAP */
# endif /* DGUX */
# ifdef LINUX
# ifndef __GNUC__
/* The Intel compiler doesn't like inline assembly */
@ -944,6 +1042,9 @@
/* possibly because Linux threads is itself a malloc client */
/* and can't deal with the signals. */
# endif
# define HEAP_START 0x1000
/* This encourages mmap to give us low addresses, */
/* thus allowing the heap to grow to ~3GB */
# ifdef __ELF__
# define DYNAMIC_LOADING
# ifdef UNDEFINED /* includes ro data */
@ -952,7 +1053,7 @@
# endif
# include <features.h>
# if defined(__GLIBC__) && __GLIBC__ >= 2
# define LINUX_DATA_START
# define SEARCH_FOR_DATA_START
# else
extern char **__environ;
# define DATASTART ((ptr_t)(&__environ))
@ -1006,8 +1107,12 @@
/* 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__))
# undef STACK_GRAN
@ -1061,16 +1166,9 @@
# ifdef __ELF__
# define DYNAMIC_LOADING
# endif
/* Handle unmapped hole i386*-*-freebsd[45]* may put between etext and edata. */
extern char etext[];
extern char edata[];
extern char end[];
# define NEED_FIND_LIMIT
# define DATASTART ((ptr_t)(etext))
# define MIN(x,y) ((x) < (y) ? (x) : (y))
# define DATAEND (MIN (GC_find_limit (DATASTART, TRUE), DATASTART2))
# define DATASTART2 ((ptr_t)(edata))
# define DATAEND2 ((ptr_t)(end))
extern char * GC_FreeBSDGetDataStart();
# define DATASTART GC_FreeBSDGetDataStart(0x1000, &etext)
# endif
# ifdef NETBSD
# define OS_TYPE "NETBSD"
@ -1149,7 +1247,11 @@
# define DATASTART ((ptr_t)(__data_start))
# define ALIGNMENT 4
# define USE_GENERIC_PUSH_REGS
# define LINUX_STACKBOTTOM
# if __GLIBC__ == 2 && __GLIBC_MINOR__ >= 2 || __GLIBC__ > 2
# define LINUX_STACKBOTTOM
# else
# define STACKBOTTOM 0x80000000
# endif
# endif /* Linux */
# ifdef EWS4800
# define HEURISTIC2
@ -1203,7 +1305,8 @@
/* heap sections so they're not */
/* considered as roots. */
# define OS_TYPE "IRIX5"
# define MPROTECT_VDB
/*# define MPROTECT_VDB DOB: this should work, but there is evidence */
/* of recent breakage. */
# ifdef _MIPS_SZPTR
# define CPP_WORDSZ _MIPS_SZPTR
# define ALIGNMENT (_MIPS_SZPTR/8)
@ -1226,28 +1329,46 @@
# define ALIGNMENT 4
# define HEURISTIC2
# define USE_GENERIC_PUSH_REGS
extern int _fdata[];
# define DATASTART ((ptr_t)(_fdata))
extern int _end[];
# define DATAEND ((ptr_t)(_end))
# define DYNAMIC_LOADING
# ifdef __ELF__
extern int etext[];
# define DATASTART GC_data_start
# define NEED_FIND_LIMIT
# define DYNAMIC_LOADING
# else
# define DATASTART ((ptr_t) 0x10000000)
# define STACKBOTTOM ((ptr_t) 0x7ffff000)
# endif /* _ELF_ */
# endif
# endif
# ifdef RS6000
# define MACH_TYPE "RS6000"
# ifdef ALIGNMENT
# undef ALIGNMENT
# endif
# ifdef IA64
# undef IA64 /* DOB: some AIX installs stupidly define IA64 in /usr/include/sys/systemcfg.h */
# endif
# ifdef __64BIT__
# define ALIGNMENT 8
# define CPP_WORDSZ 64
# define STACKBOTTOM ((ptr_t)0x1000000000000000)
# else
# define ALIGNMENT 4
# define CPP_WORDSZ 32
# define STACKBOTTOM ((ptr_t)((ulong)&errno))
# endif
/* From AIX linker man page:
_text Specifies the first location of the program.
_etext Specifies the first location after the program.
_data Specifies the first location of the data.
_edata Specifies the first location after the initialized data
_end or end Specifies the first location after all data.
*/
extern int _data[], _end[];
# define DATASTART ((ptr_t)((ulong)_data))
# define DATAEND ((ptr_t)((ulong)_end))
extern int errno;
# define STACKBOTTOM ((ptr_t)((ulong)&errno))
# define USE_GENERIC_PUSH_REGS
# define DYNAMIC_LOADING
/* For really old versions of AIX, this may have to be removed. */
@ -1311,15 +1432,23 @@
# define OS_TYPE "LINUX"
# define LINUX_STACKBOTTOM
# define DYNAMIC_LOADING
# define LINUX_DATA_START
# define SEARCH_FOR_DATA_START
extern int _end[];
# define DATAEND (_end)
# define DATAEND (&_end)
# endif /* LINUX */
# endif /* HP_PA */
# ifdef ALPHA
# define MACH_TYPE "ALPHA"
# define ALIGNMENT 8
# define CPP_WORDSZ 64
# ifndef LINUX
# define USE_GENERIC_PUSH_REGS
/* Gcc and probably the DEC/Compaq compiler spill pointers to preserved */
/* fp registers in some cases when the target is a 21264. The assembly */
/* code doesn't handle that yet, and version dependencies make that a */
/* bit tricky. Do the easy thing for now. */
# endif
# ifdef NETBSD
# define OS_TYPE "NETBSD"
# define HEURISTIC2
@ -1327,13 +1456,11 @@
# define ELFCLASS32 32
# define ELFCLASS64 64
# define ELF_CLASS ELFCLASS64
# define CPP_WORDSZ 64
# define DYNAMIC_LOADING
# endif
# ifdef OPENBSD
# define OS_TYPE "OPENBSD"
# define HEURISTIC2
# define CPP_WORDSZ 64
# ifdef __ELF__ /* since OpenBSD/Alpha 2.9 */
# define DATASTART GC_data_start
# define ELFCLASS32 32
@ -1357,17 +1484,16 @@
extern char edata[];
extern char end[];
# define NEED_FIND_LIMIT
# define DATASTART ((ptr_t)(etext))
# define DATASTART ((ptr_t)(&etext))
# define DATAEND (GC_find_limit (DATASTART, TRUE))
# define DATASTART2 ((ptr_t)(edata))
# define DATAEND2 ((ptr_t)(end))
# define CPP_WORDSZ 64
# define DATASTART2 ((ptr_t)(&edata))
# define DATAEND2 ((ptr_t)(&end))
# endif
# ifdef OSF1
# define OS_TYPE "OSF1"
# define DATASTART ((ptr_t) 0x140000000)
extern int _end[];
# define DATAEND ((ptr_t) _end)
# define DATAEND ((ptr_t) &_end)
extern char ** environ;
/* round up from the value of environ to the nearest page boundary */
/* Probably breaks if putenv is called before collector */
@ -1378,19 +1504,19 @@
/* the text segment immediately follows the stack. */
/* Hence we give an upper pound. */
/* This is currently unused, since we disabled HEURISTIC2 */
extern int __start[];
extern int __start[];
# define HEURISTIC2_LIMIT ((ptr_t)((word)(__start) & ~(getpagesize()-1)))
# define CPP_WORDSZ 64
# define MPROTECT_VDB
# ifndef GC_OSF1_THREADS
/* Unresolved signal issues with threads. */
# define MPROTECT_VDB
# endif
# define DYNAMIC_LOADING
# endif
# ifdef LINUX
# define OS_TYPE "LINUX"
# define CPP_WORDSZ 64
# define STACKBOTTOM ((ptr_t) 0x120000000)
# ifdef __ELF__
# define SEARCH_FOR_DATA_START
# define DATASTART GC_data_start
# define DYNAMIC_LOADING
# else
# define DATASTART ((ptr_t) 0x140000000)
@ -1468,7 +1594,6 @@
extern char * GC_register_stackbottom;
# define BACKING_STORE_BASE ((ptr_t)GC_register_stackbottom)
# define SEARCH_FOR_DATA_START
# define DATASTART GC_data_start
# ifdef __GNUC__
# define DYNAMIC_LOADING
# else
@ -1502,23 +1627,25 @@
# endif
# ifdef DGUX
# define OS_TYPE "DGUX"
extern char * GC_SysVGetDataStart();
# define DATASTART (ptr_t)GC_SysVGetDataStart(0x10000, etext)
extern ptr_t GC_SysVGetDataStart();
# define DATASTART GC_SysVGetDataStart(0x10000, etext)
# endif
# define STACKBOTTOM ((char*)0xf0000000) /* determined empirically */
# endif
# ifdef S370
/* If this still works, and if anyone cares, this should probably */
/* be moved to the S390 category. */
# define MACH_TYPE "S370"
# define ALIGNMENT 4 /* Required by hardware */
# define USE_GENERIC_PUSH_REGS
# ifdef UTS4
# define OS_TYPE "UTS4"
extern int etext[];
extern int etext[];
extern int _etext[];
extern int _end[];
extern char * GC_SysVGetDataStart();
# define DATASTART (ptr_t)GC_SysVGetDataStart(0x10000, _etext)
extern ptr_t GC_SysVGetDataStart();
# define DATASTART GC_SysVGetDataStart(0x10000, _etext)
# define DATAEND (_end)
# define HEURISTIC2
# endif
@ -1528,23 +1655,23 @@
# define MACH_TYPE "S390"
# define USE_GENERIC_PUSH_REGS
# ifndef __s390x__
# define ALIGNMENT 4
# define CPP_WORDSZ 32
# define ALIGNMENT 4
# define CPP_WORDSZ 32
# else
# define ALIGNMENT 8
# define CPP_WORDSZ 64
# define HBLKSIZE 4096
# define ALIGNMENT 8
# define CPP_WORDSZ 64
# define HBLKSIZE 4096
# endif
# ifdef LINUX
# define OS_TYPE "LINUX"
# define LINUX_STACKBOTTOM
# define DYNAMIC_LOADING
extern int __data_start[];
extern int __data_start[];
# define DATASTART ((ptr_t)(__data_start))
extern int _end[];
# define DATAEND (_end)
# define CACHE_LINE_SIZE 256
# define GETPAGESIZE() 4096
extern int _end[];
# define DATAEND (_end)
# define CACHE_LINE_SIZE 256
# define GETPAGESIZE() 4096
# endif
# endif
@ -1562,13 +1689,8 @@
# ifdef NETBSD
# define OS_TYPE "NETBSD"
# define HEURISTIC2
# ifdef __ELF__
# define DATASTART GC_data_start
# define DYNAMIC_LOADING
# else
extern char etext[];
# define DATASTART ((ptr_t)(etext))
# endif
extern char etext[];
# define DATASTART ((ptr_t)(etext))
# define USE_GENERIC_PUSH_REGS
# endif
# ifdef LINUX
@ -1581,7 +1703,7 @@
# define DYNAMIC_LOADING
# include <features.h>
# if defined(__GLIBC__) && __GLIBC__ >= 2
# define LINUX_DATA_START
# define SEARCH_FOR_DATA_START
# else
extern char **__environ;
# define DATASTART ((ptr_t)(&__environ))
@ -1628,7 +1750,7 @@
# define STACKBOTTOM ((ptr_t) 0x7c000000)
# define USE_GENERIC_PUSH_REGS
# define DYNAMIC_LOADING
# define LINUX_DATA_START
# define SEARCH_FOR_DATA_START
extern int _end[];
# define DATAEND (_end)
# endif
@ -1645,7 +1767,9 @@
# define MACH_TYPE "X86_64"
# define ALIGNMENT 8
# define CPP_WORDSZ 64
# define HBLKSIZE 4096
# ifndef HBLKSIZE
# define HBLKSIZE 4096
# endif
# define CACHE_LINE_SIZE 64
# define USE_GENERIC_PUSH_REGS
# ifdef LINUX
@ -1665,7 +1789,7 @@
# define DATASTART ((ptr_t)((((word) (_etext)) + 0xfff) & ~0xfff))
# endif
# include <features.h>
# define LINUX_DATA_START
# define SEARCH_FOR_DATA_START
extern int _end[];
# define DATAEND (_end)
# else
@ -1679,19 +1803,6 @@
# endif
# endif
#ifdef LINUX_DATA_START
/* Some Linux distributions arrange to define __data_start. Some */
/* define data_start as a weak symbol. The latter is technically */
/* broken, since the user program may define data_start, in which */
/* case we lose. Nonetheless, we try both, prefering __data_start. */
/* We assume gcc. */
# pragma weak __data_start
extern int __data_start[];
# pragma weak data_start
extern int data_start[];
# define DATASTART ((ptr_t)(__data_start != 0? __data_start : data_start))
#endif
#if defined(LINUX) && defined(REDIRECT_MALLOC)
/* Rld appears to allocate some memory with its own allocator, and */
/* some through malloc, which might be redirected. To make this */
@ -1730,15 +1841,15 @@
# endif
# if defined(SUNOS5) || defined(DRSNX) || defined(UTS4)
/* OS has SVR4 generic features. Probably others also qualify. */
/* OS has SVR4 generic features. Probably others also qualify. */
# define SVR4
# endif
# if defined(SUNOS5) || defined(DRSNX)
/* OS has SUNOS5 style semi-undocumented interface to dynamic */
/* loader. */
/* OS has SUNOS5 style semi-undocumented interface to dynamic */
/* loader. */
# define SUNOS5DL
/* OS has SUNOS5 style signal handlers. */
/* OS has SUNOS5 style signal handlers. */
# define SUNOS5SIGS
# endif
@ -1747,13 +1858,14 @@
# endif
# if defined(SVR4) || defined(LINUX) || defined(IRIX) || defined(HPUX) \
|| defined(OPENBSD) || defined(NETBSD) || defined(FREEBSD) \
|| defined(BSD) || defined(_AIX) || defined(MACOSX) || defined(OSF1)
|| defined(OPENBSD) || defined(NETBSD) || defined(FREEBSD) \
|| defined(DGUX) || defined(BSD) \
|| defined(_AIX) || defined(DARWIN) || defined(OSF1)
# define UNIX_LIKE /* Basic Unix-like system calls work. */
# endif
# if CPP_WORDSZ != 32 && CPP_WORDSZ != 64
-> bad word size
-> bad word size
# endif
# ifdef PCR
@ -1767,13 +1879,13 @@
# endif
# ifdef SRC_M3
/* Postponed for now. */
/* Postponed for now. */
# undef PROC_VDB
# undef MPROTECT_VDB
# endif
# ifdef SMALL_CONFIG
/* Presumably not worth the space it takes. */
/* Presumably not worth the space it takes. */
# undef PROC_VDB
# undef MPROTECT_VDB
# endif
@ -1813,49 +1925,50 @@
/* platforms as well, though it should be avoided in win32. */
# endif /* LINUX */
# if defined(SEARCH_FOR_DATA_START) && defined(GC_PRIVATE_H)
# if defined(SEARCH_FOR_DATA_START)
extern ptr_t GC_data_start;
# define DATASTART GC_data_start
# endif
# ifndef CLEAR_DOUBLE
# define CLEAR_DOUBLE(x) \
((word*)x)[0] = 0; \
((word*)x)[1] = 0;
((word*)x)[0] = 0; \
((word*)x)[1] = 0;
# endif /* CLEAR_DOUBLE */
/* Internally we use GC_SOLARIS_THREADS to test for either old or pthreads. */
/* Internally we use GC_SOLARIS_THREADS to test for either old or pthreads. */
# if defined(GC_SOLARIS_PTHREADS) && !defined(GC_SOLARIS_THREADS)
# define GC_SOLARIS_THREADS
# endif
# if defined(GC_IRIX_THREADS) && !defined(IRIX5)
--> inconsistent configuration
--> inconsistent configuration
# endif
# if defined(GC_LINUX_THREADS) && !defined(LINUX)
--> inconsistent configuration
--> inconsistent configuration
# endif
# if defined(GC_SOLARIS_THREADS) && !defined(SUNOS5)
--> inconsistent configuration
--> inconsistent configuration
# endif
# if defined(GC_HPUX_THREADS) && !defined(HPUX)
--> inconsistent configuration
--> inconsistent configuration
# endif
# if defined(GC_WIN32_THREADS) && !defined(MSWIN32)
/* Ideally CYGWIN32 should work, in addition to MSWIN32. I suspect */
/* the necessary code is mostly there, but nobody has actually made */
/* sure the right combination of pieces is compiled in, etc. */
--> inconsistent configuration
# if defined(GC_AIX_THREADS) && !defined(_AIX)
--> inconsistent configuration
# endif
# if defined(GC_WIN32_THREADS) && !defined(MSWIN32) && !defined(CYGWIN32)
--> inconsistent configuration
# endif
# if defined(PCR) || defined(SRC_M3) || \
defined(GC_SOLARIS_THREADS) || defined(GC_WIN32_THREADS) || \
defined(GC_PTHREADS)
defined(GC_SOLARIS_THREADS) || defined(GC_WIN32_THREADS) || \
defined(GC_PTHREADS)
# define THREADS
# endif
# if defined(HP_PA) || defined(M88K) || defined(POWERPC) && !defined(MACOSX) \
|| defined(LINT) || defined(MSWINCE) \
|| (defined(I386) && defined(__LCC__))
# if defined(HP_PA) || defined(M88K) || defined(POWERPC) && !defined(DARWIN) \
|| defined(LINT) || defined(MSWINCE) || defined(ARM32) \
|| (defined(I386) && defined(__LCC__))
/* Use setjmp based hack to mark from callee-save registers. */
/* The define should move to the individual platform */
/* descriptions. */
@ -1867,36 +1980,26 @@
/* include assembly code to do it well. */
# endif
/* Can we save call chain in objects for debugging? */
/* SET NFRAMES (# of saved frames) and NARGS (#of args for each frame) */
/* to reasonable values for the platform. */
/* Set SAVE_CALL_CHAIN if we can. SAVE_CALL_COUNT can be specified at */
/* build time, though we feel free to adjust it slightly. */
/* Define NEED_CALLINFO if we either save the call stack or */
/* GC_ADD_CALLER is defined. */
#ifdef LINUX
# include <features.h>
# if __GLIBC__ == 2 && __GLIBC_MINOR__ >= 1 || __GLIBC__ > 2
# define HAVE_BUILTIN_BACKTRACE
# endif
#endif
/* Can we save call chain in objects for debugging? */
/* SET NFRAMES (# of saved frames) and NARGS (#of args for each */
/* frame) to reasonable values for the platform. */
/* Set SAVE_CALL_CHAIN if we can. SAVE_CALL_COUNT can be specified */
/* at build time, though we feel free to adjust it slightly. */
/* Define NEED_CALLINFO if we either save the call stack or */
/* GC_ADD_CALLER is defined. */
/* GC_CAN_SAVE_CALL_STACKS is set in gc.h. */
#if defined(SPARC)
# define CAN_SAVE_CALL_STACKS
# define CAN_SAVE_CALL_ARGS
#endif
#if (defined(I386) || defined(X86_64)) && defined(LINUX)
/* SAVE_CALL_CHAIN is supported if the code is compiled to save */
/* frame pointers by default, i.e. no -fomit-frame-pointer flag. */
# define CAN_SAVE_CALL_STACKS
/* SAVE_CALL_CHAIN is supported if the code is compiled to save */
/* frame pointers by default, i.e. no -fomit-frame-pointer flag. */
# define CAN_SAVE_CALL_ARGS
#endif
#if defined(HAVE_BUILTIN_BACKTRACE) && !defined(CAN_SAVE_CALL_STACKS)
# define CAN_SAVE_CALL_STACKS
#endif
# if defined(SAVE_CALL_COUNT) && !defined(GC_ADD_CALLER) \
&& defined(CAN_SAVE_CALL_STACKS)
&& defined(GC_CAN_SAVE_CALL_STACKS)
# define SAVE_CALL_CHAIN
# endif
# ifdef SAVE_CALL_CHAIN
@ -1909,7 +2012,7 @@
# ifdef SAVE_CALL_CHAIN
# ifndef SAVE_CALL_COUNT
# define NFRAMES 6 /* Number of frames to save. Even for */
/* alignment reasons. */
/* alignment reasons. */
# else
# define NFRAMES ((SAVE_CALL_COUNT + 1) & ~1)
# endif
@ -1925,4 +2028,96 @@
# define DBG_HDRS_ALL
# endif
# if defined(POINTER_MASK) && !defined(POINTER_SHIFT)
# define POINTER_SHIFT 0
# endif
# if defined(POINTER_SHIFT) && !defined(POINTER_MASK)
# define POINTER_MASK ((GC_word)(-1))
# endif
# if !defined(FIXUP_POINTER) && defined(POINTER_MASK)
# define FIXUP_POINTER(p) (p) = ((p) & (POINTER_MASK) << POINTER_SHIFT)
# endif
# if defined(FIXUP_POINTER)
# define NEED_FIXUP_POINTER 1
# else
# define NEED_FIXUP_POINTER 0
# define FIXUP_POINTER(p)
# endif
#ifdef GC_PRIVATE_H
/* This relies on some type definitions from gc_priv.h, from */
/* where it's normally included. */
/* */
/* How to get heap memory from the OS: */
/* Note that sbrk()-like allocation is preferred, since it */
/* usually makes it possible to merge consecutively allocated */
/* chunks. It also avoids unintented recursion with */
/* -DREDIRECT_MALLOC. */
/* GET_MEM() returns a HLKSIZE aligned chunk. */
/* 0 is taken to mean failure. */
/* In the case os USE_MMAP, the argument must also be a */
/* physical page size. */
/* GET_MEM is currently not assumed to retrieve 0 filled space, */
/* though we should perhaps take advantage of the case in which */
/* does. */
struct hblk; /* See gc_priv.h. */
# ifdef PCR
char * real_malloc();
# define GET_MEM(bytes) HBLKPTR(real_malloc((size_t)bytes + GC_page_size) \
+ GC_page_size-1)
# else
# ifdef OS2
void * os2_alloc(size_t bytes);
# define GET_MEM(bytes) HBLKPTR((ptr_t)os2_alloc((size_t)bytes \
+ GC_page_size) \
+ GC_page_size-1)
# else
# if defined(NEXT) || defined(DOS4GW) || \
(defined(AMIGA) && !defined(GC_AMIGA_FASTALLOC)) || \
(defined(SUNOS5) && !defined(USE_MMAP))
# define GET_MEM(bytes) HBLKPTR((size_t) \
calloc(1, (size_t)bytes + GC_page_size) \
+ GC_page_size-1)
# else
# ifdef MSWIN32
extern ptr_t GC_win32_get_mem();
# define GET_MEM(bytes) (struct hblk *)GC_win32_get_mem(bytes)
# else
# ifdef MACOS
# if defined(USE_TEMPORARY_MEMORY)
extern Ptr GC_MacTemporaryNewPtr(size_t size,
Boolean clearMemory);
# define GET_MEM(bytes) HBLKPTR( \
GC_MacTemporaryNewPtr(bytes + GC_page_size, true) \
+ GC_page_size-1)
# else
# define GET_MEM(bytes) HBLKPTR( \
NewPtrClear(bytes + GC_page_size) + GC_page_size-1)
# endif
# else
# ifdef MSWINCE
extern ptr_t GC_wince_get_mem();
# define GET_MEM(bytes) (struct hblk *)GC_wince_get_mem(bytes)
# else
# if defined(AMIGA) && defined(GC_AMIGA_FASTALLOC)
extern void *GC_amiga_get_mem(size_t size);
# define GET_MEM(bytes) HBLKPTR((size_t) \
GC_amiga_get_mem((size_t)bytes + GC_page_size) \
+ GC_page_size-1)
# else
extern ptr_t GC_unix_get_mem();
# define GET_MEM(bytes) (struct hblk *)GC_unix_get_mem(bytes)
# endif
# endif
# endif
# endif
# endif
# endif
# endif
#endif /* GC_PRIVATE_H */
# endif /* GCCONFIG_H */

View File

@ -16,7 +16,8 @@
# define DETACHED 2 /* Thread is intended to be detached. */
# define CLIENT_OWNS_STACK 4
/* Stack was supplied by client. */
# define SUSPENDED 8 /* Currently suspended. */
# define SUSPNDED 8 /* Currently suspended. */
/* SUSPENDED is used insystem header. */
ptr_t stack;
size_t stack_size;
cond_t join_cv;

View File

@ -85,7 +85,7 @@ static __inline__ void * PREFIXED(getspecific) (tsd * key) {
unsigned hash_val = CACHE_HASH(qtid);
tse * volatile * entry_ptr = key -> cache + hash_val;
tse * entry = *entry_ptr; /* Must be loaded only once. */
if (entry -> qtid == qtid) {
if (EXPECT(entry -> qtid == qtid, 1)) {
GC_ASSERT(entry -> thread == pthread_self());
return entry -> value;
}

View File

@ -1,726 +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 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. This relies on properties
* not guaranteed by the Pthread standard. It may or may not be portable
* to other implementations.
*
* This now also includes an initial attempt at thread support for
* HP/UX 11.
*
* Note that there is a lot of code duplication between linux_threads.c
* and irix_threads.c; any changes made here may need to be reflected
* there too.
*/
# if defined(GC_IRIX_THREADS)
# include "private/gc_priv.h"
# include <pthread.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
#undef pthread_detach
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. */
# define CLIENT_OWNS_STACK 4
/* Stack was supplied by client. */
ptr_t stack;
ptr_t stack_ptr; /* Valid only when stopped. */
/* But must be within stack region at */
/* all times. */
size_t stack_size; /* 0 for original thread. */
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.
* We use SIG_SUSPEND, defined in gc_priv.h.
*/
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_ptr = (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;
size_t GC_min_stack_sz;
# define N_FREE_LISTS 25
ptr_t GC_stack_free_lists[N_FREE_LISTS] = { 0 };
/* GC_stack_free_lists[i] is free list for stacks of */
/* size GC_min_stack_sz*2**i. */
/* Free lists are linked through first word. */
/* Return a stack of size at least *stack_size. *stack_size is */
/* replaced by the actual stack size. */
/* Caller holds allocation lock. */
ptr_t GC_stack_alloc(size_t * stack_size)
{
register size_t requested_sz = *stack_size;
register size_t search_sz = GC_min_stack_sz;
register int index = 0; /* = log2(search_sz/GC_min_stack_sz) */
register ptr_t result;
while (search_sz < requested_sz) {
search_sz *= 2;
index++;
}
if ((result = GC_stack_free_lists[index]) == 0
&& (result = GC_stack_free_lists[index+1]) != 0) {
/* Try next size up. */
search_sz *= 2; index++;
}
if (result != 0) {
GC_stack_free_lists[index] = *(ptr_t *)result;
} else {
result = (ptr_t) GC_scratch_alloc(search_sz + 2*GC_page_size);
result = (ptr_t)(((word)result + GC_page_size) & ~(GC_page_size - 1));
/* Protect hottest page to detect overflow. */
# ifdef STACK_GROWS_UP
/* mprotect(result + search_sz, GC_page_size, PROT_NONE); */
# else
/* mprotect(result, GC_page_size, PROT_NONE); */
result += GC_page_size;
# endif
}
*stack_size = search_sz;
return(result);
}
/* Caller holds allocation lock. */
void GC_stack_free(ptr_t stack, size_t size)
{
register int index = 0;
register size_t search_sz = GC_min_stack_sz;
while (search_sz < size) {
search_sz *= 2;
index++;
}
if (search_sz != size) ABORT("Bad stack size");
*(ptr_t *)stack = GC_stack_free_lists[index];
GC_stack_free_lists[index] = stack;
}
# 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;
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_INTERNAL_MALLOC(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. */
void GC_delete_thread(pthread_t id)
{
int hv = ((word)id) % THREAD_TABLE_SZ;
register GC_thread p = GC_threads[hv];
register GC_thread prev = 0;
while (!pthread_equal(p -> id, id)) {
prev = p;
p = p -> next;
}
if (prev == 0) {
GC_threads[hv] = p -> next;
} else {
prev -> next = p -> next;
}
}
/* 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;
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];
while (p != 0 && !pthread_equal(p -> id, id)) p = p -> next;
return(p);
}
/* 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;
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"); */
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);
}
# ifdef MMAP_STACKS
--> not really supported yet.
int GC_is_thread_stack(ptr_t addr)
{
register int i;
register GC_thread p;
for (i = 0; i < THREAD_TABLE_SZ; i++) {
for (p = GC_threads[i]; p != 0; p = p -> next) {
if (p -> stack_size != 0) {
if (p -> stack <= addr &&
addr < p -> stack + p -> stack_size)
return 1;
}
}
}
return 0;
}
# endif
/* 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 sp = GC_approx_sp();
register ptr_t hot, cold;
pthread_t me = pthread_self();
if (!GC_thr_initialized) GC_thr_init();
/* GC_printf1("Pushing stacks from thread 0x%x\n", me); */
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)) {
hot = GC_approx_sp();
} else {
hot = p -> stack_ptr;
}
if (p -> stack_size != 0) {
# ifdef STACK_GROWS_UP
cold = p -> stack;
# else
cold = p -> stack + p -> stack_size;
# endif
} else {
/* The original stack. */
cold = GC_stackbottom;
}
# ifdef STACK_GROWS_UP
GC_push_all_stack(cold, hot);
# else
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_thr_initialized = TRUE;
GC_min_stack_sz = HBLKSIZE;
(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");
/* Add the initial thread, so we can stop it. */
t = GC_new_thread(pthread_self());
t -> stack_size = 0;
t -> stack_ptr = (ptr_t)(&t);
t -> flags = DETACHED;
}
int GC_pthread_sigmask(int how, const sigset_t *set, sigset_t *oset)
{
sigset_t fudged_set;
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;
ptr_t stack;
size_t stack_size;
sem_t registered; /* 1 ==> in our thread table, but */
/* parent hasn't yet noticed. */
};
void GC_thread_exit_proc(void *arg)
{
GC_thread me;
LOCK();
me = GC_lookup_thread(pthread_self());
if (me -> flags & DETACHED) {
GC_delete_thread(pthread_self());
} else {
me -> flags |= FINISHED;
}
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();
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;
if (result == 0) {
LOCK();
/* Here the pthread thread id may have been recycled. */
GC_delete_gc_thread(thread, thread_gc_id);
UNLOCK();
}
return result;
}
int GC_pthread_detach(pthread_t thread)
{
int result;
GC_thread thread_gc_id;
LOCK();
thread_gc_id = GC_lookup_thread(thread);
UNLOCK();
result = pthread_detach(thread);
if (result == 0) {
LOCK();
thread_gc_id -> flags |= DETACHED;
/* Here the pthread thread id may have been recycled. */
if (thread_gc_id -> flags & FINISHED) {
GC_delete_gc_thread(thread, thread_gc_id);
}
UNLOCK();
}
return result;
}
void * GC_start_routine(void * arg)
{
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 = si -> stack;
me -> stack_size = si -> stack_size;
me -> stack_ptr = (ptr_t)si -> stack + si -> stack_size - sizeof(word);
UNLOCK();
start = si -> start_routine;
start_arg = si -> arg;
sem_post(&(si -> registered));
pthread_cleanup_push(GC_thread_exit_proc, 0);
result = (*start)(start_arg);
me -> status = result;
me -> flags |= FINISHED;
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);
}
# define copy_attr(pa_ptr, source) *(pa_ptr) = *(source)
int
GC_pthread_create(pthread_t *new_thread,
const pthread_attr_t *attr,
void *(*start_routine)(void *), void *arg)
{
int result;
GC_thread t;
void * stack;
size_t stacksize;
pthread_attr_t new_attr;
int detachstate;
word my_flags = 0;
struct start_info * si = GC_malloc(sizeof(struct start_info));
/* This is otherwise saved only in an area mmapped by the thread */
/* library, which isn't visible to the collector. */
if (0 == si) return(ENOMEM);
if (0 != sem_init(&(si -> registered), 0, 0)) {
ABORT("sem_init failed");
}
si -> start_routine = start_routine;
si -> arg = arg;
LOCK();
if (!GC_is_initialized) GC_init();
if (NULL == attr) {
stack = 0;
(void) pthread_attr_init(&new_attr);
} else {
copy_attr(&new_attr, attr);
pthread_attr_getstackaddr(&new_attr, &stack);
}
pthread_attr_getstacksize(&new_attr, &stacksize);
pthread_attr_getdetachstate(&new_attr, &detachstate);
if (stacksize < GC_min_stack_sz) ABORT("Stack too small");
if (0 == stack) {
stack = (void *)GC_stack_alloc(&stacksize);
if (0 == stack) {
UNLOCK();
return(ENOMEM);
}
pthread_attr_setstackaddr(&new_attr, stack);
} else {
my_flags |= CLIENT_OWNS_STACK;
}
if (PTHREAD_CREATE_DETACHED == detachstate) my_flags |= DETACHED;
si -> flags = my_flags;
si -> stack = stack;
si -> stack_size = stacksize;
result = pthread_create(new_thread, &new_attr, GC_start_routine, si);
if (0 == new_thread && !(my_flags & CLIENT_OWNS_STACK)) {
GC_stack_free(stack, stacksize);
}
UNLOCK();
/* 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. */
while (0 != sem_wait(&(si -> registered))) {
if (errno != EINTR) {
GC_printf1("Sem_wait: errno = %ld\n", (unsigned long) errno);
ABORT("sem_wait failed");
}
}
sem_destroy(&(si -> registered));
pthread_attr_destroy(&new_attr); /* Probably unnecessary under Irix */
return(result);
}
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
unsigned long 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
#ifndef LINT
int GC_no_Irix_threads;
#endif
# endif /* GC_IRIX_THREADS */

File diff suppressed because it is too large Load Diff

View File

@ -74,7 +74,8 @@ asm static void PushMacRegisters()
/* on your architecture. Run the test_setjmp program to see whether */
/* there is any chance it will work. */
#ifndef USE_GENERIC_PUSH_REGS
#if !defined(USE_GENERIC_PUSH_REGS) && !defined(USE_ASM_PUSH_REGS)
#undef HAVE_PUSH_REGS
void GC_push_regs()
{
# ifdef RT
@ -91,6 +92,7 @@ void GC_push_regs()
asm("pushl r8"); asm("calls $1,_GC_push_one");
asm("pushl r7"); asm("calls $1,_GC_push_one");
asm("pushl r6"); asm("calls $1,_GC_push_one");
# define HAVE_PUSH_REGS
# endif
# if defined(M68K) && (defined(SUNOS4) || defined(NEXT))
/* M68K SUNOS - could be replaced by generic code */
@ -113,6 +115,7 @@ void GC_push_regs()
asm("movl d7,sp@"); asm("jbsr _GC_push_one");
asm("addqw #0x4,sp"); /* put stack back where it was */
# define HAVE_PUSH_REGS
# endif
# if defined(M68K) && defined(HP)
@ -135,6 +138,7 @@ void GC_push_regs()
asm("mov.l %d7,(%sp)"); asm("jsr _GC_push_one");
asm("addq.w &0x4,%sp"); /* put stack back where it was */
# define HAVE_PUSH_REGS
# endif /* M68K HP */
# if defined(M68K) && defined(AMIGA)
@ -158,6 +162,7 @@ void GC_push_regs()
asm("mov.l %d7,(%sp)"); asm("jsr _GC_push_one");
asm("addq.w &0x4,%sp"); /* put stack back where it was */
# define HAVE_PUSH_REGS
# else /* !__GNUC__ */
GC_push_one(getreg(REG_A2));
GC_push_one(getreg(REG_A3));
@ -174,6 +179,7 @@ void GC_push_regs()
GC_push_one(getreg(REG_D5));
GC_push_one(getreg(REG_D6));
GC_push_one(getreg(REG_D7));
# define HAVE_PUSH_REGS
# endif /* !__GNUC__ */
# endif /* AMIGA */
@ -196,10 +202,12 @@ void GC_push_regs()
PushMacReg(d7);
add.w #4,sp ; fix stack.
}
# define HAVE_PUSH_REGS
# undef PushMacReg
# endif /* THINK_C */
# if defined(__MWERKS__)
PushMacRegisters();
# define HAVE_PUSH_REGS
# endif /* __MWERKS__ */
# endif /* MACOS */
@ -222,13 +230,15 @@ void GC_push_regs()
asm("pushl %esi"); asm("call _GC_push_one"); asm("addl $4,%esp");
asm("pushl %edi"); asm("call _GC_push_one"); asm("addl $4,%esp");
asm("pushl %ebx"); asm("call _GC_push_one"); asm("addl $4,%esp");
# define HAVE_PUSH_REGS
# endif
# if ( defined(I386) && defined(LINUX) && defined(__ELF__) ) \
|| ( defined(I386) && defined(FREEBSD) && defined(__ELF__) ) \
|| ( defined(I386) && defined(NETBSD) && defined(__ELF__) ) \
|| ( defined(I386) && defined(OPENBSD) && defined(__ELF__) ) \
|| ( defined(I386) && defined(HURD) && defined(__ELF__) )
|| ( defined(I386) && defined(HURD) && defined(__ELF__) ) \
|| ( defined(I386) && defined(DGUX) )
/* This is modified for Linux with ELF (Note: _ELF_ only) */
/* This section handles FreeBSD with ELF. */
@ -243,6 +253,7 @@ void GC_push_regs()
asm("pushl %esi; call GC_push_one; addl $4,%esp");
asm("pushl %edi; call GC_push_one; addl $4,%esp");
asm("pushl %ebx; call GC_push_one; addl $4,%esp");
# define HAVE_PUSH_REGS
# endif
# if ( defined(I386) && defined(BEOS) && defined(__ELF__) )
@ -254,6 +265,7 @@ void GC_push_regs()
asm("pushl %esi; call GC_push_one; addl $4,%esp");
asm("pushl %edi; call GC_push_one; addl $4,%esp");
asm("pushl %ebx; call GC_push_one; addl $4,%esp");
# define HAVE_PUSH_REGS
# endif
# if defined(I386) && defined(MSWIN32) && !defined(__MINGW32__) \
@ -280,6 +292,7 @@ void GC_push_regs()
__asm push edi
__asm call GC_push_one
__asm add esp,4
# define HAVE_PUSH_REGS
# endif
# if defined(I386) && (defined(SVR4) || defined(SCO) || defined(SCO_ELF))
@ -291,6 +304,7 @@ void GC_push_regs()
asm("pushl %ebp"); asm("call GC_push_one"); asm("addl $4,%esp");
asm("pushl %esi"); asm("call GC_push_one"); asm("addl $4,%esp");
asm("pushl %edi"); asm("call GC_push_one"); asm("addl $4,%esp");
# define HAVE_PUSH_REGS
# endif
# ifdef NS32K
@ -299,14 +313,12 @@ void GC_push_regs()
asm ("movd r5, tos"); asm ("bsr ?_GC_push_one"); asm ("adjspb $-4");
asm ("movd r6, tos"); asm ("bsr ?_GC_push_one"); asm ("adjspb $-4");
asm ("movd r7, tos"); asm ("bsr ?_GC_push_one"); asm ("adjspb $-4");
# define HAVE_PUSH_REGS
# endif
# if defined(SPARC)
{
word GC_save_regs_in_stack();
GC_save_regs_ret_val = GC_save_regs_in_stack();
}
GC_save_regs_ret_val = GC_save_regs_in_stack();
# define HAVE_PUSH_REGS
# endif
# ifdef RT
@ -322,6 +334,7 @@ void GC_push_regs()
asm("cas r11, r13, r0"); GC_push_one(TMP_SP); /* through */
asm("cas r11, r14, r0"); GC_push_one(TMP_SP); /* r15 */
asm("cas r11, r15, r0"); GC_push_one(TMP_SP);
# define HAVE_PUSH_REGS
# endif
# if defined(M68K) && defined(SYSV)
@ -345,6 +358,7 @@ void GC_push_regs()
asm("movl %d7,%sp@"); asm("jbsr GC_push_one");
asm("addqw #0x4,%sp"); /* put stack back where it was */
# define HAVE_PUSH_REGS
# else /* !__GNUC__*/
asm("subq.w &0x4,%sp"); /* allocate word on top of stack */
@ -362,6 +376,7 @@ void GC_push_regs()
asm("mov.l %d7,(%sp)"); asm("jsr GC_push_one");
asm("addq.w &0x4,%sp"); /* put stack back where it was */
# define HAVE_PUSH_REGS
# endif /* !__GNUC__ */
# endif /* M68K/SYSV */
@ -371,21 +386,19 @@ void GC_push_regs()
extern int *__libc_stack_end;
GC_push_all_stack (sp, __libc_stack_end);
# define HAVE_PUSH_REGS
/* Isn't this redundant with the code to push the stack? */
}
# endif
/* other machines... */
# if !defined(M68K) && !defined(VAX) && !defined(RT)
# if !defined(SPARC) && !defined(I386) && !defined(NS32K)
# if !defined(POWERPC) && !defined(UTS4)
# if !defined(PJ) && !(defined(MIPS) && defined(LINUX))
--> bad news <--
# endif
# endif
# endif
# if !defined(HAVE_PUSH_REGS)
--> We just generated an empty GC_push_regs, which
--> is almost certainly broken. Try defining
--> USE_GENERIC_PUSH_REGS instead.
# endif
}
#endif /* !USE_GENERIC_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)
@ -427,8 +440,6 @@ ptr_t cold_gc_frame;
/* needed on IA64, since some non-windowed registers are */
/* preserved. */
{
word GC_save_regs_in_stack();
GC_save_regs_ret_val = GC_save_regs_in_stack();
/* On IA64 gcc, could use __builtin_ia64_flushrs() and */
/* __builtin_ia64_flushrs(). The latter will be done */
@ -445,7 +456,7 @@ ptr_t cold_gc_frame;
/* the stack. Return sp. */
# ifdef SPARC
asm(" .seg \"text\"");
# ifdef SVR4
# if defined(SVR4) || defined(NETBSD)
asm(" .globl GC_save_regs_in_stack");
asm("GC_save_regs_in_stack:");
asm(" .type GC_save_regs_in_stack,#function");

View File

@ -182,6 +182,7 @@ register int k;
ptr_t result;
DCL_LOCK_STATE;
if (GC_have_errors) GC_print_all_errors();
GC_INVOKE_FINALIZERS();
if (SMALL_OBJ(lb)) {
DISABLE_SIGNALS();
@ -294,6 +295,11 @@ DCL_LOCK_STATE;
return(GENERAL_MALLOC((word)lb, NORMAL));
}
/* See above comment on signals. */
GC_ASSERT(0 == obj_link(op)
|| (word)obj_link(op)
<= (word)GC_greatest_plausible_heap_addr
&& (word)obj_link(op)
>= (word)GC_least_plausible_heap_addr);
*opp = obj_link(op);
obj_link(op) = 0;
GC_words_allocd += lw;
@ -338,6 +344,7 @@ DCL_LOCK_STATE;
return((GC_PTR)REDIRECT_MALLOC(n*lb));
}
#ifndef strdup
# include <string.h>
# ifdef __STDC__
char *strdup(const char *s)
@ -346,11 +353,16 @@ DCL_LOCK_STATE;
char *s;
# endif
{
size_t len = strlen + 1;
size_t len = strlen(s) + 1;
char * result = ((char *)REDIRECT_MALLOC(len+1));
BCOPY(s, result, len+1);
return result;
}
#endif /* !defined(strdup) */
/* If strdup is macro defined, we assume that it actually calls malloc, */
/* and thus the right thing will happen even without overriding it. */
/* This seems to be true on most Linux systems. */
# endif /* REDIRECT_MALLOC */
/* Explicitly deallocate an object p. */
@ -373,6 +385,7 @@ DCL_LOCK_STATE;
/* Required by ANSI. It's not my fault ... */
h = HBLKPTR(p);
hhdr = HDR(h);
GC_ASSERT(GC_base(p) == p);
# if defined(REDIRECT_MALLOC) && \
(defined(GC_SOLARIS_THREADS) || defined(GC_LINUX_THREADS) \
|| defined(__MINGW32__)) /* Should this be MSWIN32 in general? */
@ -454,7 +467,10 @@ void GC_free_inner(GC_PTR p)
}
#endif /* THREADS */
# ifdef REDIRECT_MALLOC
# if defined(REDIRECT_MALLOC) && !defined(REDIRECT_FREE)
# define REDIRECT_FREE GC_free
# endif
# ifdef REDIRECT_FREE
# ifdef __STDC__
void free(GC_PTR p)
# else
@ -463,7 +479,7 @@ void GC_free_inner(GC_PTR p)
# endif
{
# ifndef IGNORE_FREE
GC_free(p);
REDIRECT_FREE(p);
# endif
}
# endif /* REDIRECT_MALLOC */

View File

@ -142,7 +142,11 @@ int obj_kind;
}
}
# if defined(REDIRECT_MALLOC) || defined(REDIRECT_REALLOC)
# if defined(REDIRECT_MALLOC) && !defined(REDIRECT_REALLOC)
# define REDIRECT_REALLOC GC_realloc
# endif
# ifdef REDIRECT_REALLOC
# ifdef __STDC__
GC_PTR realloc(GC_PTR p, size_t lb)
# else
@ -151,13 +155,9 @@ int obj_kind;
size_t lb;
# endif
{
# ifdef REDIRECT_REALLOC
return(REDIRECT_REALLOC(p, lb));
# else
return(GC_realloc(p, lb));
# endif
return(REDIRECT_REALLOC(p, lb));
}
# endif /* REDIRECT_MALLOC */
# endif /* REDIRECT_REALLOC */
/* The same thing, except caller does not hold allocation lock. */
@ -177,6 +177,7 @@ register int k;
lw = ROUNDED_UP_WORDS(lb);
n_blocks = OBJ_SZ_TO_BLOCKS(lw);
init = GC_obj_kinds[k].ok_init;
if (GC_have_errors) GC_print_all_errors();
GC_INVOKE_FINALIZERS();
DISABLE_SIGNALS();
LOCK();
@ -286,6 +287,7 @@ register struct obj_kind * kind = GC_obj_kinds + k;
register ptr_t op;
DCL_LOCK_STATE;
if (GC_have_errors) GC_print_all_errors();
GC_INVOKE_FINALIZERS();
DISABLE_SIGNALS();
LOCK();
@ -354,6 +356,7 @@ DCL_LOCK_STATE;
return;
}
lw = ALIGNED_WORDS(lb);
if (GC_have_errors) GC_print_all_errors();
GC_INVOKE_FINALIZERS();
DISABLE_SIGNALS();
LOCK();
@ -375,6 +378,7 @@ DCL_LOCK_STATE;
while ((hbp = *rlh) != 0) {
hhdr = HDR(hbp);
*rlh = hhdr -> hb_next;
hhdr -> hb_last_reclaimed = (unsigned short) GC_gc_no;
# ifdef PARALLEL_MARK
{
signed_word my_words_allocd_tmp = GC_words_allocd_tmp;
@ -575,6 +579,44 @@ DCL_LOCK_STATE;
}
}
#ifdef __STDC__
/* Not well tested nor integrated. */
/* Debug version is tricky and currently missing. */
#include <limits.h>
GC_PTR GC_memalign(size_t align, size_t lb)
{
size_t new_lb;
size_t offset;
ptr_t result;
# ifdef ALIGN_DOUBLE
if (align <= WORDS_TO_BYTES(2) && lb > align) return GC_malloc(lb);
# endif
if (align <= WORDS_TO_BYTES(1)) return GC_malloc(lb);
if (align >= HBLKSIZE/2 || lb >= HBLKSIZE/2) {
if (align > HBLKSIZE) return GC_oom_fn(LONG_MAX-1024) /* Fail */;
return GC_malloc(lb <= HBLKSIZE? HBLKSIZE : lb);
/* Will be HBLKSIZE aligned. */
}
/* We could also try to make sure that the real rounded-up object size */
/* is a multiple of align. That would be correct up to HBLKSIZE. */
new_lb = lb + align - 1;
result = GC_malloc(new_lb);
offset = (word)result % align;
if (offset != 0) {
offset = align - offset;
if (!GC_all_interior_pointers) {
if (offset >= VALID_OFFSET_SZ) return GC_malloc(HBLKSIZE);
GC_register_displacement(offset);
}
}
result = (GC_PTR) ((ptr_t)result + offset);
GC_ASSERT((word)result % align == 0);
return result;
}
#endif
# ifdef ATOMIC_UNCOLLECTABLE
/* Allocate lb bytes of pointerfree, untraced, uncollectable data */
/* This is normally roughly equivalent to the system malloc. */

View File

@ -19,6 +19,10 @@
# include <stdio.h>
# include "private/gc_pmark.h"
#if defined(MSWIN32) && defined(__GNUC__)
# include <excpt.h>
#endif
/* We put this here to minimize the risk of inlining. */
/*VARARGS*/
#ifdef __WATCOMC__
@ -261,20 +265,20 @@ static void alloc_mark_stack();
/* remains valid until all marking is complete. */
/* A zero value indicates that it's OK to miss some */
/* register values. */
GC_bool GC_mark_some(cold_gc_frame)
ptr_t cold_gc_frame;
/* We hold the allocation lock. In the case of */
/* incremental collection, the world may not be stopped.*/
#ifdef MSWIN32
/* For win32, this is called after we establish a structured */
/* exception handler, in case Windows unmaps one of our root */
/* segments. See below. In either case, we acquire the */
/* allocator lock long before we get here. */
GC_bool GC_mark_some_inner(cold_gc_frame)
ptr_t cold_gc_frame;
#else
GC_bool GC_mark_some(cold_gc_frame)
ptr_t cold_gc_frame;
#endif
{
#if defined(MSWIN32) && !defined(__GNUC__)
/* Windows 98 appears to asynchronously create and remove writable */
/* memory mappings, for reasons we haven't yet understood. Since */
/* we look for writable regions to determine the root set, we may */
/* try to mark from an address range that disappeared since we */
/* started the collection. Thus we have to recover from faults here. */
/* This code does not appear to be necessary for Windows 95/NT/2000. */
/* Note that this code should never generate an incremental GC write */
/* fault. */
__try {
#endif /* defined(MSWIN32) && !defined(__GNUC__) */
switch(GC_mark_state) {
case MS_NONE:
return(FALSE);
@ -395,25 +399,132 @@ ptr_t cold_gc_frame;
ABORT("GC_mark_some: bad state");
return(FALSE);
}
#if defined(MSWIN32) && !defined(__GNUC__)
} __except (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ?
EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) {
# ifdef CONDPRINT
if (GC_print_stats) {
GC_printf0("Caught ACCESS_VIOLATION in marker. "
"Memory mapping disappeared.\n");
}
# endif /* CONDPRINT */
/* We have bad roots on the stack. Discard mark stack. */
/* Rescan from marked objects. Redetermine roots. */
GC_invalidate_mark_state();
scan_ptr = 0;
return FALSE;
}
#endif /* defined(MSWIN32) && !defined(__GNUC__) */
}
#ifdef MSWIN32
# ifdef __GNUC__
typedef struct {
EXCEPTION_REGISTRATION ex_reg;
void *alt_path;
} ext_ex_regn;
static EXCEPTION_DISPOSITION mark_ex_handler(
struct _EXCEPTION_RECORD *ex_rec,
void *est_frame,
struct _CONTEXT *context,
void *disp_ctxt)
{
if (ex_rec->ExceptionCode == STATUS_ACCESS_VIOLATION) {
ext_ex_regn *xer = (ext_ex_regn *)est_frame;
/* Unwind from the inner function assuming the standard */
/* function prologue. */
/* Assumes code has not been compiled with */
/* -fomit-frame-pointer. */
context->Esp = context->Ebp;
context->Ebp = *((DWORD *)context->Esp);
context->Esp = context->Esp - 8;
/* Resume execution at the "real" handler within the */
/* wrapper function. */
context->Eip = (DWORD )(xer->alt_path);
return ExceptionContinueExecution;
} else {
return ExceptionContinueSearch;
}
}
# endif /* __GNUC__ */
GC_bool GC_mark_some(cold_gc_frame)
ptr_t cold_gc_frame;
{
GC_bool ret_val;
# ifndef __GNUC__
/* Windows 98 appears to asynchronously create and remove */
/* writable memory mappings, for reasons we haven't yet */
/* understood. Since we look for writable regions to */
/* determine the root set, we may try to mark from an */
/* address range that disappeared since we started the */
/* collection. Thus we have to recover from faults here. */
/* This code does not appear to be necessary for Windows */
/* 95/NT/2000. Note that this code should never generate */
/* an incremental GC write fault. */
__try {
# else /* __GNUC__ */
/* Manually install an exception handler since GCC does */
/* not yet support Structured Exception Handling (SEH) on */
/* Win32. */
ext_ex_regn er;
er.alt_path = &&handle_ex;
er.ex_reg.handler = mark_ex_handler;
asm volatile ("movl %%fs:0, %0" : "=r" (er.ex_reg.prev));
asm volatile ("movl %0, %%fs:0" : : "r" (&er));
# endif /* __GNUC__ */
ret_val = GC_mark_some_inner(cold_gc_frame);
# ifndef __GNUC__
} __except (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ?
EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) {
# else /* __GNUC__ */
/* Prevent GCC from considering the following code unreachable */
/* and thus eliminating it. */
if (er.alt_path != 0)
goto rm_handler;
handle_ex:
/* Execution resumes from here on an access violation. */
# endif /* __GNUC__ */
# ifdef CONDPRINT
if (GC_print_stats) {
GC_printf0("Caught ACCESS_VIOLATION in marker. "
"Memory mapping disappeared.\n");
}
# endif /* CONDPRINT */
/* We have bad roots on the stack. Discard mark stack. */
/* Rescan from marked objects. Redetermine roots. */
GC_invalidate_mark_state();
scan_ptr = 0;
ret_val = FALSE;
# ifndef __GNUC__
}
# else /* __GNUC__ */
rm_handler:
/* Uninstall the exception handler */
asm volatile ("mov %0, %%fs:0" : : "r" (er.ex_reg.prev));
# endif /* __GNUC__ */
return ret_val;
}
#endif /* MSWIN32 */
GC_bool GC_mark_stack_empty()
{
return(GC_mark_stack_top < GC_mark_stack);
@ -434,13 +545,7 @@ GC_bool GC_mark_stack_empty()
/* for the large object. */
/* - just return current if it does not point to a large object. */
/*ARGSUSED*/
# ifdef PRINT_BLACK_LIST
ptr_t GC_find_start(current, hhdr, new_hdr_p, source)
ptr_t source;
# else
ptr_t GC_find_start(current, hhdr, new_hdr_p)
# define source 0
# endif
ptr_t GC_find_start(current, hhdr, new_hdr_p)
register ptr_t current;
register hdr *hhdr, **new_hdr_p;
{
@ -468,7 +573,6 @@ register hdr *hhdr, **new_hdr_p;
} else {
return(current);
}
# undef source
}
void GC_invalidate_mark_state()
@ -546,8 +650,8 @@ mse * mark_stack_limit;
/* Large length. */
/* Process part of the range to avoid pushing too much on the */
/* stack. */
GC_ASSERT(descr < GC_greatest_plausible_heap_addr
- GC_least_plausible_heap_addr);
GC_ASSERT(descr < (word)GC_greatest_plausible_heap_addr
- (word)GC_least_plausible_heap_addr);
# ifdef PARALLEL_MARK
# define SHARE_BYTES 2048
if (descr > SHARE_BYTES && GC_parallel
@ -578,6 +682,7 @@ mse * mark_stack_limit;
while (descr != 0) {
if ((signed_word)descr < 0) {
current = *current_p;
FIXUP_POINTER(current);
if ((ptr_t)current >= least_ha && (ptr_t)current < greatest_ha) {
PREFETCH(current);
HC_PUSH_CONTENTS((ptr_t)current, mark_stack_top,
@ -652,6 +757,7 @@ mse * mark_stack_limit;
PREFETCH((ptr_t)limit - PREF_DIST*CACHE_LINE_SIZE);
GC_ASSERT(limit >= current_p);
deferred = *limit;
FIXUP_POINTER(deferred);
limit = (word *)((char *)limit - ALIGNMENT);
if ((ptr_t)deferred >= least_ha && (ptr_t)deferred < greatest_ha) {
PREFETCH(deferred);
@ -661,6 +767,7 @@ mse * mark_stack_limit;
/* Unroll once, so we don't do too many of the prefetches */
/* based on limit. */
deferred = *limit;
FIXUP_POINTER(deferred);
limit = (word *)((char *)limit - ALIGNMENT);
if ((ptr_t)deferred >= least_ha && (ptr_t)deferred < greatest_ha) {
PREFETCH(deferred);
@ -675,6 +782,7 @@ mse * mark_stack_limit;
/* Since HC_PUSH_CONTENTS expands to a lot of code, */
/* we don't. */
current = *current_p;
FIXUP_POINTER(current);
PREFETCH((ptr_t)current_p + PREF_DIST*CACHE_LINE_SIZE);
if ((ptr_t)current >= least_ha && (ptr_t)current < greatest_ha) {
/* Prefetch the contents of the object we just pushed. It's */
@ -726,22 +834,33 @@ mse * GC_steal_mark_stack(mse * low, mse * high, mse * local,
mse *top = local - 1;
unsigned i = 0;
/* Make sure that prior writes to the mark stack are visible. */
/* On some architectures, the fact that the reads are */
/* volatile should suffice. */
# if !defined(IA64) && !defined(HP_PA) && !defined(I386)
GC_memory_barrier();
# endif
GC_ASSERT(high >= low-1 && high - low + 1 <= GC_mark_stack_size);
for (p = low; p <= high && i <= max; ++p) {
word descr = *(volatile word *) &(p -> mse_descr);
/* In the IA64 memory model, the following volatile store is */
/* ordered after this read of descr. Thus a thread must read */
/* the original nonzero value. HP_PA appears to be similar, */
/* and if I'm reading the P4 spec correctly, X86 is probably */
/* also OK. In some other cases we need a barrier. */
# if !defined(IA64) && !defined(HP_PA) && !defined(I386)
GC_memory_barrier();
# endif
if (descr != 0) {
*(volatile word *) &(p -> mse_descr) = 0;
/* More than one thread may get this entry, but that's only */
/* a minor performance problem. */
++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);
/* There is no synchronization here. We assume that at */
/* least one thread will see the original descriptor. */
/* Otherwise we need a barrier. */
/* More than one thread may get this entry, but that's only */
/* a minor performance problem. */
/* If this is a big object, count it as */
/* size/256 + 1 objects. */
++i;
@ -778,7 +897,7 @@ void GC_return_mark_stack(mse * low, mse * high)
BCOPY(low, my_start, stack_size * sizeof(mse));
GC_ASSERT(GC_mark_stack_top = my_top);
# if !defined(IA64) && !defined(HP_PA)
GC_memory_write_barrier();
GC_memory_barrier();
# endif
/* On IA64, the volatile write acts as a release barrier. */
GC_mark_stack_top = my_top + stack_size;
@ -1342,8 +1461,8 @@ ptr_t top;
# define GC_least_plausible_heap_addr least_ha
if (top == 0) return;
/* check all pointers in range and put in push if they appear */
/* to be valid. */
/* check all pointers in range and push if they appear */
/* to be valid. */
lim = t - 1 /* longword */;
for (p = b; p <= lim; p = (word *)(((char *)p) + ALIGNMENT)) {
q = *p;
@ -1366,7 +1485,7 @@ ptr_t bottom;
ptr_t top;
ptr_t cold_gc_frame;
{
if (GC_all_interior_pointers) {
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. */
@ -1375,6 +1494,7 @@ ptr_t cold_gc_frame;
GC_push_all_stack(bottom, top);
return;
}
GC_ASSERT(bottom <= cold_gc_frame && cold_gc_frame <= top);
# ifdef STACK_GROWS_DOWN
GC_push_all(cold_gc_frame - sizeof(ptr_t), top);
GC_push_all_eager(bottom, cold_gc_frame);
@ -1395,7 +1515,7 @@ void GC_push_all_stack(bottom, top)
ptr_t bottom;
ptr_t top;
{
if (GC_all_interior_pointers) {
if (!NEED_FIXUP_POINTER && GC_all_interior_pointers) {
GC_push_all(bottom, top);
} else {
GC_push_all_eager(bottom, top);

View File

@ -274,6 +274,28 @@ void GC_clear_roots GC_PROTO((void))
ENABLE_SIGNALS();
}
/* Internal use only; lock held. */
static void GC_remove_root_at_pos(i)
int i;
{
GC_root_size -= (GC_static_roots[i].r_end - GC_static_roots[i].r_start);
GC_static_roots[i].r_start = GC_static_roots[n_root_sets-1].r_start;
GC_static_roots[i].r_end = GC_static_roots[n_root_sets-1].r_end;
GC_static_roots[i].r_tmp = GC_static_roots[n_root_sets-1].r_tmp;
n_root_sets--;
}
#if !defined(MSWIN32) && !defined(MSWINCE)
static void GC_rebuild_root_index()
{
register int i;
for (i = 0; i < RT_SIZE; i++) GC_root_index[i] = 0;
for (i = 0; i < n_root_sets; i++)
add_roots_to_index(GC_static_roots + i);
}
#endif
/* Internal use only; lock held. */
void GC_remove_tmp_roots()
{
@ -281,27 +303,44 @@ void GC_remove_tmp_roots()
for (i = 0; i < n_root_sets; ) {
if (GC_static_roots[i].r_tmp) {
GC_root_size -=
(GC_static_roots[i].r_end - GC_static_roots[i].r_start);
GC_static_roots[i].r_start = GC_static_roots[n_root_sets-1].r_start;
GC_static_roots[i].r_end = GC_static_roots[n_root_sets-1].r_end;
GC_static_roots[i].r_tmp = GC_static_roots[n_root_sets-1].r_tmp;
n_root_sets--;
GC_remove_root_at_pos(i);
} else {
i++;
}
}
#if !defined(MSWIN32) && !defined(MSWINCE)
GC_rebuild_root_index();
#endif
}
#if !defined(MSWIN32) && !defined(MSWINCE)
void GC_remove_roots(b, e)
char * b; char * e;
{
DCL_LOCK_STATE;
DISABLE_SIGNALS();
LOCK();
GC_remove_roots_inner(b, e);
UNLOCK();
ENABLE_SIGNALS();
}
/* Should only be called when the lock is held */
void GC_remove_roots_inner(b,e)
char * b; char * e;
{
int i;
for (i = 0; i < n_root_sets; ) {
if (GC_static_roots[i].r_start >= (ptr_t)b && GC_static_roots[i].r_end <= (ptr_t)e) {
GC_remove_root_at_pos(i);
} else {
i++;
}
}
# if !defined(MSWIN32) && !defined(MSWINCE)
{
register int i;
for (i = 0; i < RT_SIZE; i++) GC_root_index[i] = 0;
for (i = 0; i < n_root_sets; i++)
add_roots_to_index(GC_static_roots + i);
}
# endif
GC_rebuild_root_index();
}
#endif /* !defined(MSWIN32) && !defined(MSWINCE) */
#if defined(MSWIN32) || defined(_WIN32_WCE_EMULATION)
/* Workaround for the OS mapping and unmapping behind our back: */
@ -573,8 +612,11 @@ ptr_t cold_gc_frame;
/* Mark thread local free lists, even if their mark */
/* descriptor excludes the link field. */
/* If the world is not stopped, this is unsafe. It is */
/* also unnecessary, since we will do this again with the */
/* world stopped. */
# ifdef THREAD_LOCAL_ALLOC
GC_mark_thread_local_free_lists();
if (GC_world_stopped) GC_mark_thread_local_free_lists();
# endif
/*

View File

@ -1,5 +1,10 @@
#include <sys/regdef.h>
#include <sys/asm.h>
/* This file must be preprocessed. But the SGI assembler always does */
/* that. Furthermore, a generic preprocessor won't do, since some of */
/* the SGI-supplied include files rely on behavior of the MIPS */
/* assembler. Hence we treat and name this file as though it required */
/* no preprocessing. */
# define call_push(x) move $4,x; jal GC_push_one

View File

@ -46,8 +46,10 @@
# ifdef GC_SOLARIS_THREADS
mutex_t GC_allocate_ml; /* Implicitly initialized. */
# else
# ifdef GC_WIN32_THREADS
# if !defined(GC_NOT_DLL) && (defined(_DLL) || defined(GC_DLL))
# if defined(GC_WIN32_THREADS)
# if defined(GC_PTHREADS)
pthread_mutex_t GC_allocate_ml = PTHREAD_MUTEX_INITIALIZER;
# elif defined(GC_DLL)
__declspec(dllexport) CRITICAL_SECTION GC_allocate_ml;
# else
CRITICAL_SECTION GC_allocate_ml;
@ -75,8 +77,8 @@
#undef STACKBASE
#endif
/* Dont unnecessarily call GC_register_main_static_data() in case */
/* dyn_load.c isn't linked in. */
/* Dont unnecessarily call GC_register_main_static_data() in case */
/* dyn_load.c isn't linked in. */
#ifdef DYNAMIC_LOADING
# define GC_REGISTER_MAIN_STATIC_DATA() GC_register_main_static_data()
#else
@ -90,6 +92,7 @@ GC_bool GC_debugging_started = FALSE;
/* defined here so we don't have to load debug_malloc.o */
void (*GC_check_heap) GC_PROTO((void)) = (void (*) GC_PROTO((void)))0;
void (*GC_print_all_smashed) GC_PROTO((void)) = (void (*) GC_PROTO((void)))0;
void (*GC_start_call_back) GC_PROTO((void)) = (void (*) GC_PROTO((void)))0;
@ -109,6 +112,10 @@ GC_bool GC_print_stats = 0;
GC_bool GC_print_back_height = 0;
#ifndef NO_DEBUGGING
GC_bool GC_dump_regularly = 0; /* Generate regular debugging dumps. */
#endif
#ifdef FIND_LEAK
int GC_find_leak = 1;
#else
@ -137,6 +144,13 @@ GC_PTR (*GC_oom_fn) GC_PROTO((size_t bytes_requested)) = GC_default_oom_fn;
extern signed_word GC_mem_found;
void * GC_project2(arg1, arg2)
void *arg1;
void *arg2;
{
return arg2;
}
# ifdef MERGE_SIZES
/* Set things up so that GC_size_map[i] >= words(i), */
/* but not too much bigger */
@ -455,7 +469,7 @@ void GC_init()
DISABLE_SIGNALS();
#ifdef MSWIN32
#if defined(GC_WIN32_THREADS) && !defined(GC_PTHREADS)
if (!GC_is_initialized) InitializeCriticalSection(&GC_allocate_ml);
#endif /* MSWIN32 */
@ -473,6 +487,15 @@ void GC_init()
GC_init_parallel();
}
# endif /* PARALLEL_MARK || THREAD_LOCAL_ALLOC */
# if defined(DYNAMIC_LOADING) && defined(DARWIN)
{
/* This must be called WITHOUT the allocation lock held
and before any threads are created */
extern void GC_init_dyld();
GC_init_dyld();
}
# endif
}
#if defined(MSWIN32) || defined(MSWINCE)
@ -485,6 +508,22 @@ void GC_init()
extern void GC_setpagesize();
#ifdef MSWIN32
extern GC_bool GC_no_win32_dlls;
#else
# define GC_no_win32_dlls FALSE
#endif
void GC_exit_check GC_PROTO((void))
{
GC_gcollect();
}
#ifdef SEARCH_FOR_DATA_START
extern void GC_init_linux_data_start GC_PROTO((void));
#endif
#ifdef UNIX_LIKE
extern void GC_set_and_save_fault_handler GC_PROTO((void (*handler)(int)));
@ -495,12 +534,23 @@ int sig;
GC_err_printf1("Caught signal %d: looping in handler\n", sig);
for(;;);
}
#endif
#ifdef MSWIN32
extern GC_bool GC_no_win32_dlls;
#else
# define GC_no_win32_dlls FALSE
static GC_bool installed_looping_handler = FALSE;
void maybe_install_looping_handler()
{
/* Install looping handler before the write fault handler, so we */
/* handle write faults correctly. */
if (!installed_looping_handler && 0 != GETENV("GC_LOOP_ON_ABORT")) {
GC_set_and_save_fault_handler(looping_handler);
installed_looping_handler = TRUE;
}
}
#else /* !UNIX_LIKE */
# define maybe_install_looping_handler()
#endif
void GC_init_inner()
@ -515,14 +565,21 @@ void GC_init_inner()
GC_print_stats = 1;
# endif
# if defined(MSWIN32) || defined(MSWINCE)
InitializeCriticalSection(&GC_write_cs);
InitializeCriticalSection(&GC_write_cs);
# endif
if (0 != GETENV("GC_PRINT_STATS")) {
GC_print_stats = 1;
}
# ifndef NO_DEBUGGING
if (0 != GETENV("GC_DUMP_REGULARLY")) {
GC_dump_regularly = 1;
}
# endif
if (0 != GETENV("GC_FIND_LEAK")) {
GC_find_leak = 1;
# ifdef __STDC__
atexit(GC_exit_check);
# endif
}
if (0 != GETENV("GC_ALL_INTERIOR_POINTERS")) {
GC_all_interior_pointers = 1;
@ -560,11 +617,7 @@ void GC_init_inner()
}
}
}
# ifdef UNIX_LIKE
if (0 != GETENV("GC_LOOP_ON_ABORT")) {
GC_set_and_save_fault_handler(looping_handler);
}
# endif
maybe_install_looping_handler();
/* Adjust normal object descriptor for extra allocation. */
if (ALIGNMENT > GC_DS_TAGS && EXTRA_BYTES != 0) {
GC_obj_kinds[NORMAL].ok_descriptor = ((word)(-ALIGNMENT) | GC_DS_LENGTH);
@ -599,11 +652,21 @@ void GC_init_inner()
# if defined(LINUX) && defined(IA64)
GC_register_stackbottom = GC_get_register_stack_base();
# endif
} else {
# if defined(LINUX) && defined(IA64)
if (GC_register_stackbottom == 0) {
WARN("GC_register_stackbottom should be set with GC_stackbottom", 0);
/* The following is likely to fail, since we rely on */
/* alignment properties that may not hold with a user set */
/* GC_stackbottom. */
GC_register_stackbottom = GC_get_register_stack_base();
}
# endif
}
# endif
GC_ASSERT(sizeof (ptr_t) == sizeof(word));
GC_ASSERT(sizeof (signed_word) == sizeof(word));
GC_ASSERT(sizeof (struct hblk) == HBLKSIZE);
GC_STATIC_ASSERT(sizeof (ptr_t) == sizeof(word));
GC_STATIC_ASSERT(sizeof (signed_word) == sizeof(word));
GC_STATIC_ASSERT(sizeof (struct hblk) == HBLKSIZE);
# ifndef THREADS
# if defined(STACK_GROWS_UP) && defined(STACK_GROWS_DOWN)
ABORT(
@ -642,6 +705,18 @@ void GC_init_inner()
initial_heap_sz = divHBLKSZ(initial_heap_sz);
}
}
{
char * sz_str = GETENV("GC_MAXIMUM_HEAP_SIZE");
if (sz_str != NULL) {
word max_heap_sz = (word)atol(sz_str);
if (max_heap_sz < initial_heap_sz * HBLKSIZE) {
WARN("Bad maximum heap size %s - ignoring it.\n",
sz_str);
}
if (0 == GC_max_retries) GC_max_retries = 2;
GC_set_max_heap_size(max_heap_sz);
}
}
if (!GC_expand_hp_inner(initial_heap_sz)) {
GC_err_printf0("Can't start up: not enough memory\n");
EXIT();
@ -677,6 +752,7 @@ void GC_init_inner()
GC_incremental = TRUE;
}
# endif /* !SMALL_CONFIG */
COND_DUMP;
/* Get black list set up and/or incrmental GC started */
if (!GC_dont_precollect || GC_incremental) GC_gcollect_inner();
GC_is_initialized = TRUE;
@ -712,8 +788,9 @@ void GC_enable_incremental GC_PROTO(())
if (GC_incremental) goto out;
GC_setpagesize();
if (GC_no_win32_dlls) goto out;
# ifndef GC_SOLARIS_THREADS
GC_dirty_init();
# ifndef GC_SOLARIS_THREADS
maybe_install_looping_handler(); /* Before write fault handler! */
GC_dirty_init();
# endif
if (!GC_is_initialized) {
GC_init_inner();
@ -932,6 +1009,17 @@ GC_warn_proc GC_current_warn_proc = GC_default_warn_proc;
return(result);
}
# if defined(__STDC__) || defined(__cplusplus)
GC_word GC_set_free_space_divisor (GC_word value)
# else
GC_word GC_set_free_space_divisor (value)
GC_word value;
# endif
{
GC_word old = GC_free_space_divisor;
GC_free_space_divisor = value;
return old;
}
#ifndef PCR
void GC_abort(msg)
@ -958,122 +1046,18 @@ GC_CONST char * msg;
}
#endif
#ifdef NEED_CALLINFO
#ifdef HAVE_BUILTIN_BACKTRACE
# include <execinfo.h>
# ifdef LINUX
# include <unistd.h>
# endif
#endif
void GC_print_callers (info)
struct callinfo info[NFRAMES];
{
register int i;
# if NFRAMES == 1
GC_err_printf0("\tCaller at allocation:\n");
# else
GC_err_printf0("\tCall chain at allocation:\n");
# endif
for (i = 0; i < NFRAMES; i++) {
if (info[i].ci_pc == 0) break;
# if NARGS > 0
{
int j;
GC_err_printf0("\t\targs: ");
for (j = 0; j < NARGS; j++) {
if (j != 0) GC_err_printf0(", ");
GC_err_printf2("%d (0x%X)", ~(info[i].ci_arg[j]),
~(info[i].ci_arg[j]));
}
GC_err_printf0("\n");
}
# endif
# if defined(HAVE_BUILTIN_BACKTRACE) && !defined(REDIRECT_MALLOC)
/* Unfortunately backtrace_symbols calls malloc, which makes */
/* it dangersous if that has been redirected. */
{
char **sym_name =
backtrace_symbols((void **)(&(info[i].ci_pc)), 1);
char *name = sym_name[0];
GC_bool found_it = (strchr(name, '(') != 0);
FILE *pipe;
# ifdef LINUX
if (!found_it) {
# define EXE_SZ 100
static char exe_name[EXE_SZ];
# define CMD_SZ 200
char cmd_buf[CMD_SZ];
# define RESULT_SZ 200
static char result_buf[RESULT_SZ];
size_t result_len;
static GC_bool found_exe_name = FALSE;
static GC_bool will_fail = FALSE;
int ret_code;
/* Unfortunately, this is the common case for the */
/* main executable. */
/* Try to get it via a hairy and expensive scheme. */
/* First we get the name of the executable: */
if (will_fail) goto out;
if (!found_exe_name) {
ret_code = readlink("/proc/self/exe", exe_name, EXE_SZ);
if (ret_code < 0 || ret_code >= EXE_SZ || exe_name[0] != '/') {
will_fail = TRUE; /* Dont try again. */
goto out;
}
exe_name[ret_code] = '\0';
found_exe_name = TRUE;
}
/* Then we use popen to start addr2line -e <exe> <addr> */
/* There are faster ways to do this, but hopefully this */
/* isn't time critical. */
sprintf(cmd_buf, "/usr/bin/addr2line -e %s 0x%lx", exe_name,
(unsigned long)info[i].ci_pc);
pipe = popen(cmd_buf, "r");
if (pipe < 0 || fgets(result_buf, RESULT_SZ, pipe) == 0) {
will_fail = TRUE;
goto out;
}
result_len = strlen(result_buf);
if (result_buf[result_len - 1] == '\n') --result_len;
if (result_buf[0] == '?'
|| result_buf[result_len-2] == ':'
&& result_buf[result_len-1] == '0')
goto out;
if (result_len < RESULT_SZ - 25) {
/* Add in hex address */
sprintf(result_buf + result_len, " [0x%lx]",
(unsigned long)info[i].ci_pc);
}
name = result_buf;
pclose(pipe);
out:
}
# endif
GC_err_printf1("\t\t%s\n", name);
free(sym_name);
}
# else
GC_err_printf1("\t\t##PC##= 0x%lx\n", info[i].ci_pc);
# endif
}
}
#endif /* SAVE_CALL_CHAIN */
/* Needed by SRC_M3, gcj, and should perhaps be the official interface */
/* to GC_dont_gc. */
void GC_enable()
{
LOCK();
GC_dont_gc--;
UNLOCK();
}
void GC_disable()
{
LOCK();
GC_dont_gc++;
UNLOCK();
}
#if !defined(NO_DEBUGGING)
@ -1088,6 +1072,8 @@ void GC_dump()
GC_print_hblkfreelist();
GC_printf0("\n***Blocks in use:\n");
GC_print_block_list();
GC_printf0("\n***Finalization statistics:\n");
GC_print_finalization_stats();
}
#endif /* NO_DEBUGGING */

View File

@ -1,336 +0,0 @@
#! /bin/sh
# Common stub for a few missing GNU programs while installing.
# Copyright 1996, 1997, 1999, 2000 Free Software Foundation, Inc.
# Originally by Fran,cois Pinard <pinard@iro.umontreal.ca>, 1996.
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2, or (at your option)
# any later version.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
# 02111-1307, USA.
# As a special exception to the GNU General Public License, if you
# distribute this file as part of a program that contains a
# configuration script generated by Autoconf, you may include it under
# the same distribution terms that you use for the rest of that program.
if test $# -eq 0; then
echo 1>&2 "Try \`$0 --help' for more information"
exit 1
fi
run=:
# In the cases where this matters, `missing' is being run in the
# srcdir already.
if test -f configure.ac; then
configure_ac=configure.ac
else
configure_ac=configure.in
fi
case "$1" in
--run)
# Try to run requested program, and just exit if it succeeds.
run=
shift
"$@" && exit 0
;;
esac
# If it does not exist, or fails to run (possibly an outdated version),
# try to emulate it.
case "$1" in
-h|--h|--he|--hel|--help)
echo "\
$0 [OPTION]... PROGRAM [ARGUMENT]...
Handle \`PROGRAM [ARGUMENT]...' for when PROGRAM is missing, or return an
error status if there is no known handling for PROGRAM.
Options:
-h, --help display this help and exit
-v, --version output version information and exit
--run try to run the given command, and emulate it if it fails
Supported PROGRAM values:
aclocal touch file \`aclocal.m4'
autoconf touch file \`configure'
autoheader touch file \`config.h.in'
automake touch all \`Makefile.in' files
bison create \`y.tab.[ch]', if possible, from existing .[ch]
flex create \`lex.yy.c', if possible, from existing .c
help2man touch the output file
lex create \`lex.yy.c', if possible, from existing .c
makeinfo touch the output file
tar try tar, gnutar, gtar, then tar without non-portable flags
yacc create \`y.tab.[ch]', if possible, from existing .[ch]"
;;
-v|--v|--ve|--ver|--vers|--versi|--versio|--version)
echo "missing 0.4 - GNU automake"
;;
-*)
echo 1>&2 "$0: Unknown \`$1' option"
echo 1>&2 "Try \`$0 --help' for more information"
exit 1
;;
aclocal*)
if test -z "$run" && ($1 --version) > /dev/null 2>&1; then
# We have it, but it failed.
exit 1
fi
echo 1>&2 "\
WARNING: \`$1' is missing on your system. You should only need it if
you modified \`acinclude.m4' or \`${configure_ac}'. You might want
to install the \`Automake' and \`Perl' packages. Grab them from
any GNU archive site."
touch aclocal.m4
;;
autoconf)
if test -z "$run" && ($1 --version) > /dev/null 2>&1; then
# We have it, but it failed.
exit 1
fi
echo 1>&2 "\
WARNING: \`$1' is missing on your system. You should only need it if
you modified \`${configure_ac}'. You might want to install the
\`Autoconf' and \`GNU m4' packages. Grab them from any GNU
archive site."
touch configure
;;
autoheader)
if test -z "$run" && ($1 --version) > /dev/null 2>&1; then
# We have it, but it failed.
exit 1
fi
echo 1>&2 "\
WARNING: \`$1' is missing on your system. You should only need it if
you modified \`acconfig.h' or \`${configure_ac}'. You might want
to install the \`Autoconf' and \`GNU m4' packages. Grab them
from any GNU archive site."
files=`sed -n 's/^[ ]*A[CM]_CONFIG_HEADER(\([^)]*\)).*/\1/p' ${configure_ac}`
test -z "$files" && files="config.h"
touch_files=
for f in $files; do
case "$f" in
*:*) touch_files="$touch_files "`echo "$f" |
sed -e 's/^[^:]*://' -e 's/:.*//'`;;
*) touch_files="$touch_files $f.in";;
esac
done
touch $touch_files
;;
automake*)
if test -z "$run" && ($1 --version) > /dev/null 2>&1; then
# We have it, but it failed.
exit 1
fi
echo 1>&2 "\
WARNING: \`$1' is missing on your system. You should only need it if
you modified \`Makefile.am', \`acinclude.m4' or \`${configure_ac}'.
You might want to install the \`Automake' and \`Perl' packages.
Grab them from any GNU archive site."
find . -type f -name Makefile.am -print |
sed 's/\.am$/.in/' |
while read f; do touch "$f"; done
;;
autom4te)
if test -z "$run" && ($1 --version) > /dev/null 2>&1; then
# We have it, but it failed.
exit 1
fi
echo 1>&2 "\
WARNING: \`$1' is needed, and you do not seem to have it handy on your
system. You might have modified some files without having the
proper tools for further handling them.
You can get \`$1Help2man' as part of \`Autoconf' from any GNU
archive site."
file=`echo "$*" | sed -n 's/.*--output[ =]*\([^ ]*\).*/\1/p'`
test -z "$file" && file=`echo "$*" | sed -n 's/.*-o[ ]*\([^ ]*\).*/\1/p'`
if test -f "$file"; then
touch $file
else
test -z "$file" || exec >$file
echo "#! /bin/sh"
echo "# Created by GNU Automake missing as a replacement of"
echo "# $ $@"
echo "exit 0"
chmod +x $file
exit 1
fi
;;
bison|yacc)
echo 1>&2 "\
WARNING: \`$1' is missing on your system. You should only need it if
you modified a \`.y' file. You may need the \`Bison' package
in order for those modifications to take effect. You can get
\`Bison' from any GNU archive site."
rm -f y.tab.c y.tab.h
if [ $# -ne 1 ]; then
eval LASTARG="\${$#}"
case "$LASTARG" in
*.y)
SRCFILE=`echo "$LASTARG" | sed 's/y$/c/'`
if [ -f "$SRCFILE" ]; then
cp "$SRCFILE" y.tab.c
fi
SRCFILE=`echo "$LASTARG" | sed 's/y$/h/'`
if [ -f "$SRCFILE" ]; then
cp "$SRCFILE" y.tab.h
fi
;;
esac
fi
if [ ! -f y.tab.h ]; then
echo >y.tab.h
fi
if [ ! -f y.tab.c ]; then
echo 'main() { return 0; }' >y.tab.c
fi
;;
lex|flex)
echo 1>&2 "\
WARNING: \`$1' is missing on your system. You should only need it if
you modified a \`.l' file. You may need the \`Flex' package
in order for those modifications to take effect. You can get
\`Flex' from any GNU archive site."
rm -f lex.yy.c
if [ $# -ne 1 ]; then
eval LASTARG="\${$#}"
case "$LASTARG" in
*.l)
SRCFILE=`echo "$LASTARG" | sed 's/l$/c/'`
if [ -f "$SRCFILE" ]; then
cp "$SRCFILE" lex.yy.c
fi
;;
esac
fi
if [ ! -f lex.yy.c ]; then
echo 'main() { return 0; }' >lex.yy.c
fi
;;
help2man)
if test -z "$run" && ($1 --version) > /dev/null 2>&1; then
# We have it, but it failed.
exit 1
fi
echo 1>&2 "\
WARNING: \`$1' is missing on your system. You should only need it if
you modified a dependency of a manual page. You may need the
\`Help2man' package in order for those modifications to take
effect. You can get \`Help2man' from any GNU archive site."
file=`echo "$*" | sed -n 's/.*-o \([^ ]*\).*/\1/p'`
if test -z "$file"; then
file=`echo "$*" | sed -n 's/.*--output=\([^ ]*\).*/\1/p'`
fi
if [ -f "$file" ]; then
touch $file
else
test -z "$file" || exec >$file
echo ".ab help2man is required to generate this page"
exit 1
fi
;;
makeinfo)
if test -z "$run" && (makeinfo --version) > /dev/null 2>&1; then
# We have makeinfo, but it failed.
exit 1
fi
echo 1>&2 "\
WARNING: \`$1' is missing on your system. You should only need it if
you modified a \`.texi' or \`.texinfo' file, or any other file
indirectly affecting the aspect of the manual. The spurious
call might also be the consequence of using a buggy \`make' (AIX,
DU, IRIX). You might want to install the \`Texinfo' package or
the \`GNU make' package. Grab either from any GNU archive site."
file=`echo "$*" | sed -n 's/.*-o \([^ ]*\).*/\1/p'`
if test -z "$file"; then
file=`echo "$*" | sed 's/.* \([^ ]*\) *$/\1/'`
file=`sed -n '/^@setfilename/ { s/.* \([^ ]*\) *$/\1/; p; q; }' $file`
fi
touch $file
;;
tar)
shift
if test -n "$run"; then
echo 1>&2 "ERROR: \`tar' requires --run"
exit 1
fi
# We have already tried tar in the generic part.
# Look for gnutar/gtar before invocation to avoid ugly error
# messages.
if (gnutar --version > /dev/null 2>&1); then
gnutar ${1+"$@"} && exit 0
fi
if (gtar --version > /dev/null 2>&1); then
gtar ${1+"$@"} && exit 0
fi
firstarg="$1"
if shift; then
case "$firstarg" in
*o*)
firstarg=`echo "$firstarg" | sed s/o//`
tar "$firstarg" ${1+"$@"} && exit 0
;;
esac
case "$firstarg" in
*h*)
firstarg=`echo "$firstarg" | sed s/h//`
tar "$firstarg" ${1+"$@"} && exit 0
;;
esac
fi
echo 1>&2 "\
WARNING: I can't seem to be able to run \`tar' with the given arguments.
You may want to install GNU tar or Free paxutils, or check the
command line arguments."
exit 1
;;
*)
echo 1>&2 "\
WARNING: \`$1' is needed, and you do not seem to have it handy on your
system. You might have modified some files without having the
proper tools for further handling them. Check the \`README' file,
it often tells you about the needed prerequirements for installing
this package. You may also peek at any GNU archive site, in case
some other package would contain this missing \`$1' program."
exit 1
;;
esac
exit 0

File diff suppressed because it is too large Load Diff

View File

@ -1,95 +0,0 @@
.text
.set linkageArea,24
.set params,4
.set alignment,4
.set spaceToSave,linkageArea+params+alignment
.set spaceToSave8,spaceToSave+8
; Mark from machine registers that are saved by C compiler
.globl _GC_push_regs
_GC_push_regs:
; PROLOG
mflr r0 ; get return address
stw r0,8(r1) ; save return address
stwu r1,-spaceToSave(r1) ; skip over caller save area
;
mr r3,r2 ; mark from r2. Well Im not really sure
; that this is necessary or even the right
; thing to do - at least it doesnt harm...
; According to Apples docs it points to
; the direct data area, whatever that is...
bl L_GC_push_one$stub
mr r3,r13 ; mark from r13-r31
bl L_GC_push_one$stub
mr r3,r14
bl L_GC_push_one$stub
mr r3,r15
bl L_GC_push_one$stub
mr r3,r16
bl L_GC_push_one$stub
mr r3,r17
bl L_GC_push_one$stub
mr r3,r18
bl L_GC_push_one$stub
mr r3,r19
bl L_GC_push_one$stub
mr r3,r20
bl L_GC_push_one$stub
mr r3,r21
bl L_GC_push_one$stub
mr r3,r22
bl L_GC_push_one$stub
mr r3,r23
bl L_GC_push_one$stub
mr r3,r24
bl L_GC_push_one$stub
mr r3,r25
bl L_GC_push_one$stub
mr r3,r26
bl L_GC_push_one$stub
mr r3,r27
bl L_GC_push_one$stub
mr r3,r28
bl L_GC_push_one$stub
mr r3,r29
bl L_GC_push_one$stub
mr r3,r30
bl L_GC_push_one$stub
mr r3,r31
bl L_GC_push_one$stub
; EPILOG
lwz r0,spaceToSave8(r1) ; get return address back
mtlr r0 ; reset link register
addic r1,r1,spaceToSave ; restore stack pointer
blr
.data
.picsymbol_stub
L_GC_push_one$stub:
.indirect_symbol _GC_push_one
mflr r0
bcl 20,31,L0$_GC_push_one
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)
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
.non_lazy_symbol_pointer
L_GC_push_one$non_lazy_ptr:
.indirect_symbol _GC_push_one
.long 0

View File

@ -79,7 +79,7 @@ void (*GC_same_obj_print_proc) GC_PROTO((GC_PTR, GC_PTR))
return(p);
}
sz = WORDS_TO_BYTES(hhdr -> hb_sz);
if (sz > WORDS_TO_BYTES(MAXOBJSZ)) {
if (sz > MAXOBJBYTES) {
base = (ptr_t)HBLKPTR(p);
limit = base + sz;
if ((ptr_t)p >= limit) {
@ -165,7 +165,7 @@ void (*GC_is_valid_displacement_print_proc) GC_PROTO((GC_PTR)) =
pdispl = HBLKDISPL(p);
map_entry = MAP_ENTRY((hhdr -> hb_map), pdispl);
if (map_entry == OBJ_INVALID
|| sz > MAXOBJSZ && (ptr_t)p >= (ptr_t)h + sz) {
|| sz > MAXOBJBYTES && (ptr_t)p >= (ptr_t)h + sz) {
goto fail;
}
return(p);

View File

@ -27,23 +27,61 @@ signed_word GC_mem_found = 0;
/* nonzero. */
#endif /* PARALLEL_MARK */
static void report_leak(p, sz)
ptr_t p;
word sz;
/* We defer printing of leaked objects until we're done with the GC */
/* cycle, since the routine for printing objects needs to run outside */
/* the collector, e.g. without the allocation lock. */
#define MAX_LEAKED 40
ptr_t GC_leaked[MAX_LEAKED];
unsigned GC_n_leaked = 0;
GC_bool GC_have_errors = FALSE;
void GC_add_leaked(leaked)
ptr_t leaked;
{
if (HDR(p) -> hb_obj_kind == PTRFREE) {
GC_err_printf0("Leaked atomic object at ");
} else {
GC_err_printf0("Leaked composite object at ");
if (GC_n_leaked < MAX_LEAKED) {
GC_have_errors = TRUE;
GC_leaked[GC_n_leaked++] = leaked;
/* Make sure it's not reclaimed this cycle */
GC_set_mark_bit(leaked);
}
GC_print_heap_obj(p);
GC_err_printf0("\n");
}
static GC_bool printing_errors = FALSE;
/* Print all objects on the list after printing any smashed objs. */
/* Clear both lists. */
void GC_print_all_errors ()
{
unsigned i;
LOCK();
if (printing_errors) {
UNLOCK();
return;
}
printing_errors = TRUE;
UNLOCK();
if (GC_debugging_started) GC_print_all_smashed();
for (i = 0; i < GC_n_leaked; ++i) {
ptr_t p = GC_leaked[i];
if (HDR(p) -> hb_obj_kind == PTRFREE) {
GC_err_printf0("Leaked atomic object at ");
} else {
GC_err_printf0("Leaked composite object at ");
}
GC_print_heap_obj(p);
GC_err_printf0("\n");
GC_free(p);
GC_leaked[i] = 0;
}
GC_n_leaked = 0;
printing_errors = FALSE;
}
# define FOUND_FREE(hblk, word_no) \
{ \
report_leak((ptr_t)hblk + WORDS_TO_BYTES(word_no), \
HDR(hblk) -> hb_sz); \
GC_add_leaked((ptr_t)hblk + WORDS_TO_BYTES(word_no)); \
}
/*
@ -866,7 +904,7 @@ void GC_print_block_list()
* Clear *flp.
* This must be done before dropping a list of free gcj-style objects,
* since may otherwise end up with dangling "descriptor" pointers.
* It may help for other pointer-containg objects.
* It may help for other pointer-containing objects.
*/
void GC_clear_fl_links(flp)
ptr_t *flp;

View File

@ -13,9 +13,8 @@
/*
* Support code for Solaris threads. Provides functionality we wish Sun
* had provided. Relies on some information we probably shouldn't rely on.
* Modified Peter C. for Solaris Posix Threads.
* Modified by Peter C. for Solaris Posix Threads.
*/
/* Boehm, September 14, 1994 4:44 pm PDT */
# if defined(GC_SOLARIS_PTHREADS)
# include "private/gc_priv.h"

View File

@ -37,6 +37,10 @@
# include <unistd.h>
# include <errno.h>
#ifdef HANDLE_FORK
--> Not yet supported. Try porting the code from linux_threads.c.
#endif
/*
* This is the default size of the LWP arrays. If there are more LWPs
* than this when a stop-the-world GC happens, set_max_lwps will be
@ -361,7 +365,7 @@ static void restart_all_lwps()
sizeof (prgregset_t)) != 0) {
int j;
for(j = 0; j < NGREG; j++)
for(j = 0; j < NPRGREG; j++)
{
GC_printf3("%i: %x -> %x\n", j,
GC_lwp_registers[i][j],
@ -821,7 +825,7 @@ int GC_thr_suspend(thread_t target_thread)
if (result == 0) {
t = GC_lookup_thread(target_thread);
if (t == 0) ABORT("thread unknown to GC");
t -> flags |= SUSPENDED;
t -> flags |= SUSPNDED;
}
UNLOCK();
return(result);
@ -837,7 +841,7 @@ int GC_thr_continue(thread_t target_thread)
if (result == 0) {
t = GC_lookup_thread(target_thread);
if (t == 0) ABORT("thread unknown to GC");
t -> flags &= ~SUSPENDED;
t -> flags &= ~SUSPNDED;
}
UNLOCK();
return(result);
@ -923,7 +927,7 @@ GC_thr_create(void *stack_base, size_t stack_size,
my_flags |= CLIENT_OWNS_STACK;
}
if (flags & THR_DETACHED) my_flags |= DETACHED;
if (flags & THR_SUSPENDED) my_flags |= SUSPENDED;
if (flags & THR_SUSPENDED) my_flags |= SUSPNDED;
result = thr_create(stack, stack_size, start_routine,
arg, flags & ~THR_DETACHED, &my_new_thread);
if (result == 0) {

View File

@ -37,7 +37,7 @@ loop:
stx %g0,[%o3] ! *(long *)p = 0
cmp %o3,%o1
bgu,pt %xcc, loop ! if (p > limit) goto loop
add %o3,-8,%o3 ! p -= 8 (delay slot)
add %o3,-8,%o3 ! p -= 8 (delay slot)
retl
mov %o2,%sp ! Restore sp., delay slot
#else /* 32 bit SPARC */

View File

@ -43,7 +43,7 @@
# include "gc_local_alloc.h"
# endif
# include "private/gc_priv.h" /* For output, locking, MIN_WORDS, */
/* and some statistics. */
/* and some statistics. */
# include "private/gcconfig.h"
# if defined(MSWIN32) || defined(MSWINCE)
@ -68,14 +68,14 @@
# include <pthread.h>
# endif
# ifdef GC_WIN32_THREADS
# ifndef MSWINCE
# include <process.h>
# define GC_CreateThread(a,b,c,d,e,f) ((HANDLE) _beginthreadex(a,b,c,d,e,f))
# endif
# if defined(GC_WIN32_THREADS) && !defined(GC_PTHREADS)
static CRITICAL_SECTION incr_cs;
# endif
#ifdef __STDC__
# include <stdarg.h>
#endif
/* Allocation Statistics */
int stubborn_count = 0;
@ -205,40 +205,6 @@ sexpr y;
}
# endif
sexpr small_cons (x, y)
sexpr x;
sexpr y;
{
register sexpr r;
collectable_count++;
r = (sexpr) GC_MALLOC(sizeof(struct SEXPR));
if (r == 0) {
(void)GC_printf0("Out of memory\n");
exit(1);
}
r -> sexpr_car = x;
r -> sexpr_cdr = y;
return(r);
}
sexpr small_cons_uncollectable (x, y)
sexpr x;
sexpr y;
{
register sexpr r;
uncollectable_count++;
r = (sexpr) GC_MALLOC_UNCOLLECTABLE(sizeof(struct SEXPR));
if (r == 0) {
(void)GC_printf0("Out of memory\n");
exit(1);
}
r -> sexpr_car = x;
r -> sexpr_cdr = (sexpr)(~(unsigned long)y);
return(r);
}
#ifdef GC_GCJ_SUPPORT
#include "gc_mark.h"
@ -279,6 +245,93 @@ struct GC_ms_entry * fake_gcj_mark_proc(word * addr,
return(mark_stack_ptr);
}
#endif /* GC_GCJ_SUPPORT */
#ifdef THREAD_LOCAL_ALLOC
#undef GC_REDIRECT_TO_LOCAL
#include "gc_local_alloc.h"
sexpr local_cons (x, y)
sexpr x;
sexpr y;
{
register sexpr r;
register int *p;
register int my_extra = extra_count;
static int my_random = 0;
collectable_count++;
r = (sexpr) GC_LOCAL_MALLOC(sizeof(struct SEXPR) + my_extra);
# ifdef GC_GCJ_SUPPORT
if (collectable_count % 2 == 0) {
r = (sexpr) GC_LOCAL_GCJ_MALLOC(sizeof(struct SEXPR) + sizeof(GC_word) + my_extra,
&gcj_class_struct1);
r = (sexpr) ((GC_word *)r + 1);
}
# endif
if (r == 0) {
(void)GC_printf0("Out of memory\n");
exit(1);
}
for (p = (int *)r;
((char *)p) < ((char *)r) + my_extra + sizeof(struct SEXPR); p++) {
if (*p) {
(void)GC_printf1("Found nonzero at 0x%lx (local) - allocator is broken\n",
(unsigned long)p);
FAIL;
}
*p = 13;
}
r -> sexpr_car = x;
r -> sexpr_cdr = y;
my_extra++;
if ( my_extra >= 5000 || my_extra == 200 && ++my_random % 37 != 0) {
extra_count = 0;
} else {
extra_count = my_extra;
}
return(r);
}
#endif /* THREAD_LOCAL_ALLOC */
sexpr small_cons (x, y)
sexpr x;
sexpr y;
{
register sexpr r;
collectable_count++;
r = (sexpr) GC_MALLOC(sizeof(struct SEXPR));
if (r == 0) {
(void)GC_printf0("Out of memory\n");
exit(1);
}
r -> sexpr_car = x;
r -> sexpr_cdr = y;
return(r);
}
sexpr small_cons_uncollectable (x, y)
sexpr x;
sexpr y;
{
register sexpr r;
uncollectable_count++;
r = (sexpr) GC_MALLOC_UNCOLLECTABLE(sizeof(struct SEXPR));
if (r == 0) {
(void)GC_printf0("Out of memory\n");
exit(1);
}
r -> sexpr_car = x;
r -> sexpr_cdr = (sexpr)(~(unsigned long)y);
return(r);
}
#ifdef GC_GCJ_SUPPORT
sexpr gcj_cons(x, y)
sexpr x;
sexpr y;
@ -323,6 +376,9 @@ sexpr x, y;
sexpr reverse(x)
sexpr x;
{
# ifdef TEST_WITH_SYSTEM_MALLOC
malloc(100000);
# endif
return( reverse1(x, nil) );
}
@ -365,6 +421,35 @@ int low, up;
}
#endif /* GC_GCJ_SUPPORT */
#ifdef THREAD_LOCAL_ALLOC
/* Return reverse(x) concatenated with y */
sexpr local_reverse1(x, y)
sexpr x, y;
{
if (is_nil(x)) {
return(y);
} else {
return( local_reverse1(cdr(x), local_cons(car(x), y)) );
}
}
sexpr local_reverse(x)
sexpr x;
{
return( local_reverse1(x, nil) );
}
sexpr local_ints(low, up)
int low, up;
{
if (low > up) {
return(nil);
} else {
return(local_cons(local_cons(INT_TO_SEXPR(low), nil), local_ints(low+1, up)));
}
}
#endif /* THREAD_LOCAL_ALLOC */
/* To check uncollectable allocation we build lists with disguised cdr */
/* pointers, and make sure they don't go away. */
sexpr uncollectable_ints(low, up)
@ -435,25 +520,24 @@ sexpr x;
}
}
/* Try to force a to be strangely aligned */
struct {
char dummy;
sexpr aa;
} A;
#define a A.aa
/*
* A tiny list reversal test to check thread creation.
*/
#ifdef THREADS
# ifdef GC_WIN32_THREADS
unsigned __stdcall tiny_reverse_test(void * arg)
# if defined(GC_WIN32_THREADS) && !defined(CYGWIN32)
DWORD __stdcall tiny_reverse_test(void * arg)
# else
void * tiny_reverse_test(void * arg)
# endif
{
check_ints(reverse(reverse(ints(1,10))), 1, 10);
int i;
for (i = 0; i < 5; ++i) {
check_ints(reverse(reverse(ints(1,10))), 1, 10);
# ifdef THREAD_LOCAL_ALLOC
check_ints(local_reverse(local_reverse(local_ints(1,10))), 1, 10);
# endif
}
return 0;
}
@ -477,7 +561,7 @@ struct {
# elif defined(GC_WIN32_THREADS)
void fork_a_thread()
{
unsigned thread_id;
DWORD thread_id;
HANDLE h;
h = GC_CreateThread(NULL, 0, tiny_reverse_test, 0, 0, &thread_id);
if (h == (HANDLE)NULL) {
@ -506,6 +590,13 @@ struct {
#endif
/* Try to force a to be strangely aligned */
struct {
char dummy;
sexpr aa;
} A;
#define a A.aa
/*
* Repeatedly reverse lists built out of very different sized cons cells.
* Check that we didn't lose anything.
@ -563,7 +654,9 @@ void reverse_test()
h = (sexpr *)GC_REALLOC((GC_PTR)h, 2000 * sizeof(sexpr));
# ifdef GC_GCJ_SUPPORT
h[1999] = gcj_ints(1,200);
h[1999] = gcj_reverse(h[1999]);
for (i = 0; i < 51; ++i)
h[1999] = gcj_reverse(h[1999]);
/* Leave it as the reveresed list for now. */
# else
h[1999] = ints(1,200);
# endif
@ -594,6 +687,9 @@ void reverse_test()
/* 49 integers. Thus this is thread safe without locks, */
/* assuming atomic pointer assignments. */
a = reverse(reverse(a));
# ifdef THREAD_LOCAL_ALLOC
a = local_reverse(local_reverse(a));
# endif
# if !defined(AT_END) && !defined(THREADS)
/* This is not thread safe, since realloc explicitly deallocates */
if (i & 1) {
@ -621,6 +717,8 @@ void reverse_test()
b = c = 0;
}
#undef a
/*
* The rest of this builds balanced binary trees, checks that they don't
* disappear, and tests finalization.
@ -655,15 +753,17 @@ VOLATILE int dropped_something = 0;
# if defined(GC_PTHREADS)
static pthread_mutex_t incr_lock = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_lock(&incr_lock);
# endif
# ifdef GC_WIN32_THREADS
EnterCriticalSection(&incr_cs);
# else
# ifdef GC_WIN32_THREADS
EnterCriticalSection(&incr_cs);
# endif
# endif
if ((int)(GC_word)client_data != t -> level) {
(void)GC_printf0("Wrong finalization data - collector is broken\n");
FAIL;
}
finalized_count++;
t -> level = -1; /* detect duplicate finalization immediately */
# ifdef PCR
PCR_ThCrSec_ExitSys();
# endif
@ -672,9 +772,10 @@ VOLATILE int dropped_something = 0;
# endif
# if defined(GC_PTHREADS)
pthread_mutex_unlock(&incr_lock);
# endif
# ifdef GC_WIN32_THREADS
LeaveCriticalSection(&incr_cs);
# else
# ifdef GC_WIN32_THREADS
LeaveCriticalSection(&incr_cs);
# endif
# endif
}
@ -746,9 +847,10 @@ int n;
# if defined(GC_PTHREADS)
static pthread_mutex_t incr_lock = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_lock(&incr_lock);
# endif
# ifdef GC_WIN32_THREADS
EnterCriticalSection(&incr_cs);
# else
# ifdef GC_WIN32_THREADS
EnterCriticalSection(&incr_cs);
# endif
# endif
/* Losing a count here causes erroneous report of failure. */
finalizable_count++;
@ -761,9 +863,10 @@ int n;
# endif
# if defined(GC_PTHREADS)
pthread_mutex_unlock(&incr_lock);
# endif
# ifdef GC_WIN32_THREADS
LeaveCriticalSection(&incr_cs);
# else
# ifdef GC_WIN32_THREADS
LeaveCriticalSection(&incr_cs);
# endif
# endif
}
@ -1068,6 +1171,25 @@ void fail_proc1(GC_PTR x)
fail_count++;
}
static void uniq(void *p, ...) {
va_list a;
void *q[100];
int n = 0, i, j;
q[n++] = p;
va_start(a,p);
for (;(q[n] = va_arg(a,void *));n++) ;
va_end(a);
for (i=0; i<n; i++)
for (j=0; j<i; j++)
if (q[i] == q[j]) {
GC_printf0(
"Apparently failed to mark form some function arguments.\n"
"Perhaps GC_push_regs was configured incorrectly?\n"
);
FAIL;
}
}
#endif /* __STDC__ */
#ifdef THREADS
@ -1148,6 +1270,19 @@ void run_one_test()
"GC_is_valid_displacement produced incorrect result\n");
FAIL;
}
# if defined(__STDC__) && !defined(MSWIN32) && !defined(MSWINCE)
/* Harder to test under Windows without a gc.h declaration. */
{
size_t i;
extern void *GC_memalign();
GC_malloc(17);
for (i = sizeof(GC_word); i < 512; i *= 2) {
GC_word result = (GC_word) GC_memalign(i, 17);
if (result % i != 0 || result == 0 || *(int *)result != 0) FAIL;
}
}
# endif
# ifndef ALL_INTERIOR_POINTERS
# if defined(RS6000) || defined(POWERPC)
if (!TEST_FAIL_COUNT(1)) {
@ -1167,6 +1302,21 @@ void run_one_test()
# ifdef GC_GCJ_SUPPORT
GC_REGISTER_DISPLACEMENT(sizeof(struct fake_vtable *));
GC_init_gcj_malloc(0, (void *)fake_gcj_mark_proc);
# endif
/* Make sure that fn arguments are visible to the collector. */
# ifdef __STDC__
uniq(
GC_malloc(12), GC_malloc(12), GC_malloc(12),
(GC_gcollect(),GC_malloc(12)),
GC_malloc(12), GC_malloc(12), GC_malloc(12),
(GC_gcollect(),GC_malloc(12)),
GC_malloc(12), GC_malloc(12), GC_malloc(12),
(GC_gcollect(),GC_malloc(12)),
GC_malloc(12), GC_malloc(12), GC_malloc(12),
(GC_gcollect(),GC_malloc(12)),
GC_malloc(12), GC_malloc(12), GC_malloc(12),
(GC_gcollect(),GC_malloc(12)),
(void *)0);
# endif
/* Repeated list reversal test. */
reverse_test();
@ -1183,6 +1333,15 @@ void run_one_test()
LOCK();
n_tests++;
UNLOCK();
# if defined(THREADS) && defined(HANDLE_FORK)
if (fork() == 0) {
GC_gcollect();
tiny_reverse_test(0);
GC_gcollect();
GC_printf0("Finished a child process\n");
exit(0);
}
# endif
/* GC_printf1("Finished %x\n", pthread_self()); */
}
@ -1202,7 +1361,7 @@ void check_heap_stats()
}
# else
if (sizeof(char *) > 4) {
max_heap_sz = 15000000;
max_heap_sz = 19000000;
} else {
max_heap_sz = 11000000;
}
@ -1212,7 +1371,7 @@ void check_heap_stats()
# ifdef SAVE_CALL_CHAIN
max_heap_sz *= 3;
# ifdef SAVE_CALL_COUNT
max_heap_sz *= SAVE_CALL_COUNT/4;
max_heap_sz += max_heap_sz * SAVE_CALL_COUNT/4;
# endif
# endif
# endif
@ -1327,6 +1486,10 @@ void SetMinimumStack(long minSize)
# endif
n_tests = 0;
#if defined(__APPLE__) && defined(__MACH__)
GC_INIT();
#endif
# if defined(DJGPP)
/* No good way to determine stack base from library; do it */
/* manually on this platform. */
@ -1340,13 +1503,18 @@ void SetMinimumStack(long minSize)
# endif
GC_INIT(); /* Only needed if gc is dynamic library. */
(void) GC_set_warn_proc(warn_proc);
# if (defined(MPROTECT_VDB) || defined(PROC_VDB)) && !defined(MAKE_BACK_GRAPH)
# if (defined(MPROTECT_VDB) || defined(PROC_VDB)) \
&& !defined(MAKE_BACK_GRAPH)
GC_enable_incremental();
(void) GC_printf0("Switched to incremental mode\n");
# if defined(MPROTECT_VDB)
(void)GC_printf0("Emulating dirty bits with mprotect/signals\n");
# else
# ifdef PROC_VDB
(void)GC_printf0("Reading dirty bits from /proc\n");
# else
(void)GC_printf0("Using DEFAULT_VDB dirty bit implementation\n");
# endif
# endif
# endif
run_one_test();
@ -1378,9 +1546,9 @@ void SetMinimumStack(long minSize)
}
# endif
#ifdef GC_WIN32_THREADS
#if defined(GC_WIN32_THREADS) && !defined(CYGWIN32)
unsigned __stdcall thr_run_one_test(void *arg)
DWORD __stdcall thr_run_one_test(void *arg)
{
run_one_test();
return 0;
@ -1412,7 +1580,7 @@ LRESULT CALLBACK window_proc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
return ret;
}
unsigned __stdcall thr_window(void *arg)
DWORD __stdcall thr_window(void *arg)
{
WNDCLASS win_class = {
CS_NOCLOSE,
@ -1474,10 +1642,11 @@ int APIENTRY WinMain(HINSTANCE instance, HINSTANCE prev, LPSTR cmd, int n)
# ifdef MSWINCE
HANDLE win_thr_h;
# endif
unsigned thread_id;
DWORD thread_id;
# if 0
GC_enable_incremental();
# endif
GC_init();
InitializeCriticalSection(&incr_cs);
(void) GC_set_warn_proc(warn_proc);
# ifdef MSWINCE
@ -1625,15 +1794,30 @@ main()
(void)GC_printf0("pthread_default_stacksize_np failed.\n");
}
# endif /* GC_HPUX_THREADS */
# if defined(__APPLE__) && defined(__MACH__)
GC_INIT();
# endif
pthread_attr_init(&attr);
# if defined(GC_IRIX_THREADS) || defined(GC_FREEBSD_THREADS)
# if defined(GC_IRIX_THREADS) || defined(GC_FREEBSD_THREADS) \
|| defined(GC_DARWIN_THREADS) || defined(GC_AIX_THREADS)
pthread_attr_setstacksize(&attr, 1000000);
# endif
n_tests = 0;
# if defined(MPROTECT_VDB) && !defined(PARALLEL_MARK) &&!defined(REDIRECT_MALLOC) && !defined(MAKE_BACK_GRAPH)
# if (defined(MPROTECT_VDB)) \
&& !defined(PARALLEL_MARK) &&!defined(REDIRECT_MALLOC) \
&& !defined(MAKE_BACK_GRAPH)
GC_enable_incremental();
(void) GC_printf0("Switched to incremental mode\n");
(void) GC_printf0("Emulating dirty bits with mprotect/signals\n");
# if defined(MPROTECT_VDB)
(void)GC_printf0("Emulating dirty bits with mprotect/signals\n");
# else
# ifdef PROC_VDB
(void)GC_printf0("Reading dirty bits from /proc\n");
# else
(void)GC_printf0("Using DEFAULT_VDB dirty bit implementation\n");
# endif
# endif
# endif
(void) GC_set_warn_proc(warn_proc);
if ((code = pthread_key_create(&fl_key, 0)) != 0) {

View File

@ -28,7 +28,10 @@ few minutes to complete.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifdef __GNUC__
#define USE_STD_ALLOCATOR
#ifdef USE_STD_ALLOCATOR
# include "gc_allocator.h"
#elif __GNUC__
# include "new_gc_alloc.h"
#else
# include "gc_alloc.h"
@ -189,25 +192,32 @@ int APIENTRY WinMain(
# endif
#endif
GC_init();
# if defined(MACOS) // MacOS
char* argv_[] = {"test_cpp", "10"}; // doesn't
argv = argv_; // have a
argc = sizeof(argv_)/sizeof(argv_[0]); // commandline
# endif
int i, iters, n;
# if !defined(MACOS)
# ifdef USE_STD_ALLOCATOR
int *x = gc_allocator<int>().allocate(1);
int **xptr = traceable_allocator<int *>().allocate(1);
# else
# ifdef __GNUC__
int *x = (int *)gc_alloc::allocate(sizeof(int));
int *x = (int *)gc_alloc::allocate(sizeof(int));
# else
int *x = (int *)alloc::allocate(sizeof(int));
int *x = (int *)alloc::allocate(sizeof(int));
# endif
*x = 29;
x -= 3;
# endif
*x = 29;
# ifdef USE_STD_ALLOCATOR
*xptr = x;
x = 0;
# endif
if (argc != 2 || (0 >= (n = atoi( argv[ 1 ] )))) {
GC_printf0( "usage: test_cpp number-of-iterations\n" );
exit( 1 );}
GC_printf0( "usage: test_cpp number-of-iterations\nAssuming 10 iters\n" );
n = 10;}
for (iters = 1; iters <= n; iters++) {
GC_printf1( "Starting iteration %d\n", iters );
@ -268,9 +278,10 @@ int APIENTRY WinMain(
D::Test();
F::Test();}
# if !defined(__GNUC__) && !defined(MACOS)
my_assert (29 == x[3]);
# ifdef USE_STD_ALLOCATOR
x = *xptr;
# endif
my_assert (29 == x[0]);
GC_printf0( "The test appears to have succeeded.\n" );
return( 0 );}

View File

@ -4,13 +4,14 @@
int main()
{
# if defined(GC_USE_LD_WRAP)
printf("-Wl,--wrap -Wl,read -Wl,--wrap -Wl,dlopen "
printf("-Wl,--wrap -Wl,dlopen "
"-Wl,--wrap -Wl,pthread_create -Wl,--wrap -Wl,pthread_join "
"-Wl,--wrap -Wl,pthread_detach "
"-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_FREEBSD_THREADS) || defined(GC_SOLARIS_PTHREADS) \
|| defined(GC_DARWIN_THREADS) || defined(GC_AIX_THREADS)
printf("-lpthread\n");
# endif
# if defined(GC_HPUX_THREADS) || defined(GC_OSF1_THREADS)
@ -18,6 +19,17 @@ int main()
# endif
# if defined(GC_SOLARIS_THREADS) && !defined(GC_SOLARIS_PTHREADS)
printf("-lthread -ldl\n");
# endif
# if defined(GC_WIN32_THREADS) && defined(CYGWIN32)
printf("-lpthread\n");
# endif
# if defined(GC_OSF1_THREADS)
printf("-pthread -lrt"); /* DOB: must be -pthread, not -lpthread */
# endif
/* You need GCC 3.0.3 to build this one! */
/* DG/UX native gcc doesnt know what "-pthread" is */
# if defined(GC_DGUX386_THREADS)
printf("-ldl -pthread\n");
# endif
return 0;
}

View File

@ -437,6 +437,7 @@ void GC_init_explicit_typing()
for (; bm != 0; bm >>= 1, current_p++) {
if (bm & 1) {
current = *current_p;
FIXUP_POINTER(current);
if ((ptr_t)current >= least_ha && (ptr_t)current <= greatest_ha) {
PUSH_CONTENTS((ptr_t)current, mark_stack_ptr,
mark_stack_limit, current_p, exit1);
@ -674,9 +675,9 @@ DCL_LOCK_STATE;
if( !FASTLOCK_SUCCEEDED() || (op = *opp) == 0 ) {
FASTUNLOCK();
op = (ptr_t)GENERAL_MALLOC((word)lb, GC_explicit_kind);
if (0 == op) return(0);
if (0 == op) return 0;
# ifdef MERGE_SIZES
lw = GC_size_map[lb]; /* May have been uninitialized. */
lw = GC_size_map[lb]; /* May have been uninitialized. */
# endif
} else {
*opp = obj_link(op);
@ -720,7 +721,7 @@ DCL_LOCK_STATE;
FASTUNLOCK();
op = (ptr_t)GENERAL_MALLOC_IOP(lb, GC_explicit_kind);
# ifdef MERGE_SIZES
lw = GC_size_map[lb]; /* May have been uninitialized. */
lw = GC_size_map[lb]; /* May have been uninitialized. */
# endif
} else {
*opp = obj_link(op);

View File

@ -1,11 +1,30 @@
#define GC_VERSION_MAJOR 6
#define GC_VERSION_MINOR 1
#define GC_ALPHA_VERSION 3
/* The version here should match that in configure/configure.in */
/* 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_ALPHA_VERSION 1
#ifndef GC_NOT_ALPHA
# define GC_NOT_ALPHA 0xff
#endif
#if defined(GC_VERSION_MAJOR)
# if GC_TMP_VERSION_MAJOR != GC_VERSION_MAJOR || \
GC_TMP_VERSION_MINOR != GC_VERSION_MINOR || \
defined(GC_ALPHA_VERSION) != (GC_TMP_ALPHA_VERSION != GC_NOT_ALPHA) || \
defined(GC_ALPHA_VERSION) && GC_TMP_ALPHA_VERSION != GC_ALPHA_VERSION
# error Inconsistent version info. Check version.h and configure.in.
# endif
#else
# define GC_VERSION_MAJOR GC_TMP_VERSION_MAJOR
# define GC_VERSION_MINOR GC_TMP_VERSION_MINOR
# define GC_ALPHA_VERSION GC_TMP_ALPHA_VERSION
#endif
#ifndef GC_NO_VERSION_VAR
unsigned GC_version = ((GC_VERSION_MAJOR << 16) | (GC_VERSION_MINOR << 8) | GC_ALPHA_VERSION);
unsigned GC_version = ((GC_VERSION_MAJOR << 16) | (GC_VERSION_MINOR << 8) | GC_TMP_ALPHA_VERSION);
#endif /* GC_NO_VERSION_VAR */

View File

@ -1,13 +1,28 @@
#if defined(GC_WIN32_THREADS)
#if defined(GC_WIN32_THREADS)
#include "private/gc_priv.h"
#if 0
#define STRICT
#include <windows.h>
#ifdef CYGWIN32
# include <errno.h>
/* Cygwin-specific forward decls */
# undef pthread_create
# undef pthread_sigmask
# undef pthread_join
# undef dlopen
# define DEBUG_CYGWIN_THREADS 0
GC_bool GC_thr_initialized = FALSE;
void * GC_start_routine(void * arg);
void GC_thread_exit_proc(void *arg);
#endif
#define MAX_THREADS 64
#ifndef MAX_THREADS
# define MAX_THREADS 64
#endif
struct thread_entry {
LONG in_use;
@ -18,6 +33,12 @@ struct thread_entry {
/* !in_use ==> stack == 0 */
CONTEXT context;
GC_bool suspended;
# ifdef CYGWIN32
void *status; /* hold exit value until join in case it's a pointer */
pthread_t pthread_id;
# endif
};
volatile GC_bool GC_please_stop = FALSE;
@ -29,6 +50,12 @@ void GC_push_thread_structures GC_PROTO((void))
/* Unlike the other threads implementations, the thread table here */
/* contains no pointers to the collectable heap. Thus we have */
/* no private structures we need to preserve. */
# ifdef CYGWIN32
{ int i; /* pthreads may keep a pointer in the thread exit value */
for (i = 0; i < MAX_THREADS; i++)
if (thread_table[i].in_use) GC_push_all((ptr_t)&(thread_table[i].status),(ptr_t)(&(thread_table[i].status)+1));
}
# endif
}
void GC_stop_world()
@ -36,6 +63,10 @@ void GC_stop_world()
DWORD thread_id = GetCurrentThreadId();
int i;
#ifdef CYGWIN32
if (!GC_thr_initialized) ABORT("GC_stop_world() called before GC_thr_init()");
#endif
GC_please_stop = TRUE;
for (i = 0; i < MAX_THREADS; i++)
if (thread_table[i].stack != 0
@ -53,11 +84,15 @@ void GC_stop_world()
DWORD exitCode;
if (GetExitCodeThread(thread_table[i].handle,&exitCode) &&
exitCode != STILL_ACTIVE) {
thread_table[i].stack = 0;
thread_table[i].stack = 0; /* prevent stack from being pushed */
# ifndef CYGWIN32
/* this breaks pthread_join on Cygwin, which is guaranteed to */
/* only see user pthreads */
thread_table[i].in_use = FALSE;
CloseHandle(thread_table[i].handle);
BZERO((void *)(&thread_table[i].context), sizeof(CONTEXT));
continue;
# endif
continue;
}
if (SuspendThread(thread_table[i].handle) == (DWORD)-1)
ABORT("SuspendThread failed");
@ -335,9 +370,13 @@ void GC_get_next_stack(char *start, char **lo, char **hi)
if (*lo < start) *lo = start;
}
#if !defined(MSWINCE) && !(defined(__MINGW32__) && !defined(_DLL))
#if !defined(CYGWIN32)
HANDLE WINAPI GC_CreateThread(
#if !defined(MSWINCE) && defined(GC_DLL)
/* We register threads from DllMain */
GC_API HANDLE GC_CreateThread(
LPSECURITY_ATTRIBUTES lpThreadAttributes,
DWORD dwStackSize, LPTHREAD_START_ROUTINE lpStartAddress,
LPVOID lpParameter, DWORD dwCreationFlags, LPDWORD lpThreadId )
@ -346,7 +385,10 @@ HANDLE WINAPI GC_CreateThread(
lpParameter, dwCreationFlags, lpThreadId);
}
#else /* !defined(MSWINCE) && !(defined(__MINGW32__) && !defined(_DLL)) */
#else /* defined(MSWINCE) || !defined(GC_DLL)) */
/* We have no DllMain to take care of new threads. Thus we */
/* must properly intercept thread creation. */
typedef struct {
HANDLE child_ready_h, parent_ready_h;
@ -400,7 +442,17 @@ HANDLE WINAPI GC_CreateThread(
/* fill in ID and handle; tell child this is done */
thread_table[i].id = *lpThreadId;
thread_table[i].handle = thread_h;
if (!DuplicateHandle(GetCurrentProcess(),
thread_h,
GetCurrentProcess(),
&thread_table[i].handle,
0,
0,
DUPLICATE_SAME_ACCESS)) {
DWORD last_error = GetLastError();
GC_printf1("Last error code: %lx\n", last_error);
ABORT("DuplicateHandle failed");
}
SetEvent (parent_ready_h);
/* wait for child to fill in stack and copy args */
@ -470,7 +522,9 @@ static DWORD WINAPI thread_start(LPVOID arg)
return ret;
}
#endif /* !defined(MSWINCE) && !(defined(__MINGW32__) && !defined(_DLL)) */
#endif /* !defined(MSWINCE) && !(defined(__MINGW32__) && !defined(_DLL)) */
#endif /* !CYGWIN32 */
#ifdef MSWINCE
@ -527,13 +581,255 @@ DWORD WINAPI main_thread_start(LPVOID arg)
LONG WINAPI GC_write_fault_handler(struct _EXCEPTION_POINTERS *exc_info);
#ifdef GC_DLL
/* threadAttach/threadDetach routines used by both CYGWIN and DLL
* implementation, since both recieve explicit notification on thread
* creation/destruction.
*/
static void threadAttach() {
int i;
/* It appears to be unsafe to acquire a lock here, since this */
/* code is apparently not preeemptible on some systems. */
/* (This is based on complaints, not on Microsoft's official */
/* documentation, which says this should perform "only simple */
/* inititalization tasks".) */
/* Hence we make do with nonblocking synchronization. */
/* The following should be a noop according to the win32 */
/* documentation. There is empirical evidence that it */
/* isn't. - HB */
# if defined(MPROTECT_VDB)
if (GC_incremental) SetUnhandledExceptionFilter(GC_write_fault_handler);
# endif
/* cast away volatile qualifier */
for (i = 0; InterlockedExchange((LONG*)&thread_table[i].in_use,1) != 0; i++) {
/* Compare-and-swap would make this cleaner, but that's not */
/* supported before Windows 98 and NT 4.0. In Windows 2000, */
/* InterlockedExchange is supposed to be replaced by */
/* InterlockedExchangePointer, but that's not really what I */
/* want here. */
if (i == MAX_THREADS - 1)
ABORT("too many threads");
}
thread_table[i].id = GetCurrentThreadId();
# ifdef CYGWIN32
thread_table[i].pthread_id = pthread_self();
# endif
if (!DuplicateHandle(GetCurrentProcess(),
GetCurrentThread(),
GetCurrentProcess(),
(HANDLE*)&thread_table[i].handle,
0,
0,
DUPLICATE_SAME_ACCESS)) {
DWORD last_error = GetLastError();
GC_printf1("Last error code: %lx\n", last_error);
ABORT("DuplicateHandle failed");
}
thread_table[i].stack = GC_get_stack_base();
if (thread_table[i].stack == NULL)
ABORT("Failed to find stack base in threadAttach");
/* If this thread is being created while we are trying to stop */
/* the world, wait here. Hopefully this can't happen on any */
/* systems that don't allow us to block here. */
while (GC_please_stop) Sleep(20);
}
static void threadDetach(DWORD thread_id) {
int i;
LOCK();
for (i = 0;
i < MAX_THREADS &&
(!thread_table[i].in_use || thread_table[i].id != thread_id);
i++) {}
if (i >= MAX_THREADS ) {
WARN("thread %ld not found on detach", (GC_word)thread_id);
} else {
thread_table[i].stack = 0;
thread_table[i].in_use = FALSE;
CloseHandle(thread_table[i].handle);
/* cast away volatile qualifier */
BZERO((void *)&thread_table[i].context, sizeof(CONTEXT));
}
UNLOCK();
}
#ifdef CYGWIN32
/* Called by GC_init() - we hold the allocation lock. */
void GC_thr_init() {
if (GC_thr_initialized) return;
GC_thr_initialized = TRUE;
#if 0
/* this might already be handled in GC_init... */
InitializeCriticalSection(&GC_allocate_ml);
#endif
/* Add the initial thread, so we can stop it. */
threadAttach();
}
struct start_info {
void *(*start_routine)(void *);
void *arg;
};
int GC_pthread_join(pthread_t pthread_id, void **retval) {
int result;
int i;
# if DEBUG_CYGWIN_THREADS
GC_printf3("thread 0x%x(0x%x) is joining thread 0x%x.\n",(int)pthread_self(),
GetCurrentThreadId(), (int)pthread_id);
# endif
/* Can't do any table lookups here, because thread being joined
might not have registered itself yet */
result = pthread_join(pthread_id, retval);
LOCK();
for (i = 0; !thread_table[i].in_use || thread_table[i].pthread_id != pthread_id;
i++) {
if (i == MAX_THREADS - 1) {
GC_printf1("Failed to find thread 0x%x in pthread_join()\n", pthread_id);
ABORT("thread not found on detach");
}
}
UNLOCK();
threadDetach(thread_table[i].id);
# if DEBUG_CYGWIN_THREADS
GC_printf3("thread 0x%x(0x%x) completed join with thread 0x%x.\n",
(int)pthread_self(), GetCurrentThreadId(), (int)pthread_id);
# endif
return result;
}
/* Cygwin-pthreads calls CreateThread internally, but it's not
* easily interceptible by us..
* so intercept pthread_create instead
*/
int
GC_pthread_create(pthread_t *new_thread,
const pthread_attr_t *attr,
void *(*start_routine)(void *), void *arg) {
int result;
struct start_info * si;
if (!GC_is_initialized) GC_init();
/* make sure GC is initialized (i.e. main thread is attached) */
/* This is otherwise saved only in an area mmapped by the thread */
/* library, which isn't visible to the collector. */
si = GC_malloc_uncollectable(sizeof(struct start_info));
if (0 == si) return(EAGAIN);
si -> start_routine = start_routine;
si -> arg = arg;
# if DEBUG_CYGWIN_THREADS
GC_printf2("About to create a thread from 0x%x(0x%x)\n",(int)pthread_self(),
GetCurrentThreadId);
# endif
result = pthread_create(new_thread, attr, GC_start_routine, si);
if (result) { /* failure */
GC_free(si);
}
return(result);
}
void * GC_start_routine(void * arg)
{
struct start_info * si = arg;
void * result;
void *(*start)(void *);
void *start_arg;
pthread_t pthread_id;
int i;
# if DEBUG_CYGWIN_THREADS
GC_printf2("thread 0x%x(0x%x) starting...\n",(int)pthread_self(),
GetCurrentThreadId());
# endif
/* 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. */
threadAttach();
UNLOCK();
start = si -> start_routine;
start_arg = si -> arg;
pthread_id = pthread_self();
GC_free(si); /* was allocated uncollectable */
pthread_cleanup_push(GC_thread_exit_proc, pthread_id);
result = (*start)(start_arg);
pthread_cleanup_pop(0);
# if DEBUG_CYGWIN_THREADS
GC_printf2("thread 0x%x(0x%x) returned from start routine.\n",
(int)pthread_self(),GetCurrentThreadId());
# endif
LOCK();
for (i = 0; thread_table[i].pthread_id != pthread_id; i++) {
if (i == MAX_THREADS - 1)
ABORT("thread not found on exit");
}
thread_table[i].status = result;
UNLOCK();
return(result);
}
void GC_thread_exit_proc(void *arg)
{
pthread_t pthread_id = (pthread_t)arg;
int i;
# if DEBUG_CYGWIN_THREADS
GC_printf2("thread 0x%x(0x%x) called pthread_exit().\n",
(int)pthread_self(),GetCurrentThreadId());
# endif
LOCK();
for (i = 0; thread_table[i].pthread_id != pthread_id; i++) {
if (i == MAX_THREADS - 1)
ABORT("thread not found on exit");
}
UNLOCK();
#if 0
/* TODO: we need a way to get the exit value after a pthread_exit so we can stash it safely away */
thread_table[i].status = ???
#endif
}
/* nothing required here... */
int GC_pthread_sigmask(int how, const sigset_t *set, sigset_t *oset) {
return pthread_sigmask(how, set, oset);
}
int GC_pthread_detach(pthread_t thread) {
return pthread_detach(thread);
}
#else /* !CYGWIN32 */
/*
* This isn't generally safe, since DllMain is not premptible.
* If another thread holds the lock while this runs we're in trouble.
* We avoid acquiring locks here, since this doesn't seem to be preemptable.
* Pontus Rydin suggests wrapping the thread start routine instead.
*/
#ifdef GC_DLL
BOOL WINAPI DllMain(HINSTANCE inst, ULONG reason, LPVOID reserved)
{
switch (reason) {
@ -542,75 +838,13 @@ BOOL WINAPI DllMain(HINSTANCE inst, ULONG reason, LPVOID reserved)
GC_init(); /* Force initialization before thread attach. */
/* fall through */
case DLL_THREAD_ATTACH:
{
int i;
/* It appears to be unsafe to acquire a lock here, since this */
/* code is apparently not preeemptible on some systems. */
/* (This is based on complaints, not on Microsoft's official */
/* documentation, which says this should perform "only simple */
/* inititalization tasks".) */
/* Hence we make do with nonblocking synchronization. */
/* The following should be a noop according to the win32 */
/* documentation. There is empirical evidence that it */
/* isn't. - HB */
# ifdef MPROTECT_VDB
if (GC_incremental) SetUnhandledExceptionFilter(GC_write_fault_handler);
# endif
for (i = 0;
/* cast away volatile qualifier */
InterlockedExchange((LPLONG) &thread_table[i].in_use, 1) != 0;
i++) {
/* Compare-and-swap would make this cleaner, but that's not */
/* supported before Windows 98 and NT 4.0. In Windows 2000, */
/* InterlockedExchange is supposed to be replaced by */
/* InterlockedExchangePointer, but that's not really what I */
/* want here. */
if (i == MAX_THREADS - 1)
ABORT("too many threads");
}
thread_table[i].id = GetCurrentThreadId();
if (!DuplicateHandle(GetCurrentProcess(),
GetCurrentThread(),
GetCurrentProcess(),
/* cast away volatile qualifier */
(HANDLE *) &thread_table[i].handle,
0,
0,
DUPLICATE_SAME_ACCESS)) {
DWORD last_error = GetLastError();
GC_printf1("Last error code: %lx\n", last_error);
ABORT("DuplicateHandle failed");
}
thread_table[i].stack = GC_get_stack_base();
/* If this thread is being created while we are trying to stop */
/* the world, wait here. Hopefully this can't happen on any */
/* systems that don't allow us to block here. */
while (GC_please_stop) Sleep(20);
}
threadAttach();
break;
case DLL_THREAD_DETACH:
{
int i;
DWORD thread_id = GetCurrentThreadId();
LOCK();
for (i = 0;
i < MAX_THREADS &&
(thread_table[i].stack == 0 || thread_table[i].id != thread_id);
i++) {}
if (i >= MAX_THREADS) {
WARN("thread %ld not found on detach", (GC_word)thread_id);
} else {
thread_table[i].stack = 0;
thread_table[i].in_use = FALSE;
CloseHandle(thread_table[i].handle);
/* cast away volatile qualifier */
BZERO((void *) &thread_table[i].context, sizeof(CONTEXT));
}
UNLOCK();
}
threadDetach(GetCurrentThreadId());
break;
case DLL_PROCESS_DETACH:
{
int i;
@ -636,8 +870,8 @@ BOOL WINAPI DllMain(HINSTANCE inst, ULONG reason, LPVOID reserved)
}
return TRUE;
}
# endif /* GC_DLL */
#endif /* GC_DLL */
#endif /* !CYGWIN32 */
# endif /* !MSWINCE */