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:
parent
1cb1de7ead
commit
30c3de1ffb
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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 $<
|
||||
|
|
|
@ -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. */
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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
|
File diff suppressed because it is too large
Load Diff
|
@ -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"
|
||||
;;
|
||||
*)
|
||||
;;
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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
|
||||
|
|
@ -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:
|
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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.
|
||||
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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.
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 */
|
||||
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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 */
|
||||
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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();}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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 */
|
||||
|
||||
|
|
|
@ -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 */
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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; \
|
||||
}
|
||||
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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( \
|
||||
|
|
|
@ -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. */
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
@ -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");
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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. */
|
||||
|
|
218
boehm-gc/mark.c
218
boehm-gc/mark.c
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
||||
/*
|
||||
|
|
|
@ -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
|
||||
|
246
boehm-gc/misc.c
246
boehm-gc/misc.c
|
@ -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 */
|
||||
|
|
336
boehm-gc/missing
336
boehm-gc/missing
|
@ -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
|
1472
boehm-gc/os_dep.c
1472
boehm-gc/os_dep.c
File diff suppressed because it is too large
Load Diff
|
@ -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
|
||||
|
||||
|
||||
|
||||
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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 );}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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 */
|
||||
|
||||
|
|
Loading…
Reference in New Issue