mirror of git://gcc.gnu.org/git/gcc.git
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,20 +1,22 @@
|
||||||
# Makefile for Borland C++ 4.5 on NT
|
# Makefile for Borland C++ 5.5 on NT
|
||||||
# For Borland 5.0, replace bc45 by bc5.
|
|
||||||
# If you have the Borland assembler, remove "-DUSE_GENERIC"
|
# If you have the Borland assembler, remove "-DUSE_GENERIC"
|
||||||
#
|
#
|
||||||
bc= c:\bc45
|
bc= c:\Borland\BCC55
|
||||||
bcbin= $(bc)\bin
|
bcbin= $(bc)\bin
|
||||||
bclib= $(bc)\lib
|
bclib= $(bc)\lib
|
||||||
bcinclude= $(bc)\include
|
bcinclude= $(bc)\include
|
||||||
|
|
||||||
|
gcinclude1 = $(bc)\gc6.2\include
|
||||||
|
gcinclude2 = $(bc)\gc6.2\cord
|
||||||
|
|
||||||
cc= $(bcbin)\bcc32
|
cc= $(bcbin)\bcc32
|
||||||
rc= $(bcbin)\brc32
|
rc= $(bcbin)\brc32
|
||||||
lib= $(bcbin)\tlib
|
lib= $(bcbin)\tlib
|
||||||
link= $(bcbin)\tlink32
|
link= $(bcbin)\ilink32
|
||||||
cflags= -R -v -vi -H -H=gc.csm -I$(bcinclude);cord -L$(bclib) \
|
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
|
-w-pro -w-aus -w-par -w-ccc -w-rch -a4 -D__STDC__=0
|
||||||
#defines= -DSILENT
|
#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:
|
.c.obj:
|
||||||
$(cc) @&&|
|
$(cc) @&&|
|
||||||
|
@ -39,11 +41,11 @@ OBJS= $(XXXOBJS:XXX=)
|
||||||
|
|
||||||
all: gctest.exe cord\de.exe test_cpp.exe
|
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)
|
gc.lib: $(OBJS)
|
||||||
-del gc.lib
|
del gc.lib
|
||||||
tlib $* @&&|
|
$(lib) $* @&&|
|
||||||
$(XXXOBJS:XXX=+)
|
$(XXXOBJS:XXX=+)
|
||||||
|
|
|
|
||||||
|
|
||||||
|
@ -52,7 +54,7 @@ gctest.exe: tests\test.obj gc.lib
|
||||||
$(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_cmds.h
|
||||||
|
|
||||||
cord\de.exe: cord\cordbscs.obj cord\cordxtra.obj cord\de.obj cord\de_win.obj \
|
cord\de.exe: cord\cordbscs.obj cord\cordxtra.obj cord\de.obj cord\de_win.obj \
|
||||||
|
@ -63,7 +65,7 @@ cord\de.exe: cord\cordbscs.obj cord\cordxtra.obj cord\de.obj cord\de_win.obj \
|
||||||
|
|
|
|
||||||
$(rc) cord\de_win.res cord\de.exe
|
$(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
|
gc_cpp.cpp: gc_cpp.cc
|
||||||
copy gc_cpp.cc gc_cpp.cpp
|
copy gc_cpp.cc gc_cpp.cpp
|
||||||
|
@ -71,7 +73,7 @@ gc_cpp.cpp: gc_cpp.cc
|
||||||
test_cpp.cpp: tests\test_cpp.cc
|
test_cpp.cpp: tests\test_cpp.cc
|
||||||
copy tests\test_cpp.cc test_cpp.cpp
|
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) @&&|
|
$(cc) @&&|
|
||||||
$(cflags) -W -e$* test_cpp.obj gc.lib
|
$(cflags) -W -e$* test_cpp.obj gc.lib
|
||||||
|
|
|
|
||||||
|
@ -79,4 +81,8 @@ test_cpp.exe: test_cpp.obj gc_cpp.h gc.h gc.lib
|
||||||
scratch:
|
scratch:
|
||||||
-del *.obj *.res *.exe *.csm cord\*.obj cord\*.res cord\*.exe cord\*.csm
|
-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>
|
2003-07-25 Roger Sayle <roger@eyesopen.com>
|
||||||
|
|
||||||
* configure.host: Only use +ESdbgasm when using the HPUX native
|
* configure.host: Only use +ESdbgasm when using the HPUX native
|
||||||
|
|
|
@ -74,7 +74,7 @@
|
||||||
// implementations, and it sometimes has a significant performance
|
// implementations, and it sometimes has a significant performance
|
||||||
// impact. However, it is dangerous for many not-quite-ANSI C
|
// impact. However, it is dangerous for many not-quite-ANSI C
|
||||||
// programs that call things like printf in asynchronous signal handlers.
|
// 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.
|
// new syntax "operator new[]" for allocating and deleting arrays.
|
||||||
// See gc_cpp.h for details. No effect on the C part of the collector.
|
// See gc_cpp.h for details. No effect on the C part of the collector.
|
||||||
// This is defined implicitly in a few environments.
|
// This is defined implicitly in a few environments.
|
||||||
|
|
|
@ -72,7 +72,7 @@
|
||||||
// implementations, and it sometimes has a significant performance
|
// implementations, and it sometimes has a significant performance
|
||||||
// impact. However, it is dangerous for many not-quite-ANSI C
|
// impact. However, it is dangerous for many not-quite-ANSI C
|
||||||
// programs that call things like printf in asynchronous signal handlers.
|
// 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.
|
// new syntax "operator new[]" for allocating and deleting arrays.
|
||||||
// See gc_cpp.h for details. No effect on the C part of the collector.
|
// See gc_cpp.h for details. No effect on the C part of the collector.
|
||||||
// This is defined implicitly in a few environments.
|
// This is defined implicitly in a few environments.
|
||||||
|
|
|
@ -18,15 +18,23 @@ MULTICLEAN = true
|
||||||
|
|
||||||
noinst_LTLIBRARIES = libgcjgc.la libgcjgc_convenience.la
|
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 \
|
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 \
|
dyn_load.c finalize.c gc_dlopen.c gcj_mlc.c headers.c aix_irix_threads.c \
|
||||||
linux_threads.c malloc.c mallocx.c mark.c mark_rts.c misc.c new_hblk.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 \
|
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 \
|
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 \
|
EXTRA_GC_SOURCES = alpha_mach_dep.S \
|
||||||
mips_sgi_mach_dep.S mips_ultrix_mach_dep.s powerpc_macosx_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 \
|
rs6000_mach_dep.s sparc_mach_dep.S sparc_netbsd_mach_dep.s \
|
||||||
sparc_sunos4_mach_dep.s ia64_save_regs_in_stack.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.
|
## FIXME: relies on internal code generated by automake.
|
||||||
all_objs = @addobjs@ $(libgcjgc_la_OBJECTS)
|
all_objs = @addobjs@ $(libgcjgc_la_OBJECTS)
|
||||||
$(all_objs) : include/private/gcconfig.h include/private/gc_priv.h \
|
$(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.
|
## FIXME: we shouldn't have to do this, but automake forces us to.
|
||||||
.s.lo:
|
.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:
|
# To build the parallel collector on Linux, add to the above:
|
||||||
# -DGC_LINUX_THREADS -DPARALLEL_MARK -DTHREAD_LOCAL_ALLOC
|
# -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
|
# -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
|
# 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
|
# 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.
|
# Also requires -D_REENTRANT or -D_POSIX_C_SOURCE=199506L. See README.hp.
|
||||||
# -DGC_LINUX_THREADS enables support for Xavier Leroy's Linux threads.
|
# -DGC_LINUX_THREADS enables support for Xavier Leroy's Linux threads.
|
||||||
# see README.linux. -D_REENTRANT may also be required.
|
# 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
|
# -DALL_INTERIOR_POINTERS allows all pointers to the interior
|
||||||
# of objects to be recognized. (See gc_priv.h for consequences.)
|
# of objects to be recognized. (See gc_priv.h for consequences.)
|
||||||
# Alternatively, GC_all_interior_pointers can be set at process
|
# 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.
|
# 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
|
# This is defined implicitly in a few environments. Must also be defined
|
||||||
# by clients that use gc_cpp.h.
|
# by clients that use gc_cpp.h.
|
||||||
# -DREDIRECT_MALLOC=X causes malloc, realloc, and free to be
|
# -DREDIRECT_MALLOC=X causes malloc to be defined as alias for X.
|
||||||
# defined as aliases for X, GC_realloc, and GC_free, respectively.
|
# 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
|
# Calloc and strdup are redefined in terms of the new malloc. X should
|
||||||
# be either GC_malloc or GC_malloc_uncollectable, or
|
# be either GC_malloc or GC_malloc_uncollectable, or
|
||||||
# GC_debug_malloc_replacement. (The latter invokes GC_debug_malloc
|
# GC_debug_malloc_replacement. (The latter invokes GC_debug_malloc
|
||||||
# with dummy source location information, but still results in
|
# 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
|
# 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
|
# 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,
|
# 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,
|
# The canonical use is -DREDIRECT_REALLOC=GC_debug_realloc_replacement,
|
||||||
# together with -DREDIRECT_MALLOC=GC_debug_malloc_replacement to
|
# together with -DREDIRECT_MALLOC=GC_debug_malloc_replacement to
|
||||||
# generate leak reports with call stacks for both malloc and realloc.
|
# 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
|
# -DIGNORE_FREE turns calls to free into a noop. Only useful with
|
||||||
# -DREDIRECT_MALLOC.
|
# -DREDIRECT_MALLOC.
|
||||||
# -DNO_DEBUGGING removes GC_dump and the debugging routines it calls.
|
# -DNO_DEBUGGING removes GC_dump and the debugging routines it calls.
|
||||||
|
@ -197,8 +215,11 @@ HOSTCFLAGS=$(CFLAGS)
|
||||||
# 15% or so.
|
# 15% or so.
|
||||||
# -DUSE_3DNOW_PREFETCH causes the collector to issue AMD 3DNow style
|
# -DUSE_3DNOW_PREFETCH causes the collector to issue AMD 3DNow style
|
||||||
# prefetch instructions. Same restrictions as USE_I686_PREFETCH.
|
# prefetch instructions. Same restrictions as USE_I686_PREFETCH.
|
||||||
# UNTESTED!!
|
# Minimally tested. Didn't appear to be an obvious win on a K6-2/500.
|
||||||
# -DGC_USE_LD_WRAP in combination with the gld flags listed in README.linux
|
# -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
|
# causes the collector some system and pthread calls in a more transparent
|
||||||
# fashion than the usual macro-based approach. Requires GNU ld, and
|
# fashion than the usual macro-based approach. Requires GNU ld, and
|
||||||
# currently probably works only with Linux.
|
# currently probably works only with Linux.
|
||||||
|
@ -226,6 +247,24 @@ HOSTCFLAGS=$(CFLAGS)
|
||||||
# -DSTUBBORN_ALLOC allows allocation of "hard to change" objects, and thus
|
# -DSTUBBORN_ALLOC allows allocation of "hard to change" objects, and thus
|
||||||
# makes incremental collection easier. Was enabled by default until 6.0.
|
# makes incremental collection easier. Was enabled by default until 6.0.
|
||||||
# Rarely used, to my knowledge.
|
# 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)
|
CXXFLAGS= $(CFLAGS)
|
||||||
|
@ -233,15 +272,15 @@ AR= ar
|
||||||
RANLIB= ranlib
|
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_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
|
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 \
|
sparc_mach_dep.S include/gc.h include/gc_typed.h \
|
||||||
include/private/gc_hdrs.h include/private/gc_priv.h \
|
include/private/gc_hdrs.h include/private/gc_priv.h \
|
||||||
include/private/gcconfig.h include/private/gc_pmark.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 \
|
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 \
|
gcname.c include/weakpointer.h include/private/gc_locks.h \
|
||||||
gcc_support.c mips_ultrix_mach_dep.s include/gc_alloc.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 \
|
include/new_gc_alloc.h include/gc_allocator.h \
|
||||||
sparc_netbsd_mach_dep.s \
|
include/javaxfc.h sparc_sunos4_mach_dep.s sparc_netbsd_mach_dep.s \
|
||||||
include/private/solaris_threads.h include/gc_backptr.h \
|
include/private/solaris_threads.h include/gc_backptr.h \
|
||||||
hpux_test_and_clear.s include/gc_gcj.h \
|
hpux_test_and_clear.s include/gc_gcj.h \
|
||||||
include/gc_local_alloc.h include/private/dbg_mlc.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/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_FILES= README.QUICK doc/README.Mac doc/README.MacOSX doc/README.OS2 \
|
||||||
doc/README.amiga doc/README.cords doc/debugging.html \
|
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.win32 doc/barrett_diagram doc/README \
|
||||||
doc/README.contributors doc/README.changes doc/gc.man \
|
doc/README.contributors doc/README.changes doc/gc.man \
|
||||||
doc/README.environment doc/tree.html doc/gcdescr.html \
|
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= tests/test.c tests/test_cpp.cc tests/trace_test.c \
|
||||||
tests/leak_test.c tests/thread_leak_test.c
|
tests/leak_test.c tests/thread_leak_test.c
|
||||||
|
|
||||||
GNU_BUILD_FILES= configure.in Makefile.am configure acinclude.m4 \
|
GNU_BUILD_FILES= configure.in Makefile.am configure acinclude.m4 \
|
||||||
libtool.m4 install-sh configure.host Makefile.in \
|
libtool.m4 install-sh configure.host Makefile.in \
|
||||||
aclocal.m4 config.sub config.guess ltconfig \
|
ltconfig aclocal.m4 config.sub config.guess \
|
||||||
ltmain.sh mkinstalldirs
|
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 \
|
OTHER_MAKEFILES= OS2_MAKEFILE NT_MAKEFILE NT_THREADS_MAKEFILE gc.mak \
|
||||||
BCC_MAKEFILE EMX_MAKEFILE WCC_MAKEFILE Makefile.dj \
|
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 \
|
MacProjects.sit.hqx MacOS.c \
|
||||||
Mac_files/datastart.c Mac_files/dataend.c \
|
Mac_files/datastart.c Mac_files/dataend.c \
|
||||||
Mac_files/MacOS_config.h Mac_files/MacOS_Test_config.h \
|
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 \
|
version.h AmigaOS.c \
|
||||||
$(TESTS) $(GNU_BUILD_FILES) $(OTHER_MAKEFILES)
|
$(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: \
|
$(OBJS) tests/test.o dyn_load.o dyn_load_sunos53.o: \
|
||||||
$(srcdir)/include/private/gc_priv.h \
|
$(srcdir)/include/private/gc_priv.h \
|
||||||
$(srcdir)/include/private/gc_hdrs.h $(srcdir)/include/private/gc_locks.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 \
|
$(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
|
# The dependency on Makefile is needed. Changing
|
||||||
# options such as -DSILENT affects the size of GC_arrays,
|
# options such as -DSILENT affects the size of GC_arrays,
|
||||||
# invalidating all .o files that rely on gc_priv.h
|
# 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
|
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
|
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
|
# gcc -shared -Wl,-soname=libgc.so.0 -o libgc.so.0 $(LIBOBJS) dyn_load.lo
|
||||||
# touch liblinuxgc.so
|
# touch liblinuxgc.so
|
||||||
|
|
||||||
mach_dep.o: $(srcdir)/mach_dep.c $(srcdir)/mips_sgi_mach_dep.s $(srcdir)/mips_ultrix_mach_dep.s \
|
mach_dep.o: $(srcdir)/mach_dep.c $(srcdir)/mips_sgi_mach_dep.s \
|
||||||
$(srcdir)/rs6000_mach_dep.s $(srcdir)/powerpc_macosx_mach_dep.s $(UTILS)
|
$(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
|
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 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 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 DARWIN $(AS) -o mach_dep.o $(srcdir)/powerpc_darwin_mach_dep.s
|
||||||
./if_mach POWERPC MACOSX $(AS) -o mach_dep.o $(srcdir)/powerpc_macosx_mach_dep.s
|
./if_mach ALPHA LINUX $(CC) -c -o mach_dep.o $(srcdir)/alpha_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 SPARC SUNOS5 $(CC) -c -o mach_dep.o $(srcdir)/sparc_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 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
|
./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 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 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 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 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 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`
|
./if_mach IA64 LINUX $(CC) $(CFLAGS) -o cord/de $(srcdir)/cord/de.c cord/cordbscs.o cord/cordxtra.o gc.a -lcurses `./threadlibs`
|
||||||
|
|
|
@ -152,7 +152,7 @@ CFLAGS= -O -I$(srcdir)/include -DATOMIC_UNCOLLECTABLE -DNO_SIGNALS -DALL_INTERIO
|
||||||
# currently probably works only with Linux.
|
# currently probably works only with Linux.
|
||||||
|
|
||||||
|
|
||||||
CXXFLAGS= $(CFLAGS) -DOPERATOR_NEW_ARRAY
|
CXXFLAGS= $(CFLAGS) -DGC_OPERATOR_NEW_ARRAY
|
||||||
AR= ar
|
AR= ar
|
||||||
RANLIB= ranlib
|
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
|
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 \
|
sparc_mach_dep.S include/gc.h include/gc_typed.h \
|
||||||
include/private/gc_hdrs.h include/private/gc_priv.h \
|
include/private/gc_hdrs.h include/private/gc_priv.h \
|
||||||
include/private/gcconfig.h include/private/gc_mark.h \
|
include/private/gcconfig.h include/private/gc_mark.h \
|
||||||
include/gc_inl.h include/gc_inline.h gc.man \
|
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 \
|
include/private/solaris_threads.h include/gc_backptr.h \
|
||||||
hpux_test_and_clear.s include/gc_gcj.h \
|
hpux_test_and_clear.s include/gc_gcj.h \
|
||||||
include/gc_local_alloc.h include/private/dbg_mlc.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)
|
include/leak_detector.h $(CORD_SRCS)
|
||||||
|
|
||||||
OTHER_FILES= Makefile PCR-Makefile OS2_MAKEFILE NT_MAKEFILE BCC_MAKEFILE \
|
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
|
gcc -shared -o liblinuxgc.so $(OBJS) dyn_load.o -lo
|
||||||
ln liblinuxgc.so libgc.so
|
ln liblinuxgc.so libgc.so
|
||||||
|
|
||||||
mach_dep.o: $(srcdir)/mach_dep.c $(srcdir)/mips_sgi_mach_dep.s $(srcdir)/mips_ultrix_mach_dep.s \
|
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)
|
$(srcdir)/rs6000_mach_dep.s $(srcdir)/powerpc_darwin_mach_dep.s $(UTILS)
|
||||||
rm -f mach_dep.o
|
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 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 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 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 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 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 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_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
|
./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
|
# This Makefile.in is free software; the Free Software Foundation
|
||||||
# gives unlimited permission to copy and/or distribute it,
|
# gives unlimited permission to copy and/or distribute it,
|
||||||
# with or without modifications, as long as this notice is preserved.
|
# with or without modifications, as long as this notice is preserved.
|
||||||
|
@ -66,9 +66,11 @@ target_triplet = @target@
|
||||||
AR = @AR@
|
AR = @AR@
|
||||||
AS = @AS@
|
AS = @AS@
|
||||||
CC = @CC@
|
CC = @CC@
|
||||||
|
CFLAGS = @CFLAGS@
|
||||||
CPP = @CPP@
|
CPP = @CPP@
|
||||||
CXX = @CXX@
|
CXX = @CXX@
|
||||||
CXXCPP = @CXXCPP@
|
CXXCPP = @CXXCPP@
|
||||||
|
CXXFLAGS = @CXXFLAGS@
|
||||||
CXXINCLUDES = @CXXINCLUDES@
|
CXXINCLUDES = @CXXINCLUDES@
|
||||||
DLLTOOL = @DLLTOOL@
|
DLLTOOL = @DLLTOOL@
|
||||||
EXEEXT = @EXEEXT@
|
EXEEXT = @EXEEXT@
|
||||||
|
@ -89,7 +91,10 @@ RANLIB = @RANLIB@
|
||||||
STRIP = @STRIP@
|
STRIP = @STRIP@
|
||||||
THREADLIBS = @THREADLIBS@
|
THREADLIBS = @THREADLIBS@
|
||||||
VERSION = @VERSION@
|
VERSION = @VERSION@
|
||||||
|
addincludes = @addincludes@
|
||||||
|
addlibs = @addlibs@
|
||||||
addobjs = @addobjs@
|
addobjs = @addobjs@
|
||||||
|
addtests = @addtests@
|
||||||
gc_basedir = @gc_basedir@
|
gc_basedir = @gc_basedir@
|
||||||
mkinstalldirs = @mkinstalldirs@
|
mkinstalldirs = @mkinstalldirs@
|
||||||
target_all = @target_all@
|
target_all = @target_all@
|
||||||
|
@ -109,17 +114,21 @@ MULTIDO = true
|
||||||
MULTICLEAN = true
|
MULTICLEAN = true
|
||||||
|
|
||||||
noinst_LTLIBRARIES = libgcjgc.la libgcjgc_convenience.la
|
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 \
|
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 \
|
dyn_load.c finalize.c gc_dlopen.c gcj_mlc.c headers.c aix_irix_threads.c \
|
||||||
linux_threads.c malloc.c mallocx.c mark.c mark_rts.c misc.c new_hblk.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 \
|
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 \
|
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 \
|
EXTRA_GC_SOURCES = alpha_mach_dep.S \
|
||||||
mips_sgi_mach_dep.S mips_ultrix_mach_dep.s powerpc_macosx_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 \
|
rs6000_mach_dep.s sparc_mach_dep.S sparc_netbsd_mach_dep.s \
|
||||||
sparc_sunos4_mach_dep.s ia64_save_regs_in_stack.s
|
sparc_sunos4_mach_dep.s ia64_save_regs_in_stack.s
|
||||||
|
|
||||||
|
@ -213,24 +222,53 @@ DEFS = @DEFS@ -I. -I$(srcdir)
|
||||||
CPPFLAGS = @CPPFLAGS@
|
CPPFLAGS = @CPPFLAGS@
|
||||||
LDFLAGS = @LDFLAGS@
|
LDFLAGS = @LDFLAGS@
|
||||||
LIBS = @LIBS@
|
LIBS = @LIBS@
|
||||||
libgcjgc_la_OBJECTS = allchblk.lo alloc.lo blacklst.lo checksums.lo \
|
@POWERPC_DARWIN_FALSE@libgcjgc_la_OBJECTS = allchblk.lo alloc.lo \
|
||||||
dbg_mlc.lo dyn_load.lo finalize.lo gc_dlopen.lo gcj_mlc.lo headers.lo \
|
@POWERPC_DARWIN_FALSE@blacklst.lo checksums.lo dbg_mlc.lo dyn_load.lo \
|
||||||
irix_threads.lo linux_threads.lo malloc.lo mallocx.lo mark.lo \
|
@POWERPC_DARWIN_FALSE@finalize.lo gc_dlopen.lo gcj_mlc.lo headers.lo \
|
||||||
mark_rts.lo misc.lo new_hblk.lo obj_map.lo os_dep.lo pcr_interface.lo \
|
@POWERPC_DARWIN_FALSE@aix_irix_threads.lo malloc.lo mallocx.lo mark.lo \
|
||||||
ptr_chck.lo real_malloc.lo reclaim.lo solaris_pthreads.lo \
|
@POWERPC_DARWIN_FALSE@mark_rts.lo misc.lo new_hblk.lo obj_map.lo \
|
||||||
solaris_threads.lo specific.lo stubborn.lo typd_mlc.lo backgraph.lo \
|
@POWERPC_DARWIN_FALSE@os_dep.lo pcr_interface.lo ptr_chck.lo \
|
||||||
win32_threads.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_LDFLAGS =
|
||||||
libgcjgc_convenience_la_OBJECTS = allchblk.lo alloc.lo blacklst.lo \
|
@POWERPC_DARWIN_FALSE@libgcjgc_convenience_la_OBJECTS = allchblk.lo \
|
||||||
checksums.lo dbg_mlc.lo dyn_load.lo finalize.lo gc_dlopen.lo gcj_mlc.lo \
|
@POWERPC_DARWIN_FALSE@alloc.lo blacklst.lo checksums.lo dbg_mlc.lo \
|
||||||
headers.lo irix_threads.lo linux_threads.lo malloc.lo mallocx.lo \
|
@POWERPC_DARWIN_FALSE@dyn_load.lo finalize.lo gc_dlopen.lo gcj_mlc.lo \
|
||||||
mark.lo mark_rts.lo misc.lo new_hblk.lo obj_map.lo os_dep.lo \
|
@POWERPC_DARWIN_FALSE@headers.lo aix_irix_threads.lo malloc.lo \
|
||||||
pcr_interface.lo ptr_chck.lo real_malloc.lo reclaim.lo \
|
@POWERPC_DARWIN_FALSE@mallocx.lo mark.lo mark_rts.lo misc.lo \
|
||||||
solaris_pthreads.lo solaris_threads.lo specific.lo stubborn.lo \
|
@POWERPC_DARWIN_FALSE@new_hblk.lo obj_map.lo os_dep.lo pcr_interface.lo \
|
||||||
typd_mlc.lo backgraph.lo win32_threads.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)
|
check_PROGRAMS = gctest$(EXEEXT)
|
||||||
gctest_DEPENDENCIES = ./libgcjgc.la
|
gctest_DEPENDENCIES = ./libgcjgc.la
|
||||||
CFLAGS = @CFLAGS@
|
|
||||||
COMPILE = $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
|
COMPILE = $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
|
||||||
CCLD = $(CC)
|
CCLD = $(CC)
|
||||||
DIST_COMMON = ChangeLog Makefile.am Makefile.in acinclude.m4 aclocal.m4 \
|
DIST_COMMON = ChangeLog Makefile.am Makefile.in acinclude.m4 aclocal.m4 \
|
||||||
|
@ -368,7 +406,7 @@ maintainer-clean-recursive:
|
||||||
dot_seen=no; \
|
dot_seen=no; \
|
||||||
rev=''; list='$(SUBDIRS)'; for subdir in $$list; do \
|
rev=''; list='$(SUBDIRS)'; for subdir in $$list; do \
|
||||||
rev="$$subdir $$rev"; \
|
rev="$$subdir $$rev"; \
|
||||||
test "$$subdir" = "." && dot_seen=yes; \
|
test "$$subdir" != "." || dot_seen=yes; \
|
||||||
done; \
|
done; \
|
||||||
test "$$dot_seen" = "no" && rev=". $$rev"; \
|
test "$$dot_seen" = "no" && rev=". $$rev"; \
|
||||||
target=`echo $@ | sed s/-recursive//`; \
|
target=`echo $@ | sed s/-recursive//`; \
|
||||||
|
@ -598,7 +636,9 @@ mostlyclean distclean maintainer-clean
|
||||||
test.o: tests/test.c
|
test.o: tests/test.c
|
||||||
$(COMPILE) -c $(srcdir)/tests/test.c
|
$(COMPILE) -c $(srcdir)/tests/test.c
|
||||||
$(all_objs) : include/private/gcconfig.h include/private/gc_priv.h \
|
$(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:
|
.s.lo:
|
||||||
$(LTCOMPILE) -Wp,-P -x assembler-with-cpp -c $<
|
$(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 };
|
struct hblk * GC_hblkfreelist[N_HBLK_FLS+1] = { 0 };
|
||||||
|
|
||||||
#ifndef USE_MUNMAP
|
#ifndef USE_MUNMAP
|
||||||
|
|
||||||
word GC_free_bytes[N_HBLK_FLS+1] = { 0 };
|
word GC_free_bytes[N_HBLK_FLS+1] = { 0 };
|
||||||
/* Number of free bytes on each list. */
|
/* Number of free bytes on each list. */
|
||||||
|
|
||||||
/* Is bytes + the number of free bytes on lists n .. N_HBLK_FLS */
|
/* Is bytes + the number of free bytes on lists n .. N_HBLK_FLS */
|
||||||
/* > GC_max_large_allocd_bytes? */
|
/* > 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;
|
word bytes;
|
||||||
int n;
|
int n;
|
||||||
{
|
{
|
||||||
|
@ -583,11 +587,11 @@ int n;
|
||||||
if (!GC_use_entire_heap
|
if (!GC_use_entire_heap
|
||||||
&& size_avail != size_needed
|
&& size_avail != size_needed
|
||||||
&& USED_HEAP_SIZE >= GC_requested_heapsize
|
&& USED_HEAP_SIZE >= GC_requested_heapsize
|
||||||
&& !GC_incremental && GC_should_collect()) {
|
&& !TRUE_INCREMENTAL && GC_should_collect()) {
|
||||||
# ifdef USE_MUNMAP
|
# ifdef USE_MUNMAP
|
||||||
continue;
|
continue;
|
||||||
# else
|
# 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 */
|
/* previous request for large blocks, we go ahead */
|
||||||
/* and split. Assuming a steady state, that should */
|
/* and split. Assuming a steady state, that should */
|
||||||
/* be safe. It means that we can use the full */
|
/* 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)) {
|
if (!GC_enough_large_bytes_left(GC_large_allocd_bytes, n)) {
|
||||||
continue;
|
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 */
|
# endif /* !USE_MUNMAP */
|
||||||
}
|
}
|
||||||
/* If the next heap block is obviously better, go on. */
|
/* 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;
|
GC_bool GC_need_full_gc = FALSE;
|
||||||
/* Need full GC do to heap growth. */
|
/* 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;
|
word GC_used_heap_size_after_full = 0;
|
||||||
|
|
||||||
char * GC_copyright[] =
|
char * GC_copyright[] =
|
||||||
|
@ -160,7 +167,7 @@ static word min_words_allocd()
|
||||||
+ (GC_large_free_bytes >> 2)
|
+ (GC_large_free_bytes >> 2)
|
||||||
/* use a bit more of large empty heap */
|
/* use a bit more of large empty heap */
|
||||||
+ total_root_size);
|
+ total_root_size);
|
||||||
if (GC_incremental) {
|
if (TRUE_INCREMENTAL) {
|
||||||
return scan_size / (2 * GC_free_space_divisor);
|
return scan_size / (2 * GC_free_space_divisor);
|
||||||
} else {
|
} else {
|
||||||
return scan_size / GC_free_space_divisor;
|
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 */
|
/* managed object should not alter result, assuming the client */
|
||||||
/* is playing by the rules. */
|
/* is playing by the rules. */
|
||||||
result = (signed_word)GC_words_allocd
|
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) {
|
if (result > (signed_word)GC_words_allocd) {
|
||||||
result = GC_words_allocd;
|
result = GC_words_allocd;
|
||||||
/* probably client bug or unfortunate scheduling */
|
/* probably client bug or unfortunate scheduling */
|
||||||
|
@ -250,7 +258,6 @@ void GC_maybe_gc()
|
||||||
|
|
||||||
if (GC_should_collect()) {
|
if (GC_should_collect()) {
|
||||||
if (!GC_incremental) {
|
if (!GC_incremental) {
|
||||||
GC_notify_full_gc();
|
|
||||||
GC_gcollect_inner();
|
GC_gcollect_inner();
|
||||||
n_partial_gcs = 0;
|
n_partial_gcs = 0;
|
||||||
return;
|
return;
|
||||||
|
@ -302,10 +309,14 @@ void GC_maybe_gc()
|
||||||
/*
|
/*
|
||||||
* Stop the world garbage collection. Assumes lock held, signals disabled.
|
* 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.
|
* 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_bool GC_try_to_collect_inner(stop_func)
|
||||||
GC_stop_func stop_func;
|
GC_stop_func stop_func;
|
||||||
{
|
{
|
||||||
|
# ifdef CONDPRINT
|
||||||
|
CLOCK_TYPE start_time, current_time;
|
||||||
|
# endif
|
||||||
if (GC_dont_gc) return FALSE;
|
if (GC_dont_gc) return FALSE;
|
||||||
if (GC_incremental && GC_collection_in_progress()) {
|
if (GC_incremental && GC_collection_in_progress()) {
|
||||||
# ifdef CONDPRINT
|
# ifdef CONDPRINT
|
||||||
|
@ -320,8 +331,10 @@ GC_stop_func stop_func;
|
||||||
GC_collect_a_little_inner(1);
|
GC_collect_a_little_inner(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (stop_func == GC_never_stop_func) GC_notify_full_gc();
|
||||||
# ifdef CONDPRINT
|
# ifdef CONDPRINT
|
||||||
if (GC_print_stats) {
|
if (GC_print_stats) {
|
||||||
|
if (GC_print_stats) GET_TIME(start_time);
|
||||||
GC_printf2(
|
GC_printf2(
|
||||||
"Initiating full world-stop collection %lu after %ld allocd bytes\n",
|
"Initiating full world-stop collection %lu after %ld allocd bytes\n",
|
||||||
(unsigned long) GC_gc_no+1,
|
(unsigned long) GC_gc_no+1,
|
||||||
|
@ -360,6 +373,13 @@ GC_stop_func stop_func;
|
||||||
return(FALSE);
|
return(FALSE);
|
||||||
}
|
}
|
||||||
GC_finish_collection();
|
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);
|
return(TRUE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -430,6 +450,7 @@ int GC_collect_a_little GC_PROTO(())
|
||||||
result = (int)GC_collection_in_progress();
|
result = (int)GC_collection_in_progress();
|
||||||
UNLOCK();
|
UNLOCK();
|
||||||
ENABLE_SIGNALS();
|
ENABLE_SIGNALS();
|
||||||
|
if (!result && GC_debugging_started) GC_print_all_smashed();
|
||||||
return(result);
|
return(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -448,16 +469,17 @@ GC_stop_func stop_func;
|
||||||
CLOCK_TYPE start_time, current_time;
|
CLOCK_TYPE start_time, current_time;
|
||||||
# endif
|
# endif
|
||||||
|
|
||||||
# if defined(REGISTER_LIBRARIES_EARLY)
|
|
||||||
GC_cond_register_dynamic_libraries();
|
|
||||||
# endif
|
|
||||||
STOP_WORLD();
|
|
||||||
# ifdef PRINTTIMES
|
# ifdef PRINTTIMES
|
||||||
GET_TIME(start_time);
|
GET_TIME(start_time);
|
||||||
# endif
|
# endif
|
||||||
# if defined(CONDPRINT) && !defined(PRINTTIMES)
|
# if defined(CONDPRINT) && !defined(PRINTTIMES)
|
||||||
if (GC_print_stats) GET_TIME(start_time);
|
if (GC_print_stats) GET_TIME(start_time);
|
||||||
# endif
|
# endif
|
||||||
|
# if defined(REGISTER_LIBRARIES_EARLY)
|
||||||
|
GC_cond_register_dynamic_libraries();
|
||||||
|
# endif
|
||||||
|
STOP_WORLD();
|
||||||
|
IF_THREADS(GC_world_stopped = TRUE);
|
||||||
# ifdef CONDPRINT
|
# ifdef CONDPRINT
|
||||||
if (GC_print_stats) {
|
if (GC_print_stats) {
|
||||||
GC_printf1("--> Marking for collection %lu ",
|
GC_printf1("--> Marking for collection %lu ",
|
||||||
|
@ -488,6 +510,7 @@ GC_stop_func stop_func;
|
||||||
}
|
}
|
||||||
# endif
|
# endif
|
||||||
GC_deficit = i; /* Give the mutator a chance. */
|
GC_deficit = i; /* Give the mutator a chance. */
|
||||||
|
IF_THREADS(GC_world_stopped = FALSE);
|
||||||
START_WORLD();
|
START_WORLD();
|
||||||
return(FALSE);
|
return(FALSE);
|
||||||
}
|
}
|
||||||
|
@ -521,6 +544,8 @@ GC_stop_func stop_func;
|
||||||
(*GC_check_heap)();
|
(*GC_check_heap)();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
IF_THREADS(GC_world_stopped = FALSE);
|
||||||
|
START_WORLD();
|
||||||
# ifdef PRINTTIMES
|
# ifdef PRINTTIMES
|
||||||
GET_TIME(current_time);
|
GET_TIME(current_time);
|
||||||
GC_printf1("World-stopped marking took %lu msecs\n",
|
GC_printf1("World-stopped marking took %lu msecs\n",
|
||||||
|
@ -534,7 +559,6 @@ GC_stop_func stop_func;
|
||||||
}
|
}
|
||||||
# endif
|
# endif
|
||||||
# endif
|
# endif
|
||||||
START_WORLD();
|
|
||||||
return(TRUE);
|
return(TRUE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -611,6 +635,7 @@ void GC_finish_collection()
|
||||||
GC_print_address_map();
|
GC_print_address_map();
|
||||||
}
|
}
|
||||||
# endif
|
# endif
|
||||||
|
COND_DUMP;
|
||||||
if (GC_find_leak) {
|
if (GC_find_leak) {
|
||||||
/* Mark all objects on the free list. All objects should be */
|
/* Mark all objects on the free list. All objects should be */
|
||||||
/* marked when we're done. */
|
/* marked when we're done. */
|
||||||
|
@ -707,6 +732,7 @@ void GC_finish_collection()
|
||||||
GC_words_allocd = 0;
|
GC_words_allocd = 0;
|
||||||
GC_words_wasted = 0;
|
GC_words_wasted = 0;
|
||||||
GC_mem_freed = 0;
|
GC_mem_freed = 0;
|
||||||
|
GC_finalizer_mem_freed = 0;
|
||||||
|
|
||||||
# ifdef USE_MUNMAP
|
# ifdef USE_MUNMAP
|
||||||
GC_unmap_old();
|
GC_unmap_old();
|
||||||
|
@ -730,6 +756,7 @@ void GC_finish_collection()
|
||||||
int result;
|
int result;
|
||||||
DCL_LOCK_STATE;
|
DCL_LOCK_STATE;
|
||||||
|
|
||||||
|
if (GC_debugging_started) GC_print_all_smashed();
|
||||||
GC_INVOKE_FINALIZERS();
|
GC_INVOKE_FINALIZERS();
|
||||||
DISABLE_SIGNALS();
|
DISABLE_SIGNALS();
|
||||||
LOCK();
|
LOCK();
|
||||||
|
@ -741,14 +768,17 @@ void GC_finish_collection()
|
||||||
EXIT_GC();
|
EXIT_GC();
|
||||||
UNLOCK();
|
UNLOCK();
|
||||||
ENABLE_SIGNALS();
|
ENABLE_SIGNALS();
|
||||||
if(result) GC_INVOKE_FINALIZERS();
|
if(result) {
|
||||||
|
if (GC_debugging_started) GC_print_all_smashed();
|
||||||
|
GC_INVOKE_FINALIZERS();
|
||||||
|
}
|
||||||
return(result);
|
return(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
void GC_gcollect GC_PROTO(())
|
void GC_gcollect GC_PROTO(())
|
||||||
{
|
{
|
||||||
GC_notify_full_gc();
|
|
||||||
(void)GC_try_to_collect(GC_never_stop_func);
|
(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. */
|
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 &&
|
if (!GC_incremental && !GC_dont_gc &&
|
||||||
(GC_dont_expand && GC_words_allocd > 0 || GC_should_collect())) {
|
(GC_dont_expand && GC_words_allocd > 0 || GC_should_collect())) {
|
||||||
GC_notify_full_gc();
|
|
||||||
GC_gcollect_inner();
|
GC_gcollect_inner();
|
||||||
} else {
|
} else {
|
||||||
word blocks_to_get = GC_heapsize/(HBLKSIZE*GC_free_space_divisor)
|
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)) {
|
&& !GC_expand_hp_inner(needed_blocks)) {
|
||||||
if (GC_fail_count++ < GC_max_retries) {
|
if (GC_fail_count++ < GC_max_retries) {
|
||||||
WARN("Out of Memory! Trying to continue ...\n", 0);
|
WARN("Out of Memory! Trying to continue ...\n", 0);
|
||||||
GC_notify_full_gc();
|
|
||||||
GC_gcollect_inner();
|
GC_gcollect_inner();
|
||||||
} else {
|
} else {
|
||||||
# if !defined(AMIGA) || !defined(GC_AMIGA_FASTALLOC)
|
# if !defined(AMIGA) || !defined(GC_AMIGA_FASTALLOC)
|
||||||
|
@ -1005,14 +1033,15 @@ ptr_t GC_allocobj(sz, kind)
|
||||||
word sz;
|
word sz;
|
||||||
int kind;
|
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);
|
if (sz == 0) return(0);
|
||||||
|
|
||||||
while (*flh == 0) {
|
while (*flh == 0) {
|
||||||
ENTER_GC();
|
ENTER_GC();
|
||||||
/* Do our share of marking work */
|
/* 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 */
|
/* Sweep blocks for objects of this size */
|
||||||
GC_continue_reclaim(sz, kind);
|
GC_continue_reclaim(sz, kind);
|
||||||
EXIT_GC();
|
EXIT_GC();
|
||||||
|
@ -1021,13 +1050,21 @@ int kind;
|
||||||
}
|
}
|
||||||
if (*flh == 0) {
|
if (*flh == 0) {
|
||||||
ENTER_GC();
|
ENTER_GC();
|
||||||
|
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)) {
|
if (!GC_collect_or_expand((word)1,FALSE)) {
|
||||||
EXIT_GC();
|
EXIT_GC();
|
||||||
return(0);
|
return(0);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
EXIT_GC();
|
EXIT_GC();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
/* Successful allocation; reset failure count. */
|
||||||
|
GC_fail_count = 0;
|
||||||
|
|
||||||
return(*flh);
|
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 The configuration host
|
||||||
# host_cpu The configuration host CPU
|
# host_cpu The configuration host CPU
|
||||||
# target_optspace --enable-target-optspace ("yes", "no", "")
|
# target_optspace --enable-target-optspace ("yes", "no", "")
|
||||||
|
# GCC should be "yes" if using gcc
|
||||||
|
|
||||||
# It sets the following shell variables:
|
# It sets the following shell variables:
|
||||||
# gc_cflags Special CFLAGS to use when building
|
# gc_cflags Special CFLAGS to use when building
|
||||||
|
|
||||||
|
gc_cflags=""
|
||||||
|
|
||||||
# We should set -fexceptions if we are using gcc and might be used
|
# We should set -fexceptions if we are using gcc and might be used
|
||||||
# inside something like gcj. This is the zeroth approximation:
|
# inside something like gcj. This is the zeroth approximation:
|
||||||
|
if test :"$GCC": = :yes: ; then
|
||||||
|
gc_cflags="${gc_cflags} -fexceptions"
|
||||||
|
else
|
||||||
case "$host" in
|
case "$host" in
|
||||||
*-*-linux* )
|
|
||||||
gc_cflags=-fexceptions
|
|
||||||
;;
|
|
||||||
hppa*-*-hpux* )
|
hppa*-*-hpux* )
|
||||||
if test $GCC != "yes" ; then
|
if test :$GCC: != :"yes": ; then
|
||||||
gc_cflags=+ESdbgasm
|
gc_cflags="${gc_flags} +ESdbgasm"
|
||||||
fi
|
fi
|
||||||
|
# :TODO: actaully we should check using Autoconf if
|
||||||
|
# the compiler supports this option.
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
|
fi
|
||||||
|
|
||||||
case "${target_optspace}:${host}" in
|
case "${target_optspace}:${host}" in
|
||||||
yes:*)
|
yes:*)
|
||||||
|
@ -48,7 +54,7 @@ esac
|
||||||
|
|
||||||
case "${host}" in
|
case "${host}" in
|
||||||
mips-tx39-*|mipstx39-unknown-*)
|
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
|
THREADS=posix
|
||||||
THREADLIBS=-lpthread
|
THREADLIBS=-lpthread
|
||||||
case "$host" in
|
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(GC_LINUX_THREADS)
|
||||||
AC_DEFINE(_REENTRANT)
|
AC_DEFINE(_REENTRANT)
|
||||||
if test "${enable_parallel_mark}"; then
|
if test "${enable_parallel_mark}" = yes; then
|
||||||
AC_DEFINE(PARALLEL_MARK)
|
AC_DEFINE(PARALLEL_MARK)
|
||||||
fi
|
fi
|
||||||
AC_DEFINE(THREAD_LOCAL_ALLOC)
|
AC_DEFINE(THREAD_LOCAL_ALLOC)
|
||||||
|
@ -85,6 +85,10 @@ case "$THREADS" in
|
||||||
AC_DEFINE(GC_LINUX_THREADS)
|
AC_DEFINE(GC_LINUX_THREADS)
|
||||||
AC_DEFINE(_REENTRANT)
|
AC_DEFINE(_REENTRANT)
|
||||||
;;
|
;;
|
||||||
|
*-*-aix*)
|
||||||
|
AC_DEFINE(GC_AIX_THREADS)
|
||||||
|
AC_DEFINE(_REENTRANT)
|
||||||
|
;;
|
||||||
*-*-hpux*)
|
*-*-hpux*)
|
||||||
AC_MSG_WARN("Only HP/UX 11 threads are supported.")
|
AC_MSG_WARN("Only HP/UX 11 threads are supported.")
|
||||||
AC_DEFINE(GC_HPUX_THREADS)
|
AC_DEFINE(GC_HPUX_THREADS)
|
||||||
|
@ -109,16 +113,52 @@ case "$THREADS" in
|
||||||
AC_DEFINE(GC_IRIX_THREADS)
|
AC_DEFINE(GC_IRIX_THREADS)
|
||||||
;;
|
;;
|
||||||
*-*-cygwin*)
|
*-*-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
|
esac
|
||||||
;;
|
;;
|
||||||
win32)
|
win32)
|
||||||
AC_DEFINE(GC_WIN32_THREADS)
|
AC_DEFINE(GC_WIN32_THREADS)
|
||||||
|
dnl Wine getenv may not return NULL for missing entry
|
||||||
AC_DEFINE(NO_GETENV)
|
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
|
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)
|
decosf1 | irix | mach | os2 | solaris | dce | vxworks)
|
||||||
AC_MSG_ERROR(thread package $THREADS not yet supported)
|
AC_MSG_ERROR(thread package $THREADS not yet supported)
|
||||||
|
@ -129,7 +169,22 @@ case "$THREADS" in
|
||||||
esac
|
esac
|
||||||
AC_SUBST(THREADLIBS)
|
AC_SUBST(THREADLIBS)
|
||||||
|
|
||||||
|
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")
|
AC_CHECK_LIB(dl, dlopen, EXTRA_TEST_LIBS="$EXTRA_TEST_LIBS -ldl")
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
AC_SUBST(EXTRA_TEST_LIBS)
|
AC_SUBST(EXTRA_TEST_LIBS)
|
||||||
|
|
||||||
target_all=libgcjgc.la
|
target_all=libgcjgc.la
|
||||||
|
@ -147,6 +202,9 @@ TARGET_ECOS="$with_ecos"
|
||||||
)
|
)
|
||||||
|
|
||||||
addobjs=
|
addobjs=
|
||||||
|
addlibs=
|
||||||
|
addincludes=
|
||||||
|
addtests=
|
||||||
CXXINCLUDES=
|
CXXINCLUDES=
|
||||||
case "$TARGET_ECOS" in
|
case "$TARGET_ECOS" in
|
||||||
no)
|
no)
|
||||||
|
@ -157,21 +215,46 @@ case "$TARGET_ECOS" in
|
||||||
addobjs="$addobjs ecos.lo"
|
addobjs="$addobjs ecos.lo"
|
||||||
;;
|
;;
|
||||||
esac
|
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(CXX)
|
||||||
|
|
||||||
AC_SUBST(INCLUDES)
|
AC_SUBST(INCLUDES)
|
||||||
AC_SUBST(CXXINCLUDES)
|
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=
|
machdep=
|
||||||
case "$host" in
|
case "$host" in
|
||||||
alpha*-*-openbsd*)
|
alpha*-*-openbsd*)
|
||||||
machdep="alpha_mach_dep.lo"
|
machdep="alpha_mach_dep.lo"
|
||||||
if test x"${ac_cv_lib_dl_dlopen}" != xyes ; then
|
if test x"${ac_cv_lib_dl_dlopen}" != xyes ; then
|
||||||
AC_MSG_WARN(OpenBSD/Alpha without dlopen(). Shared library support is disabled)
|
AC_MSG_WARN(OpenBSD/Alpha without dlopen(). Shared library support is disabled)
|
||||||
AM_DISABLE_SHARED
|
|
||||||
fi
|
fi
|
||||||
;;
|
;;
|
||||||
alpha*-*-*)
|
alpha*-*-linux*)
|
||||||
machdep="alpha_mach_dep.lo"
|
machdep="alpha_mach_dep.lo"
|
||||||
;;
|
;;
|
||||||
i?86-*-solaris2.[[89]]*)
|
i?86-*-solaris2.[[89]]*)
|
||||||
|
@ -185,12 +268,17 @@ case "$host" in
|
||||||
mips-dec-ultrix*)
|
mips-dec-ultrix*)
|
||||||
machdep="mips_ultrix_mach-dep.lo"
|
machdep="mips_ultrix_mach-dep.lo"
|
||||||
;;
|
;;
|
||||||
|
mips-nec-sysv*|mips-unknown-sysv*)
|
||||||
|
;;
|
||||||
mips*-*-linux*)
|
mips*-*-linux*)
|
||||||
;;
|
;;
|
||||||
mips-*-*)
|
mips-*-*)
|
||||||
machdep="mips_sgi_mach_dep.lo"
|
machdep="mips_sgi_mach_dep.lo"
|
||||||
AC_DEFINE(NO_EXECUTE_PERMISSION)
|
AC_DEFINE(NO_EXECUTE_PERMISSION)
|
||||||
;;
|
;;
|
||||||
|
sparc-*-netbsd*)
|
||||||
|
machdep="sparc_netbsd_mach_dep.lo"
|
||||||
|
;;
|
||||||
sparc-sun-solaris2.3*)
|
sparc-sun-solaris2.3*)
|
||||||
machdep="sparc_mach_dep.lo"
|
machdep="sparc_mach_dep.lo"
|
||||||
AC_DEFINE(SUNOS53_SHARED_LIB)
|
AC_DEFINE(SUNOS53_SHARED_LIB)
|
||||||
|
@ -203,16 +291,65 @@ case "$host" in
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
if test x"$machdep" = x; then
|
if test x"$machdep" = x; then
|
||||||
|
AC_MSG_RESULT($machdep)
|
||||||
machdep="mach_dep.lo"
|
machdep="mach_dep.lo"
|
||||||
fi
|
fi
|
||||||
addobjs="$addobjs $machdep"
|
addobjs="$addobjs $machdep"
|
||||||
AC_SUBST(addobjs)
|
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 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 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
|
case "$host" in
|
||||||
sparc-sun-solaris2*)
|
sparc-sun-solaris2*|*aix*)
|
||||||
if test "$GCC" = yes; then
|
if test "$GCC" = yes; then
|
||||||
|
AC_MSG_RESULT(yes)
|
||||||
new_CFLAGS=
|
new_CFLAGS=
|
||||||
for i in $CFLAGS; do
|
for i in $CFLAGS; do
|
||||||
case "$i" in
|
case "$i" in
|
||||||
|
@ -224,8 +361,11 @@ case "$host" in
|
||||||
esac
|
esac
|
||||||
done
|
done
|
||||||
CFLAGS="$new_CFLAGS"
|
CFLAGS="$new_CFLAGS"
|
||||||
|
else
|
||||||
|
AC_MSG_RESULT(no)
|
||||||
fi
|
fi
|
||||||
;;
|
;;
|
||||||
|
*) AC_MSG_RESULT(no) ;;
|
||||||
esac
|
esac
|
||||||
|
|
||||||
dnl We need to override the top-level CFLAGS. This is how we do it.
|
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_MSG_WARN("Client must not use -fomit-frame-pointer.")
|
||||||
AC_DEFINE(SAVE_CALL_COUNT, 8)
|
AC_DEFINE(SAVE_CALL_COUNT, 8)
|
||||||
;;
|
;;
|
||||||
|
i[3456]86-*-dgux*)
|
||||||
|
AC_DEFINE(MAKE_BACK_GRAPH)
|
||||||
|
;;
|
||||||
esac ]
|
esac ]
|
||||||
fi)
|
fi)
|
||||||
|
|
||||||
|
|
|
@ -219,7 +219,7 @@ CORD CORD_cat_char_star(CORD x, const char * y, size_t leny)
|
||||||
result->len = result_len;
|
result->len = result_len;
|
||||||
result->left = x;
|
result->left = x;
|
||||||
result->right = y;
|
result->right = y;
|
||||||
if (depth > MAX_DEPTH) {
|
if (depth >= MAX_DEPTH) {
|
||||||
return(CORD_balance((CORD)result));
|
return(CORD_balance((CORD)result));
|
||||||
} else {
|
} else {
|
||||||
return((CORD) result);
|
return((CORD) result);
|
||||||
|
@ -260,9 +260,13 @@ CORD CORD_cat(CORD x, CORD y)
|
||||||
result->len = result_len;
|
result->len = result_len;
|
||||||
result->left = x;
|
result->left = x;
|
||||||
result->right = y;
|
result->right = y;
|
||||||
|
if (depth >= MAX_DEPTH) {
|
||||||
|
return(CORD_balance((CORD)result));
|
||||||
|
} else {
|
||||||
return((CORD) result);
|
return((CORD) result);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -233,7 +233,7 @@ int CORD_vsprintf(CORD * out, CORD format, va_list args)
|
||||||
if (width == NONE && prec == NONE) {
|
if (width == NONE && prec == NONE) {
|
||||||
register char c;
|
register char c;
|
||||||
|
|
||||||
c = va_arg(args, int);
|
c = (char)va_arg(args, int);
|
||||||
CORD_ec_append(result, c);
|
CORD_ec_append(result, c);
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
@ -255,12 +255,18 @@ int CORD_vsprintf(CORD * out, CORD format, va_list args)
|
||||||
/* Use standard sprintf to perform conversion */
|
/* Use standard sprintf to perform conversion */
|
||||||
{
|
{
|
||||||
register char * buf;
|
register char * buf;
|
||||||
va_list vsprintf_args = args;
|
va_list vsprintf_args;
|
||||||
/* The above does not appear to be sanctioned */
|
|
||||||
/* by the ANSI C standard. */
|
|
||||||
int max_size = 0;
|
int max_size = 0;
|
||||||
int res;
|
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 (width == VARIABLE) width = va_arg(args, int);
|
||||||
if (prec == VARIABLE) prec = va_arg(args, int);
|
if (prec == VARIABLE) prec = va_arg(args, int);
|
||||||
if (width != NONE) max_size = width;
|
if (width != NONE) max_size = width;
|
||||||
|
|
|
@ -249,7 +249,7 @@ LRESULT CALLBACK WndProc (HWND hwnd, UINT message,
|
||||||
|
|
||||||
case IDM_HELPABOUT:
|
case IDM_HELPABOUT:
|
||||||
if( DialogBox( hInstance, "ABOUTBOX",
|
if( DialogBox( hInstance, "ABOUTBOX",
|
||||||
hwnd, lpfnAboutBox ) );
|
hwnd, lpfnAboutBox ) )
|
||||||
InvalidateRect( hwnd, NULL, TRUE );
|
InvalidateRect( hwnd, NULL, TRUE );
|
||||||
return( 0 );
|
return( 0 );
|
||||||
case IDM_HELPCONTENTS:
|
case IDM_HELPCONTENTS:
|
||||||
|
|
|
@ -60,7 +60,7 @@ ptr_t p;
|
||||||
# include <stdlib.h>
|
# include <stdlib.h>
|
||||||
|
|
||||||
# if defined(LINUX) || defined(SUNOS4) || defined(SUNOS5) \
|
# if defined(LINUX) || defined(SUNOS4) || defined(SUNOS5) \
|
||||||
|| defined(HPUX) || defined(IRIX) || defined(OSF1)
|
|| defined(HPUX) || defined(IRIX5) || defined(OSF1)
|
||||||
# define RANDOM() random()
|
# define RANDOM() random()
|
||||||
# else
|
# else
|
||||||
# define RANDOM() (long)rand()
|
# define RANDOM() (long)rand()
|
||||||
|
@ -228,6 +228,8 @@ ptr_t p;
|
||||||
|
|
||||||
#endif /* KEEP_BACK_PTRS */
|
#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. */
|
/* Store debugging info into p. Return displaced pointer. */
|
||||||
/* Assumes we don't hold allocation lock. */
|
/* Assumes we don't hold allocation lock. */
|
||||||
ptr_t GC_store_debug_info(p, sz, string, integer)
|
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 */
|
/* But that's expensive. And this way things should only appear */
|
||||||
/* inconsistent while we're in the handler. */
|
/* inconsistent while we're in the handler. */
|
||||||
LOCK();
|
LOCK();
|
||||||
|
GC_ASSERT(GC_size(p) >= sizeof(oh) + sz);
|
||||||
|
GC_ASSERT(!(SMALL_OBJ(sz) && CROSSES_HBLK(p, sz)));
|
||||||
# ifdef KEEP_BACK_PTRS
|
# ifdef KEEP_BACK_PTRS
|
||||||
((oh *)p) -> oh_back_ptr = HIDE_BACK_PTR(NOT_MARKED);
|
((oh *)p) -> oh_back_ptr = HIDE_BACK_PTR(NOT_MARKED);
|
||||||
# endif
|
# endif
|
||||||
|
@ -275,6 +279,8 @@ word integer;
|
||||||
/* There is some argument that we should disable signals here. */
|
/* There is some argument that we should disable signals here. */
|
||||||
/* But that's expensive. And this way things should only appear */
|
/* But that's expensive. And this way things should only appear */
|
||||||
/* inconsistent while we're in the handler. */
|
/* 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
|
# ifdef KEEP_BACK_PTRS
|
||||||
((oh *)p) -> oh_back_ptr = HIDE_BACK_PTR(NOT_MARKED);
|
((oh *)p) -> oh_back_ptr = HIDE_BACK_PTR(NOT_MARKED);
|
||||||
# endif
|
# endif
|
||||||
|
@ -324,10 +330,11 @@ ptr_t p;
|
||||||
{
|
{
|
||||||
register oh * ohdr = (oh *)GC_base(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_printf1("0x%lx (", ((unsigned long)ohdr + sizeof(oh)));
|
||||||
GC_err_puts(ohdr -> oh_string);
|
GC_err_puts(ohdr -> oh_string);
|
||||||
# ifdef SHORT_DBG_HDRS
|
# 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
|
# else
|
||||||
GC_err_printf2(":%ld, sz=%ld)\n", (unsigned long)(ohdr -> oh_int),
|
GC_err_printf2(":%ld, sz=%ld)\n", (unsigned long)(ohdr -> oh_int),
|
||||||
(unsigned long)(ohdr -> oh_sz));
|
(unsigned long)(ohdr -> oh_sz));
|
||||||
|
@ -342,6 +349,7 @@ ptr_t p;
|
||||||
ptr_t p;
|
ptr_t p;
|
||||||
# endif
|
# endif
|
||||||
{
|
{
|
||||||
|
GC_ASSERT(!I_HOLD_LOCK());
|
||||||
if (GC_HAS_DEBUG_INFO(p)) {
|
if (GC_HAS_DEBUG_INFO(p)) {
|
||||||
GC_print_obj(p);
|
GC_print_obj(p);
|
||||||
} else {
|
} else {
|
||||||
|
@ -355,6 +363,7 @@ ptr_t p, clobbered_addr;
|
||||||
{
|
{
|
||||||
register oh * ohdr = (oh *)GC_base(p);
|
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,
|
GC_err_printf2("0x%lx in object at 0x%lx(", (unsigned long)clobbered_addr,
|
||||||
(unsigned long)p);
|
(unsigned long)p);
|
||||||
if (clobbered_addr <= (ptr_t)(&(ohdr -> oh_sz))
|
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_check_heap_proc GC_PROTO((void));
|
||||||
|
|
||||||
|
void GC_print_all_smashed_proc GC_PROTO((void));
|
||||||
|
|
||||||
void GC_do_nothing() {}
|
void GC_do_nothing() {}
|
||||||
|
|
||||||
void GC_start_debugging()
|
void GC_start_debugging()
|
||||||
{
|
{
|
||||||
# ifndef SHORT_DBG_HDRS
|
# ifndef SHORT_DBG_HDRS
|
||||||
GC_check_heap = GC_check_heap_proc;
|
GC_check_heap = GC_check_heap_proc;
|
||||||
|
GC_print_all_smashed = GC_print_all_smashed_proc;
|
||||||
# else
|
# else
|
||||||
GC_check_heap = GC_do_nothing;
|
GC_check_heap = GC_do_nothing;
|
||||||
|
GC_print_all_smashed = GC_do_nothing;
|
||||||
# endif
|
# endif
|
||||||
GC_print_heap_obj = GC_debug_print_heap_obj_proc;
|
GC_print_heap_obj = GC_debug_print_heap_obj_proc;
|
||||||
GC_debugging_started = TRUE;
|
GC_debugging_started = TRUE;
|
||||||
|
@ -429,6 +442,62 @@ void GC_start_debugging()
|
||||||
return (GC_store_debug_info(result, (word)lb, s, (word)i));
|
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
|
# ifdef DBG_HDRS_ALL
|
||||||
/*
|
/*
|
||||||
* An allocation function for internal use.
|
* An allocation function for internal use.
|
||||||
|
@ -447,7 +516,7 @@ void GC_start_debugging()
|
||||||
(unsigned long) lb);
|
(unsigned long) lb);
|
||||||
return(0);
|
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));
|
return (GC_store_debug_info_inner(result, (word)lb, "INTERNAL", (word)0));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -461,7 +530,7 @@ void GC_start_debugging()
|
||||||
(unsigned long) lb);
|
(unsigned long) lb);
|
||||||
return(0);
|
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));
|
return (GC_store_debug_info_inner(result, (word)lb, "INTERNAL", (word)0));
|
||||||
}
|
}
|
||||||
# endif
|
# endif
|
||||||
|
@ -592,7 +661,7 @@ GC_PTR p;
|
||||||
int i;
|
int i;
|
||||||
# endif
|
# endif
|
||||||
{
|
{
|
||||||
GC_PTR result = GC_malloc_uncollectable(lb + DEBUG_BYTES);
|
GC_PTR result = GC_malloc_uncollectable(lb + UNCOLLECTABLE_DEBUG_BYTES);
|
||||||
|
|
||||||
if (result == 0) {
|
if (result == 0) {
|
||||||
GC_err_printf1("GC_debug_malloc_uncollectable(%ld) returning NIL (",
|
GC_err_printf1("GC_debug_malloc_uncollectable(%ld) returning NIL (",
|
||||||
|
@ -618,7 +687,8 @@ GC_PTR p;
|
||||||
int i;
|
int i;
|
||||||
# endif
|
# 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) {
|
if (result == 0) {
|
||||||
GC_err_printf1(
|
GC_err_printf1(
|
||||||
|
@ -774,6 +844,45 @@ void GC_debug_free_inner(GC_PTR p)
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef SHORT_DBG_HDRS
|
#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 */
|
/* Check all marked objects in the given block for validity */
|
||||||
/*ARGSUSED*/
|
/*ARGSUSED*/
|
||||||
# if defined(__STDC__) || defined(__cplusplus)
|
# if defined(__STDC__) || defined(__cplusplus)
|
||||||
|
@ -802,11 +911,7 @@ void GC_debug_free_inner(GC_PTR p)
|
||||||
&& GC_HAS_DEBUG_INFO((ptr_t)p)) {
|
&& GC_HAS_DEBUG_INFO((ptr_t)p)) {
|
||||||
ptr_t clobbered = GC_check_annotated_obj((oh *)p);
|
ptr_t clobbered = GC_check_annotated_obj((oh *)p);
|
||||||
|
|
||||||
if (clobbered != 0) {
|
if (clobbered != 0) GC_add_smashed(clobbered);
|
||||||
GC_err_printf0(
|
|
||||||
"GC_check_heap_block: found smashed location at ");
|
|
||||||
GC_print_smashed_obj((ptr_t)p, clobbered);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
word_no += sz;
|
word_no += sz;
|
||||||
p += sz;
|
p += sz;
|
||||||
|
@ -819,9 +924,11 @@ void GC_debug_free_inner(GC_PTR p)
|
||||||
void GC_check_heap_proc()
|
void GC_check_heap_proc()
|
||||||
{
|
{
|
||||||
# ifndef SMALL_CONFIG
|
# ifndef SMALL_CONFIG
|
||||||
if (sizeof(oh) & (2 * sizeof(word) - 1) != 0) {
|
# ifdef ALIGN_DOUBLE
|
||||||
ABORT("Alignment problem: object header has inappropriate size\n");
|
GC_STATIC_ASSERT((sizeof(oh) & (2 * sizeof(word) - 1)) == 0);
|
||||||
}
|
# else
|
||||||
|
GC_STATIC_ASSERT((sizeof(oh) & (sizeof(word) - 1)) == 0);
|
||||||
|
# endif
|
||||||
# endif
|
# endif
|
||||||
GC_apply_to_all_blocks(GC_check_heap_block, (word)0);
|
GC_apply_to_all_blocks(GC_check_heap_block, (word)0);
|
||||||
}
|
}
|
||||||
|
@ -908,7 +1015,7 @@ GC_PTR *ocd;
|
||||||
ptr_t base = GC_base(obj);
|
ptr_t base = GC_base(obj);
|
||||||
if (0 == base || (ptr_t)obj - base != sizeof(oh)) {
|
if (0 == base || (ptr_t)obj - base != sizeof(oh)) {
|
||||||
GC_err_printf1(
|
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);
|
obj);
|
||||||
}
|
}
|
||||||
if (0 == fn) {
|
if (0 == fn) {
|
||||||
|
@ -940,7 +1047,7 @@ GC_PTR *ocd;
|
||||||
ptr_t base = GC_base(obj);
|
ptr_t base = GC_base(obj);
|
||||||
if (0 == base || (ptr_t)obj - base != sizeof(oh)) {
|
if (0 == base || (ptr_t)obj - base != sizeof(oh)) {
|
||||||
GC_err_printf1(
|
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);
|
obj);
|
||||||
}
|
}
|
||||||
if (0 == fn) {
|
if (0 == fn) {
|
||||||
|
@ -973,7 +1080,7 @@ GC_PTR *ocd;
|
||||||
ptr_t base = GC_base(obj);
|
ptr_t base = GC_base(obj);
|
||||||
if (0 == base || (ptr_t)obj - base != sizeof(oh)) {
|
if (0 == base || (ptr_t)obj - base != sizeof(oh)) {
|
||||||
GC_err_printf1(
|
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);
|
obj);
|
||||||
}
|
}
|
||||||
if (0 == fn) {
|
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) 1988, 1989 Hans-J. Boehm, Alan J. Demers
|
||||||
Copyright (c) 1991-1996 by Xerox Corporation. All rights reserved.
|
Copyright (c) 1991-1996 by Xerox Corporation. All rights reserved.
|
||||||
Copyright (c) 1996-1999 by Silicon Graphics. 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
|
The file linux_threads.c is also
|
||||||
Copyright (c) 1998 by Fergus Henderson. All rights reserved.
|
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
|
The files Makefile.am, and configure.in are
|
||||||
Copyright (c) 2001 by Red Hat Inc. All rights reserved.
|
Copyright (c) 2001 by Red Hat Inc. All rights reserved.
|
||||||
|
|
||||||
The files config.guess and a few others are copyrighted by the Free
|
Several files supporting GNU-style builds are copyrighted by the Free
|
||||||
Software Foundation.
|
Software Foundation, and carry a different license from that given
|
||||||
|
below.
|
||||||
|
|
||||||
THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
|
THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
|
||||||
OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
|
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
|
collector. (If you are concerned about such things, I recommend you look
|
||||||
at the notice in config.guess or ltmain.sh.)
|
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
|
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
|
or equivalent is supplied. Many of these have separate README.system
|
||||||
files.
|
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),
|
(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.
|
Linux, FreeBSD, NetBSD, IRIX 5&6, HP/UX, Win32 (not Win32S) and OSF/1
|
||||||
On other machines we recommend that you do one of the following:
|
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).
|
1) Add dynamic library support (and send us the code).
|
||||||
2) Use static versions of the libraries.
|
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
|
In all cases we assume that pointer alignment is consistent with that
|
||||||
enforced by the standard C compilers. If you use a nonstandard compiler
|
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.
|
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
|
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
|
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
|
See README.darwin for the latest Darwin/MacOSX information.
|
||||||
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).
|
|
||||||
|
|
|
@ -1469,8 +1469,439 @@ Since 6.1 alpha2:
|
||||||
- Caused the Solaris and Irix thread creation primitives to call
|
- Caused the Solaris and Irix thread creation primitives to call
|
||||||
GC_init_inner().
|
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:
|
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
|
- There seem to be outstanding issues on Solaris/X86, possibly with
|
||||||
finding the data segment starting address. Information/patches would
|
finding the data segment starting address. Information/patches would
|
||||||
be appreciated.
|
be appreciated.
|
||||||
|
@ -1488,7 +1919,4 @@ To do:
|
||||||
- Incremental collector should handle large objects better. Currently,
|
- Incremental collector should handle large objects better. Currently,
|
||||||
it looks like the whole object is treated as dirty if any part of it
|
it looks like the whole object is treated as dirty if any part of it
|
||||||
is.
|
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
|
GC_INITIAL_HEAP_SIZE=<bytes> - Initial heap size in bytes. May speed up
|
||||||
process start-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.
|
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
|
This may make it easier to debug, such a process, especially
|
||||||
for multithreaded platforms that don't produce usable core
|
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
|
by setting GC_quiet. On by default if the collector
|
||||||
was built without -DSILENT.
|
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
|
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
|
maps for the process, to stderr on every GC. Useful for
|
||||||
mapping root addresses to source for deciphering leak
|
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
|
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
|
that the GC should expect to use. Note that setting this to 1
|
||||||
when multiple processors are available will preserve
|
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
|
GC_NO_BLACKLIST_WARNING - Prevents the collector from issuing
|
||||||
warnings about allocations of very large blocks.
|
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
|
of Conservative Garbage Collectors", POPL 2001, or
|
||||||
http://lib.hpl.hp.com/techpubs/2001/HPL-2001-251.html .
|
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,
|
GC_ENABLE_INCREMENTAL - Turn on incremental collection at startup. Note that,
|
||||||
depending on platform and collector configuration, this
|
depending on platform and collector configuration, this
|
||||||
may involve write protecting pieces of the heap to
|
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.
|
Use with caution.
|
||||||
|
|
||||||
GC_PAUSE_TIME_TARGET - Set the desired garbage collector pause time in msecs.
|
GC_PAUSE_TIME_TARGET - Set the desired garbage collector pause time in msecs.
|
||||||
This only has an effect if incremental collection is enabled.
|
This only has an effect if incremental collection is
|
||||||
If a collection requires appreciably more time than this,
|
enabled. If a collection requires appreciably more time
|
||||||
the client will be restarted, and the collector will need
|
than this, the client will be restarted, and the collector
|
||||||
to do additional work to compensate. The special value
|
will need to do additional work to compensate. The
|
||||||
"999999" indicates that pause time is unlimited, and the
|
special value "999999" indicates that pause time is
|
||||||
incremental collector will behave completely like a
|
unlimited, and the incremental collector will behave
|
||||||
simple generational collector. If the collector is
|
completely like a simple generational collector. If
|
||||||
configured for parallel marking, and run on a multiprocessor,
|
the collector is configured for parallel marking, and
|
||||||
incremental collection should only be used with unlimited
|
run on a multiprocessor, incremental collection should
|
||||||
pause time.
|
only be used with unlimited pause time.
|
||||||
|
|
||||||
The following turn on runtime flags that are also program settable. Checked
|
GC_FIND_LEAK - Turns on GC_find_leak and thus leak detection. Forces a
|
||||||
only during initialization. We expect that they will usually be set through
|
collection at program termination to detect leaks that would
|
||||||
other means, but this may help with debugging and testing:
|
otherwise occur after the last GC.
|
||||||
|
|
||||||
GC_FIND_LEAK - Turns on GC_find_leak and thus leak detection.
|
|
||||||
|
|
||||||
GC_ALL_INTERIOR_POINTERS - Turns on GC_all_interior_pointers and thus interior
|
GC_ALL_INTERIOR_POINTERS - Turns on GC_all_interior_pointers and thus interior
|
||||||
pointer recognition.
|
pointer recognition.
|
||||||
|
|
|
@ -1,21 +1,18 @@
|
||||||
See README.alpha for Linux on DEC AXP info.
|
See README.alpha for Linux on DEC AXP info.
|
||||||
|
|
||||||
This file applies mostly to Linux/Intel IA32. Ports to Linux on an M68K
|
This file applies mostly to Linux/Intel IA32. Ports to Linux on an M68K, IA64,
|
||||||
and PowerPC are also integrated. They should behave similarly, except that
|
SPARC, MIPS, Alpha and PowerPC are also integrated. They should behave
|
||||||
the PowerPC port lacks incremental GC support, and it is unknown to what
|
similarly, except that the PowerPC port lacks incremental GC support, and
|
||||||
extent the Linux threads code is functional. See below for M68K specific
|
it is unknown to what extent the Linux threads code is functional.
|
||||||
notes.
|
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
|
Dynamic libraries are supported on an ELF system. A static executable
|
||||||
should be linked with the gcc option "-Wl,-defsym,_DYNAMIC=0".
|
should be linked with the gcc option "-Wl,-defsym,_DYNAMIC=0".
|
||||||
|
|
||||||
The collector appears to work with Linux threads. We have seen
|
The collector appears to work reliably with Linux threads, but beware
|
||||||
intermittent hangs in sem_wait. So far we have been unable to reproduce
|
of older versions of glibc and gdb.
|
||||||
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 garbage collector uses SIGPWR and SIGXCPU if it is used with
|
The garbage collector uses SIGPWR and SIGXCPU if it is used with
|
||||||
Linux threads. These should not be touched by the client program.
|
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
|
pointers. And the VirtualQuery call has different semantics under
|
||||||
the two systems, and under different versions of win32s.)
|
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,
|
The collector test program "gctest" is linked as a GUI application,
|
||||||
but does not open any windows. Its output appears in the file
|
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
|
"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.
|
not Windows 95/98) if the memory is later passed to CreateDIBitmap.
|
||||||
To work around this problem, build the collector with -DUSE_GLOBAL_ALLOC.
|
To work around this problem, build the collector with -DUSE_GLOBAL_ALLOC.
|
||||||
This is currently incompatible with -DUSE_MUNMAP. (Thanks to Jonathan
|
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
|
For Microsoft development tools, rename NT_MAKEFILE as
|
||||||
MAKEFILE. (Make sure that the CPU environment variable is defined
|
MAKEFILE. (Make sure that the CPU environment variable is defined
|
||||||
to be i386.) In order to use the gc_cpp.h C++ interface, all
|
to be i386.) In order to use the gc_cpp.h C++ interface, all
|
||||||
client code should include gc_cpp.h.
|
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
|
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
|
collector was built as a static library (as it normally is in the
|
||||||
absence of thread support).
|
absence of thread support).
|
||||||
|
@ -64,7 +78,7 @@ absence of thread support).
|
||||||
For GNU-win32, use the regular makefile, possibly after uncommenting
|
For GNU-win32, use the regular makefile, possibly after uncommenting
|
||||||
the line "include Makefile.DLLs". The latter should be necessary only
|
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
|
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
|
in b19. This is probably fixable with a different definition of
|
||||||
DATASTART and DATAEND in gcconfig.h.
|
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.
|
All programs using gc should be compiled with 4-byte alignment.
|
||||||
For further explanations on this see comments about Borland.
|
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
|
including "gc.h" (for example, with -DGC_DLL compiler option). It's
|
||||||
important, otherwise resulting programs will not run.
|
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.
|
during which its block was last swept.
|
||||||
<LI> Verify that the offending object still has its correct contents at
|
<LI> Verify that the offending object still has its correct contents at
|
||||||
this point.
|
this point.
|
||||||
The call <TT>GC_is_marked(p)</tt> from the debugger to verify that the
|
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.
|
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
|
<LI> Determine a path from a root, i.e. static variable, stack, or
|
||||||
register variable,
|
register variable,
|
||||||
to the reclaimed object. Call <TT>GC_is_marked(q)</tt> for each object
|
to the reclaimed object. Call <TT>GC_is_marked(q)</tt> for each object
|
||||||
|
|
|
@ -55,9 +55,10 @@
|
||||||
!defined(MSWIN32) && !defined(MSWINCE) && \
|
!defined(MSWIN32) && !defined(MSWINCE) && \
|
||||||
!(defined(ALPHA) && defined(OSF1)) && \
|
!(defined(ALPHA) && defined(OSF1)) && \
|
||||||
!defined(HPUX) && !(defined(LINUX) && defined(__ELF__)) && \
|
!defined(HPUX) && !(defined(LINUX) && defined(__ELF__)) && \
|
||||||
!defined(RS6000) && !defined(SCO_ELF) && \
|
!defined(RS6000) && !defined(SCO_ELF) && !defined(DGUX) && \
|
||||||
!(defined(FREEBSD) && defined(__ELF__)) && \
|
!(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
|
--> We only know how to find data segments of dynamic libraries for the
|
||||||
--> above. Additional SVR4 variants might not be too
|
--> above. Additional SVR4 variants might not be too
|
||||||
--> hard to add.
|
--> hard to add.
|
||||||
|
@ -80,7 +81,7 @@
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(LINUX) && defined(__ELF__) || defined(SCO_ELF) || \
|
#if defined(LINUX) && defined(__ELF__) || defined(SCO_ELF) || \
|
||||||
(defined(FREEBSD) && defined(__ELF__)) || \
|
(defined(FREEBSD) && defined(__ELF__)) || defined(DGUX) || \
|
||||||
(defined(NETBSD) && defined(__ELF__)) || defined(HURD)
|
(defined(NETBSD) && defined(__ELF__)) || defined(HURD)
|
||||||
# include <stddef.h>
|
# include <stddef.h>
|
||||||
# include <elf.h>
|
# include <elf.h>
|
||||||
|
@ -264,7 +265,7 @@ void GC_register_dynamic_libraries()
|
||||||
# endif /* SUNOS */
|
# endif /* SUNOS */
|
||||||
|
|
||||||
#if defined(LINUX) && defined(__ELF__) || defined(SCO_ELF) || \
|
#if defined(LINUX) && defined(__ELF__) || defined(SCO_ELF) || \
|
||||||
(defined(FREEBSD) && defined(__ELF__)) || \
|
(defined(FREEBSD) && defined(__ELF__)) || defined(DGUX) || \
|
||||||
(defined(NETBSD) && defined(__ELF__)) || defined(HURD)
|
(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 */
|
/* Repeatedly read until buffer is filled, or EOF is encountered */
|
||||||
/* Defined in os_dep.c. */
|
/* Defined in os_dep.c. */
|
||||||
|
|
||||||
static char *parse_map_entry(char *buf_ptr, word *start, word *end,
|
char *GC_parse_map_entry(char *buf_ptr, word *start, word *end,
|
||||||
char *prot_buf, unsigned int *maj_dev);
|
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];
|
char prot_buf[5];
|
||||||
int maps_size;
|
char *buf_ptr = maps;
|
||||||
char maps_temp[32768];
|
|
||||||
char *maps_buf;
|
|
||||||
char *buf_ptr;
|
|
||||||
int count;
|
int count;
|
||||||
word start, end;
|
word start, end;
|
||||||
unsigned int maj_dev, min_dev;
|
unsigned int maj_dev;
|
||||||
word least_ha, greatest_ha;
|
word least_ha, greatest_ha;
|
||||||
unsigned i;
|
unsigned i;
|
||||||
word datastart = (word)(DATASTART);
|
word datastart = (word)(DATASTART);
|
||||||
|
|
||||||
/* Read /proc/self/maps */
|
/* Compute heap bounds. FIXME: Should be done by add_to_heap? */
|
||||||
/* Note that we may not allocate, and thus can't use stdio. */
|
|
||||||
f = open("/proc/self/maps", O_RDONLY);
|
|
||||||
if (-1 == f) ABORT("Couldn't open /proc/self/maps");
|
|
||||||
/* stat() doesn't work for /proc/self/maps, so we have to
|
|
||||||
read it to find out how large it is... */
|
|
||||||
maps_size = 0;
|
|
||||||
do {
|
|
||||||
result = GC_repeat_read(f, maps_temp, sizeof(maps_temp));
|
|
||||||
if (result <= 0) ABORT("Couldn't read /proc/self/maps");
|
|
||||||
maps_size += result;
|
|
||||||
} while (result == sizeof(maps_temp));
|
|
||||||
|
|
||||||
if (maps_size > sizeof(maps_temp)) {
|
|
||||||
/* If larger than our buffer, close and re-read it. */
|
|
||||||
close(f);
|
|
||||||
f = open("/proc/self/maps", O_RDONLY);
|
|
||||||
if (-1 == f) ABORT("Couldn't open /proc/self/maps");
|
|
||||||
maps_buf = alloca(maps_size);
|
|
||||||
if (NULL == maps_buf) ABORT("/proc/self/maps alloca failed");
|
|
||||||
result = GC_repeat_read(f, maps_buf, maps_size);
|
|
||||||
if (result <= 0) ABORT("Couldn't read /proc/self/maps");
|
|
||||||
} else {
|
|
||||||
/* Otherwise use the fixed size buffer */
|
|
||||||
maps_buf = maps_temp;
|
|
||||||
}
|
|
||||||
|
|
||||||
close(f);
|
|
||||||
maps_buf[result] = '\0';
|
|
||||||
buf_ptr = maps_buf;
|
|
||||||
/* Compute heap bounds. Should be done by add_to_heap? */
|
|
||||||
least_ha = (word)(-1);
|
least_ha = (word)(-1);
|
||||||
greatest_ha = 0;
|
greatest_ha = 0;
|
||||||
for (i = 0; i < GC_n_heap_sects; ++i) {
|
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)
|
if (greatest_ha < (word)GC_scratch_last_end_ptr)
|
||||||
greatest_ha = (word)GC_scratch_last_end_ptr;
|
greatest_ha = (word)GC_scratch_last_end_ptr;
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
|
buf_ptr = GC_parse_map_entry(buf_ptr, &start, &end, prot_buf, &maj_dev);
|
||||||
buf_ptr = parse_map_entry(buf_ptr, &start, &end, prot_buf, &maj_dev);
|
if (buf_ptr == NULL) return 1;
|
||||||
if (buf_ptr == NULL) return;
|
|
||||||
|
|
||||||
if (prot_buf[1] == 'w') {
|
if (prot_buf[1] == 'w') {
|
||||||
/* This is a writable mapping. Add it to */
|
/* This is a writable mapping. Add it to */
|
||||||
/* the root set unless it is already otherwise */
|
/* the root set unless it is already otherwise */
|
||||||
|
@ -358,16 +325,7 @@ void GC_register_dynamic_libraries()
|
||||||
# ifdef THREADS
|
# ifdef THREADS
|
||||||
if (GC_segment_is_thread_stack(start, end)) continue;
|
if (GC_segment_is_thread_stack(start, end)) continue;
|
||||||
# endif
|
# endif
|
||||||
/* The rest of this assumes that there is no mapping */
|
/* We no longer exclude the main data segment. */
|
||||||
/* spanning the beginning of the data segment, or extending */
|
|
||||||
/* beyond the entire heap at both ends. */
|
|
||||||
/* Empirically these assumptions hold. */
|
|
||||||
|
|
||||||
if (start < (word)DATAEND && end > (word)DATAEND) {
|
|
||||||
/* Rld may use space at the end of the main data */
|
|
||||||
/* segment. Thus we add that in. */
|
|
||||||
start = (word)DATAEND;
|
|
||||||
}
|
|
||||||
if (start < least_ha && end > least_ha) {
|
if (start < least_ha && end > least_ha) {
|
||||||
end = least_ha;
|
end = least_ha;
|
||||||
}
|
}
|
||||||
|
@ -378,6 +336,13 @@ void GC_register_dynamic_libraries()
|
||||||
GC_add_roots_inner((char *)start, (char *)end, TRUE);
|
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: */
|
/* 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
|
# 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 */
|
#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);
|
GC_add_roots_inner(DATASTART2, (char *)(DATAEND2), TRUE);
|
||||||
# endif
|
# endif
|
||||||
}
|
}
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
} else {
|
} else {
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
@ -534,6 +446,16 @@ GC_bool GC_register_main_static_data()
|
||||||
|
|
||||||
#if defined(NETBSD)
|
#if defined(NETBSD)
|
||||||
# include <sys/exec_elf.h>
|
# 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
|
#else
|
||||||
# include <elf.h>
|
# include <elf.h>
|
||||||
#endif
|
#endif
|
||||||
|
@ -1048,7 +970,7 @@ void GC_register_dynamic_libraries()
|
||||||
len = ldi->ldinfo_next;
|
len = ldi->ldinfo_next;
|
||||||
GC_add_roots_inner(
|
GC_add_roots_inner(
|
||||||
ldi->ldinfo_dataorg,
|
ldi->ldinfo_dataorg,
|
||||||
(unsigned long)ldi->ldinfo_dataorg
|
(ptr_t)(unsigned long)ldi->ldinfo_dataorg
|
||||||
+ ldi->ldinfo_datasize,
|
+ ldi->ldinfo_datasize,
|
||||||
TRUE);
|
TRUE);
|
||||||
ldi = len ? (struct ld_info *)((char *)ldi + len) : 0;
|
ldi = len ? (struct ld_info *)((char *)ldi + len) : 0;
|
||||||
|
@ -1056,7 +978,133 @@ void GC_register_dynamic_libraries()
|
||||||
}
|
}
|
||||||
#endif /* RS6000 */
|
#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 */
|
#else /* !DYNAMIC_LOADING */
|
||||||
|
|
||||||
|
|
|
@ -207,7 +207,8 @@ signed_word * log_size_ptr;
|
||||||
UNLOCK();
|
UNLOCK();
|
||||||
ENABLE_SIGNALS();
|
ENABLE_SIGNALS();
|
||||||
# endif
|
# 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) {
|
if (0 == new_dl) {
|
||||||
GC_finalization_failures++;
|
GC_finalization_failures++;
|
||||||
return(0);
|
return(0);
|
||||||
|
@ -433,7 +434,8 @@ finalization_mark_proc * mp;
|
||||||
UNLOCK();
|
UNLOCK();
|
||||||
ENABLE_SIGNALS();
|
ENABLE_SIGNALS();
|
||||||
# endif
|
# 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) {
|
if (0 == new_fo) {
|
||||||
GC_finalization_failures++;
|
GC_finalization_failures++;
|
||||||
return;
|
return;
|
||||||
|
@ -759,8 +761,9 @@ int GC_should_invoke_finalizers GC_PROTO((void))
|
||||||
/* Should be called without allocation lock. */
|
/* Should be called without allocation lock. */
|
||||||
int GC_invoke_finalizers()
|
int GC_invoke_finalizers()
|
||||||
{
|
{
|
||||||
register struct finalizable_object * curr_fo;
|
struct finalizable_object * curr_fo;
|
||||||
register int count = 0;
|
int count = 0;
|
||||||
|
word mem_freed_before;
|
||||||
DCL_LOCK_STATE;
|
DCL_LOCK_STATE;
|
||||||
|
|
||||||
while (GC_finalize_now != 0) {
|
while (GC_finalize_now != 0) {
|
||||||
|
@ -768,6 +771,9 @@ int GC_invoke_finalizers()
|
||||||
DISABLE_SIGNALS();
|
DISABLE_SIGNALS();
|
||||||
LOCK();
|
LOCK();
|
||||||
# endif
|
# endif
|
||||||
|
if (count == 0) {
|
||||||
|
mem_freed_before = GC_mem_freed;
|
||||||
|
}
|
||||||
curr_fo = GC_finalize_now;
|
curr_fo = GC_finalize_now;
|
||||||
# ifdef THREADS
|
# ifdef THREADS
|
||||||
if (curr_fo != 0) GC_finalize_now = fo_next(curr_fo);
|
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);
|
GC_free((GC_PTR)curr_fo);
|
||||||
# endif
|
# endif
|
||||||
}
|
}
|
||||||
|
if (count != 0 && mem_freed_before != GC_mem_freed) {
|
||||||
|
LOCK();
|
||||||
|
GC_finalizer_mem_freed += (GC_mem_freed - mem_freed_before);
|
||||||
|
UNLOCK();
|
||||||
|
}
|
||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -801,7 +812,9 @@ void GC_notify_or_invoke_finalizers GC_PROTO((void))
|
||||||
if (GC_finalize_now == 0) return;
|
if (GC_finalize_now == 0) return;
|
||||||
if (!GC_finalize_on_demand) {
|
if (!GC_finalize_on_demand) {
|
||||||
(void) GC_invoke_finalizers();
|
(void) GC_invoke_finalizers();
|
||||||
|
# ifndef THREADS
|
||||||
GC_ASSERT(GC_finalize_now == 0);
|
GC_ASSERT(GC_finalize_now == 0);
|
||||||
|
# endif /* Otherwise GC can run concurrently and add more */
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (GC_finalizer_notifier != (void (*) GC_PROTO((void)))0
|
if (GC_finalizer_notifier != (void (*) GC_PROTO((void)))0
|
||||||
|
@ -839,3 +852,17 @@ void GC_notify_or_invoke_finalizers GC_PROTO((void))
|
||||||
return(result);
|
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"
|
#include "gc_cpp.h"
|
||||||
|
|
||||||
#ifndef _MSC_VER
|
|
||||||
/* In the Visual C++ case, we moved this into the header. */
|
|
||||||
void* operator new( size_t size ) {
|
void* operator new( size_t size ) {
|
||||||
return GC_MALLOC_UNCOLLECTABLE( size );}
|
return GC_MALLOC_UNCOLLECTABLE( size );}
|
||||||
|
|
||||||
void operator delete( void* obj ) {
|
void operator delete( void* obj ) {
|
||||||
GC_FREE( obj );}
|
GC_FREE( obj );}
|
||||||
|
|
||||||
#ifdef OPERATOR_NEW_ARRAY
|
#ifdef GC_OPERATOR_NEW_ARRAY
|
||||||
|
|
||||||
void* operator new[]( size_t size ) {
|
void* operator new[]( size_t size ) {
|
||||||
return GC_MALLOC_UNCOLLECTABLE( size );}
|
return GC_MALLOC_UNCOLLECTABLE( size );}
|
||||||
|
@ -42,8 +40,22 @@ void* operator new[]( size_t size ) {
|
||||||
void operator delete[]( void* obj ) {
|
void operator delete[]( void* obj ) {
|
||||||
GC_FREE( 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 */
|
#endif /* _MSC_VER */
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -19,12 +19,14 @@
|
||||||
/*
|
/*
|
||||||
* This used to be in dyn_load.c. It was extracted into a separate file
|
* 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
|
* 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"
|
#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)
|
# if defined(dlopen) && !defined(GC_USE_LD_WRAP)
|
||||||
/* To support various threads pkgs, gc.h interposes on dlopen by */
|
/* 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 */
|
/* calls in either a multithreaded environment, or if the library */
|
||||||
/* initialization code allocates substantial amounts of GC'ed memory. */
|
/* initialization code allocates substantial amounts of GC'ed memory. */
|
||||||
/* But I don't know of a better solution. */
|
/* But I don't know of a better solution. */
|
||||||
/* This can still deadlock if the client explicitly starts a GC */
|
static void disable_gc_for_dlopen()
|
||||||
/* during the dlopen. He shouldn't do that. */
|
|
||||||
static GC_bool disable_gc_for_dlopen()
|
|
||||||
{
|
{
|
||||||
GC_bool result;
|
|
||||||
LOCK();
|
LOCK();
|
||||||
result = GC_dont_gc;
|
|
||||||
while (GC_incremental && GC_collection_in_progress()) {
|
while (GC_incremental && GC_collection_in_progress()) {
|
||||||
GC_collect_a_little_inner(1000);
|
GC_collect_a_little_inner(1000);
|
||||||
}
|
}
|
||||||
GC_dont_gc = TRUE;
|
++GC_dont_gc;
|
||||||
UNLOCK();
|
UNLOCK();
|
||||||
return(result);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Redefine dlopen to guarantee mutual exclusion with */
|
/* Redefine dlopen to guarantee mutual exclusion with */
|
||||||
|
@ -74,10 +71,9 @@
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
void * result;
|
void * result;
|
||||||
GC_bool dont_gc_save;
|
|
||||||
|
|
||||||
# ifndef USE_PROC_FOR_LIBRARIES
|
# ifndef USE_PROC_FOR_LIBRARIES
|
||||||
dont_gc_save = disable_gc_for_dlopen();
|
disable_gc_for_dlopen();
|
||||||
# endif
|
# endif
|
||||||
# ifdef GC_USE_LD_WRAP
|
# ifdef GC_USE_LD_WRAP
|
||||||
result = (void *)__real_dlopen(path, mode);
|
result = (void *)__real_dlopen(path, mode);
|
||||||
|
@ -85,7 +81,7 @@
|
||||||
result = dlopen(path, mode);
|
result = dlopen(path, mode);
|
||||||
# endif
|
# endif
|
||||||
# ifndef USE_PROC_FOR_LIBRARIES
|
# ifndef USE_PROC_FOR_LIBRARIES
|
||||||
GC_dont_gc = dont_gc_save;
|
GC_enable(); /* undoes disable_gc_for_dlopen */
|
||||||
# endif
|
# endif
|
||||||
return(result);
|
return(result);
|
||||||
}
|
}
|
||||||
|
|
|
@ -157,6 +157,7 @@ DCL_LOCK_STATE;
|
||||||
GC_words_allocd += lw;
|
GC_words_allocd += lw;
|
||||||
}
|
}
|
||||||
*(void **)op = ptr_to_struct_containing_descr;
|
*(void **)op = ptr_to_struct_containing_descr;
|
||||||
|
GC_ASSERT(((void **)op)[1] == 0);
|
||||||
UNLOCK();
|
UNLOCK();
|
||||||
} else {
|
} else {
|
||||||
LOCK();
|
LOCK();
|
||||||
|
|
|
@ -14,7 +14,7 @@ char ** envp;
|
||||||
if (strcmp(MACH_TYPE, argv[1]) != 0) return(0);
|
if (strcmp(MACH_TYPE, argv[1]) != 0) return(0);
|
||||||
if (strcmp(OS_TYPE, "") != 0 && strcmp(argv[2], "") != 0
|
if (strcmp(OS_TYPE, "") != 0 && strcmp(argv[2], "") != 0
|
||||||
&& strcmp(OS_TYPE, argv[2]) != 0) return(0);
|
&& strcmp(OS_TYPE, argv[2]) != 0) return(0);
|
||||||
printf("^^^^Starting command^^^^\n");
|
fprintf(stderr, "^^^^Starting command^^^^\n");
|
||||||
fflush(stdout);
|
fflush(stdout);
|
||||||
execvp(argv[3], argv+3);
|
execvp(argv[3], argv+3);
|
||||||
perror("Couldn't execute");
|
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
|
# This Makefile.in is free software; the Free Software Foundation
|
||||||
# gives unlimited permission to copy and/or distribute it,
|
# gives unlimited permission to copy and/or distribute it,
|
||||||
# with or without modifications, as long as this notice is preserved.
|
# with or without modifications, as long as this notice is preserved.
|
||||||
|
@ -66,9 +66,11 @@ target_triplet = @target@
|
||||||
AR = @AR@
|
AR = @AR@
|
||||||
AS = @AS@
|
AS = @AS@
|
||||||
CC = @CC@
|
CC = @CC@
|
||||||
|
CFLAGS = @CFLAGS@
|
||||||
CPP = @CPP@
|
CPP = @CPP@
|
||||||
CXX = @CXX@
|
CXX = @CXX@
|
||||||
CXXCPP = @CXXCPP@
|
CXXCPP = @CXXCPP@
|
||||||
|
CXXFLAGS = @CXXFLAGS@
|
||||||
CXXINCLUDES = @CXXINCLUDES@
|
CXXINCLUDES = @CXXINCLUDES@
|
||||||
DLLTOOL = @DLLTOOL@
|
DLLTOOL = @DLLTOOL@
|
||||||
EXEEXT = @EXEEXT@
|
EXEEXT = @EXEEXT@
|
||||||
|
@ -89,10 +91,15 @@ RANLIB = @RANLIB@
|
||||||
STRIP = @STRIP@
|
STRIP = @STRIP@
|
||||||
THREADLIBS = @THREADLIBS@
|
THREADLIBS = @THREADLIBS@
|
||||||
VERSION = @VERSION@
|
VERSION = @VERSION@
|
||||||
|
addincludes = @addincludes@
|
||||||
|
addlibs = @addlibs@
|
||||||
addobjs = @addobjs@
|
addobjs = @addobjs@
|
||||||
|
addtests = @addtests@
|
||||||
gc_basedir = @gc_basedir@
|
gc_basedir = @gc_basedir@
|
||||||
mkinstalldirs = @mkinstalldirs@
|
mkinstalldirs = @mkinstalldirs@
|
||||||
target_all = @target_all@
|
target_all = @target_all@
|
||||||
|
toolexecdir = @toolexecdir@
|
||||||
|
toolexeclibdir = @toolexeclibdir@
|
||||||
|
|
||||||
AUTOMAKE_OPTIONS = foreign
|
AUTOMAKE_OPTIONS = foreign
|
||||||
|
|
||||||
|
|
|
@ -30,91 +30,7 @@
|
||||||
|
|
||||||
# define _GC_H
|
# define _GC_H
|
||||||
|
|
||||||
/*
|
# include "gc_config_macros.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
|
|
||||||
|
|
||||||
# if defined(__STDC__) || defined(__cplusplus)
|
# if defined(__STDC__) || defined(__cplusplus)
|
||||||
# define GC_PROTO(args) args
|
# 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 */
|
/* Env variable GC_NPROC is set to > 1, or */
|
||||||
/* GC_NPROC is not set and this is an MP. */
|
/* GC_NPROC is not set and this is an MP. */
|
||||||
/* If GC_parallel is set, incremental */
|
/* If GC_parallel is set, incremental */
|
||||||
/* collection is aonly partially functional, */
|
/* collection is only partially functional, */
|
||||||
/* and may not be desirable. */
|
/* and may not be desirable. */
|
||||||
|
|
||||||
|
|
||||||
|
@ -215,8 +131,14 @@ GC_API void (* GC_finalizer_notifier)();
|
||||||
/* thread, which will call GC_invoke_finalizers */
|
/* thread, which will call GC_invoke_finalizers */
|
||||||
/* in response. */
|
/* in response. */
|
||||||
|
|
||||||
GC_API int GC_dont_gc; /* Dont collect unless explicitly requested, e.g. */
|
GC_API int GC_dont_gc; /* != 0 ==> Dont collect. In versions 6.2a1+, */
|
||||||
/* because it's not safe. */
|
/* 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;
|
GC_API int GC_dont_expand;
|
||||||
/* Dont expand heap unless explicitly requested */
|
/* Dont expand heap unless explicitly requested */
|
||||||
|
@ -316,9 +238,18 @@ GC_API unsigned long GC_time_limit;
|
||||||
/* enabled. */
|
/* enabled. */
|
||||||
# define GC_TIME_UNLIMITED 999999
|
# define GC_TIME_UNLIMITED 999999
|
||||||
/* Setting GC_time_limit to this value */
|
/* Setting GC_time_limit to this value */
|
||||||
/* will disable the "pause time exceeded */
|
/* will disable the "pause time exceeded"*/
|
||||||
/* tests. */
|
/* 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.
|
* general purpose allocation routines, with roughly malloc calling conv.
|
||||||
* The atomic versions promise that no relevant pointers are contained
|
* 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,
|
GC_API void GC_add_roots GC_PROTO((char * low_address,
|
||||||
char * high_address_plus_1));
|
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 */
|
/* Add a displacement to the set of those considered valid by the */
|
||||||
/* collector. GC_register_displacement(n) means that if p was returned */
|
/* 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 */
|
/* 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 */
|
/* (All pointers to the interior of objects from the stack are */
|
||||||
/* considered valid in any case. This applies to heap objects and */
|
/* considered valid in any case. This applies to heap objects and */
|
||||||
/* static data.) */
|
/* static data.) */
|
||||||
/* Preferably, this should be called before any other GC procedures. */
|
/* Preferably, this should be called before any other GC procedures. */
|
||||||
/* Calling it later adds to the probability of excess memory */
|
/* Calling it later adds to the probability of excess memory */
|
||||||
/* retention. */
|
/* 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. */
|
/* arbitrary interior pointers enabled, which is now the default. */
|
||||||
GC_API void GC_register_displacement GC_PROTO((GC_word n));
|
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));
|
GC_API size_t GC_get_bytes_since_gc GC_PROTO((void));
|
||||||
|
|
||||||
/* Return the total number of bytes allocated in this process. */
|
/* 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));
|
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. */
|
/* Enable incremental/generational collection. */
|
||||||
/* Not advisable unless dirty bits are */
|
/* Not advisable unless dirty bits are */
|
||||||
/* available or most heap objects 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. */
|
/* Don't use in leak finding mode. */
|
||||||
/* Ignored if GC_dont_gc is true. */
|
/* Ignored if GC_dont_gc is true. */
|
||||||
/* Only the generational piece of this is */
|
/* 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));
|
GC_API void GC_enable_incremental GC_PROTO((void));
|
||||||
|
|
||||||
/* Does incremental mode write-protect pages? Returns zero or */
|
/* 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
|
# define GC_RETURN_ADDR (GC_word)__return_address
|
||||||
#endif
|
#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
|
#ifdef GC_ADD_CALLER
|
||||||
# define GC_EXTRAS GC_RETURN_ADDR, __FILE__, __LINE__
|
# define GC_EXTRAS GC_RETURN_ADDR, __FILE__, __LINE__
|
||||||
# define GC_EXTRA_PARAMS GC_word ra, GC_CONST char * s, int i
|
# 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_PROTO((size_t size_in_bytes, GC_EXTRA_PARAMS));
|
||||||
GC_API GC_PTR GC_debug_malloc_stubborn
|
GC_API GC_PTR GC_debug_malloc_stubborn
|
||||||
GC_PROTO((size_t size_in_bytes, GC_EXTRA_PARAMS));
|
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 void GC_debug_free GC_PROTO((GC_PTR object_addr));
|
||||||
GC_API GC_PTR GC_debug_realloc
|
GC_API GC_PTR GC_debug_realloc
|
||||||
GC_PROTO((GC_PTR old_object, size_t new_size_in_bytes,
|
GC_PROTO((GC_PTR old_object, size_t new_size_in_bytes,
|
||||||
GC_EXTRA_PARAMS));
|
GC_EXTRA_PARAMS));
|
||||||
|
|
||||||
GC_API void GC_debug_change_stubborn GC_PROTO((GC_PTR));
|
GC_API void GC_debug_change_stubborn GC_PROTO((GC_PTR));
|
||||||
GC_API void GC_debug_end_stubborn_change 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
|
# ifdef GC_DEBUG
|
||||||
# define GC_MALLOC(sz) GC_debug_malloc(sz, GC_EXTRAS)
|
# 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_ATOMIC(sz) GC_debug_malloc_atomic(sz, GC_EXTRAS)
|
||||||
# define GC_MALLOC_UNCOLLECTABLE(sz) GC_debug_malloc_uncollectable(sz, \
|
# define GC_MALLOC_UNCOLLECTABLE(sz) \
|
||||||
GC_EXTRAS)
|
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_REALLOC(old, sz) GC_debug_realloc(old, sz, GC_EXTRAS)
|
||||||
# define GC_FREE(p) GC_debug_free(p)
|
# define GC_FREE(p) GC_debug_free(p)
|
||||||
# define GC_REGISTER_FINALIZER(p, f, d, of, od) \
|
# 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(sz) GC_malloc(sz)
|
||||||
# define GC_MALLOC_ATOMIC(sz) GC_malloc_atomic(sz)
|
# define GC_MALLOC_ATOMIC(sz) GC_malloc_atomic(sz)
|
||||||
# define GC_MALLOC_UNCOLLECTABLE(sz) GC_malloc_uncollectable(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_REALLOC(old, sz) GC_realloc(old, sz)
|
||||||
# define GC_FREE(p) GC_free(p)
|
# define GC_FREE(p) GC_free(p)
|
||||||
# define GC_REGISTER_FINALIZER(p, f, d, of, od) \
|
# 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, */
|
/* itself. There is a stylistic argument that this is wrong, */
|
||||||
/* but it's unavoidable for C++, since the compiler may */
|
/* but it's unavoidable for C++, since the compiler may */
|
||||||
/* silently introduce these. It's also benign in that specific */
|
/* 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 */
|
/* Note that cd will still be viewed as accessible, even if it */
|
||||||
/* refers to the object itself. */
|
/* refers to the object itself. */
|
||||||
GC_API void GC_register_finalizer_ignore_self
|
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 */
|
/* Undoes a registration by either of the above two */
|
||||||
/* routines. */
|
/* 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. */
|
/* Returns !=0 if GC_invoke_finalizers has something to do. */
|
||||||
GC_API int GC_should_invoke_finalizers GC_PROTO((void));
|
GC_API int GC_should_invoke_finalizers GC_PROTO((void));
|
||||||
|
|
||||||
|
@ -739,6 +747,10 @@ 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));
|
GC_API GC_warn_proc GC_set_warn_proc GC_PROTO((GC_warn_proc p));
|
||||||
/* Returns old warning procedure. */
|
/* 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 */
|
/* The following is intended to be used by a higher level */
|
||||||
/* (e.g. Java-like) finalization facility. It is expected */
|
/* (e.g. Java-like) finalization facility. It is expected */
|
||||||
/* that finalization code will arrange for hidden pointers to */
|
/* that finalization code will arrange for hidden pointers to */
|
||||||
|
@ -873,14 +885,17 @@ extern void GC_thr_init(); /* Needed for Solaris/X86 */
|
||||||
|
|
||||||
#endif /* THREADS && !SRC_M3 */
|
#endif /* THREADS && !SRC_M3 */
|
||||||
|
|
||||||
#if defined(GC_WIN32_THREADS)
|
#if defined(GC_WIN32_THREADS) && !defined(__CYGWIN32__) && !defined(__CYGWIN__)
|
||||||
# include <windows.h>
|
# include <windows.h>
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* All threads must be created using GC_CreateThread, so that they will be
|
* 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,
|
LPSECURITY_ATTRIBUTES lpThreadAttributes,
|
||||||
DWORD dwStackSize, LPTHREAD_START_ROUTINE lpStartAddress,
|
DWORD dwStackSize, LPTHREAD_START_ROUTINE lpStartAddress,
|
||||||
LPVOID lpParameter, DWORD dwCreationFlags, LPDWORD lpThreadId );
|
LPVOID lpParameter, DWORD dwCreationFlags, LPDWORD lpThreadId );
|
||||||
|
@ -902,7 +917,7 @@ extern void GC_thr_init(); /* Needed for Solaris/X86 */
|
||||||
# endif
|
# endif
|
||||||
# endif /* defined(_WIN32_WCE) */
|
# endif /* defined(_WIN32_WCE) */
|
||||||
|
|
||||||
#endif /* defined(GC_WIN32_THREADS) */
|
#endif /* defined(GC_WIN32_THREADS) && !cygwin */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If you are planning on putting
|
* If you are planning on putting
|
||||||
|
@ -914,15 +929,20 @@ extern void GC_thr_init(); /* Needed for Solaris/X86 */
|
||||||
# define GC_INIT() { extern end, etext; \
|
# define GC_INIT() { extern end, etext; \
|
||||||
GC_noop(&end, &etext); }
|
GC_noop(&end, &etext); }
|
||||||
#else
|
#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); }
|
# define GC_INIT() { GC_add_roots(DATASTART, DATAEND); }
|
||||||
# else
|
# else
|
||||||
|
# if defined(__APPLE__) && defined(__MACH__)
|
||||||
|
# define GC_INIT() { GC_init(); }
|
||||||
|
# else
|
||||||
# define GC_INIT()
|
# define GC_INIT()
|
||||||
# endif
|
# endif
|
||||||
# endif
|
# endif
|
||||||
|
#endif
|
||||||
|
|
||||||
#if !defined(_WIN32_WCE) \
|
#if !defined(_WIN32_WCE) \
|
||||||
&& ((defined(_MSDOS) || defined(_MSC_VER)) && (_M_IX86 >= 300) \
|
&& ((defined(_MSDOS) || defined(_MSC_VER)) && (_M_IX86 >= 300) \
|
||||||
|
|
|
@ -134,7 +134,9 @@ by UseGC. GC is an alias for UseGC, unless GC_NAME_CONFLICT is defined.
|
||||||
#include "gc.h"
|
#include "gc.h"
|
||||||
|
|
||||||
#ifndef THINK_CPLUS
|
#ifndef THINK_CPLUS
|
||||||
#define _cdecl
|
# define GC_cdecl
|
||||||
|
#else
|
||||||
|
# define GC_cdecl _cdecl
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if ! defined( GC_NO_OPERATOR_NEW_ARRAY ) \
|
#if ! defined( GC_NO_OPERATOR_NEW_ARRAY ) \
|
||||||
|
@ -159,12 +161,22 @@ enum GCPlacement {UseGC,
|
||||||
class gc {public:
|
class gc {public:
|
||||||
inline void* operator new( size_t size );
|
inline void* operator new( size_t size );
|
||||||
inline void* operator new( size_t size, GCPlacement gcp );
|
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 );
|
inline void operator delete( void* obj );
|
||||||
|
# ifndef __BORLANDC__ /* Confuses the Borland compiler. */
|
||||||
|
inline void operator delete( void*, void* );
|
||||||
|
# endif
|
||||||
|
|
||||||
#ifdef GC_OPERATOR_NEW_ARRAY
|
#ifdef GC_OPERATOR_NEW_ARRAY
|
||||||
inline void* operator new[]( size_t size );
|
inline void* operator new[]( size_t size );
|
||||||
inline void* operator new[]( size_t size, GCPlacement gcp );
|
inline void* operator new[]( size_t size, GCPlacement gcp );
|
||||||
|
inline void* operator new[]( size_t size, void *p );
|
||||||
inline void operator delete[]( void* obj );
|
inline void operator delete[]( void* obj );
|
||||||
|
# ifndef __BORLANDC__
|
||||||
|
inline void gc::operator delete[]( void*, void* );
|
||||||
|
# endif
|
||||||
#endif /* GC_OPERATOR_NEW_ARRAY */
|
#endif /* GC_OPERATOR_NEW_ARRAY */
|
||||||
};
|
};
|
||||||
/*
|
/*
|
||||||
|
@ -176,7 +188,7 @@ class gc_cleanup: virtual public gc {public:
|
||||||
inline gc_cleanup();
|
inline gc_cleanup();
|
||||||
inline virtual ~gc_cleanup();
|
inline virtual ~gc_cleanup();
|
||||||
private:
|
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
|
Instances of classes derived from "gc_cleanup" will be allocated
|
||||||
in the collected heap by default. When the collector discovers an
|
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
|
classes derived from "gc_cleanup" or containing members derived
|
||||||
from "gc_cleanup". */
|
from "gc_cleanup". */
|
||||||
|
|
||||||
#ifdef GC_OPERATOR_NEW_ARRAY
|
|
||||||
|
|
||||||
#ifdef _MSC_VER
|
#ifdef _MSC_VER
|
||||||
/** This ensures that the system default operator new[] doesn't get
|
/** 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
|
* There seems to be really redirect new in this environment without
|
||||||
* including this everywhere.
|
* including this everywhere.
|
||||||
*/
|
*/
|
||||||
inline void *operator new[]( size_t size )
|
void *operator new[]( size_t size );
|
||||||
{
|
|
||||||
return GC_MALLOC_UNCOLLECTABLE( size );
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void operator delete[](void* obj)
|
void operator delete[](void* obj);
|
||||||
{
|
|
||||||
GC_FREE(obj);
|
|
||||||
};
|
|
||||||
|
|
||||||
inline void* operator new( size_t size)
|
void* operator new( size_t size);
|
||||||
{
|
|
||||||
return GC_MALLOC_UNCOLLECTABLE( size);
|
|
||||||
};
|
|
||||||
|
|
||||||
inline void operator delete(void* obj)
|
|
||||||
{
|
|
||||||
GC_FREE(obj);
|
|
||||||
};
|
|
||||||
|
|
||||||
|
void operator delete(void* obj);
|
||||||
|
|
||||||
// This new operator is used by VC++ in case of Debug builds !
|
// This new operator is used by VC++ in case of Debug builds !
|
||||||
inline void* operator new( size_t size,
|
void* operator new( size_t size,
|
||||||
int ,//nBlockUse,
|
int ,//nBlockUse,
|
||||||
const char * szFileName,
|
const char * szFileName,
|
||||||
int nLine
|
int nLine );
|
||||||
) {
|
|
||||||
# ifndef GC_DEBUG
|
|
||||||
return GC_malloc_uncollectable( size );
|
|
||||||
# else
|
|
||||||
return GC_debug_malloc_uncollectable(size, szFileName, nLine);
|
|
||||||
# endif
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif /* _MSC_VER */
|
#endif /* _MSC_VER */
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef GC_OPERATOR_NEW_ARRAY
|
||||||
|
|
||||||
inline void* operator new[](
|
inline void* operator new[](
|
||||||
size_t size,
|
size_t size,
|
||||||
GCPlacement gcp,
|
GCPlacement gcp,
|
||||||
|
@ -283,9 +276,15 @@ inline void* gc::operator new( size_t size, GCPlacement gcp ) {
|
||||||
else
|
else
|
||||||
return GC_MALLOC_UNCOLLECTABLE( size );}
|
return GC_MALLOC_UNCOLLECTABLE( size );}
|
||||||
|
|
||||||
|
inline void* gc::operator new( size_t size, void *p ) {
|
||||||
|
return p;}
|
||||||
|
|
||||||
inline void gc::operator delete( void* obj ) {
|
inline void gc::operator delete( void* obj ) {
|
||||||
GC_FREE( obj );}
|
GC_FREE( obj );}
|
||||||
|
|
||||||
|
#ifndef __BORLANDC__
|
||||||
|
inline void gc::operator delete( void*, void* ) {}
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef GC_OPERATOR_NEW_ARRAY
|
#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 ) {
|
inline void* gc::operator new[]( size_t size, GCPlacement gcp ) {
|
||||||
return gc::operator new( size, 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 ) {
|
inline void gc::operator delete[]( void* obj ) {
|
||||||
gc::operator delete( obj );}
|
gc::operator delete( obj );}
|
||||||
|
|
||||||
|
#ifndef __BORLANDC__
|
||||||
|
inline void gc::operator delete[]( void*, void* ) {}
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif /* GC_OPERATOR_NEW_ARRAY */
|
#endif /* GC_OPERATOR_NEW_ARRAY */
|
||||||
|
|
||||||
|
|
||||||
inline gc_cleanup::~gc_cleanup() {
|
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 ) {
|
inline void gc_cleanup::cleanup( void* obj, void* displ ) {
|
||||||
((gc_cleanup*) ((char*) obj + (ptrdiff_t) displ))->~gc_cleanup();}
|
((gc_cleanup*) ((char*) obj + (ptrdiff_t) displ))->~gc_cleanup();}
|
||||||
|
|
|
@ -33,6 +33,9 @@
|
||||||
* -DTHREAD_LOCAL_ALLOC, which is currently supported only on Linux.
|
* -DTHREAD_LOCAL_ALLOC, which is currently supported only on Linux.
|
||||||
*
|
*
|
||||||
* The debugging allocators use standard, not thread-local allocation.
|
* 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
|
#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 */
|
/* be reserved for exceptional cases. That will ensure that */
|
||||||
/* performance of this call is not extremely performance critical. */
|
/* performance of this call is not extremely performance critical. */
|
||||||
/* (Otherwise we would need to inline GC_mark_and_push completely, */
|
/* (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
|
struct GC_ms_entry *GC_mark_and_push
|
||||||
GC_PROTO((GC_PTR obj,
|
GC_PROTO((GC_PTR obj,
|
||||||
struct GC_ms_entry * mark_stack_ptr,
|
struct GC_ms_entry * mark_stack_ptr,
|
||||||
|
|
|
@ -52,15 +52,30 @@
|
||||||
int GC_pthread_create(pthread_t *new_thread,
|
int GC_pthread_create(pthread_t *new_thread,
|
||||||
const pthread_attr_t *attr,
|
const pthread_attr_t *attr,
|
||||||
void *(*start_routine)(void *), void *arg);
|
void *(*start_routine)(void *), void *arg);
|
||||||
|
#ifndef GC_DARWIN_THREADS
|
||||||
int GC_pthread_sigmask(int how, const sigset_t *set, sigset_t *oset);
|
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_join(pthread_t thread, void **retval);
|
||||||
int GC_pthread_detach(pthread_t thread);
|
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_create GC_pthread_create
|
||||||
# define pthread_sigmask GC_pthread_sigmask
|
|
||||||
# define pthread_join GC_pthread_join
|
# define pthread_join GC_pthread_join
|
||||||
# define pthread_detach GC_pthread_detach
|
# define pthread_detach GC_pthread_detach
|
||||||
|
|
||||||
|
#ifndef GC_DARWIN_THREADS
|
||||||
|
# define pthread_sigmask GC_pthread_sigmask
|
||||||
# define dlopen GC_dlopen
|
# define dlopen GC_dlopen
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif /* GC_xxxxx_THREADS */
|
#endif /* GC_xxxxx_THREADS */
|
||||||
|
|
||||||
|
|
|
@ -29,14 +29,21 @@
|
||||||
# include "gc.h"
|
# include "gc.h"
|
||||||
# endif
|
# endif
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
typedef GC_word * GC_bitmap;
|
typedef GC_word * GC_bitmap;
|
||||||
/* The least significant bit of the first word is one if */
|
/* The least significant bit of the first word is one if */
|
||||||
/* the first word in the object may be a pointer. */
|
/* the first word in the object may be a pointer. */
|
||||||
|
|
||||||
|
# define GC_WORDSZ (8*sizeof(GC_word))
|
||||||
# define GC_get_bit(bm, index) \
|
# 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) \
|
# 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;
|
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 */
|
/* is intended to be called once per type, not once */
|
||||||
/* per allocation. */
|
/* 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_API GC_PTR GC_malloc_explicitly_typed
|
||||||
GC_PROTO((size_t size_in_bytes, GC_descr d));
|
GC_PROTO((size_t size_in_bytes, GC_descr d));
|
||||||
/* Allocate an object whose layout is described by 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. */
|
/* Returned object is cleared. */
|
||||||
|
|
||||||
#ifdef GC_DEBUG
|
#ifdef GC_DEBUG
|
||||||
# define GC_MALLOC_EXPLICTLY_TYPED(bytes, d) GC_MALLOC(bytes)
|
# define GC_MALLOC_EXPLICITLY_TYPED(bytes, d) GC_MALLOC(bytes)
|
||||||
# define GC_CALLOC_EXPLICTLY_TYPED(n, bytes, d) GC_MALLOC(n*bytes)
|
# define GC_CALLOC_EXPLICITLY_TYPED(n, bytes, d) GC_MALLOC(n*bytes)
|
||||||
#else
|
#else
|
||||||
# define GC_MALLOC_EXPLICTLY_TYPED(bytes, d) \
|
# define GC_MALLOC_EXPLICITLY_TYPED(bytes, d) \
|
||||||
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)
|
GC_calloc_explicitly_typed(n, bytes, d)
|
||||||
#endif /* !GC_DEBUG */
|
#endif /* !GC_DEBUG */
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
} /* matches extern "C" */
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif /* _GC_TYPED_H */
|
#endif /* _GC_TYPED_H */
|
||||||
|
|
||||||
|
|
|
@ -64,6 +64,14 @@
|
||||||
#endif
|
#endif
|
||||||
#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
|
#define GC_ALLOC_H
|
||||||
|
|
||||||
|
|
|
@ -115,16 +115,24 @@ typedef struct {
|
||||||
|
|
||||||
#ifdef SHORT_DBG_HDRS
|
#ifdef SHORT_DBG_HDRS
|
||||||
# define DEBUG_BYTES (sizeof (oh))
|
# define DEBUG_BYTES (sizeof (oh))
|
||||||
|
# define UNCOLLECTABLE_DEBUG_BYTES DEBUG_BYTES
|
||||||
#else
|
#else
|
||||||
/* Add space for END_FLAG, but use any extra space that was already */
|
/* Add space for END_FLAG, but use any extra space that was already */
|
||||||
/* added to catch off-the-end pointers. */
|
/* 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
|
#endif
|
||||||
#define USR_PTR_FROM_BASE(p) ((ptr_t)(p) + sizeof(oh))
|
#define USR_PTR_FROM_BASE(p) ((ptr_t)(p) + sizeof(oh))
|
||||||
|
|
||||||
/* Round bytes to words without adding extra byte at end. */
|
/* 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)
|
#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
|
#ifdef SAVE_CALL_CHAIN
|
||||||
# define ADD_CALL_CHAIN(base, ra) GC_save_callers(((oh *)(base)) -> oh_ci)
|
# 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)
|
# 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) \
|
#define ADVANCE(p, hhdr, source) \
|
||||||
{ \
|
{ \
|
||||||
hdr * new_hdr = GC_invalid_header; \
|
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; \
|
hhdr = new_hdr; \
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -141,19 +141,20 @@
|
||||||
# if defined(POWERPC)
|
# if defined(POWERPC)
|
||||||
inline static int GC_test_and_set(volatile unsigned int *addr) {
|
inline static int GC_test_and_set(volatile unsigned int *addr) {
|
||||||
int oldval;
|
int oldval;
|
||||||
int temp = 1; // locked value
|
int temp = 1; /* locked value */
|
||||||
|
|
||||||
__asm__ __volatile__(
|
__asm__ __volatile__(
|
||||||
"1:\tlwarx %0,0,%3\n" // load and reserve
|
"1:\tlwarx %0,0,%3\n" /* load and reserve */
|
||||||
"\tcmpwi %0, 0\n" // if load is
|
"\tcmpwi %0, 0\n" /* if load is */
|
||||||
"\tbne 2f\n" // non-zero, return already set
|
"\tbne 2f\n" /* non-zero, return already set */
|
||||||
"\tstwcx. %2,0,%1\n" // else store conditional
|
"\tstwcx. %2,0,%1\n" /* else store conditional */
|
||||||
"\tbne- 1b\n" // retry if lost reservation
|
"\tbne- 1b\n" /* retry if lost reservation */
|
||||||
"2:\t\n" // oldval is zero if we set
|
"\tsync\n" /* import barrier */
|
||||||
|
"2:\t\n" /* oldval is zero if we set */
|
||||||
: "=&r"(oldval), "=p"(addr)
|
: "=&r"(oldval), "=p"(addr)
|
||||||
: "r"(temp), "1"(addr)
|
: "r"(temp), "1"(addr)
|
||||||
: "memory");
|
: "cr0","memory");
|
||||||
return (int)oldval;
|
return oldval;
|
||||||
}
|
}
|
||||||
# define GC_TEST_AND_SET_DEFINED
|
# define GC_TEST_AND_SET_DEFINED
|
||||||
inline static void GC_clear(volatile unsigned int *addr) {
|
inline static void GC_clear(volatile unsigned int *addr) {
|
||||||
|
@ -174,12 +175,18 @@
|
||||||
" bne %2,2f\n"
|
" bne %2,2f\n"
|
||||||
" xor %0,%3,%0\n"
|
" xor %0,%3,%0\n"
|
||||||
" stl_c %0,%1\n"
|
" stl_c %0,%1\n"
|
||||||
|
# ifdef __ELF__
|
||||||
" beq %0,3f\n"
|
" beq %0,3f\n"
|
||||||
|
# else
|
||||||
|
" beq %0,1b\n"
|
||||||
|
# endif
|
||||||
" mb\n"
|
" mb\n"
|
||||||
"2:\n"
|
"2:\n"
|
||||||
|
# ifdef __ELF__
|
||||||
".section .text2,\"ax\"\n"
|
".section .text2,\"ax\"\n"
|
||||||
"3: br 1b\n"
|
"3: br 1b\n"
|
||||||
".previous"
|
".previous"
|
||||||
|
# endif
|
||||||
:"=&r" (temp), "=m" (*addr), "=&r" (oldvalue)
|
:"=&r" (temp), "=m" (*addr), "=&r" (oldvalue)
|
||||||
:"Ir" (1), "m" (*addr)
|
:"Ir" (1), "m" (*addr)
|
||||||
:"memory");
|
:"memory");
|
||||||
|
@ -187,8 +194,11 @@
|
||||||
return oldvalue;
|
return oldvalue;
|
||||||
}
|
}
|
||||||
# define GC_TEST_AND_SET_DEFINED
|
# define GC_TEST_AND_SET_DEFINED
|
||||||
/* Should probably also define GC_clear, since it needs */
|
inline static void GC_clear(volatile unsigned int *addr) {
|
||||||
/* a memory barrier ?? */
|
__asm__ __volatile__("mb" : : : "memory");
|
||||||
|
*(addr) = 0;
|
||||||
|
}
|
||||||
|
# define GC_CLEAR_DEFINED
|
||||||
# endif /* ALPHA */
|
# endif /* ALPHA */
|
||||||
# ifdef ARM32
|
# ifdef ARM32
|
||||||
inline static int GC_test_and_set(volatile unsigned int *addr) {
|
inline static int GC_test_and_set(volatile unsigned int *addr) {
|
||||||
|
@ -220,8 +230,16 @@
|
||||||
# endif
|
# endif
|
||||||
# endif /* __GNUC__ */
|
# endif /* __GNUC__ */
|
||||||
# if (defined(ALPHA) && !defined(__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_TEST_AND_SET_DEFINED
|
||||||
|
# define GC_clear(addr) { asm("mb"); *(volatile unsigned *)addr = 0; }
|
||||||
|
# define GC_CLEAR_DEFINED
|
||||||
# endif
|
# endif
|
||||||
# if defined(MSWIN32)
|
# if defined(MSWIN32)
|
||||||
# define GC_test_and_set(addr) InterlockedExchange((LPLONG)addr,1)
|
# define GC_test_and_set(addr) InterlockedExchange((LPLONG)addr,1)
|
||||||
|
@ -234,14 +252,51 @@
|
||||||
# define GC_TEST_AND_SET_DEFINED
|
# define GC_TEST_AND_SET_DEFINED
|
||||||
# elif __mips < 3 || !(defined (_ABIN32) || defined(_ABI64)) \
|
# elif __mips < 3 || !(defined (_ABIN32) || defined(_ABI64)) \
|
||||||
|| !defined(_COMPILER_VERSION) || _COMPILER_VERSION < 700
|
|| !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
|
# else
|
||||||
# define GC_test_and_set(addr) __test_and_set(addr,1)
|
# define GC_test_and_set(addr) test_and_set((void *)addr,1)
|
||||||
|
# endif
|
||||||
|
# else
|
||||||
|
# define GC_test_and_set(addr) __test_and_set32((void *)addr,1)
|
||||||
# define GC_clear(addr) __lock_release(addr);
|
# define GC_clear(addr) __lock_release(addr);
|
||||||
# define GC_CLEAR_DEFINED
|
# define GC_CLEAR_DEFINED
|
||||||
# endif
|
# endif
|
||||||
# define GC_TEST_AND_SET_DEFINED
|
# define GC_TEST_AND_SET_DEFINED
|
||||||
# endif /* MIPS */
|
# 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) */
|
# if 0 /* defined(HP_PA) */
|
||||||
/* The official recommendation seems to be to not use ldcw from */
|
/* The official recommendation seems to be to not use ldcw from */
|
||||||
/* user mode. Since multithreaded incremental collection doesn't */
|
/* user mode. Since multithreaded incremental collection doesn't */
|
||||||
|
@ -275,7 +330,7 @@
|
||||||
# endif
|
# endif
|
||||||
|
|
||||||
# if defined(GC_PTHREADS) && !defined(GC_SOLARIS_THREADS) \
|
# 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)
|
# define NO_THREAD (pthread_t)(-1)
|
||||||
# include <pthread.h>
|
# include <pthread.h>
|
||||||
# if defined(PARALLEL_MARK)
|
# if defined(PARALLEL_MARK)
|
||||||
|
@ -306,12 +361,12 @@
|
||||||
{
|
{
|
||||||
char result;
|
char result;
|
||||||
__asm__ __volatile__("lock; cmpxchgl %2, %0; setz %1"
|
__asm__ __volatile__("lock; cmpxchgl %2, %0; setz %1"
|
||||||
: "=m"(*(addr)), "=r"(result)
|
: "+m"(*(addr)), "=r"(result)
|
||||||
: "r" (new_val), "0"(*(addr)), "a"(old) : "memory");
|
: "r" (new_val), "a"(old) : "memory");
|
||||||
return (GC_bool) result;
|
return (GC_bool) result;
|
||||||
}
|
}
|
||||||
# endif /* !GENERIC_COMPARE_AND_SWAP */
|
# 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 */
|
/* We believe the processor ensures at least processor */
|
||||||
/* consistent ordering. Thus a compiler barrier */
|
/* consistent ordering. Thus a compiler barrier */
|
||||||
|
@ -319,6 +374,37 @@
|
||||||
__asm__ __volatile__("" : : : "memory");
|
__asm__ __volatile__("" : : : "memory");
|
||||||
}
|
}
|
||||||
# endif /* I386 */
|
# 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(IA64)
|
||||||
# if !defined(GENERIC_COMPARE_AND_SWAP)
|
# if !defined(GENERIC_COMPARE_AND_SWAP)
|
||||||
inline static GC_bool GC_compare_and_exchange(volatile GC_word *addr,
|
inline static GC_bool GC_compare_and_exchange(volatile GC_word *addr,
|
||||||
|
@ -330,12 +416,52 @@
|
||||||
# endif /* !GENERIC_COMPARE_AND_SWAP */
|
# endif /* !GENERIC_COMPARE_AND_SWAP */
|
||||||
# if 0
|
# if 0
|
||||||
/* Shouldn't be needed; we use volatile stores instead. */
|
/* Shouldn't be needed; we use volatile stores instead. */
|
||||||
inline static void GC_memory_write_barrier()
|
inline static void GC_memory_barrier()
|
||||||
{
|
{
|
||||||
__sync_synchronize ();
|
__sync_synchronize ();
|
||||||
}
|
}
|
||||||
# endif /* 0 */
|
# endif /* 0 */
|
||||||
# endif /* IA64 */
|
# 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(S390)
|
||||||
# if !defined(GENERIC_COMPARE_AND_SWAP)
|
# if !defined(GENERIC_COMPARE_AND_SWAP)
|
||||||
inline static GC_bool GC_compare_and_exchange(volatile C_word *addr,
|
inline static GC_bool GC_compare_and_exchange(volatile C_word *addr,
|
||||||
|
@ -427,8 +553,12 @@
|
||||||
{ GC_ASSERT(I_HOLD_LOCK()); UNSET_LOCK_HOLDER(); \
|
{ GC_ASSERT(I_HOLD_LOCK()); UNSET_LOCK_HOLDER(); \
|
||||||
pthread_mutex_unlock(&GC_allocate_ml); }
|
pthread_mutex_unlock(&GC_allocate_ml); }
|
||||||
# else /* !GC_ASSERTIONS */
|
# else /* !GC_ASSERTIONS */
|
||||||
|
# if defined(NO_PTHREAD_TRYLOCK)
|
||||||
|
# define LOCK() GC_lock();
|
||||||
|
# else /* !defined(NO_PTHREAD_TRYLOCK) */
|
||||||
# define LOCK() \
|
# define LOCK() \
|
||||||
{ if (0 != pthread_mutex_trylock(&GC_allocate_ml)) GC_lock(); }
|
{ if (0 != pthread_mutex_trylock(&GC_allocate_ml)) GC_lock(); }
|
||||||
|
# endif
|
||||||
# define UNLOCK() pthread_mutex_unlock(&GC_allocate_ml)
|
# define UNLOCK() pthread_mutex_unlock(&GC_allocate_ml)
|
||||||
# endif /* !GC_ASSERTIONS */
|
# endif /* !GC_ASSERTIONS */
|
||||||
# endif /* USE_PTHREAD_LOCKS */
|
# endif /* USE_PTHREAD_LOCKS */
|
||||||
|
@ -450,7 +580,7 @@
|
||||||
/* on Irix anymore. */
|
/* on Irix anymore. */
|
||||||
# include <mutex.h>
|
# 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) */
|
/* This is not a mutex because mutexes that obey the (optional) */
|
||||||
/* POSIX scheduling rules are subject to convoys in high contention */
|
/* POSIX scheduling rules are subject to convoys in high contention */
|
||||||
/* applications. This is basically a spin lock. */
|
/* applications. This is basically a spin lock. */
|
||||||
|
@ -471,12 +601,19 @@
|
||||||
}
|
}
|
||||||
# define EXIT_GC() GC_collecting = 0;
|
# define EXIT_GC() GC_collecting = 0;
|
||||||
# endif /* GC_IRIX_THREADS */
|
# endif /* GC_IRIX_THREADS */
|
||||||
# ifdef GC_WIN32_THREADS
|
# 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>
|
# include <windows.h>
|
||||||
GC_API CRITICAL_SECTION GC_allocate_ml;
|
GC_API CRITICAL_SECTION GC_allocate_ml;
|
||||||
# define LOCK() EnterCriticalSection(&GC_allocate_ml);
|
# define LOCK() EnterCriticalSection(&GC_allocate_ml);
|
||||||
# define UNLOCK() LeaveCriticalSection(&GC_allocate_ml);
|
# define UNLOCK() LeaveCriticalSection(&GC_allocate_ml);
|
||||||
# endif
|
# endif
|
||||||
|
# endif
|
||||||
# ifndef SET_LOCK_HOLDER
|
# ifndef SET_LOCK_HOLDER
|
||||||
# define SET_LOCK_HOLDER()
|
# define SET_LOCK_HOLDER()
|
||||||
# define UNSET_LOCK_HOLDER()
|
# define UNSET_LOCK_HOLDER()
|
||||||
|
|
|
@ -137,7 +137,7 @@ extern mse * GC_mark_stack;
|
||||||
#ifdef __STDC__
|
#ifdef __STDC__
|
||||||
# ifdef PRINT_BLACK_LIST
|
# ifdef PRINT_BLACK_LIST
|
||||||
ptr_t GC_find_start(ptr_t current, hdr *hhdr, hdr **new_hdr_p,
|
ptr_t GC_find_start(ptr_t current, hdr *hhdr, hdr **new_hdr_p,
|
||||||
ptr_t source);
|
word source);
|
||||||
# else
|
# else
|
||||||
ptr_t GC_find_start(ptr_t current, hdr *hhdr, hdr **new_hdr_p);
|
ptr_t GC_find_start(ptr_t current, hdr *hhdr, hdr **new_hdr_p);
|
||||||
# endif
|
# endif
|
||||||
|
@ -145,7 +145,7 @@ extern mse * GC_mark_stack;
|
||||||
ptr_t GC_find_start();
|
ptr_t GC_find_start();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
mse *GC_signal_mark_stack_overflow(mse *msp);
|
mse * GC_signal_mark_stack_overflow GC_PROTO((mse *msp));
|
||||||
|
|
||||||
# ifdef GATHERSTATS
|
# ifdef GATHERSTATS
|
||||||
# define ADD_TO_ATOMIC(sz) GC_atomic_in_use += (sz)
|
# 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 */
|
/* Push the contents of current onto the mark stack if it is a valid */
|
||||||
/* ptr to a currently unmarked object. Mark it. */
|
/* ptr to a currently unmarked object. Mark it. */
|
||||||
/* If we assumed a standard-conforming compiler, we could probably */
|
/* 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); \
|
GET_HDR(my_current, my_hhdr); \
|
||||||
if (IS_FORWARDING_ADDR_OR_NIL(my_hhdr)) { \
|
if (IS_FORWARDING_ADDR_OR_NIL(my_hhdr)) { \
|
||||||
hdr * new_hdr = GC_invalid_header; \
|
hdr * new_hdr = GC_invalid_header; \
|
||||||
my_current = GC_FIND_START(my_current, my_hhdr, \
|
my_current = GC_find_start(my_current, my_hhdr, &new_hdr); \
|
||||||
&new_hdr, (word)source); \
|
|
||||||
my_hhdr = new_hdr; \
|
my_hhdr = new_hdr; \
|
||||||
} \
|
} \
|
||||||
PUSH_CONTENTS_HDR(my_current, mark_stack_top, mark_stack_limit, \
|
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.
|
* 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.
|
* P is considered valid even if it is an interior pointer.
|
||||||
* Previously marked objects are not pushed. Hence we make progress even
|
* Previously marked objects are not pushed. Hence we make progress even
|
||||||
* if the mark stack overflows.
|
* if the mark stack overflows.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
# 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) \
|
# define GC_PUSH_ONE_STACK(p, source) \
|
||||||
if ((ptr_t)(p) >= (ptr_t)GC_least_plausible_heap_addr \
|
if ((ptr_t)(p) >= (ptr_t)GC_least_plausible_heap_addr \
|
||||||
&& (ptr_t)(p) < (ptr_t)GC_greatest_plausible_heap_addr) { \
|
&& (ptr_t)(p) < (ptr_t)GC_greatest_plausible_heap_addr) { \
|
||||||
PUSH_ONE_CHECKED_STACK(p, source); \
|
PUSH_ONE_CHECKED_STACK(p, source); \
|
||||||
}
|
}
|
||||||
|
# endif
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* As above, but interior pointer recognition as for
|
* As above, but interior pointer recognition as for
|
||||||
* normal for heap pointers.
|
* normal for heap pointers.
|
||||||
*/
|
*/
|
||||||
# define GC_PUSH_ONE_HEAP(p,source) \
|
# define GC_PUSH_ONE_HEAP(p,source) \
|
||||||
|
FIXUP_POINTER(p); \
|
||||||
if ((ptr_t)(p) >= (ptr_t)GC_least_plausible_heap_addr \
|
if ((ptr_t)(p) >= (ptr_t)GC_least_plausible_heap_addr \
|
||||||
&& (ptr_t)(p) < (ptr_t)GC_greatest_plausible_heap_addr) { \
|
&& (ptr_t)(p) < (ptr_t)GC_greatest_plausible_heap_addr) { \
|
||||||
GC_mark_stack_top = GC_mark_and_push( \
|
GC_mark_stack_top = GC_mark_and_push( \
|
||||||
|
|
|
@ -30,14 +30,20 @@
|
||||||
# define BSD_TIME
|
# define BSD_TIME
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef DGUX
|
||||||
|
# include <sys/types.h>
|
||||||
|
# include <sys/time.h>
|
||||||
|
# include <sys/resource.h>
|
||||||
|
#endif /* DGUX */
|
||||||
|
|
||||||
#ifdef BSD_TIME
|
#ifdef BSD_TIME
|
||||||
# include <sys/types.h>
|
# include <sys/types.h>
|
||||||
# include <sys/time.h>
|
# include <sys/time.h>
|
||||||
# include <sys/resource.h>
|
# include <sys/resource.h>
|
||||||
#endif /* BSD_TIME */
|
#endif /* BSD_TIME */
|
||||||
|
|
||||||
# ifndef GC_H
|
# ifndef _GC_H
|
||||||
# include "gc.h"
|
# include "../gc.h"
|
||||||
# endif
|
# endif
|
||||||
|
|
||||||
# ifndef GC_MARK_H
|
# ifndef GC_MARK_H
|
||||||
|
@ -210,7 +216,6 @@ typedef char * ptr_t; /* A generic pointer to which we can add */
|
||||||
# define ALIGN_DOUBLE
|
# define ALIGN_DOUBLE
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
/* ALIGN_DOUBLE requires MERGE_SIZES at present. */
|
/* ALIGN_DOUBLE requires MERGE_SIZES at present. */
|
||||||
# if defined(ALIGN_DOUBLE) && !defined(MERGE_SIZES)
|
# if defined(ALIGN_DOUBLE) && !defined(MERGE_SIZES)
|
||||||
# define MERGE_SIZES
|
# define MERGE_SIZES
|
||||||
|
@ -347,7 +352,8 @@ void GC_print_callers GC_PROTO((struct callinfo info[NFRAMES]));
|
||||||
# include <string.h>
|
# include <string.h>
|
||||||
# define BCOPY_EXISTS
|
# define BCOPY_EXISTS
|
||||||
# endif
|
# endif
|
||||||
# if defined(MACOSX)
|
# if defined(DARWIN)
|
||||||
|
# include <string.h>
|
||||||
# define BCOPY_EXISTS
|
# define BCOPY_EXISTS
|
||||||
# endif
|
# endif
|
||||||
|
|
||||||
|
@ -360,68 +366,6 @@ void GC_print_callers GC_PROTO((struct callinfo info[NFRAMES]));
|
||||||
# define BZERO(x,n) bzero((char *)(x),(int)(n))
|
# define BZERO(x,n) bzero((char *)(x),(int)(n))
|
||||||
# endif
|
# 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 */
|
/* Delay any interrupts or signals that may abort this thread. Data */
|
||||||
/* structures are in a consistent state outside this pair of calls. */
|
/* structures are in a consistent state outside this pair of calls. */
|
||||||
/* ANSI C allows both to be empty (though the standard isn't very */
|
/* ANSI C allows both to be empty (though the standard isn't very */
|
||||||
|
@ -486,7 +430,7 @@ struct hblk; /* See below. */
|
||||||
# ifdef SMALL_CONFIG
|
# ifdef SMALL_CONFIG
|
||||||
# define ABORT(msg) abort();
|
# define ABORT(msg) abort();
|
||||||
# else
|
# else
|
||||||
GC_API void GC_abort();
|
GC_API void GC_abort GC_PROTO((GC_CONST char * msg));
|
||||||
# define ABORT(msg) GC_abort(msg);
|
# define ABORT(msg) GC_abort(msg);
|
||||||
# endif
|
# endif
|
||||||
# endif
|
# endif
|
||||||
|
@ -646,9 +590,10 @@ extern GC_warn_proc GC_current_warn_proc;
|
||||||
*/
|
*/
|
||||||
|
|
||||||
# ifdef LARGE_CONFIG
|
# ifdef LARGE_CONFIG
|
||||||
# define LOG_PHT_ENTRIES 19 /* Collisions likely at 512K blocks, */
|
# define LOG_PHT_ENTRIES 20 /* Collisions likely at 1M blocks, */
|
||||||
/* which is >= 2GB. Each table takes */
|
/* which is >= 4GB. Each table takes */
|
||||||
/* 64KB. */
|
/* 128KB, some of which may never be */
|
||||||
|
/* touched. */
|
||||||
# else
|
# else
|
||||||
# ifdef SMALL_CONFIG
|
# ifdef SMALL_CONFIG
|
||||||
# define LOG_PHT_ENTRIES 14 /* Collisions are likely if heap grows */
|
# 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. */
|
/* Each hash table occupies 2K bytes. */
|
||||||
# else /* default "medium" configuration */
|
# else /* default "medium" configuration */
|
||||||
# define LOG_PHT_ENTRIES 16 /* Collisions are likely if heap grows */
|
# 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. */
|
/* Each hash table occupies 8K bytes. */
|
||||||
# endif
|
# endif
|
||||||
# endif
|
# endif
|
||||||
|
@ -897,6 +842,10 @@ struct _GC_arrays {
|
||||||
word _mem_freed;
|
word _mem_freed;
|
||||||
/* Number of explicitly deallocated words of memory */
|
/* Number of explicitly deallocated words of memory */
|
||||||
/* since last collection. */
|
/* 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_end_ptr;
|
||||||
ptr_t _scratch_last_end_ptr;
|
ptr_t _scratch_last_end_ptr;
|
||||||
/* Used by headers.c, and can easily appear to point to */
|
/* 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 */
|
/* OFFSET_TOO_BIG if the value j would be too */
|
||||||
/* large to fit in the entry. (Note that the */
|
/* large to fit in the entry. (Note that the */
|
||||||
/* size of these entries matters, both for */
|
/* 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 OFFSET_TOO_BIG 0xfe
|
||||||
# define OBJ_INVALID 0xff
|
# define OBJ_INVALID 0xff
|
||||||
# define MAP_ENTRY(map, bytes) (map)[bytes]
|
# 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_words_finalized GC_arrays._words_finalized
|
||||||
# define GC_non_gc_bytes_at_gc GC_arrays._non_gc_bytes_at_gc
|
# define GC_non_gc_bytes_at_gc GC_arrays._non_gc_bytes_at_gc
|
||||||
# define GC_mem_freed GC_arrays._mem_freed
|
# 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_end_ptr GC_arrays._scratch_end_ptr
|
||||||
# define GC_scratch_last_end_ptr GC_arrays._scratch_last_end_ptr
|
# define GC_scratch_last_end_ptr GC_arrays._scratch_last_end_ptr
|
||||||
# define GC_mark_procs GC_arrays._mark_procs
|
# define GC_mark_procs GC_arrays._mark_procs
|
||||||
|
@ -1201,17 +1151,19 @@ extern struct hblk * GC_hblkfreelist[];
|
||||||
/* header structure associated with */
|
/* header structure associated with */
|
||||||
/* block. */
|
/* block. */
|
||||||
|
|
||||||
extern GC_bool GC_is_initialized; /* GC_init() has been run. */
|
|
||||||
|
|
||||||
extern GC_bool GC_objects_are_marked; /* There are marked objects in */
|
extern GC_bool GC_objects_are_marked; /* There are marked objects in */
|
||||||
/* the heap. */
|
/* the heap. */
|
||||||
|
|
||||||
#ifndef SMALL_CONFIG
|
#ifndef SMALL_CONFIG
|
||||||
extern GC_bool GC_incremental;
|
extern GC_bool GC_incremental;
|
||||||
/* Using incremental/generational collection. */
|
/* Using incremental/generational collection. */
|
||||||
|
# define TRUE_INCREMENTAL \
|
||||||
|
(GC_incremental && GC_time_limit != GC_TIME_UNLIMITED)
|
||||||
|
/* True incremental, not just generational, mode */
|
||||||
#else
|
#else
|
||||||
# define GC_incremental FALSE
|
# define GC_incremental FALSE
|
||||||
/* Hopefully allow optimizer to remove some code. */
|
/* Hopefully allow optimizer to remove some code. */
|
||||||
|
# define TRUE_INCREMENTAL FALSE
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
extern GC_bool GC_dirty_maintained;
|
extern GC_bool GC_dirty_maintained;
|
||||||
|
@ -1229,6 +1181,10 @@ extern long GC_large_alloc_warn_interval;
|
||||||
extern long GC_large_alloc_warn_suppressed;
|
extern long GC_large_alloc_warn_suppressed;
|
||||||
/* Number of warnings suppressed so far. */
|
/* Number of warnings suppressed so far. */
|
||||||
|
|
||||||
|
#ifdef THREADS
|
||||||
|
extern GC_bool GC_world_stopped;
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Operations */
|
/* Operations */
|
||||||
# ifndef abs
|
# ifndef abs
|
||||||
# define abs(x) ((x) < 0? (-(x)) : (x))
|
# 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));
|
void GC_generic_push_regs GC_PROTO((ptr_t cold_gc_frame));
|
||||||
# else
|
# else
|
||||||
void GC_push_regs GC_PROTO((void));
|
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
|
# endif
|
||||||
/* Push register contents onto mark stack. */
|
/* Push register contents onto mark stack. */
|
||||||
/* If NURSERY is defined, the default push */
|
/* 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 */
|
/* Set all mark bits associated with */
|
||||||
/* a free list. */
|
/* a free list. */
|
||||||
void GC_add_roots_inner GC_PROTO((char * b, char * e, GC_bool tmp));
|
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));
|
GC_bool GC_is_static_root GC_PROTO((ptr_t p));
|
||||||
/* Is the address p in one of the registered static */
|
/* Is the address p in one of the registered static */
|
||||||
/* root sections? */
|
/* root sections? */
|
||||||
|
@ -1462,7 +1424,6 @@ GC_bool GC_is_tmp_root GC_PROTO((ptr_t p));
|
||||||
# endif
|
# endif
|
||||||
void GC_register_dynamic_libraries GC_PROTO((void));
|
void GC_register_dynamic_libraries GC_PROTO((void));
|
||||||
/* Add dynamic library data sections to the root set. */
|
/* Add dynamic library data sections to the root set. */
|
||||||
|
|
||||||
GC_bool GC_register_main_static_data GC_PROTO((void));
|
GC_bool GC_register_main_static_data GC_PROTO((void));
|
||||||
/* We need to register the main data segment. Returns */
|
/* We need to register the main data segment. Returns */
|
||||||
/* TRUE unless this is done implicitly as part of */
|
/* TRUE unless this is done implicitly as part of */
|
||||||
|
@ -1624,6 +1585,8 @@ GC_bool GC_collect_or_expand GC_PROTO(( \
|
||||||
/* until the blocks are available or */
|
/* until the blocks are available or */
|
||||||
/* until it fails by returning FALSE. */
|
/* until it fails by returning FALSE. */
|
||||||
|
|
||||||
|
extern GC_bool GC_is_initialized; /* GC_init() has been run. */
|
||||||
|
|
||||||
#if defined(MSWIN32) || defined(MSWINCE)
|
#if defined(MSWIN32) || defined(MSWINCE)
|
||||||
void GC_deinit GC_PROTO((void));
|
void GC_deinit GC_PROTO((void));
|
||||||
/* Free any resources allocated by */
|
/* Free any resources allocated by */
|
||||||
|
@ -1666,6 +1629,8 @@ ptr_t GC_allocobj GC_PROTO((word sz, int kind));
|
||||||
/* free list nonempty, and return its */
|
/* free list nonempty, and return its */
|
||||||
/* head. */
|
/* head. */
|
||||||
|
|
||||||
|
void GC_free_inner(GC_PTR p);
|
||||||
|
|
||||||
void GC_init_headers GC_PROTO((void));
|
void GC_init_headers GC_PROTO((void));
|
||||||
struct hblkhdr * GC_install_header GC_PROTO((struct hblk *h));
|
struct hblkhdr * GC_install_header GC_PROTO((struct hblk *h));
|
||||||
/* Install a header for block h. */
|
/* Install a header for block h. */
|
||||||
|
@ -1695,6 +1660,12 @@ void GC_notify_or_invoke_finalizers GC_PROTO((void));
|
||||||
/* finalizers to be run, and we haven't called */
|
/* finalizers to be run, and we haven't called */
|
||||||
/* this procedure yet this GC cycle. */
|
/* 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));
|
void GC_add_to_heap GC_PROTO((struct hblk *p, word bytes));
|
||||||
/* Add a HBLKSIZE aligned chunk to the heap. */
|
/* 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. */
|
/* description of the object to stderr. */
|
||||||
extern void (*GC_check_heap) GC_PROTO((void));
|
extern void (*GC_check_heap) GC_PROTO((void));
|
||||||
/* Check that all objects in the heap with */
|
/* Check that all objects in the heap with */
|
||||||
/* debugging info are intact. Print */
|
/* debugging info are intact. */
|
||||||
/* descriptions of any that are not. */
|
/* 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));
|
extern void (*GC_print_heap_obj) GC_PROTO((ptr_t p));
|
||||||
/* If possible print s followed by a more */
|
/* If possible print s followed by a more */
|
||||||
/* detailed description of the object */
|
/* detailed description of the object */
|
||||||
/* referred to by p. */
|
/* 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 */
|
extern GC_bool GC_print_stats; /* Produce at least some logging output */
|
||||||
/* Set from environment variable. */
|
/* 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. */
|
/* Macros used for collector internal allocation. */
|
||||||
/* These assume the collector lock is held. */
|
/* These assume the collector lock is held. */
|
||||||
#ifdef DBG_HDRS_ALL
|
#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_hblkfreelist GC_PROTO((void));
|
||||||
void GC_print_heap_sects GC_PROTO((void));
|
void GC_print_heap_sects GC_PROTO((void));
|
||||||
void GC_print_static_roots 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));
|
void GC_dump GC_PROTO((void));
|
||||||
|
|
||||||
#ifdef KEEP_BACK_PTRS
|
#ifdef KEEP_BACK_PTRS
|
||||||
|
@ -1866,6 +1858,16 @@ void GC_err_puts GC_PROTO((GC_CONST char *s));
|
||||||
# define GC_ASSERT(expr)
|
# define GC_ASSERT(expr)
|
||||||
# endif
|
# 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)
|
# if defined(PARALLEL_MARK) || defined(THREAD_LOCAL_ALLOC)
|
||||||
/* We need additional synchronization facilities from the thread */
|
/* We need additional synchronization facilities from the thread */
|
||||||
/* support. We believe these are less performance critical */
|
/* 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 */
|
/* in Linux glibc, but it's not exported.) Thus we continue to use */
|
||||||
/* the same hard-coded signals we've always used. */
|
/* the same hard-coded signals we've always used. */
|
||||||
# if !defined(SIG_SUSPEND)
|
# if !defined(SIG_SUSPEND)
|
||||||
# if defined(GC_LINUX_THREADS)
|
# if defined(GC_LINUX_THREADS) || defined(GC_DGUX386_THREADS)
|
||||||
# if defined(SPARC) && !defined(SIGPWR)
|
# if defined(SPARC) && !defined(SIGPWR)
|
||||||
/* SPARC/Linux doesn't properly define SIGPWR in <signal.h>.
|
/* SPARC/Linux doesn't properly define SIGPWR in <signal.h>.
|
||||||
* It is aliased to SIGLOST in asm/signal.h, though. */
|
* It is aliased to SIGLOST in asm/signal.h, though. */
|
||||||
|
|
|
@ -14,10 +14,24 @@
|
||||||
* modified is included with the above copyright notice.
|
* 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
|
#ifndef GCCONFIG_H
|
||||||
|
|
||||||
# define 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 */
|
/* Machine dependent parameters. Some tuning parameters can be found */
|
||||||
/* near the top of gc_private.h. */
|
/* near the top of gc_private.h. */
|
||||||
|
|
||||||
|
@ -25,8 +39,10 @@
|
||||||
|
|
||||||
/* First a unified test for Linux: */
|
/* First a unified test for Linux: */
|
||||||
# if defined(linux) || defined(__linux__)
|
# if defined(linux) || defined(__linux__)
|
||||||
|
# ifndef LINUX
|
||||||
# define LINUX
|
# define LINUX
|
||||||
# endif
|
# endif
|
||||||
|
# endif
|
||||||
|
|
||||||
/* And one for NetBSD: */
|
/* And one for NetBSD: */
|
||||||
# if defined(__NetBSD__)
|
# if defined(__NetBSD__)
|
||||||
|
@ -44,9 +60,9 @@
|
||||||
# endif
|
# endif
|
||||||
|
|
||||||
/* Determine the machine type: */
|
/* Determine the machine type: */
|
||||||
# if defined(__arm__) || defined(__thumb__)
|
# if defined(__XSCALE__)
|
||||||
# define ARM32
|
# define ARM32
|
||||||
# if !defined(LINUX) && !defined(NETBSD)
|
# if !defined(LINUX)
|
||||||
# define NOSYS
|
# define NOSYS
|
||||||
# define mach_type_known
|
# define mach_type_known
|
||||||
# endif
|
# endif
|
||||||
|
@ -69,7 +85,7 @@
|
||||||
# define SPARC
|
# define SPARC
|
||||||
# define mach_type_known
|
# define mach_type_known
|
||||||
# endif
|
# endif
|
||||||
# if defined(NETBSD) && defined(m68k)
|
# if defined(NETBSD) && (defined(m68k) || defined(__m68k__))
|
||||||
# define M68K
|
# define M68K
|
||||||
# define mach_type_known
|
# define mach_type_known
|
||||||
# endif
|
# endif
|
||||||
|
@ -77,7 +93,7 @@
|
||||||
# define POWERPC
|
# define POWERPC
|
||||||
# define mach_type_known
|
# define mach_type_known
|
||||||
# endif
|
# endif
|
||||||
# if defined(NETBSD) && defined(__arm__)
|
# if defined(NETBSD) && (defined(__arm32__) || defined(__arm__))
|
||||||
# define ARM32
|
# define ARM32
|
||||||
# define mach_type_known
|
# define mach_type_known
|
||||||
# endif
|
# endif
|
||||||
|
@ -90,6 +106,10 @@
|
||||||
# endif
|
# endif
|
||||||
# define mach_type_known
|
# define mach_type_known
|
||||||
# endif
|
# endif
|
||||||
|
# if defined(__NetBSD__) && defined(__vax__)
|
||||||
|
# define VAX
|
||||||
|
# define mach_type_known
|
||||||
|
# endif
|
||||||
# if defined(mips) || defined(__mips) || defined(_mips)
|
# if defined(mips) || defined(__mips) || defined(_mips)
|
||||||
# define MIPS
|
# define MIPS
|
||||||
# if defined(nec_ews) || defined(_nec_ews)
|
# if defined(nec_ews) || defined(_nec_ews)
|
||||||
|
@ -109,6 +129,13 @@
|
||||||
# endif /* !LINUX */
|
# endif /* !LINUX */
|
||||||
# define mach_type_known
|
# define mach_type_known
|
||||||
# endif
|
# 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__))
|
# if defined(sequent) && (defined(i386) || defined(__i386__))
|
||||||
# define I386
|
# define I386
|
||||||
# define SEQUENT
|
# define SEQUENT
|
||||||
|
@ -198,7 +225,11 @@
|
||||||
# define IA64
|
# define IA64
|
||||||
# define mach_type_known
|
# define mach_type_known
|
||||||
# endif
|
# 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 POWERPC
|
||||||
# define mach_type_known
|
# define mach_type_known
|
||||||
# endif
|
# endif
|
||||||
|
@ -237,19 +268,19 @@
|
||||||
# define MACOS
|
# define MACOS
|
||||||
# define mach_type_known
|
# define mach_type_known
|
||||||
# endif
|
# endif
|
||||||
# if defined(__MWERKS__) && defined(__powerc)
|
# if defined(__MWERKS__) && defined(__powerc) && !defined(__MACH__)
|
||||||
# define POWERPC
|
# define POWERPC
|
||||||
# define MACOS
|
# define MACOS
|
||||||
# define mach_type_known
|
# define mach_type_known
|
||||||
# endif
|
# endif
|
||||||
# if defined(macosx) || \
|
# if defined(macosx) || \
|
||||||
defined(__APPLE__) && defined(__MACH__) && defined(__ppc__)
|
defined(__APPLE__) && defined(__MACH__) && defined(__ppc__)
|
||||||
# define MACOSX
|
# define DARWIN
|
||||||
# define POWERPC
|
# define POWERPC
|
||||||
# define mach_type_known
|
# define mach_type_known
|
||||||
# endif
|
# endif
|
||||||
# if defined(__APPLE__) && defined(__MACH__) && defined(__i386__)
|
# if defined(__APPLE__) && defined(__MACH__) && defined(__i386__)
|
||||||
# define MACOSX
|
# define DARWIN
|
||||||
# define I386
|
# define I386
|
||||||
--> Not really supported, but at least we recognize it.
|
--> Not really supported, but at least we recognize it.
|
||||||
# endif
|
# endif
|
||||||
|
@ -291,7 +322,7 @@
|
||||||
# define CX_UX
|
# define CX_UX
|
||||||
# define mach_type_known
|
# define mach_type_known
|
||||||
# endif
|
# endif
|
||||||
# if defined(DGUX)
|
# if defined(DGUX) && defined(m88k)
|
||||||
# define M88K
|
# define M88K
|
||||||
/* DGUX defined */
|
/* DGUX defined */
|
||||||
# define mach_type_known
|
# define mach_type_known
|
||||||
|
@ -425,11 +456,12 @@
|
||||||
/* IA64 ==> Intel IPF */
|
/* IA64 ==> Intel IPF */
|
||||||
/* (e.g. Itanium) */
|
/* (e.g. Itanium) */
|
||||||
/* (LINUX and HPUX) */
|
/* (LINUX and HPUX) */
|
||||||
/* IA64_32 ==> IA64 w/32 bit ABI */
|
|
||||||
/* (HPUX) */
|
|
||||||
/* SH ==> Hitachi SuperH */
|
/* SH ==> Hitachi SuperH */
|
||||||
/* (LINUX & MSWINCE) */
|
/* (LINUX & MSWINCE) */
|
||||||
/* X86_64 ==> AMD x86-64 */
|
/* 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.
|
* defining it to be 1 will always work, but perform poorly.
|
||||||
*
|
*
|
||||||
* DATASTART is the beginning of the data segment.
|
* 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.
|
* and DATAEND for root pointers.
|
||||||
*
|
*
|
||||||
* DATAEND, if not `end' where `end' is defined as ``extern int end[];''.
|
* 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
|
* 1) define STACK_GROWS_UP if the stack grows toward higher addresses, and
|
||||||
* 2) define exactly one of
|
* 2) define exactly one of
|
||||||
* STACKBOTTOM (should be defined to be an expression)
|
* STACKBOTTOM (should be defined to be an expression)
|
||||||
|
* LINUX_STACKBOTTOM
|
||||||
* HEURISTIC1
|
* HEURISTIC1
|
||||||
* HEURISTIC2
|
* 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
|
* If either of the last two macros are defined, then STACKBOTTOM is computed
|
||||||
* during collector startup using one of the following two heuristics:
|
* during collector startup using one of the following two heuristics:
|
||||||
* HEURISTIC1: Take an address inside GC_init's frame, and round it up to
|
* 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
|
* 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,
|
* clear the two words at GC_malloc-aligned address x. By default,
|
||||||
* word stores of 0 are used instead.
|
* 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()
|
/* If we are using a recent version of gcc, we can use __builtin_unwind_init()
|
||||||
|
@ -560,18 +605,25 @@
|
||||||
# ifdef NETBSD
|
# ifdef NETBSD
|
||||||
# define OS_TYPE "NETBSD"
|
# define OS_TYPE "NETBSD"
|
||||||
# define HEURISTIC2
|
# define HEURISTIC2
|
||||||
|
# ifdef __ELF__
|
||||||
|
# define DATASTART GC_data_start
|
||||||
|
# define DYNAMIC_LOADING
|
||||||
|
# else
|
||||||
extern char etext[];
|
extern char etext[];
|
||||||
# define DATASTART ((ptr_t)(etext))
|
# define DATASTART ((ptr_t)(etext))
|
||||||
# endif
|
# endif
|
||||||
|
# endif
|
||||||
# ifdef LINUX
|
# ifdef LINUX
|
||||||
# define OS_TYPE "LINUX"
|
# define OS_TYPE "LINUX"
|
||||||
# define STACKBOTTOM ((ptr_t)0xf0000000)
|
# 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 */
|
/* # define MPROTECT_VDB - Reported to not work 9/17/01 */
|
||||||
# ifdef __ELF__
|
# ifdef __ELF__
|
||||||
# define DYNAMIC_LOADING
|
# define DYNAMIC_LOADING
|
||||||
# include <features.h>
|
# include <features.h>
|
||||||
# if defined(__GLIBC__)&& __GLIBC__>=2
|
# if defined(__GLIBC__)&& __GLIBC__>=2
|
||||||
# define LINUX_DATA_START
|
# define SEARCH_FOR_DATA_START
|
||||||
# else /* !GLIBC2 */
|
# else /* !GLIBC2 */
|
||||||
extern char **__environ;
|
extern char **__environ;
|
||||||
# define DATASTART ((ptr_t)(&__environ))
|
# define DATASTART ((ptr_t)(&__environ))
|
||||||
|
@ -666,26 +718,49 @@
|
||||||
# define DATAEND /* not needed */
|
# define DATAEND /* not needed */
|
||||||
# endif
|
# endif
|
||||||
# ifdef LINUX
|
# ifdef LINUX
|
||||||
|
# if (defined (powerpc64) || defined(__powerpc64__))
|
||||||
|
# define ALIGNMENT 8
|
||||||
|
# define CPP_WORDSZ 64
|
||||||
|
# else
|
||||||
# define ALIGNMENT 4 /* Guess. Can someone verify? */
|
# define ALIGNMENT 4 /* Guess. Can someone verify? */
|
||||||
/* This was 2, but that didn't sound right. */
|
/* This was 2, but that didn't sound right. */
|
||||||
|
# endif
|
||||||
# define OS_TYPE "LINUX"
|
# 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
|
# define LINUX_STACKBOTTOM
|
||||||
/* Stack usually starts at 0x80000000 */
|
# define DYNAMIC_LOADING
|
||||||
# define LINUX_DATA_START
|
# define SEARCH_FOR_DATA_START
|
||||||
extern int _end[];
|
extern int _end[];
|
||||||
# define DATAEND (_end)
|
# define DATAEND (_end)
|
||||||
# endif
|
# endif
|
||||||
# ifdef MACOSX
|
# ifdef DARWIN
|
||||||
/* There are reasons to suspect this may not be reliable. */
|
|
||||||
# define ALIGNMENT 4
|
# 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 DATASTART ((ptr_t) get_etext())
|
||||||
|
# define DATAEND ((ptr_t) get_end())
|
||||||
# define STACKBOTTOM ((ptr_t) 0xc0000000)
|
# define STACKBOTTOM ((ptr_t) 0xc0000000)
|
||||||
# define DATAEND /* not needed */
|
# define USE_MMAP
|
||||||
# undef MPROTECT_VDB
|
# 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>
|
# include <unistd.h>
|
||||||
# define GETPAGESIZE() getpagesize()
|
# 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
|
# endif
|
||||||
# ifdef NETBSD
|
# ifdef NETBSD
|
||||||
# define ALIGNMENT 4
|
# define ALIGNMENT 4
|
||||||
|
@ -746,8 +821,8 @@
|
||||||
# define OS_TYPE "SUNOS5"
|
# define OS_TYPE "SUNOS5"
|
||||||
extern int _etext[];
|
extern int _etext[];
|
||||||
extern int _end[];
|
extern int _end[];
|
||||||
extern char * GC_SysVGetDataStart();
|
extern ptr_t GC_SysVGetDataStart();
|
||||||
# define DATASTART (ptr_t)GC_SysVGetDataStart(0x10000, _etext)
|
# define DATASTART GC_SysVGetDataStart(0x10000, _etext)
|
||||||
# define DATAEND (_end)
|
# define DATAEND (_end)
|
||||||
# if !defined(USE_MMAP) && defined(REDIRECT_MALLOC)
|
# if !defined(USE_MMAP) && defined(REDIRECT_MALLOC)
|
||||||
# define USE_MMAP
|
# define USE_MMAP
|
||||||
|
@ -801,9 +876,9 @@
|
||||||
# endif
|
# endif
|
||||||
# ifdef DRSNX
|
# ifdef DRSNX
|
||||||
# define OS_TYPE "DRSNX"
|
# define OS_TYPE "DRSNX"
|
||||||
extern char * GC_SysVGetDataStart();
|
extern ptr_t GC_SysVGetDataStart();
|
||||||
extern int etext[];
|
extern int etext[];
|
||||||
# define DATASTART (ptr_t)GC_SysVGetDataStart(0x10000, etext)
|
# define DATASTART GC_SysVGetDataStart(0x10000, etext)
|
||||||
# define MPROTECT_VDB
|
# define MPROTECT_VDB
|
||||||
# define STACKBOTTOM ((ptr_t) 0xdfff0000)
|
# define STACKBOTTOM ((ptr_t) 0xdfff0000)
|
||||||
# define DYNAMIC_LOADING
|
# define DYNAMIC_LOADING
|
||||||
|
@ -819,13 +894,14 @@
|
||||||
extern int _etext[];
|
extern int _etext[];
|
||||||
# define DATAEND (_end)
|
# define DATAEND (_end)
|
||||||
# define SVR4
|
# define SVR4
|
||||||
|
extern ptr_t GC_SysVGetDataStart();
|
||||||
# ifdef __arch64__
|
# ifdef __arch64__
|
||||||
|
# define DATASTART GC_SysVGetDataStart(0x100000, _etext)
|
||||||
/* libc_stack_end is not set reliably for sparc64 */
|
/* libc_stack_end is not set reliably for sparc64 */
|
||||||
# define STACKBOTTOM ((ptr_t) 0x80000000000)
|
# define STACKBOTTOM ((ptr_t) 0x80000000000ULL)
|
||||||
# define DATASTART (ptr_t)GC_SysVGetDataStart(0x100000, _etext)
|
|
||||||
# else
|
# else
|
||||||
|
# define DATASTART GC_SysVGetDataStart(0x10000, _etext)
|
||||||
# define LINUX_STACKBOTTOM
|
# define LINUX_STACKBOTTOM
|
||||||
# define DATASTART (ptr_t)GC_SysVGetDataStart(0x10000, _etext)
|
|
||||||
# endif
|
# endif
|
||||||
# endif
|
# endif
|
||||||
# ifdef OPENBSD
|
# ifdef OPENBSD
|
||||||
|
@ -876,7 +952,7 @@
|
||||||
# ifdef SUNOS5
|
# ifdef SUNOS5
|
||||||
# define OS_TYPE "SUNOS5"
|
# define OS_TYPE "SUNOS5"
|
||||||
extern int _etext[], _end[];
|
extern int _etext[], _end[];
|
||||||
extern char * GC_SysVGetDataStart();
|
extern ptr_t GC_SysVGetDataStart();
|
||||||
# define DATASTART GC_SysVGetDataStart(0x1000, _etext)
|
# define DATASTART GC_SysVGetDataStart(0x1000, _etext)
|
||||||
# define DATAEND (_end)
|
# define DATAEND (_end)
|
||||||
/* # define STACKBOTTOM ((ptr_t)(_start)) worked through 2.7, */
|
/* # define STACKBOTTOM ((ptr_t)(_start)) worked through 2.7, */
|
||||||
|
@ -921,6 +997,28 @@
|
||||||
# define DYNAMIC_LOADING
|
# define DYNAMIC_LOADING
|
||||||
# define ELF_CLASS ELFCLASS32
|
# define ELF_CLASS ELFCLASS32
|
||||||
# endif
|
# 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
|
# ifdef LINUX
|
||||||
# ifndef __GNUC__
|
# ifndef __GNUC__
|
||||||
/* The Intel compiler doesn't like inline assembly */
|
/* The Intel compiler doesn't like inline assembly */
|
||||||
|
@ -944,6 +1042,9 @@
|
||||||
/* possibly because Linux threads is itself a malloc client */
|
/* possibly because Linux threads is itself a malloc client */
|
||||||
/* and can't deal with the signals. */
|
/* and can't deal with the signals. */
|
||||||
# endif
|
# endif
|
||||||
|
# define HEAP_START 0x1000
|
||||||
|
/* This encourages mmap to give us low addresses, */
|
||||||
|
/* thus allowing the heap to grow to ~3GB */
|
||||||
# ifdef __ELF__
|
# ifdef __ELF__
|
||||||
# define DYNAMIC_LOADING
|
# define DYNAMIC_LOADING
|
||||||
# ifdef UNDEFINED /* includes ro data */
|
# ifdef UNDEFINED /* includes ro data */
|
||||||
|
@ -952,7 +1053,7 @@
|
||||||
# endif
|
# endif
|
||||||
# include <features.h>
|
# include <features.h>
|
||||||
# if defined(__GLIBC__) && __GLIBC__ >= 2
|
# if defined(__GLIBC__) && __GLIBC__ >= 2
|
||||||
# define LINUX_DATA_START
|
# define SEARCH_FOR_DATA_START
|
||||||
# else
|
# else
|
||||||
extern char **__environ;
|
extern char **__environ;
|
||||||
# define DATASTART ((ptr_t)(&__environ))
|
# define DATASTART ((ptr_t)(&__environ))
|
||||||
|
@ -1006,8 +1107,12 @@
|
||||||
/* DATAEND = _data_end__ */
|
/* DATAEND = _data_end__ */
|
||||||
/* To get it right for both, we take the */
|
/* To get it right for both, we take the */
|
||||||
/* minumum/maximum of the two. */
|
/* minumum/maximum of the two. */
|
||||||
|
# ifndef MAX
|
||||||
# define MAX(x,y) ((x) > (y) ? (x) : (y))
|
# define MAX(x,y) ((x) > (y) ? (x) : (y))
|
||||||
|
# endif
|
||||||
|
# ifndef MIN
|
||||||
# define MIN(x,y) ((x) < (y) ? (x) : (y))
|
# define MIN(x,y) ((x) < (y) ? (x) : (y))
|
||||||
|
# endif
|
||||||
# define DATASTART ((ptr_t) MIN(_data_start__, _bss_start__))
|
# define DATASTART ((ptr_t) MIN(_data_start__, _bss_start__))
|
||||||
# define DATAEND ((ptr_t) MAX(_data_end__, _bss_end__))
|
# define DATAEND ((ptr_t) MAX(_data_end__, _bss_end__))
|
||||||
# undef STACK_GRAN
|
# undef STACK_GRAN
|
||||||
|
@ -1061,16 +1166,9 @@
|
||||||
# ifdef __ELF__
|
# ifdef __ELF__
|
||||||
# define DYNAMIC_LOADING
|
# define DYNAMIC_LOADING
|
||||||
# endif
|
# endif
|
||||||
/* Handle unmapped hole i386*-*-freebsd[45]* may put between etext and edata. */
|
|
||||||
extern char etext[];
|
extern char etext[];
|
||||||
extern char edata[];
|
extern char * GC_FreeBSDGetDataStart();
|
||||||
extern char end[];
|
# define DATASTART GC_FreeBSDGetDataStart(0x1000, &etext)
|
||||||
# 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))
|
|
||||||
# endif
|
# endif
|
||||||
# ifdef NETBSD
|
# ifdef NETBSD
|
||||||
# define OS_TYPE "NETBSD"
|
# define OS_TYPE "NETBSD"
|
||||||
|
@ -1149,7 +1247,11 @@
|
||||||
# define DATASTART ((ptr_t)(__data_start))
|
# define DATASTART ((ptr_t)(__data_start))
|
||||||
# define ALIGNMENT 4
|
# define ALIGNMENT 4
|
||||||
# define USE_GENERIC_PUSH_REGS
|
# define USE_GENERIC_PUSH_REGS
|
||||||
|
# if __GLIBC__ == 2 && __GLIBC_MINOR__ >= 2 || __GLIBC__ > 2
|
||||||
# define LINUX_STACKBOTTOM
|
# define LINUX_STACKBOTTOM
|
||||||
|
# else
|
||||||
|
# define STACKBOTTOM 0x80000000
|
||||||
|
# endif
|
||||||
# endif /* Linux */
|
# endif /* Linux */
|
||||||
# ifdef EWS4800
|
# ifdef EWS4800
|
||||||
# define HEURISTIC2
|
# define HEURISTIC2
|
||||||
|
@ -1203,7 +1305,8 @@
|
||||||
/* heap sections so they're not */
|
/* heap sections so they're not */
|
||||||
/* considered as roots. */
|
/* considered as roots. */
|
||||||
# define OS_TYPE "IRIX5"
|
# define OS_TYPE "IRIX5"
|
||||||
# define MPROTECT_VDB
|
/*# define MPROTECT_VDB DOB: this should work, but there is evidence */
|
||||||
|
/* of recent breakage. */
|
||||||
# ifdef _MIPS_SZPTR
|
# ifdef _MIPS_SZPTR
|
||||||
# define CPP_WORDSZ _MIPS_SZPTR
|
# define CPP_WORDSZ _MIPS_SZPTR
|
||||||
# define ALIGNMENT (_MIPS_SZPTR/8)
|
# define ALIGNMENT (_MIPS_SZPTR/8)
|
||||||
|
@ -1226,28 +1329,46 @@
|
||||||
# define ALIGNMENT 4
|
# define ALIGNMENT 4
|
||||||
# define HEURISTIC2
|
# define HEURISTIC2
|
||||||
# define USE_GENERIC_PUSH_REGS
|
# define USE_GENERIC_PUSH_REGS
|
||||||
extern int _fdata[];
|
# ifdef __ELF__
|
||||||
# define DATASTART ((ptr_t)(_fdata))
|
extern int etext[];
|
||||||
extern int _end[];
|
# define DATASTART GC_data_start
|
||||||
# define DATAEND ((ptr_t)(_end))
|
# define NEED_FIND_LIMIT
|
||||||
# define DYNAMIC_LOADING
|
# define DYNAMIC_LOADING
|
||||||
|
# else
|
||||||
|
# define DATASTART ((ptr_t) 0x10000000)
|
||||||
|
# define STACKBOTTOM ((ptr_t) 0x7ffff000)
|
||||||
|
# endif /* _ELF_ */
|
||||||
# endif
|
# endif
|
||||||
# endif
|
# endif
|
||||||
|
|
||||||
# ifdef RS6000
|
# ifdef RS6000
|
||||||
# define MACH_TYPE "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__
|
# ifdef __64BIT__
|
||||||
# define ALIGNMENT 8
|
# define ALIGNMENT 8
|
||||||
# define CPP_WORDSZ 64
|
# define CPP_WORDSZ 64
|
||||||
|
# define STACKBOTTOM ((ptr_t)0x1000000000000000)
|
||||||
# else
|
# else
|
||||||
# define ALIGNMENT 4
|
# define ALIGNMENT 4
|
||||||
# define CPP_WORDSZ 32
|
# define CPP_WORDSZ 32
|
||||||
|
# define STACKBOTTOM ((ptr_t)((ulong)&errno))
|
||||||
# endif
|
# 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[];
|
extern int _data[], _end[];
|
||||||
# define DATASTART ((ptr_t)((ulong)_data))
|
# define DATASTART ((ptr_t)((ulong)_data))
|
||||||
# define DATAEND ((ptr_t)((ulong)_end))
|
# define DATAEND ((ptr_t)((ulong)_end))
|
||||||
extern int errno;
|
extern int errno;
|
||||||
# define STACKBOTTOM ((ptr_t)((ulong)&errno))
|
|
||||||
# define USE_GENERIC_PUSH_REGS
|
# define USE_GENERIC_PUSH_REGS
|
||||||
# define DYNAMIC_LOADING
|
# define DYNAMIC_LOADING
|
||||||
/* For really old versions of AIX, this may have to be removed. */
|
/* For really old versions of AIX, this may have to be removed. */
|
||||||
|
@ -1311,15 +1432,23 @@
|
||||||
# define OS_TYPE "LINUX"
|
# define OS_TYPE "LINUX"
|
||||||
# define LINUX_STACKBOTTOM
|
# define LINUX_STACKBOTTOM
|
||||||
# define DYNAMIC_LOADING
|
# define DYNAMIC_LOADING
|
||||||
# define LINUX_DATA_START
|
# define SEARCH_FOR_DATA_START
|
||||||
extern int _end[];
|
extern int _end[];
|
||||||
# define DATAEND (_end)
|
# define DATAEND (&_end)
|
||||||
# endif /* LINUX */
|
# endif /* LINUX */
|
||||||
# endif /* HP_PA */
|
# endif /* HP_PA */
|
||||||
|
|
||||||
# ifdef ALPHA
|
# ifdef ALPHA
|
||||||
# define MACH_TYPE "ALPHA"
|
# define MACH_TYPE "ALPHA"
|
||||||
# define ALIGNMENT 8
|
# 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
|
# ifdef NETBSD
|
||||||
# define OS_TYPE "NETBSD"
|
# define OS_TYPE "NETBSD"
|
||||||
# define HEURISTIC2
|
# define HEURISTIC2
|
||||||
|
@ -1327,13 +1456,11 @@
|
||||||
# define ELFCLASS32 32
|
# define ELFCLASS32 32
|
||||||
# define ELFCLASS64 64
|
# define ELFCLASS64 64
|
||||||
# define ELF_CLASS ELFCLASS64
|
# define ELF_CLASS ELFCLASS64
|
||||||
# define CPP_WORDSZ 64
|
|
||||||
# define DYNAMIC_LOADING
|
# define DYNAMIC_LOADING
|
||||||
# endif
|
# endif
|
||||||
# ifdef OPENBSD
|
# ifdef OPENBSD
|
||||||
# define OS_TYPE "OPENBSD"
|
# define OS_TYPE "OPENBSD"
|
||||||
# define HEURISTIC2
|
# define HEURISTIC2
|
||||||
# define CPP_WORDSZ 64
|
|
||||||
# ifdef __ELF__ /* since OpenBSD/Alpha 2.9 */
|
# ifdef __ELF__ /* since OpenBSD/Alpha 2.9 */
|
||||||
# define DATASTART GC_data_start
|
# define DATASTART GC_data_start
|
||||||
# define ELFCLASS32 32
|
# define ELFCLASS32 32
|
||||||
|
@ -1357,17 +1484,16 @@
|
||||||
extern char edata[];
|
extern char edata[];
|
||||||
extern char end[];
|
extern char end[];
|
||||||
# define NEED_FIND_LIMIT
|
# define NEED_FIND_LIMIT
|
||||||
# define DATASTART ((ptr_t)(etext))
|
# define DATASTART ((ptr_t)(&etext))
|
||||||
# define DATAEND (GC_find_limit (DATASTART, TRUE))
|
# define DATAEND (GC_find_limit (DATASTART, TRUE))
|
||||||
# define DATASTART2 ((ptr_t)(edata))
|
# define DATASTART2 ((ptr_t)(&edata))
|
||||||
# define DATAEND2 ((ptr_t)(end))
|
# define DATAEND2 ((ptr_t)(&end))
|
||||||
# define CPP_WORDSZ 64
|
|
||||||
# endif
|
# endif
|
||||||
# ifdef OSF1
|
# ifdef OSF1
|
||||||
# define OS_TYPE "OSF1"
|
# define OS_TYPE "OSF1"
|
||||||
# define DATASTART ((ptr_t) 0x140000000)
|
# define DATASTART ((ptr_t) 0x140000000)
|
||||||
extern int _end[];
|
extern int _end[];
|
||||||
# define DATAEND ((ptr_t) _end)
|
# define DATAEND ((ptr_t) &_end)
|
||||||
extern char ** environ;
|
extern char ** environ;
|
||||||
/* round up from the value of environ to the nearest page boundary */
|
/* round up from the value of environ to the nearest page boundary */
|
||||||
/* Probably breaks if putenv is called before collector */
|
/* Probably breaks if putenv is called before collector */
|
||||||
|
@ -1380,17 +1506,17 @@
|
||||||
/* This is currently unused, since we disabled HEURISTIC2 */
|
/* This is currently unused, since we disabled HEURISTIC2 */
|
||||||
extern int __start[];
|
extern int __start[];
|
||||||
# define HEURISTIC2_LIMIT ((ptr_t)((word)(__start) & ~(getpagesize()-1)))
|
# define HEURISTIC2_LIMIT ((ptr_t)((word)(__start) & ~(getpagesize()-1)))
|
||||||
# define CPP_WORDSZ 64
|
# ifndef GC_OSF1_THREADS
|
||||||
|
/* Unresolved signal issues with threads. */
|
||||||
# define MPROTECT_VDB
|
# define MPROTECT_VDB
|
||||||
|
# endif
|
||||||
# define DYNAMIC_LOADING
|
# define DYNAMIC_LOADING
|
||||||
# endif
|
# endif
|
||||||
# ifdef LINUX
|
# ifdef LINUX
|
||||||
# define OS_TYPE "LINUX"
|
# define OS_TYPE "LINUX"
|
||||||
# define CPP_WORDSZ 64
|
|
||||||
# define STACKBOTTOM ((ptr_t) 0x120000000)
|
# define STACKBOTTOM ((ptr_t) 0x120000000)
|
||||||
# ifdef __ELF__
|
# ifdef __ELF__
|
||||||
# define SEARCH_FOR_DATA_START
|
# define SEARCH_FOR_DATA_START
|
||||||
# define DATASTART GC_data_start
|
|
||||||
# define DYNAMIC_LOADING
|
# define DYNAMIC_LOADING
|
||||||
# else
|
# else
|
||||||
# define DATASTART ((ptr_t) 0x140000000)
|
# define DATASTART ((ptr_t) 0x140000000)
|
||||||
|
@ -1468,7 +1594,6 @@
|
||||||
extern char * GC_register_stackbottom;
|
extern char * GC_register_stackbottom;
|
||||||
# define BACKING_STORE_BASE ((ptr_t)GC_register_stackbottom)
|
# define BACKING_STORE_BASE ((ptr_t)GC_register_stackbottom)
|
||||||
# define SEARCH_FOR_DATA_START
|
# define SEARCH_FOR_DATA_START
|
||||||
# define DATASTART GC_data_start
|
|
||||||
# ifdef __GNUC__
|
# ifdef __GNUC__
|
||||||
# define DYNAMIC_LOADING
|
# define DYNAMIC_LOADING
|
||||||
# else
|
# else
|
||||||
|
@ -1502,13 +1627,15 @@
|
||||||
# endif
|
# endif
|
||||||
# ifdef DGUX
|
# ifdef DGUX
|
||||||
# define OS_TYPE "DGUX"
|
# define OS_TYPE "DGUX"
|
||||||
extern char * GC_SysVGetDataStart();
|
extern ptr_t GC_SysVGetDataStart();
|
||||||
# define DATASTART (ptr_t)GC_SysVGetDataStart(0x10000, etext)
|
# define DATASTART GC_SysVGetDataStart(0x10000, etext)
|
||||||
# endif
|
# endif
|
||||||
# define STACKBOTTOM ((char*)0xf0000000) /* determined empirically */
|
# define STACKBOTTOM ((char*)0xf0000000) /* determined empirically */
|
||||||
# endif
|
# endif
|
||||||
|
|
||||||
# ifdef S370
|
# ifdef S370
|
||||||
|
/* If this still works, and if anyone cares, this should probably */
|
||||||
|
/* be moved to the S390 category. */
|
||||||
# define MACH_TYPE "S370"
|
# define MACH_TYPE "S370"
|
||||||
# define ALIGNMENT 4 /* Required by hardware */
|
# define ALIGNMENT 4 /* Required by hardware */
|
||||||
# define USE_GENERIC_PUSH_REGS
|
# define USE_GENERIC_PUSH_REGS
|
||||||
|
@ -1517,8 +1644,8 @@
|
||||||
extern int etext[];
|
extern int etext[];
|
||||||
extern int _etext[];
|
extern int _etext[];
|
||||||
extern int _end[];
|
extern int _end[];
|
||||||
extern char * GC_SysVGetDataStart();
|
extern ptr_t GC_SysVGetDataStart();
|
||||||
# define DATASTART (ptr_t)GC_SysVGetDataStart(0x10000, _etext)
|
# define DATASTART GC_SysVGetDataStart(0x10000, _etext)
|
||||||
# define DATAEND (_end)
|
# define DATAEND (_end)
|
||||||
# define HEURISTIC2
|
# define HEURISTIC2
|
||||||
# endif
|
# endif
|
||||||
|
@ -1562,13 +1689,8 @@
|
||||||
# ifdef NETBSD
|
# ifdef NETBSD
|
||||||
# define OS_TYPE "NETBSD"
|
# define OS_TYPE "NETBSD"
|
||||||
# define HEURISTIC2
|
# define HEURISTIC2
|
||||||
# ifdef __ELF__
|
|
||||||
# define DATASTART GC_data_start
|
|
||||||
# define DYNAMIC_LOADING
|
|
||||||
# else
|
|
||||||
extern char etext[];
|
extern char etext[];
|
||||||
# define DATASTART ((ptr_t)(etext))
|
# define DATASTART ((ptr_t)(etext))
|
||||||
# endif
|
|
||||||
# define USE_GENERIC_PUSH_REGS
|
# define USE_GENERIC_PUSH_REGS
|
||||||
# endif
|
# endif
|
||||||
# ifdef LINUX
|
# ifdef LINUX
|
||||||
|
@ -1581,7 +1703,7 @@
|
||||||
# define DYNAMIC_LOADING
|
# define DYNAMIC_LOADING
|
||||||
# include <features.h>
|
# include <features.h>
|
||||||
# if defined(__GLIBC__) && __GLIBC__ >= 2
|
# if defined(__GLIBC__) && __GLIBC__ >= 2
|
||||||
# define LINUX_DATA_START
|
# define SEARCH_FOR_DATA_START
|
||||||
# else
|
# else
|
||||||
extern char **__environ;
|
extern char **__environ;
|
||||||
# define DATASTART ((ptr_t)(&__environ))
|
# define DATASTART ((ptr_t)(&__environ))
|
||||||
|
@ -1628,7 +1750,7 @@
|
||||||
# define STACKBOTTOM ((ptr_t) 0x7c000000)
|
# define STACKBOTTOM ((ptr_t) 0x7c000000)
|
||||||
# define USE_GENERIC_PUSH_REGS
|
# define USE_GENERIC_PUSH_REGS
|
||||||
# define DYNAMIC_LOADING
|
# define DYNAMIC_LOADING
|
||||||
# define LINUX_DATA_START
|
# define SEARCH_FOR_DATA_START
|
||||||
extern int _end[];
|
extern int _end[];
|
||||||
# define DATAEND (_end)
|
# define DATAEND (_end)
|
||||||
# endif
|
# endif
|
||||||
|
@ -1645,7 +1767,9 @@
|
||||||
# define MACH_TYPE "X86_64"
|
# define MACH_TYPE "X86_64"
|
||||||
# define ALIGNMENT 8
|
# define ALIGNMENT 8
|
||||||
# define CPP_WORDSZ 64
|
# define CPP_WORDSZ 64
|
||||||
|
# ifndef HBLKSIZE
|
||||||
# define HBLKSIZE 4096
|
# define HBLKSIZE 4096
|
||||||
|
# endif
|
||||||
# define CACHE_LINE_SIZE 64
|
# define CACHE_LINE_SIZE 64
|
||||||
# define USE_GENERIC_PUSH_REGS
|
# define USE_GENERIC_PUSH_REGS
|
||||||
# ifdef LINUX
|
# ifdef LINUX
|
||||||
|
@ -1665,7 +1789,7 @@
|
||||||
# define DATASTART ((ptr_t)((((word) (_etext)) + 0xfff) & ~0xfff))
|
# define DATASTART ((ptr_t)((((word) (_etext)) + 0xfff) & ~0xfff))
|
||||||
# endif
|
# endif
|
||||||
# include <features.h>
|
# include <features.h>
|
||||||
# define LINUX_DATA_START
|
# define SEARCH_FOR_DATA_START
|
||||||
extern int _end[];
|
extern int _end[];
|
||||||
# define DATAEND (_end)
|
# define DATAEND (_end)
|
||||||
# else
|
# else
|
||||||
|
@ -1679,19 +1803,6 @@
|
||||||
# endif
|
# endif
|
||||||
# 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)
|
#if defined(LINUX) && defined(REDIRECT_MALLOC)
|
||||||
/* Rld appears to allocate some memory with its own allocator, and */
|
/* Rld appears to allocate some memory with its own allocator, and */
|
||||||
/* some through malloc, which might be redirected. To make this */
|
/* some through malloc, which might be redirected. To make this */
|
||||||
|
@ -1748,7 +1859,8 @@
|
||||||
|
|
||||||
# if defined(SVR4) || defined(LINUX) || defined(IRIX) || defined(HPUX) \
|
# if defined(SVR4) || defined(LINUX) || defined(IRIX) || defined(HPUX) \
|
||||||
|| defined(OPENBSD) || defined(NETBSD) || defined(FREEBSD) \
|
|| defined(OPENBSD) || defined(NETBSD) || defined(FREEBSD) \
|
||||||
|| defined(BSD) || defined(_AIX) || defined(MACOSX) || defined(OSF1)
|
|| defined(DGUX) || defined(BSD) \
|
||||||
|
|| defined(_AIX) || defined(DARWIN) || defined(OSF1)
|
||||||
# define UNIX_LIKE /* Basic Unix-like system calls work. */
|
# define UNIX_LIKE /* Basic Unix-like system calls work. */
|
||||||
# endif
|
# endif
|
||||||
|
|
||||||
|
@ -1813,8 +1925,9 @@
|
||||||
/* platforms as well, though it should be avoided in win32. */
|
/* platforms as well, though it should be avoided in win32. */
|
||||||
# endif /* LINUX */
|
# endif /* LINUX */
|
||||||
|
|
||||||
# if defined(SEARCH_FOR_DATA_START) && defined(GC_PRIVATE_H)
|
# if defined(SEARCH_FOR_DATA_START)
|
||||||
extern ptr_t GC_data_start;
|
extern ptr_t GC_data_start;
|
||||||
|
# define DATASTART GC_data_start
|
||||||
# endif
|
# endif
|
||||||
|
|
||||||
# ifndef CLEAR_DOUBLE
|
# ifndef CLEAR_DOUBLE
|
||||||
|
@ -1840,10 +1953,10 @@
|
||||||
# if defined(GC_HPUX_THREADS) && !defined(HPUX)
|
# if defined(GC_HPUX_THREADS) && !defined(HPUX)
|
||||||
--> inconsistent configuration
|
--> inconsistent configuration
|
||||||
# endif
|
# endif
|
||||||
# if defined(GC_WIN32_THREADS) && !defined(MSWIN32)
|
# if defined(GC_AIX_THREADS) && !defined(_AIX)
|
||||||
/* Ideally CYGWIN32 should work, in addition to MSWIN32. I suspect */
|
--> inconsistent configuration
|
||||||
/* the necessary code is mostly there, but nobody has actually made */
|
# endif
|
||||||
/* sure the right combination of pieces is compiled in, etc. */
|
# if defined(GC_WIN32_THREADS) && !defined(MSWIN32) && !defined(CYGWIN32)
|
||||||
--> inconsistent configuration
|
--> inconsistent configuration
|
||||||
# endif
|
# endif
|
||||||
|
|
||||||
|
@ -1853,8 +1966,8 @@
|
||||||
# define THREADS
|
# define THREADS
|
||||||
# endif
|
# endif
|
||||||
|
|
||||||
# if defined(HP_PA) || defined(M88K) || defined(POWERPC) && !defined(MACOSX) \
|
# if defined(HP_PA) || defined(M88K) || defined(POWERPC) && !defined(DARWIN) \
|
||||||
|| defined(LINT) || defined(MSWINCE) \
|
|| defined(LINT) || defined(MSWINCE) || defined(ARM32) \
|
||||||
|| (defined(I386) && defined(__LCC__))
|
|| (defined(I386) && defined(__LCC__))
|
||||||
/* Use setjmp based hack to mark from callee-save registers. */
|
/* Use setjmp based hack to mark from callee-save registers. */
|
||||||
/* The define should move to the individual platform */
|
/* The define should move to the individual platform */
|
||||||
|
@ -1868,35 +1981,25 @@
|
||||||
# endif
|
# endif
|
||||||
|
|
||||||
/* Can we save call chain in objects for debugging? */
|
/* Can we save call chain in objects for debugging? */
|
||||||
/* SET NFRAMES (# of saved frames) and NARGS (#of args for each frame) */
|
/* SET NFRAMES (# of saved frames) and NARGS (#of args for each */
|
||||||
/* to reasonable values for the platform. */
|
/* frame) to reasonable values for the platform. */
|
||||||
/* Set SAVE_CALL_CHAIN if we can. SAVE_CALL_COUNT can be specified at */
|
/* Set SAVE_CALL_CHAIN if we can. SAVE_CALL_COUNT can be specified */
|
||||||
/* build time, though we feel free to adjust it slightly. */
|
/* at build time, though we feel free to adjust it slightly. */
|
||||||
/* Define NEED_CALLINFO if we either save the call stack or */
|
/* Define NEED_CALLINFO if we either save the call stack or */
|
||||||
/* GC_ADD_CALLER is defined. */
|
/* GC_ADD_CALLER is defined. */
|
||||||
#ifdef LINUX
|
/* GC_CAN_SAVE_CALL_STACKS is set in gc.h. */
|
||||||
# include <features.h>
|
|
||||||
# if __GLIBC__ == 2 && __GLIBC_MINOR__ >= 1 || __GLIBC__ > 2
|
|
||||||
# define HAVE_BUILTIN_BACKTRACE
|
|
||||||
# endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if defined(SPARC)
|
#if defined(SPARC)
|
||||||
# define CAN_SAVE_CALL_STACKS
|
|
||||||
# define CAN_SAVE_CALL_ARGS
|
# define CAN_SAVE_CALL_ARGS
|
||||||
#endif
|
#endif
|
||||||
#if (defined(I386) || defined(X86_64)) && defined(LINUX)
|
#if (defined(I386) || defined(X86_64)) && defined(LINUX)
|
||||||
/* SAVE_CALL_CHAIN is supported if the code is compiled to save */
|
/* SAVE_CALL_CHAIN is supported if the code is compiled to save */
|
||||||
/* frame pointers by default, i.e. no -fomit-frame-pointer flag. */
|
/* frame pointers by default, i.e. no -fomit-frame-pointer flag. */
|
||||||
# define CAN_SAVE_CALL_STACKS
|
|
||||||
# define CAN_SAVE_CALL_ARGS
|
# define CAN_SAVE_CALL_ARGS
|
||||||
#endif
|
#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) \
|
# if defined(SAVE_CALL_COUNT) && !defined(GC_ADD_CALLER) \
|
||||||
&& defined(CAN_SAVE_CALL_STACKS)
|
&& defined(GC_CAN_SAVE_CALL_STACKS)
|
||||||
# define SAVE_CALL_CHAIN
|
# define SAVE_CALL_CHAIN
|
||||||
# endif
|
# endif
|
||||||
# ifdef SAVE_CALL_CHAIN
|
# ifdef SAVE_CALL_CHAIN
|
||||||
|
@ -1925,4 +2028,96 @@
|
||||||
# define DBG_HDRS_ALL
|
# define DBG_HDRS_ALL
|
||||||
# endif
|
# 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 */
|
# endif /* GCCONFIG_H */
|
||||||
|
|
|
@ -16,7 +16,8 @@
|
||||||
# define DETACHED 2 /* Thread is intended to be detached. */
|
# define DETACHED 2 /* Thread is intended to be detached. */
|
||||||
# define CLIENT_OWNS_STACK 4
|
# define CLIENT_OWNS_STACK 4
|
||||||
/* Stack was supplied by client. */
|
/* Stack was supplied by client. */
|
||||||
# define SUSPENDED 8 /* Currently suspended. */
|
# define SUSPNDED 8 /* Currently suspended. */
|
||||||
|
/* SUSPENDED is used insystem header. */
|
||||||
ptr_t stack;
|
ptr_t stack;
|
||||||
size_t stack_size;
|
size_t stack_size;
|
||||||
cond_t join_cv;
|
cond_t join_cv;
|
||||||
|
|
|
@ -85,7 +85,7 @@ static __inline__ void * PREFIXED(getspecific) (tsd * key) {
|
||||||
unsigned hash_val = CACHE_HASH(qtid);
|
unsigned hash_val = CACHE_HASH(qtid);
|
||||||
tse * volatile * entry_ptr = key -> cache + hash_val;
|
tse * volatile * entry_ptr = key -> cache + hash_val;
|
||||||
tse * entry = *entry_ptr; /* Must be loaded only once. */
|
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());
|
GC_ASSERT(entry -> thread == pthread_self());
|
||||||
return entry -> value;
|
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 */
|
/* on your architecture. Run the test_setjmp program to see whether */
|
||||||
/* there is any chance it will work. */
|
/* 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()
|
void GC_push_regs()
|
||||||
{
|
{
|
||||||
# ifdef RT
|
# ifdef RT
|
||||||
|
@ -91,6 +92,7 @@ void GC_push_regs()
|
||||||
asm("pushl r8"); asm("calls $1,_GC_push_one");
|
asm("pushl r8"); asm("calls $1,_GC_push_one");
|
||||||
asm("pushl r7"); asm("calls $1,_GC_push_one");
|
asm("pushl r7"); asm("calls $1,_GC_push_one");
|
||||||
asm("pushl r6"); asm("calls $1,_GC_push_one");
|
asm("pushl r6"); asm("calls $1,_GC_push_one");
|
||||||
|
# define HAVE_PUSH_REGS
|
||||||
# endif
|
# endif
|
||||||
# if defined(M68K) && (defined(SUNOS4) || defined(NEXT))
|
# if defined(M68K) && (defined(SUNOS4) || defined(NEXT))
|
||||||
/* M68K SUNOS - could be replaced by generic code */
|
/* 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("movl d7,sp@"); asm("jbsr _GC_push_one");
|
||||||
|
|
||||||
asm("addqw #0x4,sp"); /* put stack back where it was */
|
asm("addqw #0x4,sp"); /* put stack back where it was */
|
||||||
|
# define HAVE_PUSH_REGS
|
||||||
# endif
|
# endif
|
||||||
|
|
||||||
# if defined(M68K) && defined(HP)
|
# if defined(M68K) && defined(HP)
|
||||||
|
@ -135,6 +138,7 @@ void GC_push_regs()
|
||||||
asm("mov.l %d7,(%sp)"); asm("jsr _GC_push_one");
|
asm("mov.l %d7,(%sp)"); asm("jsr _GC_push_one");
|
||||||
|
|
||||||
asm("addq.w &0x4,%sp"); /* put stack back where it was */
|
asm("addq.w &0x4,%sp"); /* put stack back where it was */
|
||||||
|
# define HAVE_PUSH_REGS
|
||||||
# endif /* M68K HP */
|
# endif /* M68K HP */
|
||||||
|
|
||||||
# if defined(M68K) && defined(AMIGA)
|
# if defined(M68K) && defined(AMIGA)
|
||||||
|
@ -158,6 +162,7 @@ void GC_push_regs()
|
||||||
asm("mov.l %d7,(%sp)"); asm("jsr _GC_push_one");
|
asm("mov.l %d7,(%sp)"); asm("jsr _GC_push_one");
|
||||||
|
|
||||||
asm("addq.w &0x4,%sp"); /* put stack back where it was */
|
asm("addq.w &0x4,%sp"); /* put stack back where it was */
|
||||||
|
# define HAVE_PUSH_REGS
|
||||||
# else /* !__GNUC__ */
|
# else /* !__GNUC__ */
|
||||||
GC_push_one(getreg(REG_A2));
|
GC_push_one(getreg(REG_A2));
|
||||||
GC_push_one(getreg(REG_A3));
|
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_D5));
|
||||||
GC_push_one(getreg(REG_D6));
|
GC_push_one(getreg(REG_D6));
|
||||||
GC_push_one(getreg(REG_D7));
|
GC_push_one(getreg(REG_D7));
|
||||||
|
# define HAVE_PUSH_REGS
|
||||||
# endif /* !__GNUC__ */
|
# endif /* !__GNUC__ */
|
||||||
# endif /* AMIGA */
|
# endif /* AMIGA */
|
||||||
|
|
||||||
|
@ -196,10 +202,12 @@ void GC_push_regs()
|
||||||
PushMacReg(d7);
|
PushMacReg(d7);
|
||||||
add.w #4,sp ; fix stack.
|
add.w #4,sp ; fix stack.
|
||||||
}
|
}
|
||||||
|
# define HAVE_PUSH_REGS
|
||||||
# undef PushMacReg
|
# undef PushMacReg
|
||||||
# endif /* THINK_C */
|
# endif /* THINK_C */
|
||||||
# if defined(__MWERKS__)
|
# if defined(__MWERKS__)
|
||||||
PushMacRegisters();
|
PushMacRegisters();
|
||||||
|
# define HAVE_PUSH_REGS
|
||||||
# endif /* __MWERKS__ */
|
# endif /* __MWERKS__ */
|
||||||
# endif /* MACOS */
|
# endif /* MACOS */
|
||||||
|
|
||||||
|
@ -222,13 +230,15 @@ void GC_push_regs()
|
||||||
asm("pushl %esi"); 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");
|
asm("pushl %edi"); asm("call _GC_push_one"); asm("addl $4,%esp");
|
||||||
asm("pushl %ebx"); 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
|
# endif
|
||||||
|
|
||||||
# if ( defined(I386) && defined(LINUX) && defined(__ELF__) ) \
|
# if ( defined(I386) && defined(LINUX) && defined(__ELF__) ) \
|
||||||
|| ( defined(I386) && defined(FREEBSD) && defined(__ELF__) ) \
|
|| ( defined(I386) && defined(FREEBSD) && defined(__ELF__) ) \
|
||||||
|| ( defined(I386) && defined(NETBSD) && defined(__ELF__) ) \
|
|| ( defined(I386) && defined(NETBSD) && defined(__ELF__) ) \
|
||||||
|| ( defined(I386) && defined(OPENBSD) && 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 is modified for Linux with ELF (Note: _ELF_ only) */
|
||||||
/* This section handles FreeBSD with ELF. */
|
/* 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 %esi; call GC_push_one; addl $4,%esp");
|
||||||
asm("pushl %edi; 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");
|
asm("pushl %ebx; call GC_push_one; addl $4,%esp");
|
||||||
|
# define HAVE_PUSH_REGS
|
||||||
# endif
|
# endif
|
||||||
|
|
||||||
# if ( defined(I386) && defined(BEOS) && defined(__ELF__) )
|
# 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 %esi; call GC_push_one; addl $4,%esp");
|
||||||
asm("pushl %edi; 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");
|
asm("pushl %ebx; call GC_push_one; addl $4,%esp");
|
||||||
|
# define HAVE_PUSH_REGS
|
||||||
# endif
|
# endif
|
||||||
|
|
||||||
# if defined(I386) && defined(MSWIN32) && !defined(__MINGW32__) \
|
# if defined(I386) && defined(MSWIN32) && !defined(__MINGW32__) \
|
||||||
|
@ -280,6 +292,7 @@ void GC_push_regs()
|
||||||
__asm push edi
|
__asm push edi
|
||||||
__asm call GC_push_one
|
__asm call GC_push_one
|
||||||
__asm add esp,4
|
__asm add esp,4
|
||||||
|
# define HAVE_PUSH_REGS
|
||||||
# endif
|
# endif
|
||||||
|
|
||||||
# if defined(I386) && (defined(SVR4) || defined(SCO) || defined(SCO_ELF))
|
# 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 %ebp"); asm("call GC_push_one"); asm("addl $4,%esp");
|
||||||
asm("pushl %esi"); 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");
|
asm("pushl %edi"); asm("call GC_push_one"); asm("addl $4,%esp");
|
||||||
|
# define HAVE_PUSH_REGS
|
||||||
# endif
|
# endif
|
||||||
|
|
||||||
# ifdef NS32K
|
# ifdef NS32K
|
||||||
|
@ -299,14 +313,12 @@ void GC_push_regs()
|
||||||
asm ("movd r5, tos"); asm ("bsr ?_GC_push_one"); asm ("adjspb $-4");
|
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 r6, tos"); asm ("bsr ?_GC_push_one"); asm ("adjspb $-4");
|
||||||
asm ("movd r7, 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
|
# endif
|
||||||
|
|
||||||
# if defined(SPARC)
|
# 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
|
# endif
|
||||||
|
|
||||||
# ifdef RT
|
# ifdef RT
|
||||||
|
@ -322,6 +334,7 @@ void GC_push_regs()
|
||||||
asm("cas r11, r13, r0"); GC_push_one(TMP_SP); /* through */
|
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, r14, r0"); GC_push_one(TMP_SP); /* r15 */
|
||||||
asm("cas r11, r15, r0"); GC_push_one(TMP_SP);
|
asm("cas r11, r15, r0"); GC_push_one(TMP_SP);
|
||||||
|
# define HAVE_PUSH_REGS
|
||||||
# endif
|
# endif
|
||||||
|
|
||||||
# if defined(M68K) && defined(SYSV)
|
# if defined(M68K) && defined(SYSV)
|
||||||
|
@ -345,6 +358,7 @@ void GC_push_regs()
|
||||||
asm("movl %d7,%sp@"); asm("jbsr GC_push_one");
|
asm("movl %d7,%sp@"); asm("jbsr GC_push_one");
|
||||||
|
|
||||||
asm("addqw #0x4,%sp"); /* put stack back where it was */
|
asm("addqw #0x4,%sp"); /* put stack back where it was */
|
||||||
|
# define HAVE_PUSH_REGS
|
||||||
# else /* !__GNUC__*/
|
# else /* !__GNUC__*/
|
||||||
asm("subq.w &0x4,%sp"); /* allocate word on top of stack */
|
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("mov.l %d7,(%sp)"); asm("jsr GC_push_one");
|
||||||
|
|
||||||
asm("addq.w &0x4,%sp"); /* put stack back where it was */
|
asm("addq.w &0x4,%sp"); /* put stack back where it was */
|
||||||
|
# define HAVE_PUSH_REGS
|
||||||
# endif /* !__GNUC__ */
|
# endif /* !__GNUC__ */
|
||||||
# endif /* M68K/SYSV */
|
# endif /* M68K/SYSV */
|
||||||
|
|
||||||
|
@ -371,21 +386,19 @@ void GC_push_regs()
|
||||||
extern int *__libc_stack_end;
|
extern int *__libc_stack_end;
|
||||||
|
|
||||||
GC_push_all_stack (sp, __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
|
# endif
|
||||||
|
|
||||||
/* other machines... */
|
/* other machines... */
|
||||||
# if !defined(M68K) && !defined(VAX) && !defined(RT)
|
# if !defined(HAVE_PUSH_REGS)
|
||||||
# if !defined(SPARC) && !defined(I386) && !defined(NS32K)
|
--> We just generated an empty GC_push_regs, which
|
||||||
# if !defined(POWERPC) && !defined(UTS4)
|
--> is almost certainly broken. Try defining
|
||||||
# if !defined(PJ) && !(defined(MIPS) && defined(LINUX))
|
--> USE_GENERIC_PUSH_REGS instead.
|
||||||
--> bad news <--
|
|
||||||
# endif
|
|
||||||
# endif
|
|
||||||
# endif
|
|
||||||
# endif
|
# endif
|
||||||
}
|
}
|
||||||
#endif /* !USE_GENERIC_PUSH_REGS */
|
#endif /* !USE_GENERIC_PUSH_REGS && !USE_ASM_PUSH_REGS */
|
||||||
|
|
||||||
#if defined(USE_GENERIC_PUSH_REGS)
|
#if defined(USE_GENERIC_PUSH_REGS)
|
||||||
void GC_generic_push_regs(cold_gc_frame)
|
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 */
|
/* needed on IA64, since some non-windowed registers are */
|
||||||
/* preserved. */
|
/* preserved. */
|
||||||
{
|
{
|
||||||
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();
|
||||||
/* On IA64 gcc, could use __builtin_ia64_flushrs() and */
|
/* On IA64 gcc, could use __builtin_ia64_flushrs() and */
|
||||||
/* __builtin_ia64_flushrs(). The latter will be done */
|
/* __builtin_ia64_flushrs(). The latter will be done */
|
||||||
|
@ -445,7 +456,7 @@ ptr_t cold_gc_frame;
|
||||||
/* the stack. Return sp. */
|
/* the stack. Return sp. */
|
||||||
# ifdef SPARC
|
# ifdef SPARC
|
||||||
asm(" .seg \"text\"");
|
asm(" .seg \"text\"");
|
||||||
# ifdef SVR4
|
# if defined(SVR4) || defined(NETBSD)
|
||||||
asm(" .globl GC_save_regs_in_stack");
|
asm(" .globl GC_save_regs_in_stack");
|
||||||
asm("GC_save_regs_in_stack:");
|
asm("GC_save_regs_in_stack:");
|
||||||
asm(" .type GC_save_regs_in_stack,#function");
|
asm(" .type GC_save_regs_in_stack,#function");
|
||||||
|
|
|
@ -182,6 +182,7 @@ register int k;
|
||||||
ptr_t result;
|
ptr_t result;
|
||||||
DCL_LOCK_STATE;
|
DCL_LOCK_STATE;
|
||||||
|
|
||||||
|
if (GC_have_errors) GC_print_all_errors();
|
||||||
GC_INVOKE_FINALIZERS();
|
GC_INVOKE_FINALIZERS();
|
||||||
if (SMALL_OBJ(lb)) {
|
if (SMALL_OBJ(lb)) {
|
||||||
DISABLE_SIGNALS();
|
DISABLE_SIGNALS();
|
||||||
|
@ -294,6 +295,11 @@ DCL_LOCK_STATE;
|
||||||
return(GENERAL_MALLOC((word)lb, NORMAL));
|
return(GENERAL_MALLOC((word)lb, NORMAL));
|
||||||
}
|
}
|
||||||
/* See above comment on signals. */
|
/* 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);
|
*opp = obj_link(op);
|
||||||
obj_link(op) = 0;
|
obj_link(op) = 0;
|
||||||
GC_words_allocd += lw;
|
GC_words_allocd += lw;
|
||||||
|
@ -338,6 +344,7 @@ DCL_LOCK_STATE;
|
||||||
return((GC_PTR)REDIRECT_MALLOC(n*lb));
|
return((GC_PTR)REDIRECT_MALLOC(n*lb));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifndef strdup
|
||||||
# include <string.h>
|
# include <string.h>
|
||||||
# ifdef __STDC__
|
# ifdef __STDC__
|
||||||
char *strdup(const char *s)
|
char *strdup(const char *s)
|
||||||
|
@ -346,11 +353,16 @@ DCL_LOCK_STATE;
|
||||||
char *s;
|
char *s;
|
||||||
# endif
|
# endif
|
||||||
{
|
{
|
||||||
size_t len = strlen + 1;
|
size_t len = strlen(s) + 1;
|
||||||
char * result = ((char *)REDIRECT_MALLOC(len+1));
|
char * result = ((char *)REDIRECT_MALLOC(len+1));
|
||||||
BCOPY(s, result, len+1);
|
BCOPY(s, result, len+1);
|
||||||
return result;
|
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 */
|
# endif /* REDIRECT_MALLOC */
|
||||||
|
|
||||||
/* Explicitly deallocate an object p. */
|
/* Explicitly deallocate an object p. */
|
||||||
|
@ -373,6 +385,7 @@ DCL_LOCK_STATE;
|
||||||
/* Required by ANSI. It's not my fault ... */
|
/* Required by ANSI. It's not my fault ... */
|
||||||
h = HBLKPTR(p);
|
h = HBLKPTR(p);
|
||||||
hhdr = HDR(h);
|
hhdr = HDR(h);
|
||||||
|
GC_ASSERT(GC_base(p) == p);
|
||||||
# if defined(REDIRECT_MALLOC) && \
|
# if defined(REDIRECT_MALLOC) && \
|
||||||
(defined(GC_SOLARIS_THREADS) || defined(GC_LINUX_THREADS) \
|
(defined(GC_SOLARIS_THREADS) || defined(GC_LINUX_THREADS) \
|
||||||
|| defined(__MINGW32__)) /* Should this be MSWIN32 in general? */
|
|| defined(__MINGW32__)) /* Should this be MSWIN32 in general? */
|
||||||
|
@ -454,7 +467,10 @@ void GC_free_inner(GC_PTR p)
|
||||||
}
|
}
|
||||||
#endif /* THREADS */
|
#endif /* THREADS */
|
||||||
|
|
||||||
# ifdef REDIRECT_MALLOC
|
# if defined(REDIRECT_MALLOC) && !defined(REDIRECT_FREE)
|
||||||
|
# define REDIRECT_FREE GC_free
|
||||||
|
# endif
|
||||||
|
# ifdef REDIRECT_FREE
|
||||||
# ifdef __STDC__
|
# ifdef __STDC__
|
||||||
void free(GC_PTR p)
|
void free(GC_PTR p)
|
||||||
# else
|
# else
|
||||||
|
@ -463,7 +479,7 @@ void GC_free_inner(GC_PTR p)
|
||||||
# endif
|
# endif
|
||||||
{
|
{
|
||||||
# ifndef IGNORE_FREE
|
# ifndef IGNORE_FREE
|
||||||
GC_free(p);
|
REDIRECT_FREE(p);
|
||||||
# endif
|
# endif
|
||||||
}
|
}
|
||||||
# endif /* REDIRECT_MALLOC */
|
# 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__
|
# ifdef __STDC__
|
||||||
GC_PTR realloc(GC_PTR p, size_t lb)
|
GC_PTR realloc(GC_PTR p, size_t lb)
|
||||||
# else
|
# else
|
||||||
|
@ -151,13 +155,9 @@ int obj_kind;
|
||||||
size_t lb;
|
size_t lb;
|
||||||
# endif
|
# endif
|
||||||
{
|
{
|
||||||
# ifdef REDIRECT_REALLOC
|
|
||||||
return(REDIRECT_REALLOC(p, lb));
|
return(REDIRECT_REALLOC(p, lb));
|
||||||
# else
|
|
||||||
return(GC_realloc(p, lb));
|
|
||||||
# endif
|
|
||||||
}
|
}
|
||||||
# endif /* REDIRECT_MALLOC */
|
# endif /* REDIRECT_REALLOC */
|
||||||
|
|
||||||
|
|
||||||
/* The same thing, except caller does not hold allocation lock. */
|
/* The same thing, except caller does not hold allocation lock. */
|
||||||
|
@ -177,6 +177,7 @@ register int k;
|
||||||
lw = ROUNDED_UP_WORDS(lb);
|
lw = ROUNDED_UP_WORDS(lb);
|
||||||
n_blocks = OBJ_SZ_TO_BLOCKS(lw);
|
n_blocks = OBJ_SZ_TO_BLOCKS(lw);
|
||||||
init = GC_obj_kinds[k].ok_init;
|
init = GC_obj_kinds[k].ok_init;
|
||||||
|
if (GC_have_errors) GC_print_all_errors();
|
||||||
GC_INVOKE_FINALIZERS();
|
GC_INVOKE_FINALIZERS();
|
||||||
DISABLE_SIGNALS();
|
DISABLE_SIGNALS();
|
||||||
LOCK();
|
LOCK();
|
||||||
|
@ -286,6 +287,7 @@ register struct obj_kind * kind = GC_obj_kinds + k;
|
||||||
register ptr_t op;
|
register ptr_t op;
|
||||||
DCL_LOCK_STATE;
|
DCL_LOCK_STATE;
|
||||||
|
|
||||||
|
if (GC_have_errors) GC_print_all_errors();
|
||||||
GC_INVOKE_FINALIZERS();
|
GC_INVOKE_FINALIZERS();
|
||||||
DISABLE_SIGNALS();
|
DISABLE_SIGNALS();
|
||||||
LOCK();
|
LOCK();
|
||||||
|
@ -354,6 +356,7 @@ DCL_LOCK_STATE;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
lw = ALIGNED_WORDS(lb);
|
lw = ALIGNED_WORDS(lb);
|
||||||
|
if (GC_have_errors) GC_print_all_errors();
|
||||||
GC_INVOKE_FINALIZERS();
|
GC_INVOKE_FINALIZERS();
|
||||||
DISABLE_SIGNALS();
|
DISABLE_SIGNALS();
|
||||||
LOCK();
|
LOCK();
|
||||||
|
@ -375,6 +378,7 @@ DCL_LOCK_STATE;
|
||||||
while ((hbp = *rlh) != 0) {
|
while ((hbp = *rlh) != 0) {
|
||||||
hhdr = HDR(hbp);
|
hhdr = HDR(hbp);
|
||||||
*rlh = hhdr -> hb_next;
|
*rlh = hhdr -> hb_next;
|
||||||
|
hhdr -> hb_last_reclaimed = (unsigned short) GC_gc_no;
|
||||||
# ifdef PARALLEL_MARK
|
# ifdef PARALLEL_MARK
|
||||||
{
|
{
|
||||||
signed_word my_words_allocd_tmp = GC_words_allocd_tmp;
|
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
|
# ifdef ATOMIC_UNCOLLECTABLE
|
||||||
/* Allocate lb bytes of pointerfree, untraced, uncollectable data */
|
/* Allocate lb bytes of pointerfree, untraced, uncollectable data */
|
||||||
/* This is normally roughly equivalent to the system malloc. */
|
/* This is normally roughly equivalent to the system malloc. */
|
||||||
|
|
184
boehm-gc/mark.c
184
boehm-gc/mark.c
|
@ -19,6 +19,10 @@
|
||||||
# include <stdio.h>
|
# include <stdio.h>
|
||||||
# include "private/gc_pmark.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. */
|
/* We put this here to minimize the risk of inlining. */
|
||||||
/*VARARGS*/
|
/*VARARGS*/
|
||||||
#ifdef __WATCOMC__
|
#ifdef __WATCOMC__
|
||||||
|
@ -261,20 +265,20 @@ static void alloc_mark_stack();
|
||||||
/* remains valid until all marking is complete. */
|
/* remains valid until all marking is complete. */
|
||||||
/* A zero value indicates that it's OK to miss some */
|
/* A zero value indicates that it's OK to miss some */
|
||||||
/* register values. */
|
/* register values. */
|
||||||
|
/* 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)
|
GC_bool GC_mark_some(cold_gc_frame)
|
||||||
ptr_t 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) {
|
switch(GC_mark_state) {
|
||||||
case MS_NONE:
|
case MS_NONE:
|
||||||
return(FALSE);
|
return(FALSE);
|
||||||
|
@ -395,23 +399,130 @@ ptr_t cold_gc_frame;
|
||||||
ABORT("GC_mark_some: bad state");
|
ABORT("GC_mark_some: bad state");
|
||||||
return(FALSE);
|
return(FALSE);
|
||||||
}
|
}
|
||||||
#if 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 ?
|
} __except (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ?
|
||||||
EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) {
|
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
|
# ifdef CONDPRINT
|
||||||
if (GC_print_stats) {
|
if (GC_print_stats) {
|
||||||
GC_printf0("Caught ACCESS_VIOLATION in marker. "
|
GC_printf0("Caught ACCESS_VIOLATION in marker. "
|
||||||
"Memory mapping disappeared.\n");
|
"Memory mapping disappeared.\n");
|
||||||
}
|
}
|
||||||
# endif /* CONDPRINT */
|
# endif /* CONDPRINT */
|
||||||
|
|
||||||
/* We have bad roots on the stack. Discard mark stack. */
|
/* We have bad roots on the stack. Discard mark stack. */
|
||||||
/* Rescan from marked objects. Redetermine roots. */
|
/* Rescan from marked objects. Redetermine roots. */
|
||||||
GC_invalidate_mark_state();
|
GC_invalidate_mark_state();
|
||||||
scan_ptr = 0;
|
scan_ptr = 0;
|
||||||
return FALSE;
|
|
||||||
|
ret_val = FALSE;
|
||||||
|
|
||||||
|
# ifndef __GNUC__
|
||||||
|
|
||||||
}
|
}
|
||||||
#endif /* defined(MSWIN32) && !defined(__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()
|
GC_bool GC_mark_stack_empty()
|
||||||
|
@ -434,13 +545,7 @@ GC_bool GC_mark_stack_empty()
|
||||||
/* for the large object. */
|
/* for the large object. */
|
||||||
/* - just return current if it does not point to a large object. */
|
/* - just return current if it does not point to a large object. */
|
||||||
/*ARGSUSED*/
|
/*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)
|
ptr_t GC_find_start(current, hhdr, new_hdr_p)
|
||||||
# define source 0
|
|
||||||
# endif
|
|
||||||
register ptr_t current;
|
register ptr_t current;
|
||||||
register hdr *hhdr, **new_hdr_p;
|
register hdr *hhdr, **new_hdr_p;
|
||||||
{
|
{
|
||||||
|
@ -468,7 +573,6 @@ register hdr *hhdr, **new_hdr_p;
|
||||||
} else {
|
} else {
|
||||||
return(current);
|
return(current);
|
||||||
}
|
}
|
||||||
# undef source
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void GC_invalidate_mark_state()
|
void GC_invalidate_mark_state()
|
||||||
|
@ -546,8 +650,8 @@ mse * mark_stack_limit;
|
||||||
/* Large length. */
|
/* Large length. */
|
||||||
/* Process part of the range to avoid pushing too much on the */
|
/* Process part of the range to avoid pushing too much on the */
|
||||||
/* stack. */
|
/* stack. */
|
||||||
GC_ASSERT(descr < GC_greatest_plausible_heap_addr
|
GC_ASSERT(descr < (word)GC_greatest_plausible_heap_addr
|
||||||
- GC_least_plausible_heap_addr);
|
- (word)GC_least_plausible_heap_addr);
|
||||||
# ifdef PARALLEL_MARK
|
# ifdef PARALLEL_MARK
|
||||||
# define SHARE_BYTES 2048
|
# define SHARE_BYTES 2048
|
||||||
if (descr > SHARE_BYTES && GC_parallel
|
if (descr > SHARE_BYTES && GC_parallel
|
||||||
|
@ -578,6 +682,7 @@ mse * mark_stack_limit;
|
||||||
while (descr != 0) {
|
while (descr != 0) {
|
||||||
if ((signed_word)descr < 0) {
|
if ((signed_word)descr < 0) {
|
||||||
current = *current_p;
|
current = *current_p;
|
||||||
|
FIXUP_POINTER(current);
|
||||||
if ((ptr_t)current >= least_ha && (ptr_t)current < greatest_ha) {
|
if ((ptr_t)current >= least_ha && (ptr_t)current < greatest_ha) {
|
||||||
PREFETCH(current);
|
PREFETCH(current);
|
||||||
HC_PUSH_CONTENTS((ptr_t)current, mark_stack_top,
|
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);
|
PREFETCH((ptr_t)limit - PREF_DIST*CACHE_LINE_SIZE);
|
||||||
GC_ASSERT(limit >= current_p);
|
GC_ASSERT(limit >= current_p);
|
||||||
deferred = *limit;
|
deferred = *limit;
|
||||||
|
FIXUP_POINTER(deferred);
|
||||||
limit = (word *)((char *)limit - ALIGNMENT);
|
limit = (word *)((char *)limit - ALIGNMENT);
|
||||||
if ((ptr_t)deferred >= least_ha && (ptr_t)deferred < greatest_ha) {
|
if ((ptr_t)deferred >= least_ha && (ptr_t)deferred < greatest_ha) {
|
||||||
PREFETCH(deferred);
|
PREFETCH(deferred);
|
||||||
|
@ -661,6 +767,7 @@ mse * mark_stack_limit;
|
||||||
/* Unroll once, so we don't do too many of the prefetches */
|
/* Unroll once, so we don't do too many of the prefetches */
|
||||||
/* based on limit. */
|
/* based on limit. */
|
||||||
deferred = *limit;
|
deferred = *limit;
|
||||||
|
FIXUP_POINTER(deferred);
|
||||||
limit = (word *)((char *)limit - ALIGNMENT);
|
limit = (word *)((char *)limit - ALIGNMENT);
|
||||||
if ((ptr_t)deferred >= least_ha && (ptr_t)deferred < greatest_ha) {
|
if ((ptr_t)deferred >= least_ha && (ptr_t)deferred < greatest_ha) {
|
||||||
PREFETCH(deferred);
|
PREFETCH(deferred);
|
||||||
|
@ -675,6 +782,7 @@ mse * mark_stack_limit;
|
||||||
/* Since HC_PUSH_CONTENTS expands to a lot of code, */
|
/* Since HC_PUSH_CONTENTS expands to a lot of code, */
|
||||||
/* we don't. */
|
/* we don't. */
|
||||||
current = *current_p;
|
current = *current_p;
|
||||||
|
FIXUP_POINTER(current);
|
||||||
PREFETCH((ptr_t)current_p + PREF_DIST*CACHE_LINE_SIZE);
|
PREFETCH((ptr_t)current_p + PREF_DIST*CACHE_LINE_SIZE);
|
||||||
if ((ptr_t)current >= least_ha && (ptr_t)current < greatest_ha) {
|
if ((ptr_t)current >= least_ha && (ptr_t)current < greatest_ha) {
|
||||||
/* Prefetch the contents of the object we just pushed. It's */
|
/* 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;
|
mse *top = local - 1;
|
||||||
unsigned i = 0;
|
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);
|
GC_ASSERT(high >= low-1 && high - low + 1 <= GC_mark_stack_size);
|
||||||
for (p = low; p <= high && i <= max; ++p) {
|
for (p = low; p <= high && i <= max; ++p) {
|
||||||
word descr = *(volatile word *) &(p -> mse_descr);
|
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) {
|
if (descr != 0) {
|
||||||
*(volatile word *) &(p -> mse_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;
|
||||||
top -> mse_descr = descr;
|
top -> mse_descr = descr;
|
||||||
top -> mse_start = p -> mse_start;
|
top -> mse_start = p -> mse_start;
|
||||||
GC_ASSERT( top -> mse_descr & GC_DS_TAGS != GC_DS_LENGTH ||
|
GC_ASSERT( top -> mse_descr & GC_DS_TAGS != GC_DS_LENGTH ||
|
||||||
top -> mse_descr < GC_greatest_plausible_heap_addr
|
top -> mse_descr < GC_greatest_plausible_heap_addr
|
||||||
- GC_least_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 */
|
/* If this is a big object, count it as */
|
||||||
/* size/256 + 1 objects. */
|
/* size/256 + 1 objects. */
|
||||||
++i;
|
++i;
|
||||||
|
@ -778,7 +897,7 @@ void GC_return_mark_stack(mse * low, mse * high)
|
||||||
BCOPY(low, my_start, stack_size * sizeof(mse));
|
BCOPY(low, my_start, stack_size * sizeof(mse));
|
||||||
GC_ASSERT(GC_mark_stack_top = my_top);
|
GC_ASSERT(GC_mark_stack_top = my_top);
|
||||||
# if !defined(IA64) && !defined(HP_PA)
|
# if !defined(IA64) && !defined(HP_PA)
|
||||||
GC_memory_write_barrier();
|
GC_memory_barrier();
|
||||||
# endif
|
# endif
|
||||||
/* On IA64, the volatile write acts as a release barrier. */
|
/* On IA64, the volatile write acts as a release barrier. */
|
||||||
GC_mark_stack_top = my_top + stack_size;
|
GC_mark_stack_top = my_top + stack_size;
|
||||||
|
@ -1342,7 +1461,7 @@ ptr_t top;
|
||||||
# define GC_least_plausible_heap_addr least_ha
|
# define GC_least_plausible_heap_addr least_ha
|
||||||
|
|
||||||
if (top == 0) return;
|
if (top == 0) return;
|
||||||
/* check all pointers in range and put in push if they appear */
|
/* check all pointers in range and push if they appear */
|
||||||
/* to be valid. */
|
/* to be valid. */
|
||||||
lim = t - 1 /* longword */;
|
lim = t - 1 /* longword */;
|
||||||
for (p = b; p <= lim; p = (word *)(((char *)p) + ALIGNMENT)) {
|
for (p = b; p <= lim; p = (word *)(((char *)p) + ALIGNMENT)) {
|
||||||
|
@ -1366,7 +1485,7 @@ ptr_t bottom;
|
||||||
ptr_t top;
|
ptr_t top;
|
||||||
ptr_t cold_gc_frame;
|
ptr_t cold_gc_frame;
|
||||||
{
|
{
|
||||||
if (GC_all_interior_pointers) {
|
if (!NEED_FIXUP_POINTER && GC_all_interior_pointers) {
|
||||||
# define EAGER_BYTES 1024
|
# define EAGER_BYTES 1024
|
||||||
/* Push the hot end of the stack eagerly, so that register values */
|
/* Push the hot end of the stack eagerly, so that register values */
|
||||||
/* saved inside GC frames are marked before they disappear. */
|
/* saved inside GC frames are marked before they disappear. */
|
||||||
|
@ -1375,6 +1494,7 @@ ptr_t cold_gc_frame;
|
||||||
GC_push_all_stack(bottom, top);
|
GC_push_all_stack(bottom, top);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
GC_ASSERT(bottom <= cold_gc_frame && cold_gc_frame <= top);
|
||||||
# ifdef STACK_GROWS_DOWN
|
# ifdef STACK_GROWS_DOWN
|
||||||
GC_push_all(cold_gc_frame - sizeof(ptr_t), top);
|
GC_push_all(cold_gc_frame - sizeof(ptr_t), top);
|
||||||
GC_push_all_eager(bottom, cold_gc_frame);
|
GC_push_all_eager(bottom, cold_gc_frame);
|
||||||
|
@ -1395,7 +1515,7 @@ void GC_push_all_stack(bottom, top)
|
||||||
ptr_t bottom;
|
ptr_t bottom;
|
||||||
ptr_t top;
|
ptr_t top;
|
||||||
{
|
{
|
||||||
if (GC_all_interior_pointers) {
|
if (!NEED_FIXUP_POINTER && GC_all_interior_pointers) {
|
||||||
GC_push_all(bottom, top);
|
GC_push_all(bottom, top);
|
||||||
} else {
|
} else {
|
||||||
GC_push_all_eager(bottom, top);
|
GC_push_all_eager(bottom, top);
|
||||||
|
|
|
@ -275,23 +275,18 @@ void GC_clear_roots GC_PROTO((void))
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Internal use only; lock held. */
|
/* Internal use only; lock held. */
|
||||||
void GC_remove_tmp_roots()
|
static void GC_remove_root_at_pos(i)
|
||||||
|
int i;
|
||||||
{
|
{
|
||||||
register int i;
|
GC_root_size -= (GC_static_roots[i].r_end - GC_static_roots[i].r_start);
|
||||||
|
|
||||||
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_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_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;
|
GC_static_roots[i].r_tmp = GC_static_roots[n_root_sets-1].r_tmp;
|
||||||
n_root_sets--;
|
n_root_sets--;
|
||||||
} else {
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#if !defined(MSWIN32) && !defined(MSWINCE)
|
#if !defined(MSWIN32) && !defined(MSWINCE)
|
||||||
|
static void GC_rebuild_root_index()
|
||||||
{
|
{
|
||||||
register int i;
|
register int i;
|
||||||
|
|
||||||
|
@ -301,7 +296,51 @@ void GC_remove_tmp_roots()
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/* Internal use only; lock held. */
|
||||||
|
void GC_remove_tmp_roots()
|
||||||
|
{
|
||||||
|
register int i;
|
||||||
|
|
||||||
|
for (i = 0; i < n_root_sets; ) {
|
||||||
|
if (GC_static_roots[i].r_tmp) {
|
||||||
|
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++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
GC_rebuild_root_index();
|
||||||
|
}
|
||||||
|
#endif /* !defined(MSWIN32) && !defined(MSWINCE) */
|
||||||
|
|
||||||
#if defined(MSWIN32) || defined(_WIN32_WCE_EMULATION)
|
#if defined(MSWIN32) || defined(_WIN32_WCE_EMULATION)
|
||||||
/* Workaround for the OS mapping and unmapping behind our back: */
|
/* 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 */
|
/* Mark thread local free lists, even if their mark */
|
||||||
/* descriptor excludes the link field. */
|
/* 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
|
# ifdef THREAD_LOCAL_ALLOC
|
||||||
GC_mark_thread_local_free_lists();
|
if (GC_world_stopped) GC_mark_thread_local_free_lists();
|
||||||
# endif
|
# endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -1,5 +1,10 @@
|
||||||
#include <sys/regdef.h>
|
#include <sys/regdef.h>
|
||||||
#include <sys/asm.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
|
# define call_push(x) move $4,x; jal GC_push_one
|
||||||
|
|
236
boehm-gc/misc.c
236
boehm-gc/misc.c
|
@ -46,8 +46,10 @@
|
||||||
# ifdef GC_SOLARIS_THREADS
|
# ifdef GC_SOLARIS_THREADS
|
||||||
mutex_t GC_allocate_ml; /* Implicitly initialized. */
|
mutex_t GC_allocate_ml; /* Implicitly initialized. */
|
||||||
# else
|
# else
|
||||||
# ifdef GC_WIN32_THREADS
|
# if defined(GC_WIN32_THREADS)
|
||||||
# if !defined(GC_NOT_DLL) && (defined(_DLL) || defined(GC_DLL))
|
# if defined(GC_PTHREADS)
|
||||||
|
pthread_mutex_t GC_allocate_ml = PTHREAD_MUTEX_INITIALIZER;
|
||||||
|
# elif defined(GC_DLL)
|
||||||
__declspec(dllexport) CRITICAL_SECTION GC_allocate_ml;
|
__declspec(dllexport) CRITICAL_SECTION GC_allocate_ml;
|
||||||
# else
|
# else
|
||||||
CRITICAL_SECTION GC_allocate_ml;
|
CRITICAL_SECTION GC_allocate_ml;
|
||||||
|
@ -90,6 +92,7 @@ GC_bool GC_debugging_started = FALSE;
|
||||||
/* defined here so we don't have to load debug_malloc.o */
|
/* 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_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;
|
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;
|
GC_bool GC_print_back_height = 0;
|
||||||
|
|
||||||
|
#ifndef NO_DEBUGGING
|
||||||
|
GC_bool GC_dump_regularly = 0; /* Generate regular debugging dumps. */
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef FIND_LEAK
|
#ifdef FIND_LEAK
|
||||||
int GC_find_leak = 1;
|
int GC_find_leak = 1;
|
||||||
#else
|
#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;
|
extern signed_word GC_mem_found;
|
||||||
|
|
||||||
|
void * GC_project2(arg1, arg2)
|
||||||
|
void *arg1;
|
||||||
|
void *arg2;
|
||||||
|
{
|
||||||
|
return arg2;
|
||||||
|
}
|
||||||
|
|
||||||
# ifdef MERGE_SIZES
|
# ifdef MERGE_SIZES
|
||||||
/* Set things up so that GC_size_map[i] >= words(i), */
|
/* Set things up so that GC_size_map[i] >= words(i), */
|
||||||
/* but not too much bigger */
|
/* but not too much bigger */
|
||||||
|
@ -455,7 +469,7 @@ void GC_init()
|
||||||
|
|
||||||
DISABLE_SIGNALS();
|
DISABLE_SIGNALS();
|
||||||
|
|
||||||
#ifdef MSWIN32
|
#if defined(GC_WIN32_THREADS) && !defined(GC_PTHREADS)
|
||||||
if (!GC_is_initialized) InitializeCriticalSection(&GC_allocate_ml);
|
if (!GC_is_initialized) InitializeCriticalSection(&GC_allocate_ml);
|
||||||
#endif /* MSWIN32 */
|
#endif /* MSWIN32 */
|
||||||
|
|
||||||
|
@ -473,6 +487,15 @@ void GC_init()
|
||||||
GC_init_parallel();
|
GC_init_parallel();
|
||||||
}
|
}
|
||||||
# endif /* PARALLEL_MARK || THREAD_LOCAL_ALLOC */
|
# 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)
|
#if defined(MSWIN32) || defined(MSWINCE)
|
||||||
|
@ -485,6 +508,22 @@ void GC_init()
|
||||||
|
|
||||||
extern void GC_setpagesize();
|
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
|
#ifdef UNIX_LIKE
|
||||||
|
|
||||||
extern void GC_set_and_save_fault_handler GC_PROTO((void (*handler)(int)));
|
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);
|
GC_err_printf1("Caught signal %d: looping in handler\n", sig);
|
||||||
for(;;);
|
for(;;);
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef MSWIN32
|
static GC_bool installed_looping_handler = FALSE;
|
||||||
extern GC_bool GC_no_win32_dlls;
|
|
||||||
#else
|
void maybe_install_looping_handler()
|
||||||
# define GC_no_win32_dlls FALSE
|
{
|
||||||
|
/* 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
|
#endif
|
||||||
|
|
||||||
void GC_init_inner()
|
void GC_init_inner()
|
||||||
|
@ -517,12 +567,19 @@ void GC_init_inner()
|
||||||
# if defined(MSWIN32) || defined(MSWINCE)
|
# if defined(MSWIN32) || defined(MSWINCE)
|
||||||
InitializeCriticalSection(&GC_write_cs);
|
InitializeCriticalSection(&GC_write_cs);
|
||||||
# endif
|
# endif
|
||||||
|
|
||||||
if (0 != GETENV("GC_PRINT_STATS")) {
|
if (0 != GETENV("GC_PRINT_STATS")) {
|
||||||
GC_print_stats = 1;
|
GC_print_stats = 1;
|
||||||
}
|
}
|
||||||
|
# ifndef NO_DEBUGGING
|
||||||
|
if (0 != GETENV("GC_DUMP_REGULARLY")) {
|
||||||
|
GC_dump_regularly = 1;
|
||||||
|
}
|
||||||
|
# endif
|
||||||
if (0 != GETENV("GC_FIND_LEAK")) {
|
if (0 != GETENV("GC_FIND_LEAK")) {
|
||||||
GC_find_leak = 1;
|
GC_find_leak = 1;
|
||||||
|
# ifdef __STDC__
|
||||||
|
atexit(GC_exit_check);
|
||||||
|
# endif
|
||||||
}
|
}
|
||||||
if (0 != GETENV("GC_ALL_INTERIOR_POINTERS")) {
|
if (0 != GETENV("GC_ALL_INTERIOR_POINTERS")) {
|
||||||
GC_all_interior_pointers = 1;
|
GC_all_interior_pointers = 1;
|
||||||
|
@ -560,11 +617,7 @@ void GC_init_inner()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
# ifdef UNIX_LIKE
|
maybe_install_looping_handler();
|
||||||
if (0 != GETENV("GC_LOOP_ON_ABORT")) {
|
|
||||||
GC_set_and_save_fault_handler(looping_handler);
|
|
||||||
}
|
|
||||||
# endif
|
|
||||||
/* Adjust normal object descriptor for extra allocation. */
|
/* Adjust normal object descriptor for extra allocation. */
|
||||||
if (ALIGNMENT > GC_DS_TAGS && EXTRA_BYTES != 0) {
|
if (ALIGNMENT > GC_DS_TAGS && EXTRA_BYTES != 0) {
|
||||||
GC_obj_kinds[NORMAL].ok_descriptor = ((word)(-ALIGNMENT) | GC_DS_LENGTH);
|
GC_obj_kinds[NORMAL].ok_descriptor = ((word)(-ALIGNMENT) | GC_DS_LENGTH);
|
||||||
|
@ -599,11 +652,21 @@ void GC_init_inner()
|
||||||
# if defined(LINUX) && defined(IA64)
|
# if defined(LINUX) && defined(IA64)
|
||||||
GC_register_stackbottom = GC_get_register_stack_base();
|
GC_register_stackbottom = GC_get_register_stack_base();
|
||||||
# endif
|
# 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));
|
# endif
|
||||||
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
|
# ifndef THREADS
|
||||||
# if defined(STACK_GROWS_UP) && defined(STACK_GROWS_DOWN)
|
# if defined(STACK_GROWS_UP) && defined(STACK_GROWS_DOWN)
|
||||||
ABORT(
|
ABORT(
|
||||||
|
@ -642,6 +705,18 @@ void GC_init_inner()
|
||||||
initial_heap_sz = divHBLKSZ(initial_heap_sz);
|
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)) {
|
if (!GC_expand_hp_inner(initial_heap_sz)) {
|
||||||
GC_err_printf0("Can't start up: not enough memory\n");
|
GC_err_printf0("Can't start up: not enough memory\n");
|
||||||
EXIT();
|
EXIT();
|
||||||
|
@ -677,6 +752,7 @@ void GC_init_inner()
|
||||||
GC_incremental = TRUE;
|
GC_incremental = TRUE;
|
||||||
}
|
}
|
||||||
# endif /* !SMALL_CONFIG */
|
# endif /* !SMALL_CONFIG */
|
||||||
|
COND_DUMP;
|
||||||
/* Get black list set up and/or incrmental GC started */
|
/* Get black list set up and/or incrmental GC started */
|
||||||
if (!GC_dont_precollect || GC_incremental) GC_gcollect_inner();
|
if (!GC_dont_precollect || GC_incremental) GC_gcollect_inner();
|
||||||
GC_is_initialized = TRUE;
|
GC_is_initialized = TRUE;
|
||||||
|
@ -713,6 +789,7 @@ void GC_enable_incremental GC_PROTO(())
|
||||||
GC_setpagesize();
|
GC_setpagesize();
|
||||||
if (GC_no_win32_dlls) goto out;
|
if (GC_no_win32_dlls) goto out;
|
||||||
# ifndef GC_SOLARIS_THREADS
|
# ifndef GC_SOLARIS_THREADS
|
||||||
|
maybe_install_looping_handler(); /* Before write fault handler! */
|
||||||
GC_dirty_init();
|
GC_dirty_init();
|
||||||
# endif
|
# endif
|
||||||
if (!GC_is_initialized) {
|
if (!GC_is_initialized) {
|
||||||
|
@ -932,6 +1009,17 @@ GC_warn_proc GC_current_warn_proc = GC_default_warn_proc;
|
||||||
return(result);
|
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
|
#ifndef PCR
|
||||||
void GC_abort(msg)
|
void GC_abort(msg)
|
||||||
|
@ -958,122 +1046,18 @@ GC_CONST char * msg;
|
||||||
}
|
}
|
||||||
#endif
|
#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()
|
void GC_enable()
|
||||||
{
|
{
|
||||||
|
LOCK();
|
||||||
GC_dont_gc--;
|
GC_dont_gc--;
|
||||||
|
UNLOCK();
|
||||||
}
|
}
|
||||||
|
|
||||||
void GC_disable()
|
void GC_disable()
|
||||||
{
|
{
|
||||||
|
LOCK();
|
||||||
GC_dont_gc++;
|
GC_dont_gc++;
|
||||||
|
UNLOCK();
|
||||||
}
|
}
|
||||||
|
|
||||||
#if !defined(NO_DEBUGGING)
|
#if !defined(NO_DEBUGGING)
|
||||||
|
@ -1088,6 +1072,8 @@ void GC_dump()
|
||||||
GC_print_hblkfreelist();
|
GC_print_hblkfreelist();
|
||||||
GC_printf0("\n***Blocks in use:\n");
|
GC_printf0("\n***Blocks in use:\n");
|
||||||
GC_print_block_list();
|
GC_print_block_list();
|
||||||
|
GC_printf0("\n***Finalization statistics:\n");
|
||||||
|
GC_print_finalization_stats();
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif /* NO_DEBUGGING */
|
#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
|
|
1424
boehm-gc/os_dep.c
1424
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);
|
return(p);
|
||||||
}
|
}
|
||||||
sz = WORDS_TO_BYTES(hhdr -> hb_sz);
|
sz = WORDS_TO_BYTES(hhdr -> hb_sz);
|
||||||
if (sz > WORDS_TO_BYTES(MAXOBJSZ)) {
|
if (sz > MAXOBJBYTES) {
|
||||||
base = (ptr_t)HBLKPTR(p);
|
base = (ptr_t)HBLKPTR(p);
|
||||||
limit = base + sz;
|
limit = base + sz;
|
||||||
if ((ptr_t)p >= limit) {
|
if ((ptr_t)p >= limit) {
|
||||||
|
@ -165,7 +165,7 @@ void (*GC_is_valid_displacement_print_proc) GC_PROTO((GC_PTR)) =
|
||||||
pdispl = HBLKDISPL(p);
|
pdispl = HBLKDISPL(p);
|
||||||
map_entry = MAP_ENTRY((hhdr -> hb_map), pdispl);
|
map_entry = MAP_ENTRY((hhdr -> hb_map), pdispl);
|
||||||
if (map_entry == OBJ_INVALID
|
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;
|
goto fail;
|
||||||
}
|
}
|
||||||
return(p);
|
return(p);
|
||||||
|
|
|
@ -27,10 +27,43 @@ signed_word GC_mem_found = 0;
|
||||||
/* nonzero. */
|
/* nonzero. */
|
||||||
#endif /* PARALLEL_MARK */
|
#endif /* PARALLEL_MARK */
|
||||||
|
|
||||||
static void report_leak(p, sz)
|
/* We defer printing of leaked objects until we're done with the GC */
|
||||||
ptr_t p;
|
/* cycle, since the routine for printing objects needs to run outside */
|
||||||
word sz;
|
/* 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 (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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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) {
|
if (HDR(p) -> hb_obj_kind == PTRFREE) {
|
||||||
GC_err_printf0("Leaked atomic object at ");
|
GC_err_printf0("Leaked atomic object at ");
|
||||||
} else {
|
} else {
|
||||||
|
@ -38,12 +71,17 @@ word sz;
|
||||||
}
|
}
|
||||||
GC_print_heap_obj(p);
|
GC_print_heap_obj(p);
|
||||||
GC_err_printf0("\n");
|
GC_err_printf0("\n");
|
||||||
|
GC_free(p);
|
||||||
|
GC_leaked[i] = 0;
|
||||||
}
|
}
|
||||||
|
GC_n_leaked = 0;
|
||||||
|
printing_errors = FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
# define FOUND_FREE(hblk, word_no) \
|
# define FOUND_FREE(hblk, word_no) \
|
||||||
{ \
|
{ \
|
||||||
report_leak((ptr_t)hblk + WORDS_TO_BYTES(word_no), \
|
GC_add_leaked((ptr_t)hblk + WORDS_TO_BYTES(word_no)); \
|
||||||
HDR(hblk) -> hb_sz); \
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -866,7 +904,7 @@ void GC_print_block_list()
|
||||||
* Clear *flp.
|
* Clear *flp.
|
||||||
* This must be done before dropping a list of free gcj-style objects,
|
* This must be done before dropping a list of free gcj-style objects,
|
||||||
* since may otherwise end up with dangling "descriptor" pointers.
|
* 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)
|
void GC_clear_fl_links(flp)
|
||||||
ptr_t *flp;
|
ptr_t *flp;
|
||||||
|
|
|
@ -13,9 +13,8 @@
|
||||||
/*
|
/*
|
||||||
* Support code for Solaris threads. Provides functionality we wish Sun
|
* Support code for Solaris threads. Provides functionality we wish Sun
|
||||||
* had provided. Relies on some information we probably shouldn't rely on.
|
* 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)
|
# if defined(GC_SOLARIS_PTHREADS)
|
||||||
# include "private/gc_priv.h"
|
# include "private/gc_priv.h"
|
||||||
|
|
|
@ -37,6 +37,10 @@
|
||||||
# include <unistd.h>
|
# include <unistd.h>
|
||||||
# include <errno.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
|
* 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
|
* 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) {
|
sizeof (prgregset_t)) != 0) {
|
||||||
int j;
|
int j;
|
||||||
|
|
||||||
for(j = 0; j < NGREG; j++)
|
for(j = 0; j < NPRGREG; j++)
|
||||||
{
|
{
|
||||||
GC_printf3("%i: %x -> %x\n", j,
|
GC_printf3("%i: %x -> %x\n", j,
|
||||||
GC_lwp_registers[i][j],
|
GC_lwp_registers[i][j],
|
||||||
|
@ -821,7 +825,7 @@ int GC_thr_suspend(thread_t target_thread)
|
||||||
if (result == 0) {
|
if (result == 0) {
|
||||||
t = GC_lookup_thread(target_thread);
|
t = GC_lookup_thread(target_thread);
|
||||||
if (t == 0) ABORT("thread unknown to GC");
|
if (t == 0) ABORT("thread unknown to GC");
|
||||||
t -> flags |= SUSPENDED;
|
t -> flags |= SUSPNDED;
|
||||||
}
|
}
|
||||||
UNLOCK();
|
UNLOCK();
|
||||||
return(result);
|
return(result);
|
||||||
|
@ -837,7 +841,7 @@ int GC_thr_continue(thread_t target_thread)
|
||||||
if (result == 0) {
|
if (result == 0) {
|
||||||
t = GC_lookup_thread(target_thread);
|
t = GC_lookup_thread(target_thread);
|
||||||
if (t == 0) ABORT("thread unknown to GC");
|
if (t == 0) ABORT("thread unknown to GC");
|
||||||
t -> flags &= ~SUSPENDED;
|
t -> flags &= ~SUSPNDED;
|
||||||
}
|
}
|
||||||
UNLOCK();
|
UNLOCK();
|
||||||
return(result);
|
return(result);
|
||||||
|
@ -923,7 +927,7 @@ GC_thr_create(void *stack_base, size_t stack_size,
|
||||||
my_flags |= CLIENT_OWNS_STACK;
|
my_flags |= CLIENT_OWNS_STACK;
|
||||||
}
|
}
|
||||||
if (flags & THR_DETACHED) my_flags |= DETACHED;
|
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,
|
result = thr_create(stack, stack_size, start_routine,
|
||||||
arg, flags & ~THR_DETACHED, &my_new_thread);
|
arg, flags & ~THR_DETACHED, &my_new_thread);
|
||||||
if (result == 0) {
|
if (result == 0) {
|
||||||
|
|
|
@ -68,14 +68,14 @@
|
||||||
# include <pthread.h>
|
# include <pthread.h>
|
||||||
# endif
|
# endif
|
||||||
|
|
||||||
# ifdef GC_WIN32_THREADS
|
# if defined(GC_WIN32_THREADS) && !defined(GC_PTHREADS)
|
||||||
# ifndef MSWINCE
|
|
||||||
# include <process.h>
|
|
||||||
# define GC_CreateThread(a,b,c,d,e,f) ((HANDLE) _beginthreadex(a,b,c,d,e,f))
|
|
||||||
# endif
|
|
||||||
static CRITICAL_SECTION incr_cs;
|
static CRITICAL_SECTION incr_cs;
|
||||||
# endif
|
# endif
|
||||||
|
|
||||||
|
#ifdef __STDC__
|
||||||
|
# include <stdarg.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
/* Allocation Statistics */
|
/* Allocation Statistics */
|
||||||
int stubborn_count = 0;
|
int stubborn_count = 0;
|
||||||
|
@ -205,40 +205,6 @@ sexpr y;
|
||||||
}
|
}
|
||||||
# endif
|
# 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
|
#ifdef GC_GCJ_SUPPORT
|
||||||
|
|
||||||
#include "gc_mark.h"
|
#include "gc_mark.h"
|
||||||
|
@ -279,6 +245,93 @@ struct GC_ms_entry * fake_gcj_mark_proc(word * addr,
|
||||||
return(mark_stack_ptr);
|
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 gcj_cons(x, y)
|
||||||
sexpr x;
|
sexpr x;
|
||||||
sexpr y;
|
sexpr y;
|
||||||
|
@ -323,6 +376,9 @@ sexpr x, y;
|
||||||
sexpr reverse(x)
|
sexpr reverse(x)
|
||||||
sexpr x;
|
sexpr x;
|
||||||
{
|
{
|
||||||
|
# ifdef TEST_WITH_SYSTEM_MALLOC
|
||||||
|
malloc(100000);
|
||||||
|
# endif
|
||||||
return( reverse1(x, nil) );
|
return( reverse1(x, nil) );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -365,6 +421,35 @@ int low, up;
|
||||||
}
|
}
|
||||||
#endif /* GC_GCJ_SUPPORT */
|
#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 */
|
/* To check uncollectable allocation we build lists with disguised cdr */
|
||||||
/* pointers, and make sure they don't go away. */
|
/* pointers, and make sure they don't go away. */
|
||||||
sexpr uncollectable_ints(low, up)
|
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.
|
* A tiny list reversal test to check thread creation.
|
||||||
*/
|
*/
|
||||||
#ifdef THREADS
|
#ifdef THREADS
|
||||||
|
|
||||||
# ifdef GC_WIN32_THREADS
|
# if defined(GC_WIN32_THREADS) && !defined(CYGWIN32)
|
||||||
unsigned __stdcall tiny_reverse_test(void * arg)
|
DWORD __stdcall tiny_reverse_test(void * arg)
|
||||||
# else
|
# else
|
||||||
void * tiny_reverse_test(void * arg)
|
void * tiny_reverse_test(void * arg)
|
||||||
# endif
|
# endif
|
||||||
{
|
{
|
||||||
|
int i;
|
||||||
|
for (i = 0; i < 5; ++i) {
|
||||||
check_ints(reverse(reverse(ints(1,10))), 1, 10);
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -477,7 +561,7 @@ struct {
|
||||||
# elif defined(GC_WIN32_THREADS)
|
# elif defined(GC_WIN32_THREADS)
|
||||||
void fork_a_thread()
|
void fork_a_thread()
|
||||||
{
|
{
|
||||||
unsigned thread_id;
|
DWORD thread_id;
|
||||||
HANDLE h;
|
HANDLE h;
|
||||||
h = GC_CreateThread(NULL, 0, tiny_reverse_test, 0, 0, &thread_id);
|
h = GC_CreateThread(NULL, 0, tiny_reverse_test, 0, 0, &thread_id);
|
||||||
if (h == (HANDLE)NULL) {
|
if (h == (HANDLE)NULL) {
|
||||||
|
@ -506,6 +590,13 @@ struct {
|
||||||
|
|
||||||
#endif
|
#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.
|
* Repeatedly reverse lists built out of very different sized cons cells.
|
||||||
* Check that we didn't lose anything.
|
* Check that we didn't lose anything.
|
||||||
|
@ -563,7 +654,9 @@ void reverse_test()
|
||||||
h = (sexpr *)GC_REALLOC((GC_PTR)h, 2000 * sizeof(sexpr));
|
h = (sexpr *)GC_REALLOC((GC_PTR)h, 2000 * sizeof(sexpr));
|
||||||
# ifdef GC_GCJ_SUPPORT
|
# ifdef GC_GCJ_SUPPORT
|
||||||
h[1999] = gcj_ints(1,200);
|
h[1999] = gcj_ints(1,200);
|
||||||
|
for (i = 0; i < 51; ++i)
|
||||||
h[1999] = gcj_reverse(h[1999]);
|
h[1999] = gcj_reverse(h[1999]);
|
||||||
|
/* Leave it as the reveresed list for now. */
|
||||||
# else
|
# else
|
||||||
h[1999] = ints(1,200);
|
h[1999] = ints(1,200);
|
||||||
# endif
|
# endif
|
||||||
|
@ -594,6 +687,9 @@ void reverse_test()
|
||||||
/* 49 integers. Thus this is thread safe without locks, */
|
/* 49 integers. Thus this is thread safe without locks, */
|
||||||
/* assuming atomic pointer assignments. */
|
/* assuming atomic pointer assignments. */
|
||||||
a = reverse(reverse(a));
|
a = reverse(reverse(a));
|
||||||
|
# ifdef THREAD_LOCAL_ALLOC
|
||||||
|
a = local_reverse(local_reverse(a));
|
||||||
|
# endif
|
||||||
# if !defined(AT_END) && !defined(THREADS)
|
# if !defined(AT_END) && !defined(THREADS)
|
||||||
/* This is not thread safe, since realloc explicitly deallocates */
|
/* This is not thread safe, since realloc explicitly deallocates */
|
||||||
if (i & 1) {
|
if (i & 1) {
|
||||||
|
@ -621,6 +717,8 @@ void reverse_test()
|
||||||
b = c = 0;
|
b = c = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#undef a
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The rest of this builds balanced binary trees, checks that they don't
|
* The rest of this builds balanced binary trees, checks that they don't
|
||||||
* disappear, and tests finalization.
|
* disappear, and tests finalization.
|
||||||
|
@ -655,15 +753,17 @@ VOLATILE int dropped_something = 0;
|
||||||
# if defined(GC_PTHREADS)
|
# if defined(GC_PTHREADS)
|
||||||
static pthread_mutex_t incr_lock = PTHREAD_MUTEX_INITIALIZER;
|
static pthread_mutex_t incr_lock = PTHREAD_MUTEX_INITIALIZER;
|
||||||
pthread_mutex_lock(&incr_lock);
|
pthread_mutex_lock(&incr_lock);
|
||||||
# endif
|
# else
|
||||||
# ifdef GC_WIN32_THREADS
|
# ifdef GC_WIN32_THREADS
|
||||||
EnterCriticalSection(&incr_cs);
|
EnterCriticalSection(&incr_cs);
|
||||||
|
# endif
|
||||||
# endif
|
# endif
|
||||||
if ((int)(GC_word)client_data != t -> level) {
|
if ((int)(GC_word)client_data != t -> level) {
|
||||||
(void)GC_printf0("Wrong finalization data - collector is broken\n");
|
(void)GC_printf0("Wrong finalization data - collector is broken\n");
|
||||||
FAIL;
|
FAIL;
|
||||||
}
|
}
|
||||||
finalized_count++;
|
finalized_count++;
|
||||||
|
t -> level = -1; /* detect duplicate finalization immediately */
|
||||||
# ifdef PCR
|
# ifdef PCR
|
||||||
PCR_ThCrSec_ExitSys();
|
PCR_ThCrSec_ExitSys();
|
||||||
# endif
|
# endif
|
||||||
|
@ -672,10 +772,11 @@ VOLATILE int dropped_something = 0;
|
||||||
# endif
|
# endif
|
||||||
# if defined(GC_PTHREADS)
|
# if defined(GC_PTHREADS)
|
||||||
pthread_mutex_unlock(&incr_lock);
|
pthread_mutex_unlock(&incr_lock);
|
||||||
# endif
|
# else
|
||||||
# ifdef GC_WIN32_THREADS
|
# ifdef GC_WIN32_THREADS
|
||||||
LeaveCriticalSection(&incr_cs);
|
LeaveCriticalSection(&incr_cs);
|
||||||
# endif
|
# endif
|
||||||
|
# endif
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t counter = 0;
|
size_t counter = 0;
|
||||||
|
@ -746,9 +847,10 @@ int n;
|
||||||
# if defined(GC_PTHREADS)
|
# if defined(GC_PTHREADS)
|
||||||
static pthread_mutex_t incr_lock = PTHREAD_MUTEX_INITIALIZER;
|
static pthread_mutex_t incr_lock = PTHREAD_MUTEX_INITIALIZER;
|
||||||
pthread_mutex_lock(&incr_lock);
|
pthread_mutex_lock(&incr_lock);
|
||||||
# endif
|
# else
|
||||||
# ifdef GC_WIN32_THREADS
|
# ifdef GC_WIN32_THREADS
|
||||||
EnterCriticalSection(&incr_cs);
|
EnterCriticalSection(&incr_cs);
|
||||||
|
# endif
|
||||||
# endif
|
# endif
|
||||||
/* Losing a count here causes erroneous report of failure. */
|
/* Losing a count here causes erroneous report of failure. */
|
||||||
finalizable_count++;
|
finalizable_count++;
|
||||||
|
@ -761,9 +863,10 @@ int n;
|
||||||
# endif
|
# endif
|
||||||
# if defined(GC_PTHREADS)
|
# if defined(GC_PTHREADS)
|
||||||
pthread_mutex_unlock(&incr_lock);
|
pthread_mutex_unlock(&incr_lock);
|
||||||
# endif
|
# else
|
||||||
# ifdef GC_WIN32_THREADS
|
# ifdef GC_WIN32_THREADS
|
||||||
LeaveCriticalSection(&incr_cs);
|
LeaveCriticalSection(&incr_cs);
|
||||||
|
# endif
|
||||||
# endif
|
# endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1068,6 +1171,25 @@ void fail_proc1(GC_PTR x)
|
||||||
fail_count++;
|
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__ */
|
#endif /* __STDC__ */
|
||||||
|
|
||||||
#ifdef THREADS
|
#ifdef THREADS
|
||||||
|
@ -1148,6 +1270,19 @@ void run_one_test()
|
||||||
"GC_is_valid_displacement produced incorrect result\n");
|
"GC_is_valid_displacement produced incorrect result\n");
|
||||||
FAIL;
|
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
|
# ifndef ALL_INTERIOR_POINTERS
|
||||||
# if defined(RS6000) || defined(POWERPC)
|
# if defined(RS6000) || defined(POWERPC)
|
||||||
if (!TEST_FAIL_COUNT(1)) {
|
if (!TEST_FAIL_COUNT(1)) {
|
||||||
|
@ -1167,6 +1302,21 @@ void run_one_test()
|
||||||
# ifdef GC_GCJ_SUPPORT
|
# ifdef GC_GCJ_SUPPORT
|
||||||
GC_REGISTER_DISPLACEMENT(sizeof(struct fake_vtable *));
|
GC_REGISTER_DISPLACEMENT(sizeof(struct fake_vtable *));
|
||||||
GC_init_gcj_malloc(0, (void *)fake_gcj_mark_proc);
|
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
|
# endif
|
||||||
/* Repeated list reversal test. */
|
/* Repeated list reversal test. */
|
||||||
reverse_test();
|
reverse_test();
|
||||||
|
@ -1183,6 +1333,15 @@ void run_one_test()
|
||||||
LOCK();
|
LOCK();
|
||||||
n_tests++;
|
n_tests++;
|
||||||
UNLOCK();
|
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()); */
|
/* GC_printf1("Finished %x\n", pthread_self()); */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1202,7 +1361,7 @@ void check_heap_stats()
|
||||||
}
|
}
|
||||||
# else
|
# else
|
||||||
if (sizeof(char *) > 4) {
|
if (sizeof(char *) > 4) {
|
||||||
max_heap_sz = 15000000;
|
max_heap_sz = 19000000;
|
||||||
} else {
|
} else {
|
||||||
max_heap_sz = 11000000;
|
max_heap_sz = 11000000;
|
||||||
}
|
}
|
||||||
|
@ -1212,7 +1371,7 @@ void check_heap_stats()
|
||||||
# ifdef SAVE_CALL_CHAIN
|
# ifdef SAVE_CALL_CHAIN
|
||||||
max_heap_sz *= 3;
|
max_heap_sz *= 3;
|
||||||
# ifdef SAVE_CALL_COUNT
|
# ifdef SAVE_CALL_COUNT
|
||||||
max_heap_sz *= SAVE_CALL_COUNT/4;
|
max_heap_sz += max_heap_sz * SAVE_CALL_COUNT/4;
|
||||||
# endif
|
# endif
|
||||||
# endif
|
# endif
|
||||||
# endif
|
# endif
|
||||||
|
@ -1327,6 +1486,10 @@ void SetMinimumStack(long minSize)
|
||||||
# endif
|
# endif
|
||||||
n_tests = 0;
|
n_tests = 0;
|
||||||
|
|
||||||
|
#if defined(__APPLE__) && defined(__MACH__)
|
||||||
|
GC_INIT();
|
||||||
|
#endif
|
||||||
|
|
||||||
# if defined(DJGPP)
|
# if defined(DJGPP)
|
||||||
/* No good way to determine stack base from library; do it */
|
/* No good way to determine stack base from library; do it */
|
||||||
/* manually on this platform. */
|
/* manually on this platform. */
|
||||||
|
@ -1340,13 +1503,18 @@ void SetMinimumStack(long minSize)
|
||||||
# endif
|
# endif
|
||||||
GC_INIT(); /* Only needed if gc is dynamic library. */
|
GC_INIT(); /* Only needed if gc is dynamic library. */
|
||||||
(void) GC_set_warn_proc(warn_proc);
|
(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();
|
GC_enable_incremental();
|
||||||
(void) GC_printf0("Switched to incremental mode\n");
|
(void) GC_printf0("Switched to incremental mode\n");
|
||||||
# if defined(MPROTECT_VDB)
|
# if defined(MPROTECT_VDB)
|
||||||
(void)GC_printf0("Emulating dirty bits with mprotect/signals\n");
|
(void)GC_printf0("Emulating dirty bits with mprotect/signals\n");
|
||||||
# else
|
# else
|
||||||
|
# ifdef PROC_VDB
|
||||||
(void)GC_printf0("Reading dirty bits from /proc\n");
|
(void)GC_printf0("Reading dirty bits from /proc\n");
|
||||||
|
# else
|
||||||
|
(void)GC_printf0("Using DEFAULT_VDB dirty bit implementation\n");
|
||||||
|
# endif
|
||||||
# endif
|
# endif
|
||||||
# endif
|
# endif
|
||||||
run_one_test();
|
run_one_test();
|
||||||
|
@ -1378,9 +1546,9 @@ void SetMinimumStack(long minSize)
|
||||||
}
|
}
|
||||||
# endif
|
# 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();
|
run_one_test();
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -1412,7 +1580,7 @@ LRESULT CALLBACK window_proc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned __stdcall thr_window(void *arg)
|
DWORD __stdcall thr_window(void *arg)
|
||||||
{
|
{
|
||||||
WNDCLASS win_class = {
|
WNDCLASS win_class = {
|
||||||
CS_NOCLOSE,
|
CS_NOCLOSE,
|
||||||
|
@ -1474,10 +1642,11 @@ int APIENTRY WinMain(HINSTANCE instance, HINSTANCE prev, LPSTR cmd, int n)
|
||||||
# ifdef MSWINCE
|
# ifdef MSWINCE
|
||||||
HANDLE win_thr_h;
|
HANDLE win_thr_h;
|
||||||
# endif
|
# endif
|
||||||
unsigned thread_id;
|
DWORD thread_id;
|
||||||
# if 0
|
# if 0
|
||||||
GC_enable_incremental();
|
GC_enable_incremental();
|
||||||
# endif
|
# endif
|
||||||
|
GC_init();
|
||||||
InitializeCriticalSection(&incr_cs);
|
InitializeCriticalSection(&incr_cs);
|
||||||
(void) GC_set_warn_proc(warn_proc);
|
(void) GC_set_warn_proc(warn_proc);
|
||||||
# ifdef MSWINCE
|
# ifdef MSWINCE
|
||||||
|
@ -1625,15 +1794,30 @@ main()
|
||||||
(void)GC_printf0("pthread_default_stacksize_np failed.\n");
|
(void)GC_printf0("pthread_default_stacksize_np failed.\n");
|
||||||
}
|
}
|
||||||
# endif /* GC_HPUX_THREADS */
|
# endif /* GC_HPUX_THREADS */
|
||||||
|
# if defined(__APPLE__) && defined(__MACH__)
|
||||||
|
GC_INIT();
|
||||||
|
# endif
|
||||||
|
|
||||||
pthread_attr_init(&attr);
|
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);
|
pthread_attr_setstacksize(&attr, 1000000);
|
||||||
# endif
|
# endif
|
||||||
n_tests = 0;
|
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();
|
GC_enable_incremental();
|
||||||
(void) GC_printf0("Switched to incremental mode\n");
|
(void) GC_printf0("Switched to incremental mode\n");
|
||||||
|
# if defined(MPROTECT_VDB)
|
||||||
(void)GC_printf0("Emulating dirty bits with mprotect/signals\n");
|
(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
|
# endif
|
||||||
(void) GC_set_warn_proc(warn_proc);
|
(void) GC_set_warn_proc(warn_proc);
|
||||||
if ((code = pthread_key_create(&fl_key, 0)) != 0) {
|
if ((code = pthread_key_create(&fl_key, 0)) != 0) {
|
||||||
|
|
|
@ -28,7 +28,10 @@ few minutes to complete.
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.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"
|
# include "new_gc_alloc.h"
|
||||||
#else
|
#else
|
||||||
# include "gc_alloc.h"
|
# include "gc_alloc.h"
|
||||||
|
@ -189,25 +192,32 @@ int APIENTRY WinMain(
|
||||||
# endif
|
# endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
GC_init();
|
||||||
|
|
||||||
# if defined(MACOS) // MacOS
|
# if defined(MACOS) // MacOS
|
||||||
char* argv_[] = {"test_cpp", "10"}; // doesn't
|
char* argv_[] = {"test_cpp", "10"}; // doesn't
|
||||||
argv = argv_; // have a
|
argv = argv_; // have a
|
||||||
argc = sizeof(argv_)/sizeof(argv_[0]); // commandline
|
argc = sizeof(argv_)/sizeof(argv_[0]); // commandline
|
||||||
# endif
|
# endif
|
||||||
int i, iters, n;
|
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__
|
# ifdef __GNUC__
|
||||||
int *x = (int *)gc_alloc::allocate(sizeof(int));
|
int *x = (int *)gc_alloc::allocate(sizeof(int));
|
||||||
# else
|
# else
|
||||||
int *x = (int *)alloc::allocate(sizeof(int));
|
int *x = (int *)alloc::allocate(sizeof(int));
|
||||||
# endif
|
# endif
|
||||||
|
# endif
|
||||||
*x = 29;
|
*x = 29;
|
||||||
x -= 3;
|
# ifdef USE_STD_ALLOCATOR
|
||||||
|
*xptr = x;
|
||||||
|
x = 0;
|
||||||
# endif
|
# endif
|
||||||
if (argc != 2 || (0 >= (n = atoi( argv[ 1 ] )))) {
|
if (argc != 2 || (0 >= (n = atoi( argv[ 1 ] )))) {
|
||||||
GC_printf0( "usage: test_cpp number-of-iterations\n" );
|
GC_printf0( "usage: test_cpp number-of-iterations\nAssuming 10 iters\n" );
|
||||||
exit( 1 );}
|
n = 10;}
|
||||||
|
|
||||||
for (iters = 1; iters <= n; iters++) {
|
for (iters = 1; iters <= n; iters++) {
|
||||||
GC_printf1( "Starting iteration %d\n", iters );
|
GC_printf1( "Starting iteration %d\n", iters );
|
||||||
|
@ -268,9 +278,10 @@ int APIENTRY WinMain(
|
||||||
D::Test();
|
D::Test();
|
||||||
F::Test();}
|
F::Test();}
|
||||||
|
|
||||||
# if !defined(__GNUC__) && !defined(MACOS)
|
# ifdef USE_STD_ALLOCATOR
|
||||||
my_assert (29 == x[3]);
|
x = *xptr;
|
||||||
# endif
|
# endif
|
||||||
|
my_assert (29 == x[0]);
|
||||||
GC_printf0( "The test appears to have succeeded.\n" );
|
GC_printf0( "The test appears to have succeeded.\n" );
|
||||||
return( 0 );}
|
return( 0 );}
|
||||||
|
|
||||||
|
|
|
@ -4,13 +4,14 @@
|
||||||
int main()
|
int main()
|
||||||
{
|
{
|
||||||
# if defined(GC_USE_LD_WRAP)
|
# 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_create -Wl,--wrap -Wl,pthread_join "
|
||||||
"-Wl,--wrap -Wl,pthread_detach "
|
"-Wl,--wrap -Wl,pthread_detach "
|
||||||
"-Wl,--wrap -Wl,pthread_sigmask -Wl,--wrap -Wl,sleep\n");
|
"-Wl,--wrap -Wl,pthread_sigmask -Wl,--wrap -Wl,sleep\n");
|
||||||
# endif
|
# endif
|
||||||
# if defined(GC_LINUX_THREADS) || defined(GC_IRIX_THREADS) \
|
# 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");
|
printf("-lpthread\n");
|
||||||
# endif
|
# endif
|
||||||
# if defined(GC_HPUX_THREADS) || defined(GC_OSF1_THREADS)
|
# if defined(GC_HPUX_THREADS) || defined(GC_OSF1_THREADS)
|
||||||
|
@ -18,6 +19,17 @@ int main()
|
||||||
# endif
|
# endif
|
||||||
# if defined(GC_SOLARIS_THREADS) && !defined(GC_SOLARIS_PTHREADS)
|
# if defined(GC_SOLARIS_THREADS) && !defined(GC_SOLARIS_PTHREADS)
|
||||||
printf("-lthread -ldl\n");
|
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
|
# endif
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -437,6 +437,7 @@ void GC_init_explicit_typing()
|
||||||
for (; bm != 0; bm >>= 1, current_p++) {
|
for (; bm != 0; bm >>= 1, current_p++) {
|
||||||
if (bm & 1) {
|
if (bm & 1) {
|
||||||
current = *current_p;
|
current = *current_p;
|
||||||
|
FIXUP_POINTER(current);
|
||||||
if ((ptr_t)current >= least_ha && (ptr_t)current <= greatest_ha) {
|
if ((ptr_t)current >= least_ha && (ptr_t)current <= greatest_ha) {
|
||||||
PUSH_CONTENTS((ptr_t)current, mark_stack_ptr,
|
PUSH_CONTENTS((ptr_t)current, mark_stack_ptr,
|
||||||
mark_stack_limit, current_p, exit1);
|
mark_stack_limit, current_p, exit1);
|
||||||
|
@ -674,7 +675,7 @@ DCL_LOCK_STATE;
|
||||||
if( !FASTLOCK_SUCCEEDED() || (op = *opp) == 0 ) {
|
if( !FASTLOCK_SUCCEEDED() || (op = *opp) == 0 ) {
|
||||||
FASTUNLOCK();
|
FASTUNLOCK();
|
||||||
op = (ptr_t)GENERAL_MALLOC((word)lb, GC_explicit_kind);
|
op = (ptr_t)GENERAL_MALLOC((word)lb, GC_explicit_kind);
|
||||||
if (0 == op) return(0);
|
if (0 == op) return 0;
|
||||||
# ifdef MERGE_SIZES
|
# ifdef MERGE_SIZES
|
||||||
lw = GC_size_map[lb]; /* May have been uninitialized. */
|
lw = GC_size_map[lb]; /* May have been uninitialized. */
|
||||||
# endif
|
# endif
|
||||||
|
|
|
@ -1,11 +1,30 @@
|
||||||
#define GC_VERSION_MAJOR 6
|
/* The version here should match that in configure/configure.in */
|
||||||
#define GC_VERSION_MINOR 1
|
/* Eventually this one may become unnecessary. For now we need */
|
||||||
#define GC_ALPHA_VERSION 3
|
/* 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
|
# 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
|
#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 */
|
#endif /* GC_NO_VERSION_VAR */
|
||||||
|
|
|
@ -1,13 +1,28 @@
|
||||||
#if defined(GC_WIN32_THREADS)
|
#if defined(GC_WIN32_THREADS)
|
||||||
|
|
||||||
#include "private/gc_priv.h"
|
#include "private/gc_priv.h"
|
||||||
|
|
||||||
#if 0
|
|
||||||
#define STRICT
|
|
||||||
#include <windows.h>
|
#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
|
#endif
|
||||||
|
|
||||||
|
#ifndef MAX_THREADS
|
||||||
# define MAX_THREADS 64
|
# define MAX_THREADS 64
|
||||||
|
#endif
|
||||||
|
|
||||||
struct thread_entry {
|
struct thread_entry {
|
||||||
LONG in_use;
|
LONG in_use;
|
||||||
|
@ -18,6 +33,12 @@ struct thread_entry {
|
||||||
/* !in_use ==> stack == 0 */
|
/* !in_use ==> stack == 0 */
|
||||||
CONTEXT context;
|
CONTEXT context;
|
||||||
GC_bool suspended;
|
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;
|
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 */
|
/* Unlike the other threads implementations, the thread table here */
|
||||||
/* contains no pointers to the collectable heap. Thus we have */
|
/* contains no pointers to the collectable heap. Thus we have */
|
||||||
/* no private structures we need to preserve. */
|
/* 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()
|
void GC_stop_world()
|
||||||
|
@ -36,6 +63,10 @@ void GC_stop_world()
|
||||||
DWORD thread_id = GetCurrentThreadId();
|
DWORD thread_id = GetCurrentThreadId();
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
|
#ifdef CYGWIN32
|
||||||
|
if (!GC_thr_initialized) ABORT("GC_stop_world() called before GC_thr_init()");
|
||||||
|
#endif
|
||||||
|
|
||||||
GC_please_stop = TRUE;
|
GC_please_stop = TRUE;
|
||||||
for (i = 0; i < MAX_THREADS; i++)
|
for (i = 0; i < MAX_THREADS; i++)
|
||||||
if (thread_table[i].stack != 0
|
if (thread_table[i].stack != 0
|
||||||
|
@ -53,10 +84,14 @@ void GC_stop_world()
|
||||||
DWORD exitCode;
|
DWORD exitCode;
|
||||||
if (GetExitCodeThread(thread_table[i].handle,&exitCode) &&
|
if (GetExitCodeThread(thread_table[i].handle,&exitCode) &&
|
||||||
exitCode != STILL_ACTIVE) {
|
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;
|
thread_table[i].in_use = FALSE;
|
||||||
CloseHandle(thread_table[i].handle);
|
CloseHandle(thread_table[i].handle);
|
||||||
BZERO((void *)(&thread_table[i].context), sizeof(CONTEXT));
|
BZERO((void *)(&thread_table[i].context), sizeof(CONTEXT));
|
||||||
|
# endif
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (SuspendThread(thread_table[i].handle) == (DWORD)-1)
|
if (SuspendThread(thread_table[i].handle) == (DWORD)-1)
|
||||||
|
@ -335,9 +370,13 @@ void GC_get_next_stack(char *start, char **lo, char **hi)
|
||||||
if (*lo < start) *lo = start;
|
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,
|
LPSECURITY_ATTRIBUTES lpThreadAttributes,
|
||||||
DWORD dwStackSize, LPTHREAD_START_ROUTINE lpStartAddress,
|
DWORD dwStackSize, LPTHREAD_START_ROUTINE lpStartAddress,
|
||||||
LPVOID lpParameter, DWORD dwCreationFlags, LPDWORD lpThreadId )
|
LPVOID lpParameter, DWORD dwCreationFlags, LPDWORD lpThreadId )
|
||||||
|
@ -346,7 +385,10 @@ HANDLE WINAPI GC_CreateThread(
|
||||||
lpParameter, dwCreationFlags, lpThreadId);
|
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 {
|
typedef struct {
|
||||||
HANDLE child_ready_h, parent_ready_h;
|
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 */
|
/* fill in ID and handle; tell child this is done */
|
||||||
thread_table[i].id = *lpThreadId;
|
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);
|
SetEvent (parent_ready_h);
|
||||||
|
|
||||||
/* wait for child to fill in stack and copy args */
|
/* wait for child to fill in stack and copy args */
|
||||||
|
@ -472,6 +524,8 @@ static DWORD WINAPI thread_start(LPVOID arg)
|
||||||
}
|
}
|
||||||
#endif /* !defined(MSWINCE) && !(defined(__MINGW32__) && !defined(_DLL)) */
|
#endif /* !defined(MSWINCE) && !(defined(__MINGW32__) && !defined(_DLL)) */
|
||||||
|
|
||||||
|
#endif /* !CYGWIN32 */
|
||||||
|
|
||||||
#ifdef MSWINCE
|
#ifdef MSWINCE
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
@ -527,22 +581,11 @@ DWORD WINAPI main_thread_start(LPVOID arg)
|
||||||
|
|
||||||
LONG WINAPI GC_write_fault_handler(struct _EXCEPTION_POINTERS *exc_info);
|
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.
|
||||||
* This isn't generally safe, since DllMain is not premptible.
|
|
||||||
* If another thread holds the lock while this runs we're in trouble.
|
|
||||||
* Pontus Rydin suggests wrapping the thread start routine instead.
|
|
||||||
*/
|
*/
|
||||||
BOOL WINAPI DllMain(HINSTANCE inst, ULONG reason, LPVOID reserved)
|
static void threadAttach() {
|
||||||
{
|
|
||||||
switch (reason) {
|
|
||||||
case DLL_PROCESS_ATTACH:
|
|
||||||
InitializeCriticalSection(&GC_allocate_ml);
|
|
||||||
GC_init(); /* Force initialization before thread attach. */
|
|
||||||
/* fall through */
|
|
||||||
case DLL_THREAD_ATTACH:
|
|
||||||
{
|
|
||||||
int i;
|
int i;
|
||||||
/* It appears to be unsafe to acquire a lock here, since this */
|
/* It appears to be unsafe to acquire a lock here, since this */
|
||||||
/* code is apparently not preeemptible on some systems. */
|
/* code is apparently not preeemptible on some systems. */
|
||||||
|
@ -554,14 +597,11 @@ BOOL WINAPI DllMain(HINSTANCE inst, ULONG reason, LPVOID reserved)
|
||||||
/* The following should be a noop according to the win32 */
|
/* The following should be a noop according to the win32 */
|
||||||
/* documentation. There is empirical evidence that it */
|
/* documentation. There is empirical evidence that it */
|
||||||
/* isn't. - HB */
|
/* isn't. - HB */
|
||||||
# ifdef MPROTECT_VDB
|
# if defined(MPROTECT_VDB)
|
||||||
if (GC_incremental) SetUnhandledExceptionFilter(GC_write_fault_handler);
|
if (GC_incremental) SetUnhandledExceptionFilter(GC_write_fault_handler);
|
||||||
# endif
|
# endif
|
||||||
|
|
||||||
for (i = 0;
|
|
||||||
/* cast away volatile qualifier */
|
/* cast away volatile qualifier */
|
||||||
InterlockedExchange((LPLONG) &thread_table[i].in_use, 1) != 0;
|
for (i = 0; InterlockedExchange((LONG*)&thread_table[i].in_use,1) != 0; i++) {
|
||||||
i++) {
|
|
||||||
/* Compare-and-swap would make this cleaner, but that's not */
|
/* Compare-and-swap would make this cleaner, but that's not */
|
||||||
/* supported before Windows 98 and NT 4.0. In Windows 2000, */
|
/* supported before Windows 98 and NT 4.0. In Windows 2000, */
|
||||||
/* InterlockedExchange is supposed to be replaced by */
|
/* InterlockedExchange is supposed to be replaced by */
|
||||||
|
@ -571,10 +611,12 @@ BOOL WINAPI DllMain(HINSTANCE inst, ULONG reason, LPVOID reserved)
|
||||||
ABORT("too many threads");
|
ABORT("too many threads");
|
||||||
}
|
}
|
||||||
thread_table[i].id = GetCurrentThreadId();
|
thread_table[i].id = GetCurrentThreadId();
|
||||||
|
# ifdef CYGWIN32
|
||||||
|
thread_table[i].pthread_id = pthread_self();
|
||||||
|
# endif
|
||||||
if (!DuplicateHandle(GetCurrentProcess(),
|
if (!DuplicateHandle(GetCurrentProcess(),
|
||||||
GetCurrentThread(),
|
GetCurrentThread(),
|
||||||
GetCurrentProcess(),
|
GetCurrentProcess(),
|
||||||
/* cast away volatile qualifier */
|
|
||||||
(HANDLE*)&thread_table[i].handle,
|
(HANDLE*)&thread_table[i].handle,
|
||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
|
@ -584,20 +626,21 @@ BOOL WINAPI DllMain(HINSTANCE inst, ULONG reason, LPVOID reserved)
|
||||||
ABORT("DuplicateHandle failed");
|
ABORT("DuplicateHandle failed");
|
||||||
}
|
}
|
||||||
thread_table[i].stack = GC_get_stack_base();
|
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 */
|
/* If this thread is being created while we are trying to stop */
|
||||||
/* the world, wait here. Hopefully this can't happen on any */
|
/* the world, wait here. Hopefully this can't happen on any */
|
||||||
/* systems that don't allow us to block here. */
|
/* systems that don't allow us to block here. */
|
||||||
while (GC_please_stop) Sleep(20);
|
while (GC_please_stop) Sleep(20);
|
||||||
}
|
}
|
||||||
break;
|
|
||||||
case DLL_THREAD_DETACH:
|
static void threadDetach(DWORD thread_id) {
|
||||||
{
|
|
||||||
int i;
|
int i;
|
||||||
DWORD thread_id = GetCurrentThreadId();
|
|
||||||
LOCK();
|
LOCK();
|
||||||
for (i = 0;
|
for (i = 0;
|
||||||
i < MAX_THREADS &&
|
i < MAX_THREADS &&
|
||||||
(thread_table[i].stack == 0 || thread_table[i].id != thread_id);
|
(!thread_table[i].in_use || thread_table[i].id != thread_id);
|
||||||
i++) {}
|
i++) {}
|
||||||
if (i >= MAX_THREADS ) {
|
if (i >= MAX_THREADS ) {
|
||||||
WARN("thread %ld not found on detach", (GC_word)thread_id);
|
WARN("thread %ld not found on detach", (GC_word)thread_id);
|
||||||
|
@ -610,7 +653,198 @@ BOOL WINAPI DllMain(HINSTANCE inst, ULONG reason, LPVOID reserved)
|
||||||
}
|
}
|
||||||
UNLOCK();
|
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 */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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) {
|
||||||
|
case DLL_PROCESS_ATTACH:
|
||||||
|
InitializeCriticalSection(&GC_allocate_ml);
|
||||||
|
GC_init(); /* Force initialization before thread attach. */
|
||||||
|
/* fall through */
|
||||||
|
case DLL_THREAD_ATTACH:
|
||||||
|
threadAttach();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case DLL_THREAD_DETACH:
|
||||||
|
threadDetach(GetCurrentThreadId());
|
||||||
|
break;
|
||||||
|
|
||||||
case DLL_PROCESS_DETACH:
|
case DLL_PROCESS_DETACH:
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
@ -636,8 +870,8 @@ BOOL WINAPI DllMain(HINSTANCE inst, ULONG reason, LPVOID reserved)
|
||||||
}
|
}
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif /* GC_DLL */
|
#endif /* GC_DLL */
|
||||||
|
#endif /* !CYGWIN32 */
|
||||||
|
|
||||||
# endif /* !MSWINCE */
|
# endif /* !MSWINCE */
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue