summaryrefslogtreecommitdiffstats
path: root/boehm-gc
diff options
context:
space:
mode:
authorjsturm <jsturm@138bc75d-0d04-0410-961f-82ee72b054a4>2003-07-28 04:18:23 +0000
committerjsturm <jsturm@138bc75d-0d04-0410-961f-82ee72b054a4>2003-07-28 04:18:23 +0000
commit341281013a7334da0896c950d9c254e42692c479 (patch)
tree827bf34dcb0c2786d314e5fa136528e5a4feb6f7 /boehm-gc
parent975f1a7b2a8b2194905616d3fb05653329a2afce (diff)
downloadppe42-gcc-341281013a7334da0896c950d9c254e42692c479.tar.gz
ppe42-gcc-341281013a7334da0896c950d9c254e42692c479.zip
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. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@69880 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'boehm-gc')
-rw-r--r--boehm-gc/BCC_MAKEFILE58
-rw-r--r--boehm-gc/ChangeLog85
-rw-r--r--boehm-gc/Mac_files/MacOS_Test_config.h2
-rw-r--r--boehm-gc/Mac_files/MacOS_config.h4
-rw-r--r--boehm-gc/Makefile.am22
-rw-r--r--boehm-gc/Makefile.direct107
-rw-r--r--boehm-gc/Makefile.dj20
-rw-r--r--boehm-gc/Makefile.in88
-rw-r--r--boehm-gc/allchblk.c16
-rw-r--r--boehm-gc/alloc.c69
-rw-r--r--boehm-gc/alpha_mach_dep.s86
-rwxr-xr-xboehm-gc/configure575
-rw-r--r--boehm-gc/configure.host28
-rw-r--r--boehm-gc/configure.in163
-rw-r--r--boehm-gc/cord/cordbscs.c8
-rw-r--r--boehm-gc/cord/cordprnt.c16
-rw-r--r--boehm-gc/cord/de_win.c2
-rw-r--r--boehm-gc/dbg_mlc.c153
-rw-r--r--boehm-gc/doc/Makefile.am27
-rw-r--r--boehm-gc/doc/Makefile.in282
-rw-r--r--boehm-gc/doc/README19
-rw-r--r--boehm-gc/doc/README.MacOSX28
-rw-r--r--boehm-gc/doc/README.changes436
-rw-r--r--boehm-gc/doc/README.environment58
-rw-r--r--boehm-gc/doc/README.linux19
-rw-r--r--boehm-gc/doc/README.win3220
-rw-r--r--boehm-gc/doc/debugging.html8
-rw-r--r--boehm-gc/dyn_load.c278
-rw-r--r--boehm-gc/finalize.c37
-rw-r--r--boehm-gc/gc_cpp.cc22
-rw-r--r--boehm-gc/gc_dlopen.c20
-rw-r--r--boehm-gc/gcj_mlc.c1
-rw-r--r--boehm-gc/if_mach.c2
-rw-r--r--boehm-gc/include/Makefile.in11
-rw-r--r--boehm-gc/include/gc.h236
-rw-r--r--boehm-gc/include/gc_cpp.h72
-rw-r--r--boehm-gc/include/gc_local_alloc.h3
-rw-r--r--boehm-gc/include/gc_mark.h4
-rw-r--r--boehm-gc/include/gc_pthread_redirects.h17
-rw-r--r--boehm-gc/include/gc_typed.h32
-rw-r--r--boehm-gc/include/new_gc_alloc.h8
-rw-r--r--boehm-gc/include/private/dbg_mlc.h10
-rw-r--r--boehm-gc/include/private/gc_hdrs.h2
-rw-r--r--boehm-gc/include/private/gc_locks.h245
-rw-r--r--boehm-gc/include/private/gc_pmark.h39
-rw-r--r--boehm-gc/include/private/gc_priv.h166
-rw-r--r--boehm-gc/include/private/gcconfig.h509
-rw-r--r--boehm-gc/include/private/solaris_threads.h3
-rw-r--r--boehm-gc/include/private/specific.h2
-rw-r--r--boehm-gc/irix_threads.c726
-rw-r--r--boehm-gc/linux_threads.c1735
-rw-r--r--boehm-gc/mach_dep.c49
-rw-r--r--boehm-gc/malloc.c22
-rw-r--r--boehm-gc/mallocx.c56
-rw-r--r--boehm-gc/mark.c216
-rw-r--r--boehm-gc/mark_rts.c74
-rw-r--r--boehm-gc/mips_sgi_mach_dep.s (renamed from boehm-gc/mips_sgi_mach_dep.S)5
-rw-r--r--boehm-gc/misc.c246
-rwxr-xr-xboehm-gc/missing336
-rw-r--r--boehm-gc/os_dep.c1472
-rw-r--r--boehm-gc/powerpc_macosx_mach_dep.s95
-rw-r--r--boehm-gc/ptr_chck.c4
-rw-r--r--boehm-gc/reclaim.c62
-rw-r--r--boehm-gc/solaris_pthreads.c3
-rw-r--r--boehm-gc/solaris_threads.c12
-rw-r--r--boehm-gc/sparc_mach_dep.S2
-rw-r--r--boehm-gc/tests/test.c332
-rw-r--r--boehm-gc/tests/test_cpp.cc33
-rw-r--r--boehm-gc/threadlibs.c16
-rw-r--r--boehm-gc/typd_mlc.c7
-rw-r--r--boehm-gc/version.h27
-rw-r--r--boehm-gc/win32_threads.c400
72 files changed, 5096 insertions, 4952 deletions
diff --git a/boehm-gc/BCC_MAKEFILE b/boehm-gc/BCC_MAKEFILE
index a8e06827ebc..3f86ed56fc4 100644
--- a/boehm-gc/BCC_MAKEFILE
+++ b/boehm-gc/BCC_MAKEFILE
@@ -1,29 +1,31 @@
-# Makefile for Borland C++ 4.5 on NT
-# For Borland 5.0, replace bc45 by bc5.
+# Makefile for Borland C++ 5.5 on NT
# If you have the Borland assembler, remove "-DUSE_GENERIC"
#
-bc= c:\bc45
-bcbin= $(bc)\bin
-bclib= $(bc)\lib
+bc= c:\Borland\BCC55
+bcbin= $(bc)\bin
+bclib= $(bc)\lib
bcinclude= $(bc)\include
-cc= $(bcbin)\bcc32
-rc= $(bcbin)\brc32
-lib= $(bcbin)\tlib
-link= $(bcbin)\tlink32
-cflags= -R -v -vi -H -H=gc.csm -I$(bcinclude);cord -L$(bclib) \
- -w-pro -w-aus -w-par -w-ccc -w-rch -a4 -D__STDC__=0
+gcinclude1 = $(bc)\gc6.2\include
+gcinclude2 = $(bc)\gc6.2\cord
+
+cc= $(bcbin)\bcc32
+rc= $(bcbin)\brc32
+lib= $(bcbin)\tlib
+link= $(bcbin)\ilink32
+cflags= -O2 -R -v- -vi -H -H=gc.csm -I$(bcinclude);$(gcinclude1);$(gcinclude2) -L$(bclib) \
+ -w-pro -w-aus -w-par -w-ccc -w-rch -a4 -D__STDC__=0
#defines= -DSILENT
-defines= -DSMALL_CONFIG -DSILENT -DALL_INTERIOR_POINTERS -DUSE_GENERIC
+defines= -DSMALL_CONFIG -DSILENT -DALL_INTERIOR_POINTERS -DUSE_GENERIC -DNO_GETENV -DJAVA_FINALIZATION -DGC_OPERATOR_NEW_ARRAY
.c.obj:
$(cc) @&&|
- $(cdebug) $(cflags) $(cvars) $(defines) -o$* -c $*.c
+ $(cdebug) $(cflags) $(cvars) $(defines) -o$* -c $*.c
|
.cpp.obj:
$(cc) @&&|
- $(cdebug) $(cflags) $(cvars) $(defines) -o$* -c $*.cpp
+ $(cdebug) $(cflags) $(cvars) $(defines) -o$* -c $*.cpp
|
.rc.res:
@@ -39,31 +41,31 @@ OBJS= $(XXXOBJS:XXX=)
all: gctest.exe cord\de.exe test_cpp.exe
-$(OBJS) test.obj: gc_priv.h gc_hdrs.h gc.h gcconfig.h MAKEFILE
+$(OBJS) test.obj: include\private\gc_priv.h include\private\gc_hdrs.h include\gc.h include\private\gcconfig.h MAKEFILE
gc.lib: $(OBJS)
- -del gc.lib
- tlib $* @&&|
- $(XXXOBJS:XXX=+)
+ del gc.lib
+ $(lib) $* @&&|
+ $(XXXOBJS:XXX=+)
|
gctest.exe: tests\test.obj gc.lib
$(cc) @&&|
- $(cflags) -W -e$* tests\test.obj gc.lib
+ $(cflags) -W -e$* tests\test.obj gc.lib
|
-cord\de.obj cord\de_win.obj: cord\cord.h cord\private\cord_pos.h cord\de_win.h \
+cord\de.obj cord\de_win.obj: include\cord.h include\private\cord_pos.h cord\de_win.h \
cord\de_cmds.h
cord\de.exe: cord\cordbscs.obj cord\cordxtra.obj cord\de.obj cord\de_win.obj \
- cord\de_win.res gc.lib
+ cord\de_win.res gc.lib
$(cc) @&&|
- $(cflags) -W -e$* cord\cordbscs.obj cord\cordxtra.obj \
- cord\de.obj cord\de_win.obj gc.lib
+ $(cflags) -W -e$* cord\cordbscs.obj cord\cordxtra.obj \
+ cord\de.obj cord\de_win.obj gc.lib
|
$(rc) cord\de_win.res cord\de.exe
-gc_cpp.obj: gc_cpp.h gc.h
+gc_cpp.obj: include\gc_cpp.h include\gc.h
gc_cpp.cpp: gc_cpp.cc
copy gc_cpp.cc gc_cpp.cpp
@@ -71,12 +73,16 @@ gc_cpp.cpp: gc_cpp.cc
test_cpp.cpp: tests\test_cpp.cc
copy tests\test_cpp.cc test_cpp.cpp
-test_cpp.exe: test_cpp.obj gc_cpp.h gc.h gc.lib
+test_cpp.exe: test_cpp.obj include\gc_cpp.h include\gc.h gc.lib
$(cc) @&&|
- $(cflags) -W -e$* test_cpp.obj gc.lib
+ $(cflags) -W -e$* test_cpp.obj gc.lib
|
scratch:
-del *.obj *.res *.exe *.csm cord\*.obj cord\*.res cord\*.exe cord\*.csm
+clean:
+ del gc.lib
+ del *.obj
+ del tests\test.obj
diff --git a/boehm-gc/ChangeLog b/boehm-gc/ChangeLog
index 91acf278de0..afb1ce9fc08 100644
--- a/boehm-gc/ChangeLog
+++ b/boehm-gc/ChangeLog
@@ -1,3 +1,88 @@
+2003-07-28 Jeff Sturm <jsturm@one-point.com>
+
+ Import GC 6.3alpha1.
+ * BCC_MAKEFILE: Merge with GC 6.3alpha1 release.
+ * ChangeLog: Likewise.
+ * Makefile.am: Likewise.
+ * Makefile.direct: Likewise.
+ * Makefile.dj: Likewise.
+ * allchblk.c: Likewise.
+ * alloc.c: Likewise.
+ * backgraph.c: Likewise.
+ * configure.host: Likewise.
+ * configure.in: Likewise.
+ * dbg_mlc.c: Likewise.
+ * dyn_load.c: Likewise.
+ * finalize.c: Likewise.
+ * gc_cpp.cc: Likewise.
+ * gc_dlopen.c: Likewise.
+ * gcj_mlc.c: Likewise.
+ * if_mach.c: Likewise.
+ * mach_dep.c: Likewise.
+ * malloc.c: Likewise.
+ * mallocx.c: Likewise.
+ * mark.c: Likewise.
+ * mark_rts.c: Likewise.
+ * misc.c: Likewise.
+ * os_dep.c: Likewise.
+ * ptr_chck.c: Likewise.
+ * reclaim.c: Likewise.
+ * solaris_pthreads.c: Likewise.
+ * solaris_threads.c: Likewise.
+ * sparc_mach_dep.S: Likewise.
+ * threadlibs.c: Likewise.
+ * typd_mlc.c: Likewise.
+ * version.h: Likewise.
+ * win32_threads.c: Likewise.
+ * Mac_files/MacOS_Test_config.h: Likewise.
+ * Mac_files/MacOS_config.h: Likewise.
+ * cord/cordbscs.c: Likewise.
+ * cord/cordprnt.c: Likewise.
+ * cord/de_win.c: Likewise.
+ * doc/README: Likewise.
+ * doc/README.MacOSX: Likewise.
+ * doc/README.changes: Likewise.
+ * doc/README.environment: Likewise.
+ * doc/README.ews4800: Likewise.
+ * doc/README.linux: Likewise.
+ * doc/README.macros: Likewise.
+ * doc/README.win32: Likewise.
+ * doc/debugging.html: Likewise.
+ * doc/gcdescr.html: Likewise.
+ * doc/tree.html: Likewise.
+ * include/Makefile.in: Likewise.
+ * include/gc.h: Likewise.
+ * include/gc_cpp.h: Likewise.
+ * include/gc_local_alloc.h: Likewise.
+ * include/gc_mark.h: Likewise.
+ * include/gc_pthread_redirects.h: Likewise.
+ * include/gc_typed.h: Likewise.
+ * include/new_gc_alloc.h: Likewise.
+ * include/private/dbg_mlc.h: Likewise.
+ * include/private/gc_hdrs.h: Likewise.
+ * include/private/gc_locks.h: Likewise.
+ * include/private/gc_pmark.h: Likewise.
+ * include/private/gc_priv.h: Likewise.
+ * include/private/gcconfig.h: Likewise.
+ * include/private/solaris_threads.h: Likewise.
+ * include/private/specific.h: Likewise.
+ * tests/test.c: Likewise.
+ * tests/test_cpp.cc: Likewise.
+
+ * configure: Rebuild.
+ * Makefile.in: Rebuild.
+
+ * mips_sgi_mach_dep.s: Add.
+
+ * alpha_mach_dep.s: Remove.
+ * irix_threads.c: Remove.
+ * linux_threads.c: Remove.
+ * mips_sgi_mach_dep.S: Remove.
+ * missing: Remove.
+ * powerpc_macosx_mach_dep.s: Remove.
+ * doc/Makefile.am: Remove.
+ * doc/Makefile.in: Remove.
+
2003-07-25 Roger Sayle <roger@eyesopen.com>
* configure.host: Only use +ESdbgasm when using the HPUX native
diff --git a/boehm-gc/Mac_files/MacOS_Test_config.h b/boehm-gc/Mac_files/MacOS_Test_config.h
index c95f4bb2f3e..4e5d2527788 100644
--- a/boehm-gc/Mac_files/MacOS_Test_config.h
+++ b/boehm-gc/Mac_files/MacOS_Test_config.h
@@ -74,7 +74,7 @@
// implementations, and it sometimes has a significant performance
// impact. However, it is dangerous for many not-quite-ANSI C
// programs that call things like printf in asynchronous signal handlers.
-// -DOPERATOR_NEW_ARRAY declares that the C++ compiler supports the
+// -DGC_OPERATOR_NEW_ARRAY declares that the C++ compiler supports the
// new syntax "operator new[]" for allocating and deleting arrays.
// See gc_cpp.h for details. No effect on the C part of the collector.
// This is defined implicitly in a few environments.
diff --git a/boehm-gc/Mac_files/MacOS_config.h b/boehm-gc/Mac_files/MacOS_config.h
index 93c3c97a955..407bdf154a2 100644
--- a/boehm-gc/Mac_files/MacOS_config.h
+++ b/boehm-gc/Mac_files/MacOS_config.h
@@ -72,7 +72,7 @@
// implementations, and it sometimes has a significant performance
// impact. However, it is dangerous for many not-quite-ANSI C
// programs that call things like printf in asynchronous signal handlers.
-// -DOPERATOR_NEW_ARRAY declares that the C++ compiler supports the
+// -DGC_OPERATOR_NEW_ARRAY declares that the C++ compiler supports the
// new syntax "operator new[]" for allocating and deleting arrays.
// See gc_cpp.h for details. No effect on the C part of the collector.
// This is defined implicitly in a few environments.
@@ -86,4 +86,4 @@
// since some ports use malloc or calloc to obtain system memory.
// (Probably works for UNIX, and win32.)
// -DNO_DEBUG removes GC_dump and the debugging routines it calls.
-// Reduces code size slightly at the expense of debuggability. \ No newline at end of file
+// Reduces code size slightly at the expense of debuggability.
diff --git a/boehm-gc/Makefile.am b/boehm-gc/Makefile.am
index 4c22a0f3dac..717af6e4ac1 100644
--- a/boehm-gc/Makefile.am
+++ b/boehm-gc/Makefile.am
@@ -18,15 +18,23 @@ MULTICLEAN = true
noinst_LTLIBRARIES = libgcjgc.la libgcjgc_convenience.la
+if POWERPC_DARWIN
+asm_libgc_sources = powerpc_darwin_mach_dep.s
+else
+asm_libgc_sources =
+endif
+
GC_SOURCES = allchblk.c alloc.c blacklst.c checksums.c dbg_mlc.c \
-dyn_load.c finalize.c gc_dlopen.c gcj_mlc.c headers.c irix_threads.c \
-linux_threads.c malloc.c mallocx.c mark.c mark_rts.c misc.c new_hblk.c \
+dyn_load.c finalize.c gc_dlopen.c gcj_mlc.c headers.c aix_irix_threads.c \
+malloc.c mallocx.c mark.c mark_rts.c misc.c new_hblk.c \
obj_map.c os_dep.c pcr_interface.c ptr_chck.c real_malloc.c reclaim.c \
solaris_pthreads.c solaris_threads.c specific.c stubborn.c typd_mlc.c \
-backgraph.c win32_threads.c
+backgraph.c win32_threads.c \
+pthread_support.c pthread_stop_world.c darwin_stop_world.c \
+$(asm_libgc_sources)
-EXTRA_GC_SOURCES = alpha_mach_dep.s \
-mips_sgi_mach_dep.S mips_ultrix_mach_dep.s powerpc_macosx_mach_dep.s \
+EXTRA_GC_SOURCES = alpha_mach_dep.S \
+mips_sgi_mach_dep.s mips_ultrix_mach_dep.s powerpc_darwin_mach_dep.s \
rs6000_mach_dep.s sparc_mach_dep.S sparc_netbsd_mach_dep.s \
sparc_sunos4_mach_dep.s ia64_save_regs_in_stack.s
@@ -63,7 +71,9 @@ TESTS = gctest
## FIXME: relies on internal code generated by automake.
all_objs = @addobjs@ $(libgcjgc_la_OBJECTS)
$(all_objs) : include/private/gcconfig.h include/private/gc_priv.h \
-include/private/gc_hdrs.h include/gc.h include/gc_gcj.h include/gc_mark.h
+include/private/gc_hdrs.h include/gc.h include/gc_gcj.h \
+include/gc_pthread_redirects.h include/gc_config_macros.h \
+include/gc_mark.h @addincludes@
## FIXME: we shouldn't have to do this, but automake forces us to.
.s.lo:
diff --git a/boehm-gc/Makefile.direct b/boehm-gc/Makefile.direct
index af6192ebc45..a884ee5e0bf 100644
--- a/boehm-gc/Makefile.direct
+++ b/boehm-gc/Makefile.direct
@@ -27,8 +27,11 @@ CFLAGS= -O -I$(srcdir)/include -DATOMIC_UNCOLLECTABLE -DNO_SIGNALS -DNO_EXECUTE_
# To build the parallel collector on Linux, add to the above:
# -DGC_LINUX_THREADS -DPARALLEL_MARK -DTHREAD_LOCAL_ALLOC
-# To build the parallel collector n a static library on HP/UX, add to the above:
+# To build the parallel collector in a static library on HP/UX,
+# add to the above:
# -DGC_HPUX_THREADS -DPARALLEL_MARK -DTHREAD_LOCAL_ALLOC -DUSE_HPUX_TLS -D_POSIX_C_SOURCE=199506L
+# To build the thread-safe collector on Tru64, add to the above:
+# -pthread -DGC_OSF1_THREADS
# HOSTCC and HOSTCFLAGS are used to build executables that will be run as
# part of the build process, i.e. on the build machine. These will usually
@@ -60,6 +63,16 @@ HOSTCFLAGS=$(CFLAGS)
# Also requires -D_REENTRANT or -D_POSIX_C_SOURCE=199506L. See README.hp.
# -DGC_LINUX_THREADS enables support for Xavier Leroy's Linux threads.
# see README.linux. -D_REENTRANT may also be required.
+# -DGC_OSF1_THREADS enables support for Tru64 pthreads. Untested.
+# -DGC_FREEBSD_THREADS enables support for FreeBSD pthreads. Untested.
+# Appeared to run into some underlying thread problems.
+# -DGC_DARWIN_THREADS enables support for Mac OS X pthreads. Untested.
+# -DGC_DGUX386_THREADS enables support for DB/UX on I386 threads.
+# See README.DGUX386.
+# -DGC_WIN32_THREADS enables support for win32 threads. That makes sense
+# for this Makefile only under Cygwin.
+# -DGC_THREADS should set the appropriate one of the above macros.
+# It assumes pthreads for Solaris.
# -DALL_INTERIOR_POINTERS allows all pointers to the interior
# of objects to be recognized. (See gc_priv.h for consequences.)
# Alternatively, GC_all_interior_pointers can be set at process
@@ -93,13 +106,15 @@ HOSTCFLAGS=$(CFLAGS)
# See gc_cpp.h for details. No effect on the C part of the collector.
# This is defined implicitly in a few environments. Must also be defined
# by clients that use gc_cpp.h.
-# -DREDIRECT_MALLOC=X causes malloc, realloc, and free to be
-# defined as aliases for X, GC_realloc, and GC_free, respectively.
+# -DREDIRECT_MALLOC=X causes malloc to be defined as alias for X.
+# Unless the following macros are defined, realloc is also redirected
+# to GC_realloc, and free is redirected to GC_free.
# Calloc and strdup are redefined in terms of the new malloc. X should
# be either GC_malloc or GC_malloc_uncollectable, or
# GC_debug_malloc_replacement. (The latter invokes GC_debug_malloc
# with dummy source location information, but still results in
-# properly remembered call stacks on Linux/X86 and Solaris/SPARC.)
+# properly remembered call stacks on Linux/X86 and Solaris/SPARC.
+# It requires that the following two macros also be used.)
# The former is occasionally useful for working around leaks in code
# you don't want to (or can't) look at. It may not work for
# existing code, but it often does. Neither works on all platforms,
@@ -111,6 +126,9 @@ HOSTCFLAGS=$(CFLAGS)
# The canonical use is -DREDIRECT_REALLOC=GC_debug_realloc_replacement,
# together with -DREDIRECT_MALLOC=GC_debug_malloc_replacement to
# generate leak reports with call stacks for both malloc and realloc.
+# This also requires the following:
+# -DREDIRECT_FREE=X causes free to be redirected to X. The
+# canonical use is -DREDIRECT_FREE=GC_debug_free.
# -DIGNORE_FREE turns calls to free into a noop. Only useful with
# -DREDIRECT_MALLOC.
# -DNO_DEBUGGING removes GC_dump and the debugging routines it calls.
@@ -197,8 +215,11 @@ HOSTCFLAGS=$(CFLAGS)
# 15% or so.
# -DUSE_3DNOW_PREFETCH causes the collector to issue AMD 3DNow style
# prefetch instructions. Same restrictions as USE_I686_PREFETCH.
-# UNTESTED!!
-# -DGC_USE_LD_WRAP in combination with the gld flags listed in README.linux
+# Minimally tested. Didn't appear to be an obvious win on a K6-2/500.
+# -DUSE_PPC_PREFETCH causes the collector to issue PowerPC style
+# prefetch instructions. No effect except on PowerPC OS X platforms.
+# Performance impact untested.
+# -DGC_USE_LD_WRAP in combination with the old flags listed in README.linux
# causes the collector some system and pthread calls in a more transparent
# fashion than the usual macro-based approach. Requires GNU ld, and
# currently probably works only with Linux.
@@ -226,6 +247,24 @@ HOSTCFLAGS=$(CFLAGS)
# -DSTUBBORN_ALLOC allows allocation of "hard to change" objects, and thus
# makes incremental collection easier. Was enabled by default until 6.0.
# Rarely used, to my knowledge.
+# -DHANDLE_FORK attempts to make GC_malloc() work in a child process fork()ed
+# from a multithreaded parent. Currently only supported by pthread_support.c.
+# (Similar code should work on Solaris or Irix, but it hasn't been tried.)
+# -DTEST_WITH_SYSTEM_MALLOC causes gctest to allocate (and leak) large chunks
+# of memory with the standard system malloc. This will cause the root
+# set and collected heap to grow significantly if malloced memory is
+# somehow getting traced by the collector. This has no impact on the
+# generated library; it only affects the test.
+# -DPOINTER_MASK=0x... causes candidate pointers to be ANDed with the
+# given mask before being considered. If either this or the following
+# macro is defined, it will be assumed that all pointers stored in
+# the heap need to be processed this way. Stack and register pointers
+# will be considered both with and without processing.
+# These macros are normally needed only to support systems that use
+# high-order pointer tags. EXPERIMENTAL.
+# -DPOINTER_SHIFT=n causes the collector to left shift candidate pointers
+# by the indicated amount before trying to interpret them. Applied
+# after POINTER_MASK. EXPERIMENTAL. See also the preceding macro.
#
CXXFLAGS= $(CFLAGS)
@@ -233,15 +272,15 @@ AR= ar
RANLIB= ranlib
-OBJS= alloc.o reclaim.o allchblk.o misc.o mach_dep.o os_dep.o mark_rts.o headers.o mark.o obj_map.o blacklst.o finalize.o new_hblk.o dbg_mlc.o malloc.o stubborn.o checksums.o solaris_threads.o irix_threads.o linux_threads.o typd_mlc.o ptr_chck.o mallocx.o solaris_pthreads.o gcj_mlc.o specific.o gc_dlopen.o backgraph.o
+OBJS= alloc.o reclaim.o allchblk.o misc.o mach_dep.o os_dep.o mark_rts.o headers.o mark.o obj_map.o blacklst.o finalize.o new_hblk.o dbg_mlc.o malloc.o stubborn.o checksums.o solaris_threads.o aix_irix_threads.o pthread_support.o pthread_stop_world.o darwin_stop_world.o typd_mlc.o ptr_chck.o mallocx.o solaris_pthreads.o gcj_mlc.o specific.o gc_dlopen.o backgraph.o win32_threads.o
-CSRCS= reclaim.c allchblk.c misc.c alloc.c mach_dep.c os_dep.c mark_rts.c headers.c mark.c obj_map.c pcr_interface.c blacklst.c finalize.c new_hblk.c real_malloc.c dyn_load.c dbg_mlc.c malloc.c stubborn.c checksums.c solaris_threads.c irix_threads.c linux_threads.c typd_mlc.c ptr_chck.c mallocx.c solaris_pthreads.c gcj_mlc.c specific.c gc_dlopen.c backgraph.c
+CSRCS= reclaim.c allchblk.c misc.c alloc.c mach_dep.c os_dep.c mark_rts.c headers.c mark.c obj_map.c pcr_interface.c blacklst.c finalize.c new_hblk.c real_malloc.c dyn_load.c dbg_mlc.c malloc.c stubborn.c checksums.c solaris_threads.c aix_irix_threads.c pthread_support.c pthread_stop_world.c darwin_stop_world.c typd_mlc.c ptr_chck.c mallocx.c solaris_pthreads.c gcj_mlc.c specific.c gc_dlopen.c backgraph.c win32_threads.c
CORD_SRCS= cord/cordbscs.c cord/cordxtra.c cord/cordprnt.c cord/de.c cord/cordtest.c include/cord.h include/ec.h include/private/cord_pos.h cord/de_win.c cord/de_win.h cord/de_cmds.h cord/de_win.ICO cord/de_win.RC
CORD_OBJS= cord/cordbscs.o cord/cordxtra.o cord/cordprnt.o
-SRCS= $(CSRCS) mips_sgi_mach_dep.s rs6000_mach_dep.s alpha_mach_dep.s \
+SRCS= $(CSRCS) mips_sgi_mach_dep.s rs6000_mach_dep.s alpha_mach_dep.S \
sparc_mach_dep.S include/gc.h include/gc_typed.h \
include/private/gc_hdrs.h include/private/gc_priv.h \
include/private/gcconfig.h include/private/gc_pmark.h \
@@ -249,14 +288,17 @@ SRCS= $(CSRCS) mips_sgi_mach_dep.s rs6000_mach_dep.s alpha_mach_dep.s \
threadlibs.c if_mach.c if_not_there.c gc_cpp.cc include/gc_cpp.h \
gcname.c include/weakpointer.h include/private/gc_locks.h \
gcc_support.c mips_ultrix_mach_dep.s include/gc_alloc.h \
- include/new_gc_alloc.h include/javaxfc.h sparc_sunos4_mach_dep.s \
- sparc_netbsd_mach_dep.s \
+ include/new_gc_alloc.h include/gc_allocator.h \
+ include/javaxfc.h sparc_sunos4_mach_dep.s sparc_netbsd_mach_dep.s \
include/private/solaris_threads.h include/gc_backptr.h \
hpux_test_and_clear.s include/gc_gcj.h \
include/gc_local_alloc.h include/private/dbg_mlc.h \
- include/private/specific.h powerpc_macosx_mach_dep.s \
+ include/private/specific.h powerpc_darwin_mach_dep.s \
include/leak_detector.h include/gc_amiga_redirects.h \
- include/gc_pthread_redirects.h $(CORD_SRCS)
+ include/gc_pthread_redirects.h ia64_save_regs_in_stack.s \
+ include/gc_config_macros.h include/private/pthread_support.h \
+ include/private/pthread_stop_world.h include/private/darwin_semaphore.h \
+ include/private/darwin_stop_world.h $(CORD_SRCS)
DOC_FILES= README.QUICK doc/README.Mac doc/README.MacOSX doc/README.OS2 \
doc/README.amiga doc/README.cords doc/debugging.html \
@@ -265,15 +307,19 @@ DOC_FILES= README.QUICK doc/README.Mac doc/README.MacOSX doc/README.OS2 \
doc/README.win32 doc/barrett_diagram doc/README \
doc/README.contributors doc/README.changes doc/gc.man \
doc/README.environment doc/tree.html doc/gcdescr.html \
- doc/README.autoconf doc/README.macros doc/README.ews4800
+ doc/README.autoconf doc/README.macros doc/README.ews4800 \
+ doc/README.DGUX386 doc/README.arm.cross doc/leak.html \
+ doc/scale.html doc/gcinterface.html doc/README.darwin
TESTS= tests/test.c tests/test_cpp.cc tests/trace_test.c \
tests/leak_test.c tests/thread_leak_test.c
GNU_BUILD_FILES= configure.in Makefile.am configure acinclude.m4 \
libtool.m4 install-sh configure.host Makefile.in \
- aclocal.m4 config.sub config.guess ltconfig \
- ltmain.sh mkinstalldirs
+ ltconfig aclocal.m4 config.sub config.guess \
+ include/Makefile.am include/Makefile.in \
+ doc/Makefile.am doc/Makefile.in \
+ ltmain.sh mkinstalldirs depcomp missing
OTHER_MAKEFILES= OS2_MAKEFILE NT_MAKEFILE NT_THREADS_MAKEFILE gc.mak \
BCC_MAKEFILE EMX_MAKEFILE WCC_MAKEFILE Makefile.dj \
@@ -285,7 +331,7 @@ OTHER_FILES= Makefile setjmp_t.c callprocs pc_excludes \
MacProjects.sit.hqx MacOS.c \
Mac_files/datastart.c Mac_files/dataend.c \
Mac_files/MacOS_config.h Mac_files/MacOS_Test_config.h \
- add_gc_prefix.c gc_cpp.cpp win32_threads.c \
+ add_gc_prefix.c gc_cpp.cpp \
version.h AmigaOS.c \
$(TESTS) $(GNU_BUILD_FILES) $(OTHER_MAKEFILES)
@@ -330,16 +376,16 @@ mach_dep.o $(SRCS)
$(OBJS) tests/test.o dyn_load.o dyn_load_sunos53.o: \
$(srcdir)/include/private/gc_priv.h \
$(srcdir)/include/private/gc_hdrs.h $(srcdir)/include/private/gc_locks.h \
- $(srcdir)/include/gc.h \
+ $(srcdir)/include/gc.h $(srcdir)/include/gc_pthread_redirects.h \
$(srcdir)/include/private/gcconfig.h $(srcdir)/include/gc_typed.h \
- Makefile
+ $(srcdir)/include/gc_config_macros.h Makefile
# The dependency on Makefile is needed. Changing
# options such as -DSILENT affects the size of GC_arrays,
# invalidating all .o files that rely on gc_priv.h
mark.o typd_mlc.o finalize.o ptr_chck.o: $(srcdir)/include/gc_mark.h $(srcdir)/include/private/gc_pmark.h
-specific.o linux_threads.o: $(srcdir)/include/private/specific.h
+specific.o pthread_support.o: $(srcdir)/include/private/specific.h
solaris_threads.o solaris_pthreads.o: $(srcdir)/include/private/solaris_threads.h
@@ -434,17 +480,18 @@ liblinuxgc.so: $(OBJS) dyn_load.o
# gcc -shared -Wl,-soname=libgc.so.0 -o libgc.so.0 $(LIBOBJS) dyn_load.lo
# touch liblinuxgc.so
-mach_dep.o: $(srcdir)/mach_dep.c $(srcdir)/mips_sgi_mach_dep.s $(srcdir)/mips_ultrix_mach_dep.s \
- $(srcdir)/rs6000_mach_dep.s $(srcdir)/powerpc_macosx_mach_dep.s $(UTILS)
+mach_dep.o: $(srcdir)/mach_dep.c $(srcdir)/mips_sgi_mach_dep.s \
+ $(srcdir)/mips_ultrix_mach_dep.s \
+ $(srcdir)/rs6000_mach_dep.s $(srcdir)/powerpc_darwin_mach_dep.s \
+ $(srcdir)/sparc_mach_dep.S $(srcdir)/sparc_sunos4_mach_dep.s \
+ $(srcdir)/ia64_save_regs_in_stack.s \
+ $(srcdir)/sparc_netbsd_mach_dep.s $(UTILS)
rm -f mach_dep.o
- ./if_mach MIPS IRIX5 $(AS) -o mach_dep.o $(srcdir)/mips_sgi_mach_dep.s
+ ./if_mach MIPS IRIX5 $(CC) -c -o mach_dep.o $(srcdir)/mips_sgi_mach_dep.s
./if_mach MIPS RISCOS $(AS) -o mach_dep.o $(srcdir)/mips_ultrix_mach_dep.s
./if_mach MIPS ULTRIX $(AS) -o mach_dep.o $(srcdir)/mips_ultrix_mach_dep.s
- ./if_mach RS6000 "" $(AS) -o mach_dep.o $(srcdir)/rs6000_mach_dep.s
- ./if_mach POWERPC MACOSX $(AS) -o mach_dep.o $(srcdir)/powerpc_macosx_mach_dep.s
-# ./if_mach ALPHA "" $(AS) -o mach_dep.o $(srcdir)/alpha_mach_dep.s
-# alpha_mach_dep.s assumes that pointers are not saved in fp registers.
-# Gcc on a 21264 can spill pointers to fp registers. Oops.
+ ./if_mach POWERPC DARWIN $(AS) -o mach_dep.o $(srcdir)/powerpc_darwin_mach_dep.s
+ ./if_mach ALPHA LINUX $(CC) -c -o mach_dep.o $(srcdir)/alpha_mach_dep.S
./if_mach SPARC SUNOS5 $(CC) -c -o mach_dep.o $(srcdir)/sparc_mach_dep.S
./if_mach SPARC SUNOS4 $(AS) -o mach_dep.o $(srcdir)/sparc_sunos4_mach_dep.s
./if_mach SPARC OPENBSD $(AS) -o mach_dep.o $(srcdir)/sparc_sunos4_mach_dep.s
@@ -491,7 +538,7 @@ cord/de: $(srcdir)/cord/de.c cord/cordbscs.o cord/cordxtra.o gc.a $(UTILS)
./if_mach SPARC DRSNX $(CC) $(CFLAGS) -o cord/de $(srcdir)/cord/de.c cord/cordbscs.o cord/cordxtra.o gc.a $(CURSES) -lucb `./threadlibs`
./if_mach HP_PA HPUX $(CC) $(CFLAGS) -o cord/de $(srcdir)/cord/de.c cord/cordbscs.o cord/cordxtra.o gc.a $(CURSES) -ldld `./threadlibs`
./if_mach RS6000 "" $(CC) $(CFLAGS) -o cord/de $(srcdir)/cord/de.c cord/cordbscs.o cord/cordxtra.o gc.a -lcurses
- ./if_mach POWERPC MACOSX $(CC) $(CFLAGS) -o cord/de $(srcdir)/cord/de.c cord/cordbscs.o cord/cordxtra.o gc.a
+ ./if_mach POWERPC DARWIN $(CC) $(CFLAGS) -o cord/de $(srcdir)/cord/de.c cord/cordbscs.o cord/cordxtra.o gc.a
./if_mach I386 LINUX $(CC) $(CFLAGS) -o cord/de $(srcdir)/cord/de.c cord/cordbscs.o cord/cordxtra.o gc.a -lcurses `./threadlibs`
./if_mach ALPHA LINUX $(CC) $(CFLAGS) -o cord/de $(srcdir)/cord/de.c cord/cordbscs.o cord/cordxtra.o gc.a -lcurses `./threadlibs`
./if_mach IA64 LINUX $(CC) $(CFLAGS) -o cord/de $(srcdir)/cord/de.c cord/cordbscs.o cord/cordxtra.o gc.a -lcurses `./threadlibs`
@@ -510,7 +557,7 @@ if_not_there: $(srcdir)/if_not_there.c
clean:
rm -f gc.a *.o *.exe tests/*.o gctest gctest_dyn_link test_cpp \
setjmp_test mon.out gmon.out a.out core if_not_there if_mach \
- threadlibs $(CORD_OBJS) cord/cordtest cord/de
+ threadlibs $(CORD_OBJS) cord/cordtest cord/de
-rm -f *~
gctest: tests/test.o gc.a $(UTILS)
diff --git a/boehm-gc/Makefile.dj b/boehm-gc/Makefile.dj
index 7aadaf34b44..6097293ff0e 100644
--- a/boehm-gc/Makefile.dj
+++ b/boehm-gc/Makefile.dj
@@ -152,7 +152,7 @@ CFLAGS= -O -I$(srcdir)/include -DATOMIC_UNCOLLECTABLE -DNO_SIGNALS -DALL_INTERIO
# currently probably works only with Linux.
-CXXFLAGS= $(CFLAGS) -DOPERATOR_NEW_ARRAY
+CXXFLAGS= $(CFLAGS) -DGC_OPERATOR_NEW_ARRAY
AR= ar
RANLIB= ranlib
@@ -165,8 +165,8 @@ CORD_SRCS= cord/cordbscs.c cord/cordxtra.c cord/cordprnt.c cord/de.c cord/cordt
CORD_OBJS= cord/cordbscs.o cord/cordxtra.o cord/cordprnt.o
-SRCS= $(CSRCS) mips_sgi_mach_dep.s rs6000_mach_dep.s alpha_mach_dep.s \
- sparc_mach_dep.s include/gc.h include/gc_typed.h \
+SRCS= $(CSRCS) mips_sgi_mach_dep.S rs6000_mach_dep.s alpha_mach_dep.S \
+ sparc_mach_dep.S include/gc.h include/gc_typed.h \
include/private/gc_hdrs.h include/private/gc_priv.h \
include/private/gcconfig.h include/private/gc_mark.h \
include/gc_inl.h include/gc_inline.h gc.man \
@@ -177,7 +177,7 @@ SRCS= $(CSRCS) mips_sgi_mach_dep.s rs6000_mach_dep.s alpha_mach_dep.s \
include/private/solaris_threads.h include/gc_backptr.h \
hpux_test_and_clear.s include/gc_gcj.h \
include/gc_local_alloc.h include/private/dbg_mlc.h \
- include/private/specific.h powerpc_macosx_mach_dep.s \
+ include/private/specific.h powerpc_darwin_mach_dep.s \
include/leak_detector.h $(CORD_SRCS)
OTHER_FILES= Makefile PCR-Makefile OS2_MAKEFILE NT_MAKEFILE BCC_MAKEFILE \
@@ -284,16 +284,16 @@ liblinuxgc.so: $(OBJS) dyn_load.o
gcc -shared -o liblinuxgc.so $(OBJS) dyn_load.o -lo
ln liblinuxgc.so libgc.so
-mach_dep.o: $(srcdir)/mach_dep.c $(srcdir)/mips_sgi_mach_dep.s $(srcdir)/mips_ultrix_mach_dep.s \
- $(srcdir)/rs6000_mach_dep.s $(srcdir)/powerpc_macosx_mach_dep.s $(UTILS)
+mach_dep.o: $(srcdir)/mach_dep.c $(srcdir)/mips_sgi_mach_dep.S $(srcdir)/mips_ultrix_mach_dep.s \
+ $(srcdir)/rs6000_mach_dep.s $(srcdir)/powerpc_darwin_mach_dep.s $(UTILS)
rm -f mach_dep.o
- ./if_mach MIPS IRIX5 $(AS) -o mach_dep.o $(srcdir)/mips_sgi_mach_dep.s
+ ./if_mach MIPS IRIX5 $(AS) -o mach_dep.o $(srcdir)/mips_sgi_mach_dep.S
./if_mach MIPS RISCOS $(AS) -o mach_dep.o $(srcdir)/mips_ultrix_mach_dep.s
./if_mach MIPS ULTRIX $(AS) -o mach_dep.o $(srcdir)/mips_ultrix_mach_dep.s
./if_mach RS6000 "" $(AS) -o mach_dep.o $(srcdir)/rs6000_mach_dep.s
- ./if_mach POWERPC MACOSX $(AS) -o mach_dep.o $(srcdir)/powerpc_macosx_mach_dep.s
- ./if_mach ALPHA "" $(AS) -o mach_dep.o $(srcdir)/alpha_mach_dep.s
- ./if_mach SPARC SUNOS5 $(AS) -o mach_dep.o $(srcdir)/sparc_mach_dep.s
+ ./if_mach POWERPC MACOSX $(AS) -o mach_dep.o $(srcdir)/powerpc_darwin_mach_dep.s
+ ./if_mach ALPHA "" $(AS) -o mach_dep.o $(srcdir)/alpha_mach_dep.S
+ ./if_mach SPARC SUNOS5 $(AS) -o mach_dep.o $(srcdir)/sparc_mach_dep.S
./if_mach SPARC SUNOS4 $(AS) -o mach_dep.o $(srcdir)/sparc_sunos4_mach_dep.s
./if_not_there mach_dep.o $(CC) -c $(SPECIALCFLAGS) $(srcdir)/mach_dep.c
diff --git a/boehm-gc/Makefile.in b/boehm-gc/Makefile.in
index edecc834988..4e5bb369e7a 100644
--- a/boehm-gc/Makefile.in
+++ b/boehm-gc/Makefile.in
@@ -1,6 +1,6 @@
-# Makefile.in generated automatically by automake 1.4 from Makefile.am
+# Makefile.in generated automatically by automake 1.4-p5 from Makefile.am
-# Copyright (C) 1994, 1995-8, 1999 Free Software Foundation, Inc.
+# Copyright (C) 1994, 1995-8, 1999, 2001 Free Software Foundation, Inc.
# This Makefile.in is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
# with or without modifications, as long as this notice is preserved.
@@ -66,9 +66,11 @@ target_triplet = @target@
AR = @AR@
AS = @AS@
CC = @CC@
+CFLAGS = @CFLAGS@
CPP = @CPP@
CXX = @CXX@
CXXCPP = @CXXCPP@
+CXXFLAGS = @CXXFLAGS@
CXXINCLUDES = @CXXINCLUDES@
DLLTOOL = @DLLTOOL@
EXEEXT = @EXEEXT@
@@ -89,7 +91,10 @@ RANLIB = @RANLIB@
STRIP = @STRIP@
THREADLIBS = @THREADLIBS@
VERSION = @VERSION@
+addincludes = @addincludes@
+addlibs = @addlibs@
addobjs = @addobjs@
+addtests = @addtests@
gc_basedir = @gc_basedir@
mkinstalldirs = @mkinstalldirs@
target_all = @target_all@
@@ -109,17 +114,21 @@ MULTIDO = true
MULTICLEAN = true
noinst_LTLIBRARIES = libgcjgc.la libgcjgc_convenience.la
+@POWERPC_DARWIN_TRUE@asm_libgc_sources = @POWERPC_DARWIN_TRUE@powerpc_darwin_mach_dep.s
+@POWERPC_DARWIN_FALSE@asm_libgc_sources =
GC_SOURCES = allchblk.c alloc.c blacklst.c checksums.c dbg_mlc.c \
-dyn_load.c finalize.c gc_dlopen.c gcj_mlc.c headers.c irix_threads.c \
-linux_threads.c malloc.c mallocx.c mark.c mark_rts.c misc.c new_hblk.c \
+dyn_load.c finalize.c gc_dlopen.c gcj_mlc.c headers.c aix_irix_threads.c \
+malloc.c mallocx.c mark.c mark_rts.c misc.c new_hblk.c \
obj_map.c os_dep.c pcr_interface.c ptr_chck.c real_malloc.c reclaim.c \
solaris_pthreads.c solaris_threads.c specific.c stubborn.c typd_mlc.c \
-backgraph.c win32_threads.c
+backgraph.c win32_threads.c \
+pthread_support.c pthread_stop_world.c darwin_stop_world.c \
+$(asm_libgc_sources)
-EXTRA_GC_SOURCES = alpha_mach_dep.s \
-mips_sgi_mach_dep.S mips_ultrix_mach_dep.s powerpc_macosx_mach_dep.s \
+EXTRA_GC_SOURCES = alpha_mach_dep.S \
+mips_sgi_mach_dep.s mips_ultrix_mach_dep.s powerpc_darwin_mach_dep.s \
rs6000_mach_dep.s sparc_mach_dep.S sparc_netbsd_mach_dep.s \
sparc_sunos4_mach_dep.s ia64_save_regs_in_stack.s
@@ -213,24 +222,53 @@ DEFS = @DEFS@ -I. -I$(srcdir)
CPPFLAGS = @CPPFLAGS@
LDFLAGS = @LDFLAGS@
LIBS = @LIBS@
-libgcjgc_la_OBJECTS = allchblk.lo alloc.lo blacklst.lo checksums.lo \
-dbg_mlc.lo dyn_load.lo finalize.lo gc_dlopen.lo gcj_mlc.lo headers.lo \
-irix_threads.lo linux_threads.lo malloc.lo mallocx.lo mark.lo \
-mark_rts.lo misc.lo new_hblk.lo obj_map.lo os_dep.lo pcr_interface.lo \
-ptr_chck.lo real_malloc.lo reclaim.lo solaris_pthreads.lo \
-solaris_threads.lo specific.lo stubborn.lo typd_mlc.lo backgraph.lo \
-win32_threads.lo
+@POWERPC_DARWIN_FALSE@libgcjgc_la_OBJECTS = allchblk.lo alloc.lo \
+@POWERPC_DARWIN_FALSE@blacklst.lo checksums.lo dbg_mlc.lo dyn_load.lo \
+@POWERPC_DARWIN_FALSE@finalize.lo gc_dlopen.lo gcj_mlc.lo headers.lo \
+@POWERPC_DARWIN_FALSE@aix_irix_threads.lo malloc.lo mallocx.lo mark.lo \
+@POWERPC_DARWIN_FALSE@mark_rts.lo misc.lo new_hblk.lo obj_map.lo \
+@POWERPC_DARWIN_FALSE@os_dep.lo pcr_interface.lo ptr_chck.lo \
+@POWERPC_DARWIN_FALSE@real_malloc.lo reclaim.lo solaris_pthreads.lo \
+@POWERPC_DARWIN_FALSE@solaris_threads.lo specific.lo stubborn.lo \
+@POWERPC_DARWIN_FALSE@typd_mlc.lo backgraph.lo win32_threads.lo \
+@POWERPC_DARWIN_FALSE@pthread_support.lo pthread_stop_world.lo \
+@POWERPC_DARWIN_FALSE@darwin_stop_world.lo
+@POWERPC_DARWIN_TRUE@libgcjgc_la_OBJECTS = allchblk.lo alloc.lo \
+@POWERPC_DARWIN_TRUE@blacklst.lo checksums.lo dbg_mlc.lo dyn_load.lo \
+@POWERPC_DARWIN_TRUE@finalize.lo gc_dlopen.lo gcj_mlc.lo headers.lo \
+@POWERPC_DARWIN_TRUE@aix_irix_threads.lo malloc.lo mallocx.lo mark.lo \
+@POWERPC_DARWIN_TRUE@mark_rts.lo misc.lo new_hblk.lo obj_map.lo \
+@POWERPC_DARWIN_TRUE@os_dep.lo pcr_interface.lo ptr_chck.lo \
+@POWERPC_DARWIN_TRUE@real_malloc.lo reclaim.lo solaris_pthreads.lo \
+@POWERPC_DARWIN_TRUE@solaris_threads.lo specific.lo stubborn.lo \
+@POWERPC_DARWIN_TRUE@typd_mlc.lo backgraph.lo win32_threads.lo \
+@POWERPC_DARWIN_TRUE@pthread_support.lo pthread_stop_world.lo \
+@POWERPC_DARWIN_TRUE@darwin_stop_world.lo powerpc_darwin_mach_dep.lo
libgcjgc_convenience_la_LDFLAGS =
-libgcjgc_convenience_la_OBJECTS = allchblk.lo alloc.lo blacklst.lo \
-checksums.lo dbg_mlc.lo dyn_load.lo finalize.lo gc_dlopen.lo gcj_mlc.lo \
-headers.lo irix_threads.lo linux_threads.lo malloc.lo mallocx.lo \
-mark.lo mark_rts.lo misc.lo new_hblk.lo obj_map.lo os_dep.lo \
-pcr_interface.lo ptr_chck.lo real_malloc.lo reclaim.lo \
-solaris_pthreads.lo solaris_threads.lo specific.lo stubborn.lo \
-typd_mlc.lo backgraph.lo win32_threads.lo
+@POWERPC_DARWIN_FALSE@libgcjgc_convenience_la_OBJECTS = allchblk.lo \
+@POWERPC_DARWIN_FALSE@alloc.lo blacklst.lo checksums.lo dbg_mlc.lo \
+@POWERPC_DARWIN_FALSE@dyn_load.lo finalize.lo gc_dlopen.lo gcj_mlc.lo \
+@POWERPC_DARWIN_FALSE@headers.lo aix_irix_threads.lo malloc.lo \
+@POWERPC_DARWIN_FALSE@mallocx.lo mark.lo mark_rts.lo misc.lo \
+@POWERPC_DARWIN_FALSE@new_hblk.lo obj_map.lo os_dep.lo pcr_interface.lo \
+@POWERPC_DARWIN_FALSE@ptr_chck.lo real_malloc.lo reclaim.lo \
+@POWERPC_DARWIN_FALSE@solaris_pthreads.lo solaris_threads.lo \
+@POWERPC_DARWIN_FALSE@specific.lo stubborn.lo typd_mlc.lo backgraph.lo \
+@POWERPC_DARWIN_FALSE@win32_threads.lo pthread_support.lo \
+@POWERPC_DARWIN_FALSE@pthread_stop_world.lo darwin_stop_world.lo
+@POWERPC_DARWIN_TRUE@libgcjgc_convenience_la_OBJECTS = allchblk.lo \
+@POWERPC_DARWIN_TRUE@alloc.lo blacklst.lo checksums.lo dbg_mlc.lo \
+@POWERPC_DARWIN_TRUE@dyn_load.lo finalize.lo gc_dlopen.lo gcj_mlc.lo \
+@POWERPC_DARWIN_TRUE@headers.lo aix_irix_threads.lo malloc.lo \
+@POWERPC_DARWIN_TRUE@mallocx.lo mark.lo mark_rts.lo misc.lo new_hblk.lo \
+@POWERPC_DARWIN_TRUE@obj_map.lo os_dep.lo pcr_interface.lo ptr_chck.lo \
+@POWERPC_DARWIN_TRUE@real_malloc.lo reclaim.lo solaris_pthreads.lo \
+@POWERPC_DARWIN_TRUE@solaris_threads.lo specific.lo stubborn.lo \
+@POWERPC_DARWIN_TRUE@typd_mlc.lo backgraph.lo win32_threads.lo \
+@POWERPC_DARWIN_TRUE@pthread_support.lo pthread_stop_world.lo \
+@POWERPC_DARWIN_TRUE@darwin_stop_world.lo powerpc_darwin_mach_dep.lo
check_PROGRAMS = gctest$(EXEEXT)
gctest_DEPENDENCIES = ./libgcjgc.la
-CFLAGS = @CFLAGS@
COMPILE = $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
CCLD = $(CC)
DIST_COMMON = ChangeLog Makefile.am Makefile.in acinclude.m4 aclocal.m4 \
@@ -368,7 +406,7 @@ maintainer-clean-recursive:
dot_seen=no; \
rev=''; list='$(SUBDIRS)'; for subdir in $$list; do \
rev="$$subdir $$rev"; \
- test "$$subdir" = "." && dot_seen=yes; \
+ test "$$subdir" != "." || dot_seen=yes; \
done; \
test "$$dot_seen" = "no" && rev=". $$rev"; \
target=`echo $@ | sed s/-recursive//`; \
@@ -598,7 +636,9 @@ mostlyclean distclean maintainer-clean
test.o: tests/test.c
$(COMPILE) -c $(srcdir)/tests/test.c
$(all_objs) : include/private/gcconfig.h include/private/gc_priv.h \
-include/private/gc_hdrs.h include/gc.h include/gc_gcj.h include/gc_mark.h
+include/private/gc_hdrs.h include/gc.h include/gc_gcj.h \
+include/gc_pthread_redirects.h include/gc_config_macros.h \
+include/gc_mark.h @addincludes@
.s.lo:
$(LTCOMPILE) -Wp,-P -x assembler-with-cpp -c $<
diff --git a/boehm-gc/allchblk.c b/boehm-gc/allchblk.c
index 7d4cbd82f13..2b039397e1c 100644
--- a/boehm-gc/allchblk.c
+++ b/boehm-gc/allchblk.c
@@ -47,12 +47,16 @@ GC_bool GC_use_entire_heap = 0;
struct hblk * GC_hblkfreelist[N_HBLK_FLS+1] = { 0 };
#ifndef USE_MUNMAP
+
word GC_free_bytes[N_HBLK_FLS+1] = { 0 };
/* Number of free bytes on each list. */
/* Is bytes + the number of free bytes on lists n .. N_HBLK_FLS */
/* > GC_max_large_allocd_bytes? */
- GC_bool GC_enough_large_bytes_left(bytes,n)
+# ifdef __GNUC__
+ __inline__
+# endif
+ static GC_bool GC_enough_large_bytes_left(bytes,n)
word bytes;
int n;
{
@@ -583,11 +587,11 @@ int n;
if (!GC_use_entire_heap
&& size_avail != size_needed
&& USED_HEAP_SIZE >= GC_requested_heapsize
- && !GC_incremental && GC_should_collect()) {
+ && !TRUE_INCREMENTAL && GC_should_collect()) {
# ifdef USE_MUNMAP
continue;
# else
- /* If we enough large blocks left to cover any */
+ /* If we have enough large blocks left to cover any */
/* previous request for large blocks, we go ahead */
/* and split. Assuming a steady state, that should */
/* be safe. It means that we can use the full */
@@ -595,6 +599,12 @@ int n;
if (!GC_enough_large_bytes_left(GC_large_allocd_bytes, n)) {
continue;
}
+ /* If we are deallocating lots of memory from */
+ /* finalizers, fail and collect sooner rather */
+ /* than later. */
+ if (GC_finalizer_mem_freed > (GC_heapsize >> 4)) {
+ continue;
+ }
# endif /* !USE_MUNMAP */
}
/* If the next heap block is obviously better, go on. */
diff --git a/boehm-gc/alloc.c b/boehm-gc/alloc.c
index f2e5af05720..f53061f872d 100644
--- a/boehm-gc/alloc.c
+++ b/boehm-gc/alloc.c
@@ -72,6 +72,13 @@ int GC_full_freq = 19; /* Every 20th collection is a full */
GC_bool GC_need_full_gc = FALSE;
/* Need full GC do to heap growth. */
+#ifdef THREADS
+ GC_bool GC_world_stopped = FALSE;
+# define IF_THREADS(x) x
+#else
+# define IF_THREADS(x)
+#endif
+
word GC_used_heap_size_after_full = 0;
char * GC_copyright[] =
@@ -160,7 +167,7 @@ static word min_words_allocd()
+ (GC_large_free_bytes >> 2)
/* use a bit more of large empty heap */
+ total_root_size);
- if (GC_incremental) {
+ if (TRUE_INCREMENTAL) {
return scan_size / (2 * GC_free_space_divisor);
} else {
return scan_size / GC_free_space_divisor;
@@ -182,7 +189,8 @@ word GC_adj_words_allocd()
/* managed object should not alter result, assuming the client */
/* is playing by the rules. */
result = (signed_word)GC_words_allocd
- - (signed_word)GC_mem_freed - expl_managed;
+ - (signed_word)GC_mem_freed
+ + (signed_word)GC_finalizer_mem_freed - expl_managed;
if (result > (signed_word)GC_words_allocd) {
result = GC_words_allocd;
/* probably client bug or unfortunate scheduling */
@@ -250,7 +258,6 @@ void GC_maybe_gc()
if (GC_should_collect()) {
if (!GC_incremental) {
- GC_notify_full_gc();
GC_gcollect_inner();
n_partial_gcs = 0;
return;
@@ -302,10 +309,14 @@ void GC_maybe_gc()
/*
* Stop the world garbage collection. Assumes lock held, signals disabled.
* If stop_func is not GC_never_stop_func, then abort if stop_func returns TRUE.
+ * Return TRUE if we successfully completed the collection.
*/
GC_bool GC_try_to_collect_inner(stop_func)
GC_stop_func stop_func;
{
+# ifdef CONDPRINT
+ CLOCK_TYPE start_time, current_time;
+# endif
if (GC_dont_gc) return FALSE;
if (GC_incremental && GC_collection_in_progress()) {
# ifdef CONDPRINT
@@ -320,8 +331,10 @@ GC_stop_func stop_func;
GC_collect_a_little_inner(1);
}
}
+ if (stop_func == GC_never_stop_func) GC_notify_full_gc();
# ifdef CONDPRINT
if (GC_print_stats) {
+ if (GC_print_stats) GET_TIME(start_time);
GC_printf2(
"Initiating full world-stop collection %lu after %ld allocd bytes\n",
(unsigned long) GC_gc_no+1,
@@ -360,6 +373,13 @@ GC_stop_func stop_func;
return(FALSE);
}
GC_finish_collection();
+# if defined(CONDPRINT)
+ if (GC_print_stats) {
+ GET_TIME(current_time);
+ GC_printf1("Complete collection took %lu msecs\n",
+ MS_TIME_DIFF(current_time,start_time));
+ }
+# endif
return(TRUE);
}
@@ -430,6 +450,7 @@ int GC_collect_a_little GC_PROTO(())
result = (int)GC_collection_in_progress();
UNLOCK();
ENABLE_SIGNALS();
+ if (!result && GC_debugging_started) GC_print_all_smashed();
return(result);
}
@@ -448,16 +469,17 @@ GC_stop_func stop_func;
CLOCK_TYPE start_time, current_time;
# endif
-# if defined(REGISTER_LIBRARIES_EARLY)
- GC_cond_register_dynamic_libraries();
-# endif
- STOP_WORLD();
# ifdef PRINTTIMES
GET_TIME(start_time);
# endif
# if defined(CONDPRINT) && !defined(PRINTTIMES)
if (GC_print_stats) GET_TIME(start_time);
# endif
+# if defined(REGISTER_LIBRARIES_EARLY)
+ GC_cond_register_dynamic_libraries();
+# endif
+ STOP_WORLD();
+ IF_THREADS(GC_world_stopped = TRUE);
# ifdef CONDPRINT
if (GC_print_stats) {
GC_printf1("--> Marking for collection %lu ",
@@ -488,6 +510,7 @@ GC_stop_func stop_func;
}
# endif
GC_deficit = i; /* Give the mutator a chance. */
+ IF_THREADS(GC_world_stopped = FALSE);
START_WORLD();
return(FALSE);
}
@@ -521,6 +544,8 @@ GC_stop_func stop_func;
(*GC_check_heap)();
}
+ IF_THREADS(GC_world_stopped = FALSE);
+ START_WORLD();
# ifdef PRINTTIMES
GET_TIME(current_time);
GC_printf1("World-stopped marking took %lu msecs\n",
@@ -534,7 +559,6 @@ GC_stop_func stop_func;
}
# endif
# endif
- START_WORLD();
return(TRUE);
}
@@ -611,6 +635,7 @@ void GC_finish_collection()
GC_print_address_map();
}
# endif
+ COND_DUMP;
if (GC_find_leak) {
/* Mark all objects on the free list. All objects should be */
/* marked when we're done. */
@@ -707,6 +732,7 @@ void GC_finish_collection()
GC_words_allocd = 0;
GC_words_wasted = 0;
GC_mem_freed = 0;
+ GC_finalizer_mem_freed = 0;
# ifdef USE_MUNMAP
GC_unmap_old();
@@ -730,6 +756,7 @@ void GC_finish_collection()
int result;
DCL_LOCK_STATE;
+ if (GC_debugging_started) GC_print_all_smashed();
GC_INVOKE_FINALIZERS();
DISABLE_SIGNALS();
LOCK();
@@ -741,14 +768,17 @@ void GC_finish_collection()
EXIT_GC();
UNLOCK();
ENABLE_SIGNALS();
- if(result) GC_INVOKE_FINALIZERS();
+ if(result) {
+ if (GC_debugging_started) GC_print_all_smashed();
+ GC_INVOKE_FINALIZERS();
+ }
return(result);
}
void GC_gcollect GC_PROTO(())
{
- GC_notify_full_gc();
(void)GC_try_to_collect(GC_never_stop_func);
+ if (GC_have_errors) GC_print_all_errors();
}
word GC_n_heap_sects = 0; /* Number of sections currently in heap. */
@@ -950,7 +980,6 @@ GC_bool ignore_off_page;
{
if (!GC_incremental && !GC_dont_gc &&
(GC_dont_expand && GC_words_allocd > 0 || GC_should_collect())) {
- GC_notify_full_gc();
GC_gcollect_inner();
} else {
word blocks_to_get = GC_heapsize/(HBLKSIZE*GC_free_space_divisor)
@@ -975,7 +1004,6 @@ GC_bool ignore_off_page;
&& !GC_expand_hp_inner(needed_blocks)) {
if (GC_fail_count++ < GC_max_retries) {
WARN("Out of Memory! Trying to continue ...\n", 0);
- GC_notify_full_gc();
GC_gcollect_inner();
} else {
# if !defined(AMIGA) || !defined(GC_AMIGA_FASTALLOC)
@@ -1005,29 +1033,38 @@ ptr_t GC_allocobj(sz, kind)
word sz;
int kind;
{
- register ptr_t * flh = &(GC_obj_kinds[kind].ok_freelist[sz]);
+ ptr_t * flh = &(GC_obj_kinds[kind].ok_freelist[sz]);
+ GC_bool tried_minor = FALSE;
if (sz == 0) return(0);
while (*flh == 0) {
ENTER_GC();
/* Do our share of marking work */
- if(GC_incremental && !GC_dont_gc) GC_collect_a_little_inner(1);
+ if(TRUE_INCREMENTAL) GC_collect_a_little_inner(1);
/* Sweep blocks for objects of this size */
- GC_continue_reclaim(sz, kind);
+ GC_continue_reclaim(sz, kind);
EXIT_GC();
if (*flh == 0) {
GC_new_hblk(sz, kind);
}
if (*flh == 0) {
ENTER_GC();
- if (!GC_collect_or_expand((word)1,FALSE)) {
+ if (GC_incremental && GC_time_limit == GC_TIME_UNLIMITED
+ && ! tried_minor ) {
+ GC_collect_a_little_inner(1);
+ tried_minor = TRUE;
+ } else {
+ if (!GC_collect_or_expand((word)1,FALSE)) {
EXIT_GC();
return(0);
+ }
}
EXIT_GC();
}
}
+ /* Successful allocation; reset failure count. */
+ GC_fail_count = 0;
return(*flh);
}
diff --git a/boehm-gc/alpha_mach_dep.s b/boehm-gc/alpha_mach_dep.s
deleted file mode 100644
index a21f77ad54c..00000000000
--- a/boehm-gc/alpha_mach_dep.s
+++ /dev/null
@@ -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
diff --git a/boehm-gc/configure b/boehm-gc/configure
index ef1a1a76331..e8ca37d9e8a 100755
--- a/boehm-gc/configure
+++ b/boehm-gc/configure
@@ -41,7 +41,12 @@ ac_help="$ac_help
ac_help="$ac_help
--with-ecos enable runtime eCos target support"
ac_help="$ac_help
- --enable-shared[=PKGS] build shared libraries [default=no]"
+ --enable-shared[=PKGS] build shared libraries [default=yes]"
+ac_help="$ac_help
+ --with-target-subdir=SUBDIR
+ configuring with a cross compiler"
+ac_help="$ac_help
+ --with-cross-host=HOST configuring with a cross compiler"
ac_help="$ac_help
--enable-full-debug include full support for pointer backtracing etc."
@@ -61,7 +66,6 @@ program_suffix=NONE
program_transform_name=s,x,x,
silent=
site=
-sitefile=
srcdir=
target=NONE
verbose=
@@ -176,7 +180,6 @@ Configuration:
--help print this message
--no-create do not create output files
--quiet, --silent do not print \`checking...' messages
- --site-file=FILE use FILE as the site file
--version print the version of autoconf that created configure
Directory and file names:
--prefix=PREFIX install architecture-independent files in PREFIX
@@ -347,11 +350,6 @@ EOF
-site=* | --site=* | --sit=*)
site="$ac_optarg" ;;
- -site-file | --site-file | --site-fil | --site-fi | --site-f)
- ac_prev=sitefile ;;
- -site-file=* | --site-file=* | --site-fil=* | --site-fi=* | --site-f=*)
- sitefile="$ac_optarg" ;;
-
-srcdir | --srcdir | --srcdi | --srcd | --src | --sr)
ac_prev=srcdir ;;
-srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*)
@@ -517,16 +515,12 @@ fi
srcdir=`echo "${srcdir}" | sed 's%\([^/]\)/*$%\1%'`
# Prefer explicitly selected file to automatically selected ones.
-if test -z "$sitefile"; then
- if test -z "$CONFIG_SITE"; then
- if test "x$prefix" != xNONE; then
- CONFIG_SITE="$prefix/share/config.site $prefix/etc/config.site"
- else
- CONFIG_SITE="$ac_default_prefix/share/config.site $ac_default_prefix/etc/config.site"
- fi
+if test -z "$CONFIG_SITE"; then
+ if test "x$prefix" != xNONE; then
+ CONFIG_SITE="$prefix/share/config.site $prefix/etc/config.site"
+ else
+ CONFIG_SITE="$ac_default_prefix/share/config.site $ac_default_prefix/etc/config.site"
fi
-else
- CONFIG_SITE="$sitefile"
fi
for ac_site_file in $CONFIG_SITE; do
if test -r "$ac_site_file"; then
@@ -604,7 +598,7 @@ ac_configure=$ac_aux_dir/configure # This should be Cygnus configure.
# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff"
# ./install, which can be erroneously created by make from ./install.sh.
echo $ac_n "checking for a BSD compatible install""... $ac_c" 1>&6
-echo "configure:608: checking for a BSD compatible install" >&5
+echo "configure:602: checking for a BSD compatible install" >&5
if test -z "$INSTALL"; then
if eval "test \"`echo '$''{'ac_cv_path_install'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
@@ -657,7 +651,7 @@ test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL_PROGRAM}'
test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644'
echo $ac_n "checking whether build environment is sane""... $ac_c" 1>&6
-echo "configure:661: checking whether build environment is sane" >&5
+echo "configure:655: checking whether build environment is sane" >&5
# Just in case
sleep 1
echo timestamp > conftestfile
@@ -714,7 +708,7 @@ test "$program_suffix" != NONE &&
test "$program_transform_name" = "" && program_transform_name="s,x,x,"
echo $ac_n "checking whether ${MAKE-make} sets \${MAKE}""... $ac_c" 1>&6
-echo "configure:718: checking whether ${MAKE-make} sets \${MAKE}" >&5
+echo "configure:712: checking whether ${MAKE-make} sets \${MAKE}" >&5
set dummy ${MAKE-make}; ac_make=`echo "$2" | sed 'y%./+-%__p_%'`
if eval "test \"`echo '$''{'ac_cv_prog_make_${ac_make}_set'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
@@ -747,12 +741,12 @@ else
fi
echo $ac_n "checking for Cygwin environment""... $ac_c" 1>&6
-echo "configure:751: checking for Cygwin environment" >&5
+echo "configure:745: checking for Cygwin environment" >&5
if eval "test \"`echo '$''{'ac_cv_cygwin'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
cat > conftest.$ac_ext <<EOF
-#line 756 "configure"
+#line 750 "configure"
#include "confdefs.h"
int main() {
@@ -763,7 +757,7 @@ int main() {
return __CYGWIN__;
; return 0; }
EOF
-if { (eval echo configure:767: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+if { (eval echo configure:761: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
rm -rf conftest*
ac_cv_cygwin=yes
else
@@ -780,19 +774,19 @@ echo "$ac_t""$ac_cv_cygwin" 1>&6
CYGWIN=
test "$ac_cv_cygwin" = yes && CYGWIN=yes
echo $ac_n "checking for mingw32 environment""... $ac_c" 1>&6
-echo "configure:784: checking for mingw32 environment" >&5
+echo "configure:778: checking for mingw32 environment" >&5
if eval "test \"`echo '$''{'ac_cv_mingw32'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
cat > conftest.$ac_ext <<EOF
-#line 789 "configure"
+#line 783 "configure"
#include "confdefs.h"
int main() {
return __MINGW32__;
; return 0; }
EOF
-if { (eval echo configure:796: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+if { (eval echo configure:790: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
rm -rf conftest*
ac_cv_mingw32=yes
else
@@ -903,7 +897,7 @@ else { echo "configure: error: can not run $ac_config_sub" 1>&2; exit 1; }
fi
echo $ac_n "checking host system type""... $ac_c" 1>&6
-echo "configure:907: checking host system type" >&5
+echo "configure:901: checking host system type" >&5
host_alias=$host
case "$host_alias" in
@@ -924,7 +918,7 @@ host_os=`echo $host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'`
echo "$ac_t""$host" 1>&6
echo $ac_n "checking target system type""... $ac_c" 1>&6
-echo "configure:928: checking target system type" >&5
+echo "configure:922: checking target system type" >&5
target_alias=$target
case "$target_alias" in
@@ -942,7 +936,7 @@ target_os=`echo $target | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'`
echo "$ac_t""$target" 1>&6
echo $ac_n "checking build system type""... $ac_c" 1>&6
-echo "configure:946: checking build system type" >&5
+echo "configure:940: checking build system type" >&5
build_alias=$build
case "$build_alias" in
@@ -982,7 +976,7 @@ fi
missing_dir=`cd $ac_aux_dir && pwd`
echo $ac_n "checking for working aclocal""... $ac_c" 1>&6
-echo "configure:986: checking for working aclocal" >&5
+echo "configure:980: checking for working aclocal" >&5
# Run test in a subshell; some versions of sh will print an error if
# an executable is not found, even if stderr is redirected.
# Redirect stdin to placate older versions of autoconf. Sigh.
@@ -995,7 +989,7 @@ else
fi
echo $ac_n "checking for working autoconf""... $ac_c" 1>&6
-echo "configure:999: checking for working autoconf" >&5
+echo "configure:993: checking for working autoconf" >&5
# Run test in a subshell; some versions of sh will print an error if
# an executable is not found, even if stderr is redirected.
# Redirect stdin to placate older versions of autoconf. Sigh.
@@ -1008,7 +1002,7 @@ else
fi
echo $ac_n "checking for working automake""... $ac_c" 1>&6
-echo "configure:1012: checking for working automake" >&5
+echo "configure:1006: checking for working automake" >&5
# Run test in a subshell; some versions of sh will print an error if
# an executable is not found, even if stderr is redirected.
# Redirect stdin to placate older versions of autoconf. Sigh.
@@ -1021,7 +1015,7 @@ else
fi
echo $ac_n "checking for working autoheader""... $ac_c" 1>&6
-echo "configure:1025: checking for working autoheader" >&5
+echo "configure:1019: checking for working autoheader" >&5
# Run test in a subshell; some versions of sh will print an error if
# an executable is not found, even if stderr is redirected.
# Redirect stdin to placate older versions of autoconf. Sigh.
@@ -1034,7 +1028,7 @@ else
fi
echo $ac_n "checking for working makeinfo""... $ac_c" 1>&6
-echo "configure:1038: checking for working makeinfo" >&5
+echo "configure:1032: checking for working makeinfo" >&5
# Run test in a subshell; some versions of sh will print an error if
# an executable is not found, even if stderr is redirected.
# Redirect stdin to placate older versions of autoconf. Sigh.
@@ -1060,7 +1054,7 @@ fi
# Extract the first word of "gcc", so it can be a program name with args.
set dummy gcc; ac_word=$2
echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
-echo "configure:1064: checking for $ac_word" >&5
+echo "configure:1058: checking for $ac_word" >&5
if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
@@ -1090,7 +1084,7 @@ if test -z "$CC"; then
# Extract the first word of "cc", so it can be a program name with args.
set dummy cc; ac_word=$2
echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
-echo "configure:1094: checking for $ac_word" >&5
+echo "configure:1088: checking for $ac_word" >&5
if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
@@ -1139,7 +1133,7 @@ fi
fi
echo $ac_n "checking whether we are using GNU C""... $ac_c" 1>&6
-echo "configure:1143: checking whether we are using GNU C" >&5
+echo "configure:1137: checking whether we are using GNU C" >&5
if eval "test \"`echo '$''{'ac_cv_prog_gcc'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
@@ -1148,7 +1142,7 @@ else
yes;
#endif
EOF
-if { ac_try='${CC-cc} -E conftest.c'; { (eval echo configure:1152: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }; } | egrep yes >/dev/null 2>&1; then
+if { ac_try='${CC-cc} -E conftest.c'; { (eval echo configure:1146: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }; } | egrep yes >/dev/null 2>&1; then
ac_cv_prog_gcc=yes
else
ac_cv_prog_gcc=no
@@ -1163,7 +1157,7 @@ if test $ac_cv_prog_gcc = yes; then
ac_save_CFLAGS="$CFLAGS"
CFLAGS=
echo $ac_n "checking whether ${CC-cc} accepts -g""... $ac_c" 1>&6
-echo "configure:1167: checking whether ${CC-cc} accepts -g" >&5
+echo "configure:1161: checking whether ${CC-cc} accepts -g" >&5
if eval "test \"`echo '$''{'ac_cv_prog_cc_g'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
@@ -1200,7 +1194,7 @@ do
# Extract the first word of "$ac_prog", so it can be a program name with args.
set dummy $ac_prog; ac_word=$2
echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
-echo "configure:1204: checking for $ac_word" >&5
+echo "configure:1198: checking for $ac_word" >&5
if eval "test \"`echo '$''{'ac_cv_prog_CXX'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
@@ -1233,7 +1227,7 @@ test -n "$CXX" || CXX="gcc"
test -z "$CXX" && { echo "configure: error: no acceptable c++ found in \$PATH" 1>&2; exit 1; }
echo $ac_n "checking whether we are using GNU C++""... $ac_c" 1>&6
-echo "configure:1237: checking whether we are using GNU C++" >&5
+echo "configure:1231: checking whether we are using GNU C++" >&5
if eval "test \"`echo '$''{'ac_cv_prog_gxx'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
@@ -1242,7 +1236,7 @@ else
yes;
#endif
EOF
-if { ac_try='${CXX-g++} -E conftest.C'; { (eval echo configure:1246: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }; } | egrep yes >/dev/null 2>&1; then
+if { ac_try='${CXX-g++} -E conftest.C'; { (eval echo configure:1240: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }; } | egrep yes >/dev/null 2>&1; then
ac_cv_prog_gxx=yes
else
ac_cv_prog_gxx=no
@@ -1257,7 +1251,7 @@ if test $ac_cv_prog_gxx = yes; then
ac_save_CXXFLAGS="$CXXFLAGS"
CXXFLAGS=
echo $ac_n "checking whether ${CXX-g++} accepts -g""... $ac_c" 1>&6
-echo "configure:1261: checking whether ${CXX-g++} accepts -g" >&5
+echo "configure:1255: checking whether ${CXX-g++} accepts -g" >&5
if eval "test \"`echo '$''{'ac_cv_prog_cxx_g'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
@@ -1290,7 +1284,7 @@ fi
# NEWLIB_CONFIGURE, which doesn't work because that means that it will
# be run before AC_CANONICAL_HOST.
echo $ac_n "checking build system type""... $ac_c" 1>&6
-echo "configure:1294: checking build system type" >&5
+echo "configure:1288: checking build system type" >&5
build_alias=$build
case "$build_alias" in
@@ -1311,7 +1305,7 @@ echo "$ac_t""$build" 1>&6
# Extract the first word of "${ac_tool_prefix}as", so it can be a program name with args.
set dummy ${ac_tool_prefix}as; ac_word=$2
echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
-echo "configure:1315: checking for $ac_word" >&5
+echo "configure:1309: checking for $ac_word" >&5
if eval "test \"`echo '$''{'ac_cv_prog_AS'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
@@ -1343,7 +1337,7 @@ fi
# Extract the first word of "${ac_tool_prefix}ar", so it can be a program name with args.
set dummy ${ac_tool_prefix}ar; ac_word=$2
echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
-echo "configure:1347: checking for $ac_word" >&5
+echo "configure:1341: checking for $ac_word" >&5
if eval "test \"`echo '$''{'ac_cv_prog_AR'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
@@ -1375,7 +1369,7 @@ fi
# Extract the first word of "${ac_tool_prefix}ranlib", so it can be a program name with args.
set dummy ${ac_tool_prefix}ranlib; ac_word=$2
echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
-echo "configure:1379: checking for $ac_word" >&5
+echo "configure:1373: checking for $ac_word" >&5
if eval "test \"`echo '$''{'ac_cv_prog_RANLIB'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
@@ -1407,7 +1401,7 @@ if test -n "$ac_tool_prefix"; then
# Extract the first word of "ranlib", so it can be a program name with args.
set dummy ranlib; ac_word=$2
echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
-echo "configure:1411: checking for $ac_word" >&5
+echo "configure:1405: checking for $ac_word" >&5
if eval "test \"`echo '$''{'ac_cv_prog_RANLIB'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
@@ -1452,7 +1446,7 @@ fi
# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff"
# ./install, which can be erroneously created by make from ./install.sh.
echo $ac_n "checking for a BSD compatible install""... $ac_c" 1>&6
-echo "configure:1456: checking for a BSD compatible install" >&5
+echo "configure:1450: checking for a BSD compatible install" >&5
if test -z "$INSTALL"; then
if eval "test \"`echo '$''{'ac_cv_path_install'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
@@ -1506,7 +1500,7 @@ test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644'
echo $ac_n "checking whether to enable maintainer-specific portions of Makefiles""... $ac_c" 1>&6
-echo "configure:1510: checking whether to enable maintainer-specific portions of Makefiles" >&5
+echo "configure:1504: checking whether to enable maintainer-specific portions of Makefiles" >&5
# Check whether --enable-maintainer-mode or --disable-maintainer-mode was given.
if test "${enable_maintainer_mode+set}" = set; then
enableval="$enable_maintainer_mode"
@@ -1544,7 +1538,7 @@ if false; then
echo $ac_n "checking for executable suffix""... $ac_c" 1>&6
-echo "configure:1548: checking for executable suffix" >&5
+echo "configure:1542: checking for executable suffix" >&5
if eval "test \"`echo '$''{'ac_cv_exeext'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
@@ -1554,10 +1548,10 @@ else
rm -f conftest*
echo 'int main () { return 0; }' > conftest.$ac_ext
ac_cv_exeext=
- if { (eval echo configure:1558: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; }; then
+ if { (eval echo configure:1552: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; }; then
for file in conftest.*; do
case $file in
- *.c | *.o | *.obj | *.ilk | *.pdb) ;;
+ *.c | *.o | *.obj) ;;
*) ac_cv_exeext=`echo $file | sed -e s/conftest//` ;;
esac
done
@@ -1676,7 +1670,7 @@ ac_prog=ld
if test "$GCC" = yes; then
# Check if gcc -print-prog-name=ld gives a path.
echo $ac_n "checking for ld used by GCC""... $ac_c" 1>&6
-echo "configure:1680: checking for ld used by GCC" >&5
+echo "configure:1674: checking for ld used by GCC" >&5
case $host in
*-*-mingw*)
# gcc leaves a trailing carriage return which upsets mingw
@@ -1706,10 +1700,10 @@ echo "configure:1680: checking for ld used by GCC" >&5
esac
elif test "$with_gnu_ld" = yes; then
echo $ac_n "checking for GNU ld""... $ac_c" 1>&6
-echo "configure:1710: checking for GNU ld" >&5
+echo "configure:1704: checking for GNU ld" >&5
else
echo $ac_n "checking for non-GNU ld""... $ac_c" 1>&6
-echo "configure:1713: checking for non-GNU ld" >&5
+echo "configure:1707: checking for non-GNU ld" >&5
fi
if eval "test \"`echo '$''{'lt_cv_path_LD'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
@@ -1744,7 +1738,7 @@ else
fi
test -z "$LD" && { echo "configure: error: no acceptable ld found in \$PATH" 1>&2; exit 1; }
echo $ac_n "checking if the linker ($LD) is GNU ld""... $ac_c" 1>&6
-echo "configure:1748: checking if the linker ($LD) is GNU ld" >&5
+echo "configure:1742: checking if the linker ($LD) is GNU ld" >&5
if eval "test \"`echo '$''{'lt_cv_prog_gnu_ld'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
@@ -1761,7 +1755,7 @@ with_gnu_ld=$lt_cv_prog_gnu_ld
echo $ac_n "checking for $LD option to reload object files""... $ac_c" 1>&6
-echo "configure:1765: checking for $LD option to reload object files" >&5
+echo "configure:1759: checking for $LD option to reload object files" >&5
if eval "test \"`echo '$''{'lt_cv_ld_reload_flag'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
@@ -1773,7 +1767,7 @@ reload_flag=$lt_cv_ld_reload_flag
test -n "$reload_flag" && reload_flag=" $reload_flag"
echo $ac_n "checking for BSD-compatible nm""... $ac_c" 1>&6
-echo "configure:1777: checking for BSD-compatible nm" >&5
+echo "configure:1771: checking for BSD-compatible nm" >&5
if eval "test \"`echo '$''{'lt_cv_path_NM'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
@@ -1811,7 +1805,7 @@ NM="$lt_cv_path_NM"
echo "$ac_t""$NM" 1>&6
echo $ac_n "checking whether ln -s works""... $ac_c" 1>&6
-echo "configure:1815: checking whether ln -s works" >&5
+echo "configure:1809: checking whether ln -s works" >&5
if eval "test \"`echo '$''{'ac_cv_prog_LN_S'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
@@ -1832,7 +1826,7 @@ else
fi
echo $ac_n "checking how to recognise dependant libraries""... $ac_c" 1>&6
-echo "configure:1836: checking how to recognise dependant libraries" >&5
+echo "configure:1830: checking how to recognise dependant libraries" >&5
if eval "test \"`echo '$''{'lt_cv_deplibs_check_method'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
@@ -2005,13 +1999,13 @@ file_magic_cmd=$lt_cv_file_magic_cmd
deplibs_check_method=$lt_cv_deplibs_check_method
echo $ac_n "checking for object suffix""... $ac_c" 1>&6
-echo "configure:2009: checking for object suffix" >&5
+echo "configure:2003: checking for object suffix" >&5
if eval "test \"`echo '$''{'ac_cv_objext'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
rm -f conftest*
echo 'int i = 1;' > conftest.$ac_ext
-if { (eval echo configure:2015: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+if { (eval echo configure:2009: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
for ac_file in conftest.*; do
case $ac_file in
*.c) ;;
@@ -2035,7 +2029,7 @@ case $deplibs_check_method in
file_magic*)
if test "$file_magic_cmd" = '$MAGIC_CMD'; then
echo $ac_n "checking for ${ac_tool_prefix}file""... $ac_c" 1>&6
-echo "configure:2039: checking for ${ac_tool_prefix}file" >&5
+echo "configure:2033: checking for ${ac_tool_prefix}file" >&5
if eval "test \"`echo '$''{'lt_cv_path_MAGIC_CMD'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
@@ -2097,7 +2091,7 @@ fi
if test -z "$lt_cv_path_MAGIC_CMD"; then
if test -n "$ac_tool_prefix"; then
echo $ac_n "checking for file""... $ac_c" 1>&6
-echo "configure:2101: checking for file" >&5
+echo "configure:2095: checking for file" >&5
if eval "test \"`echo '$''{'lt_cv_path_MAGIC_CMD'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
@@ -2168,7 +2162,7 @@ esac
# Extract the first word of "${ac_tool_prefix}ranlib", so it can be a program name with args.
set dummy ${ac_tool_prefix}ranlib; ac_word=$2
echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
-echo "configure:2172: checking for $ac_word" >&5
+echo "configure:2166: checking for $ac_word" >&5
if eval "test \"`echo '$''{'ac_cv_prog_RANLIB'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
@@ -2200,7 +2194,7 @@ if test -n "$ac_tool_prefix"; then
# Extract the first word of "ranlib", so it can be a program name with args.
set dummy ranlib; ac_word=$2
echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
-echo "configure:2204: checking for $ac_word" >&5
+echo "configure:2198: checking for $ac_word" >&5
if eval "test \"`echo '$''{'ac_cv_prog_RANLIB'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
@@ -2235,7 +2229,7 @@ fi
# Extract the first word of "${ac_tool_prefix}strip", so it can be a program name with args.
set dummy ${ac_tool_prefix}strip; ac_word=$2
echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
-echo "configure:2239: checking for $ac_word" >&5
+echo "configure:2233: checking for $ac_word" >&5
if eval "test \"`echo '$''{'ac_cv_prog_STRIP'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
@@ -2267,7 +2261,7 @@ if test -n "$ac_tool_prefix"; then
# Extract the first word of "strip", so it can be a program name with args.
set dummy strip; ac_word=$2
echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
-echo "configure:2271: checking for $ac_word" >&5
+echo "configure:2265: checking for $ac_word" >&5
if eval "test \"`echo '$''{'ac_cv_prog_STRIP'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
@@ -2334,8 +2328,8 @@ test x"$pic_mode" = xno && libtool_flags="$libtool_flags --prefer-non-pic"
case $host in
*-*-irix6*)
# Find out which ABI we are using.
- echo '#line 2338 "configure"' > conftest.$ac_ext
- if { (eval echo configure:2339: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ echo '#line 2332 "configure"' > conftest.$ac_ext
+ if { (eval echo configure:2333: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
if test "$lt_cv_prog_gnu_ld" = yes; then
case `/usr/bin/file conftest.$ac_objext` in
*32-bit*)
@@ -2368,7 +2362,7 @@ case $host in
ia64-*-hpux*)
# Find out which ABI we are using.
echo 'int i;' > conftest.$ac_ext
- if { (eval echo configure:2372: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ if { (eval echo configure:2366: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
case "`/usr/bin/file conftest.o`" in
*ELF-32*)
HPUX_IA64_MODE="32"
@@ -2384,7 +2378,7 @@ ia64-*-hpux*)
x86_64-*linux*|ppc*-*linux*|powerpc*-*linux*|s390*-*linux*|sparc*-*linux*)
# Find out which ABI we are using.
echo 'int i;' > conftest.$ac_ext
- if { (eval echo configure:2388: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
+ if { (eval echo configure:2382: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
case "`/usr/bin/file conftest.o`" in
*32-bit*)
case $host in
@@ -2428,7 +2422,7 @@ x86_64-*linux*|ppc*-*linux*|powerpc*-*linux*|s390*-*linux*|sparc*-*linux*)
SAVE_CFLAGS="$CFLAGS"
CFLAGS="$CFLAGS -belf"
echo $ac_n "checking whether the C compiler needs -belf""... $ac_c" 1>&6
-echo "configure:2432: checking whether the C compiler needs -belf" >&5
+echo "configure:2426: checking whether the C compiler needs -belf" >&5
if eval "test \"`echo '$''{'lt_cv_cc_needs_belf'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
@@ -2441,14 +2435,14 @@ ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$a
cross_compiling=$ac_cv_prog_cc_cross
cat > conftest.$ac_ext <<EOF
-#line 2445 "configure"
+#line 2439 "configure"
#include "confdefs.h"
int main() {
; return 0; }
EOF
-if { (eval echo configure:2452: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+if { (eval echo configure:2446: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
rm -rf conftest*
lt_cv_cc_needs_belf=yes
else
@@ -2478,7 +2472,7 @@ echo "$ac_t""$lt_cv_cc_needs_belf" 1>&6
esac
echo $ac_n "checking how to run the C++ preprocessor""... $ac_c" 1>&6
-echo "configure:2482: checking how to run the C++ preprocessor" >&5
+echo "configure:2476: checking how to run the C++ preprocessor" >&5
if test -z "$CXXCPP"; then
if eval "test \"`echo '$''{'ac_cv_prog_CXXCPP'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
@@ -2491,12 +2485,12 @@ ac_link='${CXX-g++} -o conftest${ac_exeext} $CXXFLAGS $CPPFLAGS $LDFLAGS conftes
cross_compiling=$ac_cv_prog_cxx_cross
CXXCPP="${CXX-g++} -E"
cat > conftest.$ac_ext <<EOF
-#line 2495 "configure"
+#line 2489 "configure"
#include "confdefs.h"
#include <stdlib.h>
EOF
ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
-{ (eval echo configure:2500: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+{ (eval echo configure:2494: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
if test -z "$ac_err"; then
:
@@ -2643,7 +2637,7 @@ fi
echo $ac_n "checking whether to enable maintainer-specific portions of Makefiles""... $ac_c" 1>&6
-echo "configure:2647: checking whether to enable maintainer-specific portions of Makefiles" >&5
+echo "configure:2641: checking whether to enable maintainer-specific portions of Makefiles" >&5
# Check whether --enable-maintainer-mode or --disable-maintainer-mode was given.
if test "${enable_maintainer_mode+set}" = set; then
enableval="$enable_maintainer_mode"
@@ -2676,7 +2670,7 @@ if false; then
echo $ac_n "checking for executable suffix""... $ac_c" 1>&6
-echo "configure:2680: checking for executable suffix" >&5
+echo "configure:2674: checking for executable suffix" >&5
if eval "test \"`echo '$''{'ac_cv_exeext'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
@@ -2686,10 +2680,10 @@ else
rm -f conftest*
echo 'int main () { return 0; }' > conftest.$ac_ext
ac_cv_exeext=
- if { (eval echo configure:2690: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; }; then
+ if { (eval echo configure:2684: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; }; then
for file in conftest.*; do
case $file in
- *.c | *.o | *.obj | *.ilk | *.pdb) ;;
+ *.c | *.o | *.obj) ;;
*) ac_cv_exeext=`echo $file | sed -e s/conftest//` ;;
esac
done
@@ -2709,7 +2703,7 @@ ac_exeext=$EXEEXT
fi
echo $ac_n "checking for thread model used by GCC""... $ac_c" 1>&6
-echo "configure:2713: checking for thread model used by GCC" >&5
+echo "configure:2707: checking for thread model used by GCC" >&5
THREADS=`$CC -v 2>&1 | sed -n 's/^Thread model: //p'`
if test -z "$THREADS"; then
THREADS=no
@@ -2738,7 +2732,7 @@ case "$THREADS" in
THREADS=posix
THREADLIBS=-lpthread
case "$host" in
- x86-*-linux* | ia64-*-linux* | i586-*-linux* | i686-*-linux* | x86_64-*-linux* )
+ x86-*-linux* | ia64-*-linux* | i586-*-linux* | i686-*-linux* | x86_64-*-linux* | alpha-*-linux*)
cat >> confdefs.h <<\EOF
#define GC_LINUX_THREADS 1
EOF
@@ -2747,7 +2741,7 @@ EOF
#define _REENTRANT 1
EOF
- if test "${enable_parallel_mark}"; then
+ if test "${enable_parallel_mark}" = yes; then
cat >> confdefs.h <<\EOF
#define PARALLEL_MARK 1
EOF
@@ -2768,6 +2762,16 @@ EOF
EOF
;;
+ *-*-aix*)
+ cat >> confdefs.h <<\EOF
+#define GC_AIX_THREADS 1
+EOF
+
+ cat >> confdefs.h <<\EOF
+#define _REENTRANT 1
+EOF
+
+ ;;
*-*-hpux*)
echo "configure: warning: "Only HP/UX 11 threads are supported."" 1>&2
cat >> confdefs.h <<\EOF
@@ -2816,7 +2820,46 @@ EOF
;;
*-*-cygwin*)
- THREADLIBS=
+ cat >> confdefs.h <<\EOF
+#define GC_WIN32_THREADS 1
+EOF
+
+ ;;
+ *-*-darwin*)
+ cat >> confdefs.h <<\EOF
+#define GC_DARWIN_THREADS 1
+EOF
+
+ cat >> confdefs.h <<\EOF
+#define THREAD_LOCAL_ALLOC 1
+EOF
+
+ if test "${enable_parallel_mark}" = yes; then
+ cat >> confdefs.h <<\EOF
+#define PARALLEL_MARK 1
+EOF
+
+ fi
+ ;;
+ *-*-osf*)
+ cat >> confdefs.h <<\EOF
+#define GC_OSF1_THREADS 1
+EOF
+
+ if test "${enable_parallel_mark}" = yes; then
+ cat >> confdefs.h <<\EOF
+#define PARALLEL_MARK 1
+EOF
+
+ cat >> confdefs.h <<\EOF
+#define THREAD_LOCAL_ALLOC 1
+EOF
+
+ # May want to enable it in other cases, too.
+ # Measurements havent yet been done.
+ fi
+ INCLUDES="$INCLUDES -pthread"
+ THREADLIBS="-lpthread -lrt"
;;
esac
;;
@@ -2825,16 +2868,48 @@ EOF
#define GC_WIN32_THREADS 1
EOF
- cat >> confdefs.h <<\EOF
+ cat >> confdefs.h <<\EOF
#define NO_GETENV 1
EOF
- if test $enable_shared = yes; then
- cat >> confdefs.h <<\EOF
-#define GC_DLL 1
+ ;;
+ dgux386)
+ THREADS=dgux386
+echo "$ac_t""$THREADLIBS" 1>&6
+ # Use pthread GCC switch
+ THREADLIBS=-pthread
+ if test "${enable_parallel_mark}" = yes; then
+ cat >> confdefs.h <<\EOF
+#define PARALLEL_MARK 1
EOF
fi
+ cat >> confdefs.h <<\EOF
+#define THREAD_LOCAL_ALLOC 1
+EOF
+
+ cat >> confdefs.h <<\EOF
+#define GC_DGUX386_THREADS 1
+EOF
+
+ cat >> confdefs.h <<\EOF
+#define DGUX_THREADS 1
+EOF
+
+ # Enable _POSIX4A_DRAFT10_SOURCE with flag -pthread
+ INCLUDES="-pthread $INCLUDES"
+ ;;
+ aix)
+ THREADS=posix
+ THREADLIBS=-lpthread
+ cat >> confdefs.h <<\EOF
+#define GC_AIX_THREADS 1
+EOF
+
+ cat >> confdefs.h <<\EOF
+#define _REENTRANT 1
+EOF
+
;;
decosf1 | irix | mach | os2 | solaris | dce | vxworks)
{ echo "configure: error: thread package $THREADS not yet supported" 1>&2; exit 1; }
@@ -2845,8 +2920,28 @@ EOF
esac
-echo $ac_n "checking for dlopen in -ldl""... $ac_c" 1>&6
-echo "configure:2850: checking for dlopen in -ldl" >&5
+case "$host" in
+ powerpc-*-darwin*)
+ powerpc_darwin=true
+ ;;
+esac
+
+
+if test x$powerpc_darwin = xtrue; then
+ POWERPC_DARWIN_TRUE=
+ POWERPC_DARWIN_FALSE='#'
+else
+ POWERPC_DARWIN_TRUE='#'
+ POWERPC_DARWIN_FALSE=
+fi
+
+# We never want libdl on darwin. It is a fake libdl that just ends up making
+# dyld calls anyway
+case "$host" in
+ *-*-darwin*) ;;
+ *)
+ echo $ac_n "checking for dlopen in -ldl""... $ac_c" 1>&6
+echo "configure:2945: checking for dlopen in -ldl" >&5
ac_lib_var=`echo dl'_'dlopen | sed 'y%./+-%__p_%'`
if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
@@ -2854,7 +2949,7 @@ else
ac_save_LIBS="$LIBS"
LIBS="-ldl $LIBS"
cat > conftest.$ac_ext <<EOF
-#line 2858 "configure"
+#line 2953 "configure"
#include "confdefs.h"
/* Override any gcc2 internal prototype to avoid an error. */
/* We use char because int might match the return type of a gcc2
@@ -2865,7 +2960,7 @@ int main() {
dlopen()
; return 0; }
EOF
-if { (eval echo configure:2869: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
+if { (eval echo configure:2964: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
rm -rf conftest*
eval "ac_cv_lib_$ac_lib_var=yes"
else
@@ -2885,6 +2980,9 @@ else
echo "$ac_t""no" 1>&6
fi
+ ;;
+esac
+
target_all=libgcjgc.la
@@ -2901,6 +2999,9 @@ fi
addobjs=
+addlibs=
+addincludes=
+addtests=
CXXINCLUDES=
case "$TARGET_ECOS" in
no)
@@ -2915,17 +3016,31 @@ EOF
;;
esac
+if test "${enable_cplusplus}" = yes; then
+ addincludes="$addincludes include/gc_cpp.h include/gc_allocator.h"
+ addtests="$addtests test_cpp"
+fi
+if test "${enable_cplusplus}" = yes; then
+ CPLUSPLUS_TRUE=
+ CPLUSPLUS_FALSE='#'
+else
+ CPLUSPLUS_TRUE='#'
+ CPLUSPLUS_FALSE=
+fi
-machdep=
-case "$host" in
- alpha*-*-openbsd*)
- machdep="alpha_mach_dep.lo"
- if test x"${ac_cv_lib_dl_dlopen}" != xyes ; then
- echo "configure: warning: OpenBSD/Alpha without dlopen(). Shared library support is disabled" 1>&2
- # Check whether --enable-shared or --disable-shared was given.
+
+
+
+
+
+# Configuration of shared libraries
+#
+echo $ac_n "checking whether to build shared libraries""... $ac_c" 1>&6
+echo "configure:3043: checking whether to build shared libraries" >&5
+# Check whether --enable-shared or --disable-shared was given.
if test "${enable_shared+set}" = set; then
enableval="$enable_shared"
p=${PACKAGE-default}
@@ -2945,12 +3060,33 @@ no) enable_shared=no ;;
;;
esac
else
- enable_shared=no
+ enable_shared=yes
fi
+
+case "$host" in
+ alpha-*-openbsd*)
+ enable_shared=no
+ echo "$ac_t""no" 1>&6
+ ;;
+ *)
+ echo "$ac_t""yes" 1>&6
+ ;;
+esac
+
+# Configuration of machine-dependent code
+#
+echo $ac_n "checking which machine-dependent code should be used""... $ac_c" 1>&6
+echo "configure:3081: checking which machine-dependent code should be used" >&5
+machdep=
+case "$host" in
+ alpha*-*-openbsd*)
+ machdep="alpha_mach_dep.lo"
+ if test x"${ac_cv_lib_dl_dlopen}" != xyes ; then
+ echo "configure: warning: OpenBSD/Alpha without dlopen(). Shared library support is disabled" 1>&2
fi
;;
- alpha*-*-*)
+ alpha*-*-linux*)
machdep="alpha_mach_dep.lo"
;;
i?86-*-solaris2.[89]*)
@@ -2973,8 +3109,10 @@ EOF
mips-dec-ultrix*)
machdep="mips_ultrix_mach-dep.lo"
;;
- mips*-*-linux*)
+ mips-nec-sysv*|mips-unknown-sysv*)
;;
+ mips*-*-linux*)
+ ;;
mips-*-*)
machdep="mips_sgi_mach_dep.lo"
cat >> confdefs.h <<\EOF
@@ -2982,6 +3120,9 @@ EOF
EOF
;;
+ sparc-*-netbsd*)
+ machdep="sparc_netbsd_mach_dep.lo"
+ ;;
sparc-sun-solaris2.3*)
machdep="sparc_mach_dep.lo"
cat >> confdefs.h <<\EOF
@@ -2997,14 +3138,217 @@ EOF
;;
esac
if test x"$machdep" = x; then
+echo "$ac_t""$machdep" 1>&6
machdep="mach_dep.lo"
fi
addobjs="$addobjs $machdep"
+
+
+
+
+
+
+
+
+
+#
+# Check for AViiON Machines running DGUX
+#
+echo $ac_n "checking if host is AViiON running DGUX""... $ac_c" 1>&6
+echo "configure:3161: checking if host is AViiON running DGUX" >&5
+ac_is_dgux=no
+echo $ac_n "checking how to run the C preprocessor""... $ac_c" 1>&6
+echo "configure:3164: checking how to run the C preprocessor" >&5
+# On Suns, sometimes $CPP names a directory.
+if test -n "$CPP" && test -d "$CPP"; then
+ CPP=
+fi
+if test -z "$CPP"; then
+if eval "test \"`echo '$''{'ac_cv_prog_CPP'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ # This must be in double quotes, not single quotes, because CPP may get
+ # substituted into the Makefile and "${CC-cc}" will confuse make.
+ CPP="${CC-cc} -E"
+ # On the NeXT, cc -E runs the code through the compiler's parser,
+ # not just through cpp.
+ cat > conftest.$ac_ext <<EOF
+#line 3179 "configure"
+#include "confdefs.h"
+#include <assert.h>
+Syntax Error
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:3185: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+ :
+else
+ echo "$ac_err" >&5
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ CPP="${CC-cc} -E -traditional-cpp"
+ cat > conftest.$ac_ext <<EOF
+#line 3196 "configure"
+#include "confdefs.h"
+#include <assert.h>
+Syntax Error
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:3202: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+ :
+else
+ echo "$ac_err" >&5
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ CPP="${CC-cc} -nologo -E"
+ cat > conftest.$ac_ext <<EOF
+#line 3213 "configure"
+#include "confdefs.h"
+#include <assert.h>
+Syntax Error
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:3219: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+ :
+else
+ echo "$ac_err" >&5
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ CPP=/lib/cpp
+fi
+rm -f conftest*
+fi
+rm -f conftest*
+fi
+rm -f conftest*
+ ac_cv_prog_CPP="$CPP"
+fi
+ CPP="$ac_cv_prog_CPP"
+else
+ ac_cv_prog_CPP="$CPP"
+fi
+echo "$ac_t""$CPP" 1>&6
+
+ac_safe=`echo "sys/dg_sys_info.h" | sed 'y%./+-%__p_%'`
+echo $ac_n "checking for sys/dg_sys_info.h""... $ac_c" 1>&6
+echo "configure:3245: checking for sys/dg_sys_info.h" >&5
+if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 3250 "configure"
+#include "confdefs.h"
+#include <sys/dg_sys_info.h>
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:3255: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
+if test -z "$ac_err"; then
+ rm -rf conftest*
+ eval "ac_cv_header_$ac_safe=yes"
+else
+ echo "$ac_err" >&5
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_header_$ac_safe=no"
+fi
+rm -f conftest*
+fi
+if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ ac_is_dgux=yes;
+else
+ echo "$ac_t""no" 1>&6
+fi
+
+
+echo "$ac_t""$ac_is_dgux" 1>&6
+ ## :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
+
+
+fi
+
+# Check whether --with-target-subdir or --without-target-subdir was given.
+if test "${with_target_subdir+set}" = set; then
+ withval="$with_target_subdir"
+ :
+fi
+
+# Check whether --with-cross-host or --without-cross-host was given.
+if test "${with_cross_host+set}" = set; then
+ withval="$with_cross_host"
+ :
+fi
+
+
+# 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.
+ :
+
+
+echo $ac_n "checking for executable suffix""... $ac_c" 1>&6
+echo "configure:3315: checking for executable suffix" >&5
+if eval "test \"`echo '$''{'ac_cv_exeext'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ if test "$CYGWIN" = yes || test "$MINGW32" = yes; then
+ ac_cv_exeext=.exe
+else
+ rm -f conftest*
+ echo 'int main () { return 0; }' > conftest.$ac_ext
+ ac_cv_exeext=
+ if { (eval echo configure:3325: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; }; then
+ for file in conftest.*; do
+ case $file in
+ *.c | *.o | *.obj) ;;
+ *) ac_cv_exeext=`echo $file | sed -e s/conftest//` ;;
+ esac
+ done
+ else
+ { echo "configure: error: installation or configuration problem: compiler cannot create executables." 1>&2; exit 1; }
+ fi
+ rm -f conftest*
+ test x"${ac_cv_exeext}" = x && ac_cv_exeext=no
+fi
+fi
+
+EXEEXT=""
+test x"${ac_cv_exeext}" != xno && EXEEXT=${ac_cv_exeext}
+echo "$ac_t""${ac_cv_exeext}" 1>&6
+ac_exeext=$EXEEXT
+
+fi
+
+echo $ac_n "checking whether Solaris gcc optimization fix is necessary""... $ac_c" 1>&6
+echo "configure:3348: checking whether Solaris gcc optimization fix is necessary" >&5
case "$host" in
- sparc-sun-solaris2*)
+ sparc-sun-solaris2*|*aix*)
if test "$GCC" = yes; then
+ echo "$ac_t""yes" 1>&6
new_CFLAGS=
for i in $CFLAGS; do
case "$i" in
@@ -3016,8 +3360,11 @@ case "$host" in
esac
done
CFLAGS="$new_CFLAGS"
+ else
+ echo "$ac_t""no" 1>&6
fi
;;
+ *) echo "$ac_t""no" 1>&6 ;;
esac
MY_CFLAGS="$CFLAGS"
@@ -3095,6 +3442,12 @@ EOF
EOF
;;
+ i345686-*-dgux*)
+ cat >> confdefs.h <<\EOF
+#define MAKE_BACK_GRAPH 1
+EOF
+
+ ;;
esac
fi
fi
@@ -3311,11 +3664,19 @@ s%@STRIP@%$STRIP%g
s%@LIBTOOL@%$LIBTOOL%g
s%@CXXCPP@%$CXXCPP%g
s%@THREADLIBS@%$THREADLIBS%g
+s%@POWERPC_DARWIN_TRUE@%$POWERPC_DARWIN_TRUE%g
+s%@POWERPC_DARWIN_FALSE@%$POWERPC_DARWIN_FALSE%g
s%@EXTRA_TEST_LIBS@%$EXTRA_TEST_LIBS%g
s%@target_all@%$target_all%g
+s%@CPLUSPLUS_TRUE@%$CPLUSPLUS_TRUE%g
+s%@CPLUSPLUS_FALSE@%$CPLUSPLUS_FALSE%g
s%@INCLUDES@%$INCLUDES%g
s%@CXXINCLUDES@%$CXXINCLUDES%g
s%@addobjs@%$addobjs%g
+s%@addincludes@%$addincludes%g
+s%@addlibs@%$addlibs%g
+s%@addtests@%$addtests%g
+s%@CPP@%$CPP%g
s%@MY_CFLAGS@%$MY_CFLAGS%g
s%@toolexecdir@%$toolexecdir%g
s%@toolexeclibdir@%$toolexeclibdir%g
@@ -3327,7 +3688,7 @@ cat >> $CONFIG_STATUS <<\EOF
# Split the substitutions into bite-sized pieces for seds with
# small command number limits, like on Digital OSF/1 and HP-UX.
-ac_max_sed_cmds=60 # Maximum number of lines to put in a sed script.
+ac_max_sed_cmds=90 # Maximum number of lines to put in a sed script.
ac_file=1 # Number of current file.
ac_beg=1 # First line for current file.
ac_end=$ac_max_sed_cmds # Line after last line for current file.
diff --git a/boehm-gc/configure.host b/boehm-gc/configure.host
index 82294cf6ef1..a98a0a7cb30 100644
--- a/boehm-gc/configure.host
+++ b/boehm-gc/configure.host
@@ -14,22 +14,28 @@
# host The configuration host
# host_cpu The configuration host CPU
# target_optspace --enable-target-optspace ("yes", "no", "")
+# GCC should be "yes" if using gcc
# It sets the following shell variables:
# gc_cflags Special CFLAGS to use when building
+gc_cflags=""
+
# We should set -fexceptions if we are using gcc and might be used
# inside something like gcj. This is the zeroth approximation:
-case "$host" in
- *-*-linux* )
- gc_cflags=-fexceptions
- ;;
- hppa*-*-hpux* )
- if test $GCC != "yes" ; then
- gc_cflags=+ESdbgasm
- fi
- ;;
-esac
+if test :"$GCC": = :yes: ; then
+ gc_cflags="${gc_cflags} -fexceptions"
+else
+ case "$host" in
+ hppa*-*-hpux* )
+ if test :$GCC: != :"yes": ; then
+ gc_cflags="${gc_flags} +ESdbgasm"
+ fi
+ # :TODO: actaully we should check using Autoconf if
+ # the compiler supports this option.
+ ;;
+ esac
+fi
case "${target_optspace}:${host}" in
yes:*)
@@ -48,7 +54,7 @@ esac
case "${host}" in
mips-tx39-*|mipstx39-unknown-*)
- boehm_gc_cflags="${boehm_gc_cflags} -G 0"
+ gc_cflags="${gc_cflags} -G 0"
;;
*)
;;
diff --git a/boehm-gc/configure.in b/boehm-gc/configure.in
index 95e9d7cf06e..99686242214 100644
--- a/boehm-gc/configure.in
+++ b/boehm-gc/configure.in
@@ -73,10 +73,10 @@ case "$THREADS" in
THREADS=posix
THREADLIBS=-lpthread
case "$host" in
- x86-*-linux* | ia64-*-linux* | i586-*-linux* | i686-*-linux* | x86_64-*-linux* )
+ x86-*-linux* | ia64-*-linux* | i586-*-linux* | i686-*-linux* | x86_64-*-linux* | alpha-*-linux*)
AC_DEFINE(GC_LINUX_THREADS)
AC_DEFINE(_REENTRANT)
- if test "${enable_parallel_mark}"; then
+ if test "${enable_parallel_mark}" = yes; then
AC_DEFINE(PARALLEL_MARK)
fi
AC_DEFINE(THREAD_LOCAL_ALLOC)
@@ -85,6 +85,10 @@ case "$THREADS" in
AC_DEFINE(GC_LINUX_THREADS)
AC_DEFINE(_REENTRANT)
;;
+ *-*-aix*)
+ AC_DEFINE(GC_AIX_THREADS)
+ AC_DEFINE(_REENTRANT)
+ ;;
*-*-hpux*)
AC_MSG_WARN("Only HP/UX 11 threads are supported.")
AC_DEFINE(GC_HPUX_THREADS)
@@ -109,16 +113,52 @@ case "$THREADS" in
AC_DEFINE(GC_IRIX_THREADS)
;;
*-*-cygwin*)
- THREADLIBS=
+ AC_DEFINE(GC_WIN32_THREADS)
+ ;;
+ *-*-darwin*)
+ AC_DEFINE(GC_DARWIN_THREADS)
+ AC_DEFINE(THREAD_LOCAL_ALLOC)
+ if test "${enable_parallel_mark}" = yes; then
+ AC_DEFINE(PARALLEL_MARK)
+ fi
+ ;;
+ *-*-osf*)
+ AC_DEFINE(GC_OSF1_THREADS)
+ if test "${enable_parallel_mark}" = yes; then
+ AC_DEFINE(PARALLEL_MARK)
+ AC_DEFINE(THREAD_LOCAL_ALLOC)
+ # May want to enable it in other cases, too.
+ # Measurements havent yet been done.
+ fi
+ INCLUDES="$INCLUDES -pthread"
+ THREADLIBS="-lpthread -lrt"
;;
esac
;;
win32)
AC_DEFINE(GC_WIN32_THREADS)
+ dnl Wine getenv may not return NULL for missing entry
AC_DEFINE(NO_GETENV)
- if test $enable_shared = yes; then
- AC_DEFINE(GC_DLL)
+ ;;
+ dgux386)
+ THREADS=dgux386
+AC_MSG_RESULT($THREADLIBS)
+ # Use pthread GCC switch
+ THREADLIBS=-pthread
+ if test "${enable_parallel_mark}" = yes; then
+ AC_DEFINE(PARALLEL_MARK)
fi
+ AC_DEFINE(THREAD_LOCAL_ALLOC)
+ AC_DEFINE(GC_DGUX386_THREADS)
+ AC_DEFINE(DGUX_THREADS)
+ # Enable _POSIX4A_DRAFT10_SOURCE with flag -pthread
+ INCLUDES="-pthread $INCLUDES"
+ ;;
+ aix)
+ THREADS=posix
+ THREADLIBS=-lpthread
+ AC_DEFINE(GC_AIX_THREADS)
+ AC_DEFINE(_REENTRANT)
;;
decosf1 | irix | mach | os2 | solaris | dce | vxworks)
AC_MSG_ERROR(thread package $THREADS not yet supported)
@@ -129,7 +169,22 @@ case "$THREADS" in
esac
AC_SUBST(THREADLIBS)
-AC_CHECK_LIB(dl, dlopen, EXTRA_TEST_LIBS="$EXTRA_TEST_LIBS -ldl")
+case "$host" in
+ powerpc-*-darwin*)
+ powerpc_darwin=true
+ ;;
+esac
+AM_CONDITIONAL(POWERPC_DARWIN,test x$powerpc_darwin = xtrue)
+
+# We never want libdl on darwin. It is a fake libdl that just ends up making
+# dyld calls anyway
+case "$host" in
+ *-*-darwin*) ;;
+ *)
+ AC_CHECK_LIB(dl, dlopen, EXTRA_TEST_LIBS="$EXTRA_TEST_LIBS -ldl")
+ ;;
+esac
+
AC_SUBST(EXTRA_TEST_LIBS)
target_all=libgcjgc.la
@@ -147,6 +202,9 @@ TARGET_ECOS="$with_ecos"
)
addobjs=
+addlibs=
+addincludes=
+addtests=
CXXINCLUDES=
case "$TARGET_ECOS" in
no)
@@ -157,21 +215,46 @@ case "$TARGET_ECOS" in
addobjs="$addobjs ecos.lo"
;;
esac
+
+if test "${enable_cplusplus}" = yes; then
+ addincludes="$addincludes include/gc_cpp.h include/gc_allocator.h"
+ addtests="$addtests test_cpp"
+fi
+
+AM_CONDITIONAL(CPLUSPLUS, test "${enable_cplusplus}" = yes)
+
AC_SUBST(CXX)
AC_SUBST(INCLUDES)
AC_SUBST(CXXINCLUDES)
+# Configuration of shared libraries
+#
+AC_MSG_CHECKING(whether to build shared libraries)
+AC_ENABLE_SHARED
+
+case "$host" in
+ alpha-*-openbsd*)
+ enable_shared=no
+ AC_MSG_RESULT(no)
+ ;;
+ *)
+ AC_MSG_RESULT(yes)
+ ;;
+esac
+
+# Configuration of machine-dependent code
+#
+AC_MSG_CHECKING(which machine-dependent code should be used)
machdep=
case "$host" in
alpha*-*-openbsd*)
machdep="alpha_mach_dep.lo"
if test x"${ac_cv_lib_dl_dlopen}" != xyes ; then
AC_MSG_WARN(OpenBSD/Alpha without dlopen(). Shared library support is disabled)
- AM_DISABLE_SHARED
fi
;;
- alpha*-*-*)
+ alpha*-*-linux*)
machdep="alpha_mach_dep.lo"
;;
i?86-*-solaris2.[[89]]*)
@@ -185,12 +268,17 @@ case "$host" in
mips-dec-ultrix*)
machdep="mips_ultrix_mach-dep.lo"
;;
- mips*-*-linux*)
+ mips-nec-sysv*|mips-unknown-sysv*)
;;
+ mips*-*-linux*)
+ ;;
mips-*-*)
machdep="mips_sgi_mach_dep.lo"
AC_DEFINE(NO_EXECUTE_PERMISSION)
;;
+ sparc-*-netbsd*)
+ machdep="sparc_netbsd_mach_dep.lo"
+ ;;
sparc-sun-solaris2.3*)
machdep="sparc_mach_dep.lo"
AC_DEFINE(SUNOS53_SHARED_LIB)
@@ -203,16 +291,65 @@ case "$host" in
;;
esac
if test x"$machdep" = x; then
+AC_MSG_RESULT($machdep)
machdep="mach_dep.lo"
fi
addobjs="$addobjs $machdep"
AC_SUBST(addobjs)
+AC_SUBST(addincludes)
+AC_SUBST(addlibs)
+AC_SUBST(addtests)
+
+AC_PROG_LIBTOOL
+
+#
+# Check for AViiON Machines running DGUX
+#
+AC_MSG_CHECKING(if host is AViiON running DGUX)
+ac_is_dgux=no
+AC_CHECK_HEADER(sys/dg_sys_info.h,
+[ac_is_dgux=yes;])
+
+AC_MSG_RESULT($ac_is_dgux)
+ ## :GOTCHA: we do not check anything but sys/dg_sys_info.h
+if test $ac_is_dgux = yes; then
+ if test "$enable_full_debug" = "yes"; then
+ CFLAGS="-g -mstandard -DDGUX -D_DGUX_SOURCE -Di386 -mno-legend -O2"
+ CXXFLAGS="-g -mstandard -DDGUX -D_DGUX_SOURCE -Di386 -mno-legend -O2"
+ else
+ CFLAGS="-DDGUX -D_DGUX_SOURCE -Di386 -mno-legend -O2"
+ CXXFLAGS="-DDGUX -D_DGUX_SOURCE -Di386 -mno-legend -O2"
+ fi
+ AC_SUBST(CFLAGS)
+ AC_SUBST(CXXFLAGS)
+fi
+
+dnl We use these options to decide which functions to include.
+AC_ARG_WITH(target-subdir,
+[ --with-target-subdir=SUBDIR
+ configuring with a cross compiler])
+AC_ARG_WITH(cross-host,
+[ --with-cross-host=HOST configuring with a cross compiler])
+
+# automake wants to see AC_EXEEXT. But we don't need it. And having
+# it is actually a problem, because the compiler we're passed can't
+# necessarily do a full link. So we fool automake here.
+if false; then
+ # autoconf 2.50 runs AC_EXEEXT by default, and the macro expands
+ # to nothing, so nothing would remain between `then' and `fi' if it
+ # were not for the `:' below.
+ :
+ AC_EXEEXT
+fi
dnl As of 4.13a2, the collector will not properly work on Solaris when
dnl built with gcc and -O. So we remove -O in the appropriate case.
+dnl
+AC_MSG_CHECKING(whether Solaris gcc optimization fix is necessary)
case "$host" in
- sparc-sun-solaris2*)
+ sparc-sun-solaris2*|*aix*)
if test "$GCC" = yes; then
+ AC_MSG_RESULT(yes)
new_CFLAGS=
for i in $CFLAGS; do
case "$i" in
@@ -224,8 +361,11 @@ case "$host" in
esac
done
CFLAGS="$new_CFLAGS"
+ else
+ AC_MSG_RESULT(no)
fi
;;
+ *) AC_MSG_RESULT(no) ;;
esac
dnl We need to override the top-level CFLAGS. This is how we do it.
@@ -267,6 +407,9 @@ AC_ARG_ENABLE(full-debug,
AC_MSG_WARN("Client must not use -fomit-frame-pointer.")
AC_DEFINE(SAVE_CALL_COUNT, 8)
;;
+ i[3456]86-*-dgux*)
+ AC_DEFINE(MAKE_BACK_GRAPH)
+ ;;
esac ]
fi)
diff --git a/boehm-gc/cord/cordbscs.c b/boehm-gc/cord/cordbscs.c
index 9fc894d4946..d83f4067de7 100644
--- a/boehm-gc/cord/cordbscs.c
+++ b/boehm-gc/cord/cordbscs.c
@@ -219,7 +219,7 @@ CORD CORD_cat_char_star(CORD x, const char * y, size_t leny)
result->len = result_len;
result->left = x;
result->right = y;
- if (depth > MAX_DEPTH) {
+ if (depth >= MAX_DEPTH) {
return(CORD_balance((CORD)result));
} else {
return((CORD) result);
@@ -260,7 +260,11 @@ CORD CORD_cat(CORD x, CORD y)
result->len = result_len;
result->left = x;
result->right = y;
- return((CORD) result);
+ if (depth >= MAX_DEPTH) {
+ return(CORD_balance((CORD)result));
+ } else {
+ return((CORD) result);
+ }
}
}
diff --git a/boehm-gc/cord/cordprnt.c b/boehm-gc/cord/cordprnt.c
index 8d57f0467fb..6ecc00e8410 100644
--- a/boehm-gc/cord/cordprnt.c
+++ b/boehm-gc/cord/cordprnt.c
@@ -233,7 +233,7 @@ int CORD_vsprintf(CORD * out, CORD format, va_list args)
if (width == NONE && prec == NONE) {
register char c;
- c = va_arg(args, int);
+ c = (char)va_arg(args, int);
CORD_ec_append(result, c);
goto done;
}
@@ -255,12 +255,18 @@ int CORD_vsprintf(CORD * out, CORD format, va_list args)
/* Use standard sprintf to perform conversion */
{
register char * buf;
- va_list vsprintf_args = args;
- /* The above does not appear to be sanctioned */
- /* by the ANSI C standard. */
+ va_list vsprintf_args;
int max_size = 0;
int res;
-
+# ifdef __va_copy
+ __va_copy(vsprintf_args, args);
+# else
+# if defined(__GNUC__) /* and probably in other cases */
+ va_copy(vsprintf_args, args);
+# else
+ vsprintf_args = args;
+# endif
+# endif
if (width == VARIABLE) width = va_arg(args, int);
if (prec == VARIABLE) prec = va_arg(args, int);
if (width != NONE) max_size = width;
diff --git a/boehm-gc/cord/de_win.c b/boehm-gc/cord/de_win.c
index fedbfbe67c2..0bbd676a335 100644
--- a/boehm-gc/cord/de_win.c
+++ b/boehm-gc/cord/de_win.c
@@ -249,7 +249,7 @@ LRESULT CALLBACK WndProc (HWND hwnd, UINT message,
case IDM_HELPABOUT:
if( DialogBox( hInstance, "ABOUTBOX",
- hwnd, lpfnAboutBox ) );
+ hwnd, lpfnAboutBox ) )
InvalidateRect( hwnd, NULL, TRUE );
return( 0 );
case IDM_HELPCONTENTS:
diff --git a/boehm-gc/dbg_mlc.c b/boehm-gc/dbg_mlc.c
index 57de3dab28c..f640930d901 100644
--- a/boehm-gc/dbg_mlc.c
+++ b/boehm-gc/dbg_mlc.c
@@ -60,7 +60,7 @@ ptr_t p;
# include <stdlib.h>
# if defined(LINUX) || defined(SUNOS4) || defined(SUNOS5) \
- || defined(HPUX) || defined(IRIX) || defined(OSF1)
+ || defined(HPUX) || defined(IRIX5) || defined(OSF1)
# define RANDOM() random()
# else
# define RANDOM() (long)rand()
@@ -228,6 +228,8 @@ ptr_t p;
#endif /* KEEP_BACK_PTRS */
+# define CROSSES_HBLK(p, sz) \
+ (((word)(p + sizeof(oh) + sz - 1) ^ (word)p) >= HBLKSIZE)
/* Store debugging info into p. Return displaced pointer. */
/* Assumes we don't hold allocation lock. */
ptr_t GC_store_debug_info(p, sz, string, integer)
@@ -243,6 +245,8 @@ word integer;
/* But that's expensive. And this way things should only appear */
/* inconsistent while we're in the handler. */
LOCK();
+ GC_ASSERT(GC_size(p) >= sizeof(oh) + sz);
+ GC_ASSERT(!(SMALL_OBJ(sz) && CROSSES_HBLK(p, sz)));
# ifdef KEEP_BACK_PTRS
((oh *)p) -> oh_back_ptr = HIDE_BACK_PTR(NOT_MARKED);
# endif
@@ -275,6 +279,8 @@ word integer;
/* There is some argument that we should disable signals here. */
/* But that's expensive. And this way things should only appear */
/* inconsistent while we're in the handler. */
+ GC_ASSERT(GC_size(p) >= sizeof(oh) + sz);
+ GC_ASSERT(!(SMALL_OBJ(sz) && CROSSES_HBLK(p, sz)));
# ifdef KEEP_BACK_PTRS
((oh *)p) -> oh_back_ptr = HIDE_BACK_PTR(NOT_MARKED);
# endif
@@ -324,10 +330,11 @@ ptr_t p;
{
register oh * ohdr = (oh *)GC_base(p);
+ GC_ASSERT(!I_HOLD_LOCK());
GC_err_printf1("0x%lx (", ((unsigned long)ohdr + sizeof(oh)));
GC_err_puts(ohdr -> oh_string);
# ifdef SHORT_DBG_HDRS
- GC_err_printf1(":%ld, sz=%ld)\n", (unsigned long)(ohdr -> oh_int));
+ GC_err_printf1(":%ld)\n", (unsigned long)(ohdr -> oh_int));
# else
GC_err_printf2(":%ld, sz=%ld)\n", (unsigned long)(ohdr -> oh_int),
(unsigned long)(ohdr -> oh_sz));
@@ -342,6 +349,7 @@ ptr_t p;
ptr_t p;
# endif
{
+ GC_ASSERT(!I_HOLD_LOCK());
if (GC_HAS_DEBUG_INFO(p)) {
GC_print_obj(p);
} else {
@@ -355,6 +363,7 @@ ptr_t p, clobbered_addr;
{
register oh * ohdr = (oh *)GC_base(p);
+ GC_ASSERT(!I_HOLD_LOCK());
GC_err_printf2("0x%lx in object at 0x%lx(", (unsigned long)clobbered_addr,
(unsigned long)p);
if (clobbered_addr <= (ptr_t)(&(ohdr -> oh_sz))
@@ -376,14 +385,18 @@ ptr_t p, clobbered_addr;
void GC_check_heap_proc GC_PROTO((void));
+void GC_print_all_smashed_proc GC_PROTO((void));
+
void GC_do_nothing() {}
void GC_start_debugging()
{
# ifndef SHORT_DBG_HDRS
GC_check_heap = GC_check_heap_proc;
+ GC_print_all_smashed = GC_print_all_smashed_proc;
# else
GC_check_heap = GC_do_nothing;
+ GC_print_all_smashed = GC_do_nothing;
# endif
GC_print_heap_obj = GC_debug_print_heap_obj_proc;
GC_debugging_started = TRUE;
@@ -429,6 +442,62 @@ void GC_start_debugging()
return (GC_store_debug_info(result, (word)lb, s, (word)i));
}
+# ifdef __STDC__
+ GC_PTR GC_debug_malloc_ignore_off_page(size_t lb, GC_EXTRA_PARAMS)
+# else
+ GC_PTR GC_debug_malloc_ignore_off_page(lb, s, i)
+ size_t lb;
+ char * s;
+ int i;
+# ifdef GC_ADD_CALLER
+ --> GC_ADD_CALLER not implemented for K&R C
+# endif
+# endif
+{
+ GC_PTR result = GC_malloc_ignore_off_page(lb + DEBUG_BYTES);
+
+ if (result == 0) {
+ GC_err_printf1("GC_debug_malloc_ignore_off_page(%ld) returning NIL (",
+ (unsigned long) lb);
+ GC_err_puts(s);
+ GC_err_printf1(":%ld)\n", (unsigned long)i);
+ return(0);
+ }
+ if (!GC_debugging_started) {
+ GC_start_debugging();
+ }
+ ADD_CALL_CHAIN(result, ra);
+ return (GC_store_debug_info(result, (word)lb, s, (word)i));
+}
+
+# ifdef __STDC__
+ GC_PTR GC_debug_malloc_atomic_ignore_off_page(size_t lb, GC_EXTRA_PARAMS)
+# else
+ GC_PTR GC_debug_malloc_atomic_ignore_off_page(lb, s, i)
+ size_t lb;
+ char * s;
+ int i;
+# ifdef GC_ADD_CALLER
+ --> GC_ADD_CALLER not implemented for K&R C
+# endif
+# endif
+{
+ GC_PTR result = GC_malloc_atomic_ignore_off_page(lb + DEBUG_BYTES);
+
+ if (result == 0) {
+ GC_err_printf1("GC_debug_malloc_atomic_ignore_off_page(%ld)"
+ " returning NIL (", (unsigned long) lb);
+ GC_err_puts(s);
+ GC_err_printf1(":%ld)\n", (unsigned long)i);
+ return(0);
+ }
+ if (!GC_debugging_started) {
+ GC_start_debugging();
+ }
+ ADD_CALL_CHAIN(result, ra);
+ return (GC_store_debug_info(result, (word)lb, s, (word)i));
+}
+
# ifdef DBG_HDRS_ALL
/*
* An allocation function for internal use.
@@ -447,7 +516,7 @@ void GC_start_debugging()
(unsigned long) lb);
return(0);
}
- ADD_CALL_CHAIN(result, ra);
+ ADD_CALL_CHAIN(result, GC_RETURN_ADDR);
return (GC_store_debug_info_inner(result, (word)lb, "INTERNAL", (word)0));
}
@@ -461,7 +530,7 @@ void GC_start_debugging()
(unsigned long) lb);
return(0);
}
- ADD_CALL_CHAIN(result, ra);
+ ADD_CALL_CHAIN(result, GC_RETURN_ADDR);
return (GC_store_debug_info_inner(result, (word)lb, "INTERNAL", (word)0));
}
# endif
@@ -592,7 +661,7 @@ GC_PTR p;
int i;
# endif
{
- GC_PTR result = GC_malloc_uncollectable(lb + DEBUG_BYTES);
+ GC_PTR result = GC_malloc_uncollectable(lb + UNCOLLECTABLE_DEBUG_BYTES);
if (result == 0) {
GC_err_printf1("GC_debug_malloc_uncollectable(%ld) returning NIL (",
@@ -618,7 +687,8 @@ GC_PTR p;
int i;
# endif
{
- GC_PTR result = GC_malloc_atomic_uncollectable(lb + DEBUG_BYTES);
+ GC_PTR result =
+ GC_malloc_atomic_uncollectable(lb + UNCOLLECTABLE_DEBUG_BYTES);
if (result == 0) {
GC_err_printf1(
@@ -774,6 +844,45 @@ void GC_debug_free_inner(GC_PTR p)
}
#ifndef SHORT_DBG_HDRS
+
+/* List of smashed objects. We defer printing these, since we can't */
+/* always print them nicely with the allocation lock held. */
+/* We put them here instead of in GC_arrays, since it may be useful to */
+/* be able to look at them with the debugger. */
+#define MAX_SMASHED 20
+ptr_t GC_smashed[MAX_SMASHED];
+unsigned GC_n_smashed = 0;
+
+# if defined(__STDC__) || defined(__cplusplus)
+ void GC_add_smashed(ptr_t smashed)
+# else
+ void GC_add_smashed(smashed)
+ ptr_t smashed;
+#endif
+{
+ GC_ASSERT(GC_is_marked(GC_base(smashed)));
+ GC_smashed[GC_n_smashed] = smashed;
+ if (GC_n_smashed < MAX_SMASHED - 1) ++GC_n_smashed;
+ /* In case of overflow, we keep the first MAX_SMASHED-1 */
+ /* entries plus the last one. */
+ GC_have_errors = TRUE;
+}
+
+/* Print all objects on the list. Clear the list. */
+void GC_print_all_smashed_proc ()
+{
+ unsigned i;
+
+ GC_ASSERT(!I_HOLD_LOCK());
+ if (GC_n_smashed == 0) return;
+ GC_err_printf0("GC_check_heap_block: found smashed heap objects:\n");
+ for (i = 0; i < GC_n_smashed; ++i) {
+ GC_print_smashed_obj(GC_base(GC_smashed[i]), GC_smashed[i]);
+ GC_smashed[i] = 0;
+ }
+ GC_n_smashed = 0;
+}
+
/* Check all marked objects in the given block for validity */
/*ARGSUSED*/
# if defined(__STDC__) || defined(__cplusplus)
@@ -802,11 +911,7 @@ void GC_debug_free_inner(GC_PTR p)
&& GC_HAS_DEBUG_INFO((ptr_t)p)) {
ptr_t clobbered = GC_check_annotated_obj((oh *)p);
- if (clobbered != 0) {
- GC_err_printf0(
- "GC_check_heap_block: found smashed location at ");
- GC_print_smashed_obj((ptr_t)p, clobbered);
- }
+ if (clobbered != 0) GC_add_smashed(clobbered);
}
word_no += sz;
p += sz;
@@ -819,9 +924,11 @@ void GC_debug_free_inner(GC_PTR p)
void GC_check_heap_proc()
{
# ifndef SMALL_CONFIG
- if (sizeof(oh) & (2 * sizeof(word) - 1) != 0) {
- ABORT("Alignment problem: object header has inappropriate size\n");
- }
+# ifdef ALIGN_DOUBLE
+ GC_STATIC_ASSERT((sizeof(oh) & (2 * sizeof(word) - 1)) == 0);
+# else
+ GC_STATIC_ASSERT((sizeof(oh) & (sizeof(word) - 1)) == 0);
+# endif
# endif
GC_apply_to_all_blocks(GC_check_heap_block, (word)0);
}
@@ -842,12 +949,12 @@ struct closure {
# endif
{
struct closure * result =
-# ifdef DBG_HDRS_ALL
- (struct closure *) GC_debug_malloc(sizeof (struct closure),
- GC_EXTRAS);
-# else
- (struct closure *) GC_malloc(sizeof (struct closure));
-# endif
+# ifdef DBG_HDRS_ALL
+ (struct closure *) GC_debug_malloc(sizeof (struct closure),
+ GC_EXTRAS);
+# else
+ (struct closure *) GC_malloc(sizeof (struct closure));
+# endif
result -> cl_fn = fn;
result -> cl_data = data;
@@ -908,7 +1015,7 @@ GC_PTR *ocd;
ptr_t base = GC_base(obj);
if (0 == base || (ptr_t)obj - base != sizeof(oh)) {
GC_err_printf1(
- "GC_register_finalizer called with non-base-pointer 0x%lx\n",
+ "GC_debug_register_finalizer called with non-base-pointer 0x%lx\n",
obj);
}
if (0 == fn) {
@@ -940,7 +1047,7 @@ GC_PTR *ocd;
ptr_t base = GC_base(obj);
if (0 == base || (ptr_t)obj - base != sizeof(oh)) {
GC_err_printf1(
- "GC_register_finalizer_no_order called with non-base-pointer 0x%lx\n",
+ "GC_debug_register_finalizer_no_order called with non-base-pointer 0x%lx\n",
obj);
}
if (0 == fn) {
@@ -973,7 +1080,7 @@ GC_PTR *ocd;
ptr_t base = GC_base(obj);
if (0 == base || (ptr_t)obj - base != sizeof(oh)) {
GC_err_printf1(
- "GC_register_finalizer_ignore_self called with non-base-pointer 0x%lx\n",
+ "GC_debug_register_finalizer_ignore_self called with non-base-pointer 0x%lx\n",
obj);
}
if (0 == fn) {
diff --git a/boehm-gc/doc/Makefile.am b/boehm-gc/doc/Makefile.am
deleted file mode 100644
index 91446305581..00000000000
--- a/boehm-gc/doc/Makefile.am
+++ /dev/null
@@ -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
-
diff --git a/boehm-gc/doc/Makefile.in b/boehm-gc/doc/Makefile.in
deleted file mode 100644
index 9bf1ff5fead..00000000000
--- a/boehm-gc/doc/Makefile.in
+++ /dev/null
@@ -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:
diff --git a/boehm-gc/doc/README b/boehm-gc/doc/README
index 6ac37c6c8ce..29d954f023e 100644
--- a/boehm-gc/doc/README
+++ b/boehm-gc/doc/README
@@ -1,7 +1,7 @@
Copyright (c) 1988, 1989 Hans-J. Boehm, Alan J. Demers
Copyright (c) 1991-1996 by Xerox Corporation. All rights reserved.
Copyright (c) 1996-1999 by Silicon Graphics. All rights reserved.
-Copyright (c) 1999-2001 by Hewlett-Packard Company. All rights reserved.
+Copyright (c) 1999-2003 by Hewlett-Packard Company. All rights reserved.
The file linux_threads.c is also
Copyright (c) 1998 by Fergus Henderson. All rights reserved.
@@ -9,8 +9,9 @@ Copyright (c) 1998 by Fergus Henderson. All rights reserved.
The files Makefile.am, and configure.in are
Copyright (c) 2001 by Red Hat Inc. All rights reserved.
-The files config.guess and a few others are copyrighted by the Free
-Software Foundation.
+Several files supporting GNU-style builds are copyrighted by the Free
+Software Foundation, and carry a different license from that given
+below.
THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
@@ -27,7 +28,7 @@ are GPL'ed, but with an exception that should cover all uses in the
collector. (If you are concerned about such things, I recommend you look
at the notice in config.guess or ltmain.sh.)
-This is version 6.1alpha3 of a conservative garbage collector for C and C++.
+This is version 6.3alpha1 of a conservative garbage collector for C and C++.
You might find a more recent version of this at
@@ -228,10 +229,12 @@ and several of those are compatible with the collector.
or equivalent is supplied. Many of these have separate README.system
files.
- Dynamic libraries are completely supported only under SunOS
+ Dynamic libraries are completely supported only under SunOS/Solaris,
(and even that support is not functional on the last Sun 3 release),
-Linux, IRIX 5&6, HP-PA, Win32 (not Win32S) and OSF/1 on DEC AXP machines.
-On other machines we recommend that you do one of the following:
+Linux, FreeBSD, NetBSD, IRIX 5&6, HP/UX, Win32 (not Win32S) and OSF/1
+on DEC AXP machines plus perhaps a few others listed near the top
+of dyn_load.c. On other machines we recommend that you do one of
+the following:
1) Add dynamic library support (and send us the code).
2) Use static versions of the libraries.
@@ -245,6 +248,8 @@ On other machines we recommend that you do one of the following:
In all cases we assume that pointer alignment is consistent with that
enforced by the standard C compilers. If you use a nonstandard compiler
you may have to adjust the alignment parameters defined in gc_priv.h.
+Note that this may also be an issue with packed records/structs, if those
+enforce less alignment for pointers.
A port to a machine that is not byte addressed, or does not use 32 bit
or 64 bit addresses will require a major effort. A port to plain MSDOS
diff --git a/boehm-gc/doc/README.MacOSX b/boehm-gc/doc/README.MacOSX
index 2abf0b400f7..f5333d51ad6 100644
--- a/boehm-gc/doc/README.MacOSX
+++ b/boehm-gc/doc/README.MacOSX
@@ -1,27 +1 @@
-While the GC should work on MacOS X Server, MacOS X and Darwin, I only tested
-it on MacOS X Server.
-I've added a PPC assembly version of GC_push_regs(), thus the setjmp() hack is
-no longer necessary. Incremental collection is supported via mprotect/signal.
-The current solution isn't really optimal because the signal handler must decode
-the faulting PPC machine instruction in order to find the correct heap address.
-Further, it must poke around in the register state which the kernel saved away
-in some obscure register state structure before it calls the signal handler -
-needless to say the layout of this structure is no where documented.
-Threads and dynamic libraries are not yet supported (adding dynamic library
-support via the low-level dyld API shouldn't be that hard).
-
-The original MacOS X port was brought to you by Andrew Stone.
-
-
-June, 1 2000
-
-Dietmar Planitzer
-dave.pl@ping.at
-
-Note from Andrew Begel:
-
-One more fix to enable gc.a to link successfully into a shared library for
-MacOS X. You have to add -fno-common to the CFLAGS in the Makefile. MacOSX
-disallows common symbols in anything that eventually finds its way into a
-shared library. (I don't completely understand why, but -fno-common seems to
-work and doesn't mess up the garbage collector's functionality).
+See README.darwin for the latest Darwin/MacOSX information.
diff --git a/boehm-gc/doc/README.changes b/boehm-gc/doc/README.changes
index 232938b4375..619ea2e4a49 100644
--- a/boehm-gc/doc/README.changes
+++ b/boehm-gc/doc/README.changes
@@ -1469,8 +1469,439 @@ Since 6.1 alpha2:
- Caused the Solaris and Irix thread creation primitives to call
GC_init_inner().
+Since 6.1alpha3:
+ - Fixed typo in sparc_mach_dep.S, preventing the 64-bit version from
+ building. Increased 64-bit heap size limit in test.c slightly, since
+ a functional SPARC collector seems to slightly exceed the old limits.
+ (Thanks again to Jeff Sturm.)
+ - Use NPRGREG in solaris_threads.c, thus printing all registers if things
+ go wrong.
+ - Added GC_MARKERS environment variable to allow use of a single marker
+ thread on an MP without confusing the lock implementation.
+ - Collect much less aggressively in incremental mode with GC_TIME_UNLIMITED.
+ This is really a purely generational mode, and we can afford to
+ postpone the collection until the heap is (nearly) full.
+ - Remove read() wrapper for MPROTECT_VDB. It was causing more harm than
+ good. It is often no longer needed if system calls avoid writing to
+ pointerfull heap objects.
+ - Fix MACOSX test in gcconfig.h. (Thanks to John Clements.)
+ - Change GC_test_and_set so that it consistently has one argument.
+ Add spaces to ::: in powerpc assembly code in gc_locks.h.
+ (Thanks to Ryan Murray.)
+ - Fixed a formatting error in dbg_mlc.c. Added prototype to GC_abort()
+ declaration. (Thanks to Michael Smith.)
+ - Removed "source" argument to GC_find_start(). Eliminate GC_FIND_START().
+ - Added win32 recognition code in configure.in. Changed some of the
+ dllimport/export defines in gc.h. (Thanks to Adam Megacz.)
+ - GC_malloc_many didn't set hb_last_reclaimed when it called
+ GC_reclaim_generic. (I'm not sure this matters much, but ...)
+ - Allocating uncollectable objects with debug information sometimes
+ allocated objects that were one byte too small, since uncollectable
+ objects don't have the extra byte added at the end. (Thanks to
+ Wink Saville for pointing this out.)
+ - Added a bit more assertion checking to make sure that gcj objects
+ on free lists never have a nonzero second word.
+ - Replaced BCC_MAKEFILE with an up-to-date one. (Thanks to
+ Andre Leiradella.)
+ - Upgraded libtool, cinfigure.in and some related files to hopefully
+ support NetBSD/SPARC. (Thanks to Adrian Bunk.) Unfortunately,
+ libtool 1.4.2 seemed to be buggy due to missing quotes in several
+ "test" invocations. Fixed those in the ltmain.sh script.
+ - Some win32-specific patches, including the introduction of
+ GC_CreateThread. (Thanks to Adam Megacz.)
+ - Merged in gcj changes from Anthony Green to support embedded systems.
+ - Tried to consistently rename preprocessed assembly files with a capital
+ .S extension.
+ - Use alpha_mach_dep.S on ALPHA again. It doesn't really matter, but this
+ makes our distribution consistent with the gcc one, avoiding future merge
+ problems.
+ - Move GET_MEM definition into gcconfig.h. Include gcconfig.h slightly
+ later in gc_priv.h to avoid forward references to ptr_t.
+ - Add some testing of local allocation to test.c.
+ - Change definition of INVALID_QTID in specific.h. The -1 value was used
+ inconsistently, and too likely to collide with a valid stack address.
+ Some general clean-up of specific.[ch]. Added assertions. (Thanks
+ to Michael Smith for tracking down an intermittent bug to this
+ general area. I'm not sure it has been squashed yet, however.)
+ - On Pthread systems it was not safe to call GC_malloc() between fork()
+ and exec(). According to the applicable standards, it doesn't appear
+ to be safe to call malloc() or many other libc functions either, thus
+ it's not clear this is fixable. Added experimental support for
+ -DHANDLE_FORK in linux_threads.c which tries to support it. It may
+ succeed if libc does the right thing. I'm not sure whether it does.
+ (Thanks to Kenneth Schalk for pointing out this issue.)
+ - Documented thread local allocation primitives to require an
+ explicit GC_init call. GC_init_parallel is no longer declared to
+ be a constructor function, since that isn't portable and often
+ seems to lead to initialization order problems.
+ - Changed gc_cpp.cc and gc_cpp.h in one more attempt to make them
+ compatible with Visual C++ 6. (Thanks to Wink Saville for the
+ patch.)
+ - Some more patches for Linux on HP PA-RISC.
+ - Added include/gc_allocator.h. It implements (hopefully) standard
+ conforming (as opposed to SGI-style) allocators that allocate
+ collectable (gc_allocator) or GC-traceable, but not collectable
+ (traceable_allocator) objects. This borrows heavily from libstc++,
+ which borrows heavily from the SGI implementation, this part of
+ which was written by Matt Austern. Changed test_cpp.cc to very
+ minimally test this.
+ - On Linux/X86, retry mmap with a different start argument. That should
+ allow the collector to use more (closer to 3GB) of the address space.
+ (Thanks to Jeffrey Mark Siskind for tracking this down.)
+ - Force 64 bit alignment with GCJ support. (Reflects Bryce McKinley's
+ patch to the gcc tree.)
+ - Refined the choice of sa_handler vs. sa_sigaction in GC_dirty_init
+ to accomodate some glibc5 systems. (Thanks to Dan Fandrich for the
+ patch.)
+ - Compensated for the fact that current versions of glibc set
+ __libc_stack_end incorrectly on Linux/IA64 while initialization code
+ is running. This could cause the collector to miss 16 bytes of
+ the memory stack if GC_malloc or friends where called before main().
+ - Mostly integrated Takis Psarogiannakopoulos' port to DG/UX Inix 86.
+ This will probably take another iteration to work, since his
+ patch conflicted with the libtool upgrade.
+ - Added README.arm.cross containing some information about cross-
+ compiling to an ARM processor from Margaret Fleck.
+
+Since 6.1alpha4:
+ - Added GC_finalizer_mem_freed, and changed some of the code that
+ decided on heap expansion to look at it. Memory explicitly
+ deallocated by finalizers essentially needs to be counted as reclaimed
+ by the GC. Otherwise there are cases in which the heap can grow
+ unboundedly. (Thanks to Mark Reichert for the test case.)
+ - Integrated Adam Megacz patches to not scan dynamic libraries if
+ we are compiling with gcc on win32. Otherwise we need structured
+ exception handling to deal with asynchronously unmapped root
+ segments, and gcc doesn't directly support that.
+ - Integrated Anthony Green's patch to support Wine.
+ - GC_OPERATOR_NEW_ARRAY was misspelled OPERATOR_NEW_ARRAY in several
+ places, including gc_cpp.cc. (Thanks to Wink Saville for pointing
+ this out.)
+ - Integrated Loren James Rittle's Alpha FreeBSD patches. In
+ response to Richard Henderson's suggestion, these also
+ changed the declarations of symbols like _end on many platforms to
+ that they wouldn't mistakenly be declared as short data symbols.
+ - Integrated changes from the Debian distribution. (Thanks to Ryan Murray
+ for pointing these out.) Fix C++ comments in POWERPC port. Add ARM32
+ incremental GC support. Get rid of USE_GENERIC_PUSH_REGS for alpha/Linux,
+ this time for real. Use va_copy to get rid of cord printf problems
+ (finally).
+ - Close file descriptor used to count cpus. Thanks to Jeff Sturm for
+ pointing out the omission.
+ - Don't just drop gcj free lists in GC_start_reclaim, since that can
+ eventually cause the marker to see a bogus mark descriptor in the
+ dropped objects. The usual symptom was a very intermittent segmentation
+ fault in the marker. This mattered only if one of the GC_gcj_malloc
+ variants was used. (Thanks to Michael Smith, Jeff Sturm, Bryce
+ McKinley and Tom Tromey for helping to track this down.)
+ - Fixed Linux and Solaris/64 SPARC configuration. (Thanks to David Miller,
+ Jeff Sturm, Tom Tromey, and Christian Joensson.)
+ - Fixed a typo in strdup definition. (Thanks to Gerard A Allan.)
+ - Changed Makefile.direct to invoke $(CC) to assemble alpha_mach_dep.S.
+ This is needed on Linux. I'm not sure whether it's better or worse
+ on Tru64.
+ - Changed gc_cpp.h once more to declare operator new and friends only in
+ a Microsoft environment. This may need further fine tuning. (Thanks to
+ Johannes Schmidt for pointing out that the older code breaks on gcc3.0.4.)
+ - Don't ever override strdup if it's already macro defined. (Thanks to
+ Adnan Ali for pointing out the problem.)
+ - Changed gc_cpp.h yet again to also overload placement new. Due to the
+ C++ overloading rules, the other overloaded new operations otherwise hide
+ placement new, which causes many STL uses to break. (Thanks to Reza
+ Shahidi for reporting this, and to Matt Austern for proposing a fix.)
+ - Integrated cygwin pthreads support from Dan Bonachea.
+ - Turn on DYNAMIC_LOADING for NetBSD. (Thanks to Krister Walfridsson.)
+ - Changed printing code to print more complete GC times.
+ - Applied Mark Mitchell's Irix patch to correct some bitrot.
+ - Clarified which object-printing routines in dbg_mlc.c should hold
+ the allocation lock. Restructured the code to allow reasonable object
+ printing with -DREDIRECT_MALLOC.
+ - Fix the Linux mmap code to always start with 0x1000 as the initial hint.
+ Minor patches for 64-bit AIX, particularly to STACKBOTTOM.
+ (Thanks again to Jeffrey Mark Siskind.)
+ - Renamed "SUSPENDED" flag for Solaris threads support to avoid a conflict
+ with a system header. (Thanks to Philp Brown.)
+ - Cause win32_threads.c to handle an out of range stack pointer correctly,
+ though currently with a warning. (Thanks to Jonathan Clark for
+ observing that win32 applications may temporarily use the stack
+ pointer for other purposes, and suggesting a fix. Unfortunately, it's
+ not clear that there is a complete solution to this problem.)
+
+Since 6.1alpha5:
+ - Added GC_MAXIMUM_HEAP_SIZE environment variable.
+ - Fix configure.in for MIPS/LINUX. (Thanks to H.J. Lu.)
+ - Double page hash table size for -DLARGE_CONFIG.
+ - Integrated Bo Thorsen's X86-64 support.
+ - STACKBOTTOM definition for LINUX/MIPS was partially changed back.
+ (Thanks to H.J. Lu and Hiroshi Kawashima for resolving this.)
+ - Replaced all occurrences of LINUX_DATA_START in gcconfig.h with
+ SEARCH_FOR_DATA_START. It doesn't hurt to falll back to a search.
+ And __data_start doesn't seem to get defined correctly of the GC
+ library is loaded with LD_PRELOAD, e.g. for leak detection.
+ - If the GC_find_leak environment variable is set, do a
+ atexit(GC_gcollect) to give us at least one chance to detect leaks.
+ This may report some very benign leaks, but ...
+ - Addeded REDIRECT_FREE. It's necessary if we want leak detection with
+ LD_PRELOAD.
+ - Defer printing of leaked objects, as for smashed objects.
+ - Fixed process and descriptor leak in GC_print_callers. Try for
+ line number even if we got function name.)
+ - Ported parallel GC support and thread local allocation to Alpha.
+ Not yet well-tested.
+ - Added GC_DUMP_REGULARLY and added finalization statistics to GC_dump().
+ - Fixed Makefile.am to mention alpha_mach_dep.S instead of the defunct
+ alpha_mach_dep.s. (Thanks to Fergus Henderson.)
+ - Incorporated a change to new_gc_alloc.h, suggested by Johannes Schmidt,
+ which should make it work with gcc3.1. (I would still like to encourage
+ use of gc_allocator.h instead.)
+ - Use alpha_mach_dep.S only on Linux. (It's not clear that this is
+ optimal, but it otherwise didn't build on Tru64. Thanks to Fergus
+ Henderson.)
+ - Added ifdef to guard free() in os_dep.c. Otherwise we get a
+ compilation error on Irix. (Thanks to Dai Sato.)
+ - Added an experimental version of GC_memalign to mallocx.c. This can't
+ always work, since we don't handle alignment requests in the hblk-level
+ allocator, and we can't handle arbitrary pointer displacements unless
+ GC_all_interior_pointers is enabled. But it should work for alignment
+ requests up to HBLKSIZE. This is not yet documented in the standard
+ places.
+ - Finally debugged the OSF1/Tru64 thread support. This needs more testing,
+ since I needed to add a somewhat unconvincing workaround for signal
+ delivery issues that I don't yet completely understand. But it does
+ pass my tests, even in parallel GC mode. Incremental GC support is
+ disabled if thread support is enabled, due to the signal issues.
+ - Eliminated name-space-incorrect definition of _cdecl from gc_cpp.h.
+ - Added GC_debug_malloc_replacement and GC_debug_realloc_replacement
+ declarations to gc.h. On IA64, this is required for REDIRECT_MALLOC
+ to work correctly with these.
+ - Fixed Linux USE_PROC_FOR_LIBRARIES to work with a 64-bit /proc format.
+
+Since 6.1:
+ - Guard the test for GC_DUMP_REGULARLY in misc.c with
+ "#ifndef NO_DEBUGGING". Otherwise it fails to build with NO_DEBUGGING
+ defined. (Thanks to Manuel Serrano.)
+ - Message about retrying suspend signals was incorrectly generated even when
+ flag was not set.
+ - Cleaned up MACOSX/NEXT root registration code. There was apparently a
+ separate ifdef case in GC_register_data_segments() for no reason.
+ - Removed MPROTECT_VDB for MACOSX port, based on one negative report.
+ - Arrange for gc.h and friends to be correctly installed with GNU-style
+ "make install".
+ - Enable the GNU-style build facility include C++ support in the library
+ with --enable-cplusplus. (Thanks to Thomas Maier for some of the patch.)
+ - Mark from GC_thread_key in linux_threads.c, in case that's allocated
+ from the garbage collected heap, as it is with our own thread-specific
+ storage implementation. (Thanks to Jeff Sturm.)
+ - Mark all free list header blocks if they are heap allocated. This avoids
+ some unnecessary tracing. And it remains correct if we clear the
+ root set. (Thanks to Jeff Sturm for identifying the bug.)
+ - Improved S390/Linux support. Add S390/Linux 64-bit support. (Thanks
+ to Ulrich Weigand.)
+ - Corrected the spelling of GC_{M,C}ALLOC_EXPLICTLY_TYPED to
+ GC_{M,C}ALLOC_EXPLICITLY_TYPED in gc_typed.h. This is technically
+ an interface change. Based on the fact that nobody reported this,
+ I suspect/hope there were no clients.
+ - Cleaned up gc_typed.h so that (1) it adds an extern "C" declaration
+ when appropriate, (2) doesn't generate references to undefined internal
+ macros, and (3) allows easier manual construction of descriptors.
+ - Close the file descriptor used by GC_print_address_map().
+ - Set the "close-on-exec" bit for various file descriptors maintained
+ for the collector's internal use.
+ - Added a hack to find memory segments owned by the system allocator
+ under win32. Based on my tests, this tends to eventually find all
+ segments, though it may take a while. There appear to be cleaner,
+ but slower solutions under NT/XP. But they rely on an API that's
+ unsupported under 9X.
+ - Changed Linux PowerPC stack finding to LINUX_STACKBOTTOM. (Thanks
+ to Akira Tagoh for pointing out that HEURISTIC1 doesn't work on
+ 64-bit kernels.)
+ - Added GC_set_free_space_divisor to avoid some Windows dll issues.
+ - Added FIXUP_POINTER, POINTER_SHIFT, POINTER_MASK to allow preprocessing
+ of candidate pointers for tagging, etc.
+ - Always lock around GC_notify_full_gc(). Simplified code for
+ invoking GC_notify_full_gc().
+ - Changed the way DATASTART is defined on FreeBSD to be robust against
+ an unmapped page after etext. (Thanks to Hironori Sakamoto for
+ tracking down the intermittent failure.)
+ - Made GC_enable() and GC_disable() official. Deprecated direct update
+ of GC_dont_gc. Changed GC_gcollect to be a noop when garbage collection
+ is disabled.
+ - Call GC_register_dynamic_libraries before stopping the world on Linux,
+ in order to avoid a potential deadlock due to the dl_iterate_phdr lock.
+ - Introduced a more general mechanism for platform-dependent code to
+ decide whether the main data segment should be handled separately
+ from dynamic libraries, or registered by GC_register_dynamic_libraries.
+ The latter is more reliable and easier on Linux with dl_iterate_phdr.
+
+Since 6.2alpha1:
+ - Fixed the completely broken FreeBSD code in 6.2alpha1. (Thanks to
+ Hironori Sakamoto for the patch.)
+ - Changed IRIX reference in dbg_mlc.c to IRIX5. (Thanks to Marcus Herbert.)
+ - Attempted to work around the problems with .S filenames and the SGI
+ compiler. (Reported by several people. Untested.)
+ - Worked around an HP/UX make issue with the GNU-style build process.
+ - Fixed the --enable-cplusplus build machinery to allow builds without
+ a C++ compiler. (That was always the intent ...)
+ - Changed the debugging allocation macros to explicitly pass the return
+ address for Linux and XXXBSD on hardware for which we can't get stack
+ traces. Use __builtin_return_address(0) to generate it when possible.
+ Some of the configuration work was cleaned up (good) and moved to gc.h
+ (bad, but necessary). This should make leak detection more useful
+ on a number of platforms. (Thanks to Fabian Thylman for the suggestion.)
+ - Fixed compilation problems in dbg_mlc.c with GC_ADD_CALLER.
+ - Bumped revision number for dynamic library.
+
+Since 6.2alpha2:
+ - Don't include execinfo.h in os_dep.c when it's not needed, and may not exist.
+
+Since 6.2alpha3:
+ - Use LINUX_STACKBOTTOM for >= glibc2.2 on Linux/MIPS. (See Debian bug
+ # 177204)
+ - Integrated Jeff Sturm and Jesse Rosenstock's MACOSX threads patches.
+ - Integrated Grzegorz Jakacki's substantial GNU build patch. "Make dist"
+ should now work for the GNU build process. Documentation files
+ are installed under share/gc.
+ - Tweaked gc_cpp.h to again support the Borland compiler. (Thanks to
+ Rene Girard for pointing out the problems.)
+ - Updated BCC_MAKEFILE (thanks to Rene Girard).
+ - Added GC_ASSERT check for minimum thread stack size.
+ - Added --enable-gc-assertions.
+ - Added some web documentation to the distribution. Updated it in the
+ process.
+ - Separate gc_conf_macros.h from gc.h.
+ - Added generic GC_THREADS client-defined macro to set the appropriate
+ GC_XXX_THREADS internal macro. (gc_config_macros.h.)
+ - Add debugging versions of _ignore_off_page allocation primitves.
+ - Moved declarations of GC_make_closure and GC_debug_invoke_finalizer
+ from gc.h to gc_priv.h.
+ - Reset GC_fail_count even if only a small allocation succeeds.
+ - Integrated Brian Alliet's patch for dynamic library support on Darwin.
+ - gc_cpp.h's gc_cleanup destructor called GC_REGISTER_FINALIZER_IGNORE_SELF
+ when it should have called the lower case version, since it was
+ explicitly computing a base pointer.
+
+Since 6.2alpha4:
+ - GC_invoke_finalizers could, under rare conditions, set
+ GC_finalizer_mem_freed to an essentially random value. This could
+ possibly cause unbounded heap growth for long-running applications
+ under some conditions. (The bug was introduced in 6.1alpha5, and
+ is not in gcc3.3. Thanks to Ben Hutchings for finding it.)
+ - Attempted to sanitize the various DLL macros. GC_USE_DLL disappeared.
+ GC_DLL is used instead. All internal tests are now on GC_DLL.
+ README.macros is now more precise about the intended meaning.
+ - Include DllMain in the multithreaded win32 version only if the
+ collector is actually built as a dll. (Thanks to Mohan Embar for
+ a version of the patch.)
+ - Hide the cygwin threadAttach/Detach functions. They were violating our
+ namespace rules.
+ - Fixed an assertion in GC_check_heap_proc. Added GC_STATIC_ASSERT.
+ (Thanks again to Ben Hutchings.)
+ - Removed some obsolete definitions for Linux/PowerPC in gcconfig.h.
+ - CORD_cat was not rebalancing unbalanced trees in some cases, violating
+ a CORD invariant. Also tweaked the rebalancing rule for
+ CORD_cat_char_star. (Thanks to Alexandr Petrosian for the bug report
+ and patch.)
+ - Added hand-coded structured exception handling support to mark.c.
+ This should enable support of dynamic libraries under win32 with
+ gcc-compiled code. (Thanks to Ranjit Mathew for the patch.)
+ Turned on dynamic library scanning for win32/gcc.
+ - Removed some remnants of read wrapping. (Thanks to Kenneth Schalk.)
+ GC_USE_LD_WRAP ws probably broken in recent versions.
+ - The build could fail on some platforms since gcconfig.h could include
+ declarations mentioning ptr_t, which was not defined, e.g. when if_mach
+ was built. (Thanks to Yann Dirson for pointing this out.) Also
+ cleaned up tests for GC_PRIVATE_H in gcconfig.h a bit.
+ - The GC_LOOP_ON_ABORT environment variable interfered with incremental
+ collection, since the write fault handler was erroneously overridden.
+ Handlers are now set up in the correct order.
+ - It used to be possible to call GC_mark_thread_local_free_lists() while
+ the world was not stopped during an incremental GC. This was not safe.
+ Fortunately, it was also unnecessary. Added GC_world_stopped flag
+ to avoid it. (This caused occasional crashes in GC_set_fl_marks
+ with thread local allocation and incremental GC. This probably happened
+ primarily on old, slow multiprocessors.)
+ - Allowed overriding of MAX_THREADS in win32_threads.c from the build
+ command line. (Patch from Yannis Bres.)
+ - Taught the IA64/linux code to determine the register backing store base from
+ /proc/self/maps after checking the __libc symbol, but before guessing.
+ (__libc symbols are on the endangered list, and the guess is likely to not
+ always be right for 2.6 kernels.) Restructured the code to read and parse
+ /proc/self/maps so it only exists in one place (all platforms).
+ - The -DUSE_PROC_FOR_LIBRARIES code was broken on Linux. It claimed that it
+ also registered the main data segment, but didn't actually do so. (I don't
+ think anyone actually uses this configuration, but ...)
+ - Made another attempt to get --enablecplusplus to do the right thing.
+ Since there are unavoidable problems with C programs linking against a
+ dynamic library that includes C++ code, I separated out the c++ code into
+ libgccpp.
+
+Since 6.2alpha5:
+ - There was extra underscore in the name of GC_save_registers_in_stack
+ for NetBSD/SPARC. (Thanks to Jaap Boender for the patch.)
+ - Integrated Brian Alliet's patch for Darwin. This restructured the
+ linuxthreads/pthreads support to separate generic pthreads support
+ from more the system-dependent thread-stopping code. I believe this
+ should make it easier to eliminate the code duplication between
+ pthreads platforms in the future. The patch included some other
+ code cleanups.
+ - Integrated Dan Bonachea's patch to support AIX threads. This required
+ substantial manual integration, mostly due to conflicts with other
+ recent threads changes. It may take another iteration to
+ get it to work.
+ - Removed HPUX/PA-RISC support from aix_irix_threads.c. It wasn't used
+ anyway and it cluttered up the code. And anything we can do to migrate
+ towards generic pthreads support is a good thing.
+ - Added a more explicit test for tracing of function arguments to test.c.
+ (Thanks to Dan Grayson.)
+ - Added Akira Tagoh's PowerPC64 patch.
+ - Fixed some bit rot in the Cygwin port. (Thanks to Dan Bonachea for
+ pointing it out.) Gc.h now includes just windows.h, not winbase.h.
+ - Declared GC_save_regs_in_stack() in gc_priv.h. Remove other declarations.
+ - Changed --enable-cplusplus to use automake consitionals. The old way
+ confused libtool. "Make install" didn't work correctly for the old version.
+ Previously --enable-cplusplus was broken on cygwin.
+ - Changed the C version of GC_push_regs to fail at compile time if it is
+ generated with an empty body. This seems to have been the cause of one
+ or two subtle failures on unusual platforms. Those failures should
+ now occur at build time and be easily fixable.
+
+Since 6.2alpha6:
+ - Integrated a second round of Irix/AIX patches from Dan Bonachea.
+ Renamed mips_sgi_mach_dep.S back to mips_sgi_mach_dep.s, since it requires
+ the Irix assembler to do the C preprocessing; gcc -E doesn't work.
+ - Fixed Makefile.direct for DARWIN. (Thanks to Manuel Serrano.)
+ - There was a race between GC_pthread_detach and thread exit that could
+ result in a thread structure being deallocated by GC_pthread_detach
+ eventhough it was still needed by the thread exit code. (Thanks to
+ Dick Porter for the small test case that allowed this to be debugged.)
+ - Fixed version parsing for non-alpha versions in acinclude.m4 and
+ version checking in version.h.
+
+Since 6.2:
+ - Integrated some NetBSD patches forwarded to me by Marc Recht. These
+ were already in the NetBSD package.
+ - GC_pthread_create waited for the semaphore even if pthread_create failed.
+ Thanks to Dick Porter for the pthread_support.c patch. Applied the
+ analogous fix for aix_irix_threads.c.
+ - Added Rainer Orth's Tru64 fixes.
+ - The check for exceeding the thread table size in win32 threadDetach
+ was incorrect. (Thanks to Alexandr Petrosian for the patch.)
+ - Applied Andrew Begel's patch to correct some reentrancy issues
+ with dynamic loading on Darwin.
+ - GC_CreateThread() was neglecting to duplicate the thread handle in
+ the table. (Thanks to Tum Nguyen for the patch.)
+ - Pass +ESdbgasm only on PA-RISC machines with vendor compiler.
+ (Thanks to Roger Sayle for the patch.)
+ - Applied more AIX threads patches from Scott Ananian.
To do:
+ - A dynamic libgc.so references dlopen unconditionally, but doesn't link
+ against libdl.
+ - GC_proc_fd for Solaris is not correctly updated in response to a
+ fork() call. Thus incremental collection in the child won't work
+ correctly. (Thanks to Ben Cottrell for pointing this out.)
+ - --enable-redirect-malloc is mostly untested and known not to work
+ on some platforms.
- There seem to be outstanding issues on Solaris/X86, possibly with
finding the data segment starting address. Information/patches would
be appreciated.
@@ -1488,7 +1919,4 @@ To do:
- Incremental collector should handle large objects better. Currently,
it looks like the whole object is treated as dirty if any part of it
is.
- - Cord/cordprnt.c doesn't build on a few platforms (notably PowerPC), since
- we make some unwarranted assumptions about how varargs are handled. This
- currently makes the cord-aware versions of printf unusable on some platforms.
- Fixing this is unfortunately not trivial.
+
diff --git a/boehm-gc/doc/README.environment b/boehm-gc/doc/README.environment
index c7daddb0aca..d1f3b5c053b 100644
--- a/boehm-gc/doc/README.environment
+++ b/boehm-gc/doc/README.environment
@@ -5,6 +5,8 @@ platforms.
GC_INITIAL_HEAP_SIZE=<bytes> - Initial heap size in bytes. May speed up
process start-up.
+GC_MAXIMUM_HEAP_SIZE=<bytes> - Maximum collected heap size.
+
GC_LOOP_ON_ABORT - Causes the collector abort routine to enter a tight loop.
This may make it easier to debug, such a process, especially
for multithreaded platforms that don't produce usable core
@@ -19,6 +21,11 @@ GC_PRINT_STATS - Turn on as much logging as is easily feasible without
by setting GC_quiet. On by default if the collector
was built without -DSILENT.
+GC_DUMP_REGULARLY - Generate a GC debugging dump GC_dump() on startup
+ and during every collection. Very verbose. Useful
+ if you have a bug to report, but please include only the
+ last complete dump.
+
GC_PRINT_ADDRESS_MAP - Linux only. Dump /proc/self/maps, i.e. various address
maps for the process, to stderr on every GC. Useful for
mapping root addresses to source for deciphering leak
@@ -27,7 +34,14 @@ GC_PRINT_ADDRESS_MAP - Linux only. Dump /proc/self/maps, i.e. various address
GC_NPROCS=<n> - Linux w/threads only. Explicitly sets the number of processors
that the GC should expect to use. Note that setting this to 1
when multiple processors are available will preserve
- correctness, but may lead to really horrible performance.
+ correctness, but may lead to really horrible performance,
+ since the lock implementation will immediately yield without
+ first spinning.
+
+GC_MARKERS=<n> - Linux w/threads and parallel marker only. Set the number
+ of marker threads. This is normaly set to the number of
+ processors. It is safer to adjust GC_MARKERS than GC_NPROCS,
+ since GC_MARKERS has no impact on the lock implementation.
GC_NO_BLACKLIST_WARNING - Prevents the collector from issuing
warnings about allocations of very large blocks.
@@ -62,6 +76,20 @@ GC_PRINT_BACK_HEIGHT - Print max length of chain through unreachable objects
of Conservative Garbage Collectors", POPL 2001, or
http://lib.hpl.hp.com/techpubs/2001/HPL-2001-251.html .
+GC_RETRY_SIGNALS, GC_NO_RETRY_SIGNALS - Try to compensate for lost
+ thread suspend signals in linux_threads.c. On by
+ default for GC_OSF1_THREADS, off otherwise. Note
+ that this does not work around a possible loss of
+ thread restart signals. This seems to be necessary for
+ some versions of Tru64. Since we've previously seen
+ similar issues on some other operating systems, it
+ was turned into a runtime flag to enable last-minute
+ work-arounds.
+
+The following turn on runtime flags that are also program settable. Checked
+only during initialization. We expect that they will usually be set through
+other means, but this may help with debugging and testing:
+
GC_ENABLE_INCREMENTAL - Turn on incremental collection at startup. Note that,
depending on platform and collector configuration, this
may involve write protecting pieces of the heap to
@@ -71,22 +99,20 @@ GC_ENABLE_INCREMENTAL - Turn on incremental collection at startup. Note that,
Use with caution.
GC_PAUSE_TIME_TARGET - Set the desired garbage collector pause time in msecs.
- This only has an effect if incremental collection is enabled.
- If a collection requires appreciably more time than this,
- the client will be restarted, and the collector will need
- to do additional work to compensate. The special value
- "999999" indicates that pause time is unlimited, and the
- incremental collector will behave completely like a
- simple generational collector. If the collector is
- configured for parallel marking, and run on a multiprocessor,
- incremental collection should only be used with unlimited
- pause time.
-
-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:
+ This only has an effect if incremental collection is
+ enabled. If a collection requires appreciably more time
+ than this, the client will be restarted, and the collector
+ will need to do additional work to compensate. The
+ special value "999999" indicates that pause time is
+ unlimited, and the incremental collector will behave
+ completely like a simple generational collector. If
+ the collector is configured for parallel marking, and
+ run on a multiprocessor, incremental collection should
+ only be used with unlimited pause time.
-GC_FIND_LEAK - Turns on GC_find_leak and thus leak detection.
+GC_FIND_LEAK - Turns on GC_find_leak and thus leak detection. Forces a
+ collection at program termination to detect leaks that would
+ otherwise occur after the last GC.
GC_ALL_INTERIOR_POINTERS - Turns on GC_all_interior_pointers and thus interior
pointer recognition.
diff --git a/boehm-gc/doc/README.linux b/boehm-gc/doc/README.linux
index efd0a26bfb8..1d0fd4c3fb6 100644
--- a/boehm-gc/doc/README.linux
+++ b/boehm-gc/doc/README.linux
@@ -1,21 +1,18 @@
See README.alpha for Linux on DEC AXP info.
-This file applies mostly to Linux/Intel IA32. Ports to Linux on an M68K
-and PowerPC are also integrated. They should behave similarly, except that
-the PowerPC port lacks incremental GC support, and it is unknown to what
-extent the Linux threads code is functional. See below for M68K specific
-notes.
+This file applies mostly to Linux/Intel IA32. Ports to Linux on an M68K, IA64,
+SPARC, MIPS, Alpha and PowerPC are also integrated. They should behave
+similarly, except that the PowerPC port lacks incremental GC support, and
+it is unknown to what extent the Linux threads code is functional.
+See below for M68K specific notes.
-Incremental GC is supported on Intel IA32 and M68K.
+Incremental GC is generally supported.
Dynamic libraries are supported on an ELF system. A static executable
should be linked with the gcc option "-Wl,-defsym,_DYNAMIC=0".
-The collector appears to work with Linux threads. We have seen
-intermittent hangs in sem_wait. So far we have been unable to reproduce
-these unless the process was being debugged or traced. Thus it's
-possible that the only real issue is that the debugger loses
-signals on rare occasions.
+The collector appears to work reliably with Linux threads, but beware
+of older versions of glibc and gdb.
The garbage collector uses SIGPWR and SIGXCPU if it is used with
Linux threads. These should not be touched by the client program.
diff --git a/boehm-gc/doc/README.win32 b/boehm-gc/doc/README.win32
index b1a6ec59664..a40b375f550 100644
--- a/boehm-gc/doc/README.win32
+++ b/boehm-gc/doc/README.win32
@@ -21,6 +21,13 @@ registrations are ignored, but not terribly quickly.)
pointers. And the VirtualQuery call has different semantics under
the two systems, and under different versions of win32s.)
+Win32 applications compiled with some flavor of gcc currently behave
+like win32s applications, in that dynamic library data segments are
+not scanned. (Gcc does not directly support Microsoft's "structured
+exception handling". It turns out that use of this feature is
+unavoidable if you scan arbitrary memory segments obtained from
+VirtualQuery.)
+
The collector test program "gctest" is linked as a GUI application,
but does not open any windows. Its output appears in the file
"gc.log". It may be started from the file manager. The hour glass
@@ -50,13 +57,20 @@ This appears to cause problems under Windows NT and Windows 2000 (but
not Windows 95/98) if the memory is later passed to CreateDIBitmap.
To work around this problem, build the collector with -DUSE_GLOBAL_ALLOC.
This is currently incompatible with -DUSE_MUNMAP. (Thanks to Jonathan
-Clark for tracking this down.)
+Clark for tracking this down. There's some chance this may be fixed
+in 6.1alpha4, since we now separate heap sections with an unused page.)
For Microsoft development tools, rename NT_MAKEFILE as
MAKEFILE. (Make sure that the CPU environment variable is defined
to be i386.) In order to use the gc_cpp.h C++ interface, all
client code should include gc_cpp.h.
+If you would prefer a VC++.NET project file, ask boehm@acm.org. One has
+been contributed, but it seems to contain some absolute paths etc., so
+it can presumably only be a starting point, and is not in the standard
+distribution. It is unclear (to me, Hans Boehm) whether it is feasible to
+change that.
+
Clients may need to define GC_NOT_DLL before including gc.h, if the
collector was built as a static library (as it normally is in the
absence of thread support).
@@ -64,7 +78,7 @@ absence of thread support).
For GNU-win32, use the regular makefile, possibly after uncommenting
the line "include Makefile.DLLs". The latter should be necessary only
if you want to package the collector as a DLL. The GNU-win32 port is
-believed to work only for b18, not b19, probably dues to linker changes
+believed to work only for b18, not b19, probably due to linker changes
in b19. This is probably fixable with a different definition of
DATASTART and DATAEND in gcconfig.h.
@@ -147,7 +161,7 @@ To compile the collector and testing programs use the command:
All programs using gc should be compiled with 4-byte alignment.
For further explanations on this see comments about Borland.
-If gc compiled as dll, the macro ``GC_DLL'' should be defined before
+If the gc is compiled as dll, the macro ``GC_DLL'' should be defined before
including "gc.h" (for example, with -DGC_DLL compiler option). It's
important, otherwise resulting programs will not run.
diff --git a/boehm-gc/doc/debugging.html b/boehm-gc/doc/debugging.html
index 04773fa66a3..22273fed4bc 100644
--- a/boehm-gc/doc/debugging.html
+++ b/boehm-gc/doc/debugging.html
@@ -248,8 +248,12 @@ The <TT>hb_last_reclaimed</tt> field will identify the collection number
during which its block was last swept.
<LI> Verify that the offending object still has its correct contents at
this point.
-The call <TT>GC_is_marked(p)</tt> from the debugger to verify that the
-object has not been marked, and is about to be reclaimed.
+Then call <TT>GC_is_marked(p)</tt> from the debugger to verify that the
+object has not been marked, and is about to be reclaimed. Note that
+<TT>GC_is_marked(p)</tt> expects the real address of an object (the
+address of the debug header if there is one), and thus it may
+be more appropriate to call <TT>GC_is_marked(GC_base(p))</tt>
+instead.
<LI> Determine a path from a root, i.e. static variable, stack, or
register variable,
to the reclaimed object. Call <TT>GC_is_marked(q)</tt> for each object
diff --git a/boehm-gc/dyn_load.c b/boehm-gc/dyn_load.c
index 71ad5fb1d78..5ae0e0dcccd 100644
--- a/boehm-gc/dyn_load.c
+++ b/boehm-gc/dyn_load.c
@@ -55,9 +55,10 @@
!defined(MSWIN32) && !defined(MSWINCE) && \
!(defined(ALPHA) && defined(OSF1)) && \
!defined(HPUX) && !(defined(LINUX) && defined(__ELF__)) && \
- !defined(RS6000) && !defined(SCO_ELF) && \
+ !defined(RS6000) && !defined(SCO_ELF) && !defined(DGUX) && \
!(defined(FREEBSD) && defined(__ELF__)) && \
- !(defined(NETBSD) && defined(__ELF__)) && !defined(HURD)
+ !(defined(NETBSD) && defined(__ELF__)) && !defined(HURD) && \
+ !defined(DARWIN)
--> We only know how to find data segments of dynamic libraries for the
--> above. Additional SVR4 variants might not be too
--> hard to add.
@@ -80,7 +81,7 @@
#endif
#if defined(LINUX) && defined(__ELF__) || defined(SCO_ELF) || \
- (defined(FREEBSD) && defined(__ELF__)) || \
+ (defined(FREEBSD) && defined(__ELF__)) || defined(DGUX) || \
(defined(NETBSD) && defined(__ELF__)) || defined(HURD)
# include <stddef.h>
# include <elf.h>
@@ -264,7 +265,7 @@ void GC_register_dynamic_libraries()
# endif /* SUNOS */
#if defined(LINUX) && defined(__ELF__) || defined(SCO_ELF) || \
- (defined(FREEBSD) && defined(__ELF__)) || \
+ (defined(FREEBSD) && defined(__ELF__)) || defined(DGUX) || \
(defined(NETBSD) && defined(__ELF__)) || defined(HURD)
@@ -282,56 +283,23 @@ extern ssize_t GC_repeat_read(int fd, char *buf, size_t count);
/* Repeatedly read until buffer is filled, or EOF is encountered */
/* Defined in os_dep.c. */
-static char *parse_map_entry(char *buf_ptr, word *start, word *end,
- char *prot_buf, unsigned int *maj_dev);
+char *GC_parse_map_entry(char *buf_ptr, word *start, word *end,
+ char *prot_buf, unsigned int *maj_dev);
+word GC_apply_to_maps(word (*fn)(char *));
+ /* From os_dep.c */
-void GC_register_dynamic_libraries()
+word GC_register_map_entries(char *maps)
{
- int f;
- int result;
char prot_buf[5];
- int maps_size;
- char maps_temp[32768];
- char *maps_buf;
- char *buf_ptr;
+ char *buf_ptr = maps;
int count;
word start, end;
- unsigned int maj_dev, min_dev;
+ unsigned int maj_dev;
word least_ha, greatest_ha;
unsigned i;
word datastart = (word)(DATASTART);
- /* Read /proc/self/maps */
- /* Note that we may not allocate, and thus can't use stdio. */
- f = open("/proc/self/maps", O_RDONLY);
- if (-1 == f) ABORT("Couldn't open /proc/self/maps");
- /* stat() doesn't work for /proc/self/maps, so we have to
- read it to find out how large it is... */
- maps_size = 0;
- do {
- result = GC_repeat_read(f, maps_temp, sizeof(maps_temp));
- if (result <= 0) ABORT("Couldn't read /proc/self/maps");
- maps_size += result;
- } while (result == sizeof(maps_temp));
-
- if (maps_size > sizeof(maps_temp)) {
- /* If larger than our buffer, close and re-read it. */
- close(f);
- f = open("/proc/self/maps", O_RDONLY);
- if (-1 == f) ABORT("Couldn't open /proc/self/maps");
- maps_buf = alloca(maps_size);
- if (NULL == maps_buf) ABORT("/proc/self/maps alloca failed");
- result = GC_repeat_read(f, maps_buf, maps_size);
- if (result <= 0) ABORT("Couldn't read /proc/self/maps");
- } else {
- /* Otherwise use the fixed size buffer */
- maps_buf = maps_temp;
- }
-
- close(f);
- maps_buf[result] = '\0';
- buf_ptr = maps_buf;
- /* Compute heap bounds. Should be done by add_to_heap? */
+ /* Compute heap bounds. FIXME: Should be done by add_to_heap? */
least_ha = (word)(-1);
greatest_ha = 0;
for (i = 0; i < GC_n_heap_sects; ++i) {
@@ -342,11 +310,10 @@ void GC_register_dynamic_libraries()
}
if (greatest_ha < (word)GC_scratch_last_end_ptr)
greatest_ha = (word)GC_scratch_last_end_ptr;
- for (;;) {
-
- buf_ptr = parse_map_entry(buf_ptr, &start, &end, prot_buf, &maj_dev);
- if (buf_ptr == NULL) return;
+ for (;;) {
+ buf_ptr = GC_parse_map_entry(buf_ptr, &start, &end, prot_buf, &maj_dev);
+ if (buf_ptr == NULL) return 1;
if (prot_buf[1] == 'w') {
/* This is a writable mapping. Add it to */
/* the root set unless it is already otherwise */
@@ -358,16 +325,7 @@ void GC_register_dynamic_libraries()
# ifdef THREADS
if (GC_segment_is_thread_stack(start, end)) continue;
# endif
- /* The rest of this assumes that there is no mapping */
- /* spanning the beginning of the data segment, or extending */
- /* beyond the entire heap at both ends. */
- /* Empirically these assumptions hold. */
-
- if (start < (word)DATAEND && end > (word)DATAEND) {
- /* Rld may use space at the end of the main data */
- /* segment. Thus we add that in. */
- start = (word)DATAEND;
- }
+ /* We no longer exclude the main data segment. */
if (start < least_ha && end > least_ha) {
end = least_ha;
}
@@ -377,7 +335,14 @@ void GC_register_dynamic_libraries()
if (start >= least_ha && end <= greatest_ha) continue;
GC_add_roots_inner((char *)start, (char *)end, TRUE);
}
- }
+ }
+ return 1;
+}
+
+void GC_register_dynamic_libraries()
+{
+ if (!GC_apply_to_maps(GC_register_map_entries))
+ ABORT("Failed to read /proc for library registration.");
}
/* We now take care of the main data segment ourselves: */
@@ -387,60 +352,6 @@ GC_bool GC_register_main_static_data()
}
# define HAVE_REGISTER_MAIN_STATIC_DATA
-//
-// parse_map_entry parses an entry from /proc/self/maps so we can
-// locate all writable data segments that belong to shared libraries.
-// The format of one of these entries and the fields we care about
-// is as follows:
-// XXXXXXXX-XXXXXXXX r-xp 00000000 30:05 260537 name of mapping...\n
-// ^^^^^^^^ ^^^^^^^^ ^^^^ ^^
-// start end prot maj_dev
-// 0 9 18 32
-//
-// The parser is called with a pointer to the entry and the return value
-// is either NULL or is advanced to the next entry(the byte after the
-// trailing '\n'.)
-//
-#define OFFSET_MAP_START 0
-#define OFFSET_MAP_END 9
-#define OFFSET_MAP_PROT 18
-#define OFFSET_MAP_MAJDEV 32
-
-static char *parse_map_entry(char *buf_ptr, word *start, word *end,
- char *prot_buf, unsigned int *maj_dev)
-{
- int i;
- unsigned int val;
- char *tok;
-
- if (buf_ptr == NULL || *buf_ptr == '\0') {
- return NULL;
- }
-
- memcpy(prot_buf, buf_ptr+OFFSET_MAP_PROT, 4); // do the protections first
- prot_buf[4] = '\0';
-
- if (prot_buf[1] == 'w') { // we can skip all of this if it's not writable
-
- tok = buf_ptr;
- buf_ptr[OFFSET_MAP_START+8] = '\0';
- *start = strtoul(tok, NULL, 16);
-
- tok = buf_ptr+OFFSET_MAP_END;
- buf_ptr[OFFSET_MAP_END+8] = '\0';
- *end = strtoul(tok, NULL, 16);
-
- buf_ptr += OFFSET_MAP_MAJDEV;
- tok = buf_ptr;
- while (*buf_ptr != ':') buf_ptr++;
- *buf_ptr++ = '\0';
- *maj_dev = strtoul(tok, NULL, 16);
- }
-
- while (*buf_ptr && *buf_ptr++ != '\n');
-
- return buf_ptr;
-}
#endif /* USE_PROC_FOR_LIBRARIES */
@@ -508,6 +419,7 @@ GC_bool GC_register_dynamic_libraries_dl_iterate_phdr()
GC_add_roots_inner(DATASTART2, (char *)(DATAEND2), TRUE);
# endif
}
+
return TRUE;
} else {
return FALSE;
@@ -534,6 +446,16 @@ GC_bool GC_register_main_static_data()
#if defined(NETBSD)
# include <sys/exec_elf.h>
+/* for compatibility with 1.4.x */
+# ifndef DT_DEBUG
+# define DT_DEBUG 21
+# endif
+# ifndef PT_LOAD
+# define PT_LOAD 1
+# endif
+# ifndef PF_W
+# define PF_W 2
+# endif
#else
# include <elf.h>
#endif
@@ -1048,7 +970,7 @@ void GC_register_dynamic_libraries()
len = ldi->ldinfo_next;
GC_add_roots_inner(
ldi->ldinfo_dataorg,
- (unsigned long)ldi->ldinfo_dataorg
+ (ptr_t)(unsigned long)ldi->ldinfo_dataorg
+ ldi->ldinfo_datasize,
TRUE);
ldi = len ? (struct ld_info *)((char *)ldi + len) : 0;
@@ -1056,7 +978,133 @@ void GC_register_dynamic_libraries()
}
#endif /* RS6000 */
+#ifdef DARWIN
+
+#include <mach-o/dyld.h>
+#include <mach-o/getsect.h>
+
+/*#define DARWIN_DEBUG*/
+
+const static struct {
+ const char *seg;
+ const char *sect;
+} GC_dyld_sections[] = {
+ { SEG_DATA, SECT_DATA },
+ { SEG_DATA, SECT_BSS },
+ { SEG_DATA, SECT_COMMON }
+};
+
+#ifdef DARWIN_DEBUG
+static const char *GC_dyld_name_for_hdr(struct mach_header *hdr) {
+ unsigned long i,c;
+ c = _dyld_image_count();
+ for(i=0;i<c;i++) if(_dyld_get_image_header(i) == hdr)
+ return _dyld_get_image_name(i);
+ return NULL;
+}
+#endif
+
+/* This should never be called by a thread holding the lock */
+static void GC_dyld_image_add(struct mach_header* hdr, unsigned long slide) {
+ unsigned long start,end,i;
+ const struct section *sec;
+ for(i=0;i<sizeof(GC_dyld_sections)/sizeof(GC_dyld_sections[0]);i++) {
+ sec = getsectbynamefromheader(
+ hdr,GC_dyld_sections[i].seg,GC_dyld_sections[i].sect);
+ if(sec == NULL || sec->size == 0) continue;
+ start = slide + sec->addr;
+ end = start + sec->size;
+# ifdef DARWIN_DEBUG
+ GC_printf4("Adding section at %p-%p (%lu bytes) from image %s\n",
+ start,end,sec->size,GC_dyld_name_for_hdr(hdr));
+# endif
+ GC_add_roots((char*)start,(char*)end);
+ }
+# ifdef DARWIN_DEBUG
+ GC_print_static_roots();
+# endif
+}
+
+/* This should never be called by a thread holding the lock */
+static void GC_dyld_image_remove(struct mach_header* hdr, unsigned long slide) {
+ unsigned long start,end,i;
+ const struct section *sec;
+ for(i=0;i<sizeof(GC_dyld_sections)/sizeof(GC_dyld_sections[0]);i++) {
+ sec = getsectbynamefromheader(
+ hdr,GC_dyld_sections[i].seg,GC_dyld_sections[i].sect);
+ if(sec == NULL || sec->size == 0) continue;
+ start = slide + sec->addr;
+ end = start + sec->size;
+# ifdef DARWIN_DEBUG
+ GC_printf4("Removing section at %p-%p (%lu bytes) from image %s\n",
+ start,end,sec->size,GC_dyld_name_for_hdr(hdr));
+# endif
+ GC_remove_roots((char*)start,(char*)end);
+ }
+# ifdef DARWIN_DEBUG
+ GC_print_static_roots();
+# endif
+}
+
+void GC_register_dynamic_libraries() {
+ /* Currently does nothing. The callbacks are setup by GC_init_dyld()
+ The dyld library takes it from there. */
+}
+
+/* The _dyld_* functions have an internal lock so no _dyld functions
+ can be called while the world is stopped without the risk of a deadlock.
+ Because of this we MUST setup callbacks BEFORE we ever stop the world.
+ This should be called BEFORE any thread in created and WITHOUT the
+ allocation lock held. */
+
+void GC_init_dyld() {
+ static GC_bool initialized = FALSE;
+ char *bind_fully_env = NULL;
+
+ if(initialized) return;
+
+# ifdef DARWIN_DEBUG
+ GC_printf0("Registering dyld callbacks...\n");
+# endif
+
+ /* Apple's Documentation:
+ When you call _dyld_register_func_for_add_image, the dynamic linker runtime
+ calls the specified callback (func) once for each of the images that is
+ currently loaded into the program. When a new image is added to the program,
+ your callback is called again with the mach_header for the new image, and the
+ virtual memory slide amount of the new image.
+
+ This WILL properly register already linked libraries and libraries
+ linked in the future
+ */
+
+ _dyld_register_func_for_add_image(GC_dyld_image_add);
+ _dyld_register_func_for_remove_image(GC_dyld_image_remove);
+
+ /* Set this early to avoid reentrancy issues. */
+ initialized = TRUE;
+
+ bind_fully_env = getenv("DYLD_BIND_AT_LAUNCH");
+
+ if (bind_fully_env == NULL) {
+# ifdef DARWIN_DEBUG
+ GC_printf0("Forcing full bind of GC code...\n");
+# endif
+
+ if(!_dyld_bind_fully_image_containing_address((unsigned long*)GC_malloc))
+ GC_abort("_dyld_bind_fully_image_containing_address failed");
+ }
+
+}
+
+#define HAVE_REGISTER_MAIN_STATIC_DATA
+GC_bool GC_register_main_static_data()
+{
+ /* Already done through dyld callbacks */
+ return FALSE;
+}
+#endif /* DARWIN */
#else /* !DYNAMIC_LOADING */
diff --git a/boehm-gc/finalize.c b/boehm-gc/finalize.c
index a316010a680..3b9d9f5ea1e 100644
--- a/boehm-gc/finalize.c
+++ b/boehm-gc/finalize.c
@@ -207,7 +207,8 @@ signed_word * log_size_ptr;
UNLOCK();
ENABLE_SIGNALS();
# endif
- new_dl = GC_oom_fn(sizeof(struct disappearing_link));
+ new_dl = (struct disappearing_link *)
+ GC_oom_fn(sizeof(struct disappearing_link));
if (0 == new_dl) {
GC_finalization_failures++;
return(0);
@@ -433,7 +434,8 @@ finalization_mark_proc * mp;
UNLOCK();
ENABLE_SIGNALS();
# endif
- new_fo = GC_oom_fn(sizeof(struct finalizable_object));
+ new_fo = (struct finalizable_object *)
+ GC_oom_fn(sizeof(struct finalizable_object));
if (0 == new_fo) {
GC_finalization_failures++;
return;
@@ -759,8 +761,9 @@ int GC_should_invoke_finalizers GC_PROTO((void))
/* Should be called without allocation lock. */
int GC_invoke_finalizers()
{
- register struct finalizable_object * curr_fo;
- register int count = 0;
+ struct finalizable_object * curr_fo;
+ int count = 0;
+ word mem_freed_before;
DCL_LOCK_STATE;
while (GC_finalize_now != 0) {
@@ -768,6 +771,9 @@ int GC_invoke_finalizers()
DISABLE_SIGNALS();
LOCK();
# endif
+ if (count == 0) {
+ mem_freed_before = GC_mem_freed;
+ }
curr_fo = GC_finalize_now;
# ifdef THREADS
if (curr_fo != 0) GC_finalize_now = fo_next(curr_fo);
@@ -789,6 +795,11 @@ int GC_invoke_finalizers()
GC_free((GC_PTR)curr_fo);
# endif
}
+ if (count != 0 && mem_freed_before != GC_mem_freed) {
+ LOCK();
+ GC_finalizer_mem_freed += (GC_mem_freed - mem_freed_before);
+ UNLOCK();
+ }
return count;
}
@@ -801,7 +812,9 @@ void GC_notify_or_invoke_finalizers GC_PROTO((void))
if (GC_finalize_now == 0) return;
if (!GC_finalize_on_demand) {
(void) GC_invoke_finalizers();
- GC_ASSERT(GC_finalize_now == 0);
+# ifndef THREADS
+ GC_ASSERT(GC_finalize_now == 0);
+# endif /* Otherwise GC can run concurrently and add more */
return;
}
if (GC_finalizer_notifier != (void (*) GC_PROTO((void)))0
@@ -839,3 +852,17 @@ void GC_notify_or_invoke_finalizers GC_PROTO((void))
return(result);
}
+#if !defined(NO_DEBUGGING)
+
+void GC_print_finalization_stats()
+{
+ struct finalizable_object *fo = GC_finalize_now;
+ size_t ready = 0;
+
+ GC_printf2("%lu finalization table entries; %lu disappearing links\n",
+ GC_fo_entries, GC_dl_entries);
+ for (; 0 != fo; fo = fo_next(fo)) ++ready;
+ GC_printf1("%lu objects are eligible for immediate finalization\n", ready);
+}
+
+#endif /* NO_DEBUGGING */
diff --git a/boehm-gc/gc_cpp.cc b/boehm-gc/gc_cpp.cc
index a97091c817c..f8b803a8baa 100644
--- a/boehm-gc/gc_cpp.cc
+++ b/boehm-gc/gc_cpp.cc
@@ -26,15 +26,13 @@ Authors: John R. Ellis and Jesse Hull
#include "gc_cpp.h"
-#ifndef _MSC_VER
-/* In the Visual C++ case, we moved this into the header. */
void* operator new( size_t size ) {
return GC_MALLOC_UNCOLLECTABLE( size );}
void operator delete( void* obj ) {
GC_FREE( obj );}
-#ifdef OPERATOR_NEW_ARRAY
+#ifdef GC_OPERATOR_NEW_ARRAY
void* operator new[]( size_t size ) {
return GC_MALLOC_UNCOLLECTABLE( size );}
@@ -42,8 +40,22 @@ void* operator new[]( size_t size ) {
void operator delete[]( void* obj ) {
GC_FREE( obj );}
-#endif /* OPERATOR_NEW_ARRAY */
+#endif /* GC_OPERATOR_NEW_ARRAY */
-#endif /* _MSC_VER */
+#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 */
diff --git a/boehm-gc/gc_dlopen.c b/boehm-gc/gc_dlopen.c
index eafaa2b1b46..4c690edcfe4 100644
--- a/boehm-gc/gc_dlopen.c
+++ b/boehm-gc/gc_dlopen.c
@@ -19,12 +19,14 @@
/*
* This used to be in dyn_load.c. It was extracted into a separate file
* to avoid having to link against libdl.{a,so} if the client doesn't call
- * dlopen. -HB
+ * dlopen. Of course this fails if the collector is in a dynamic
+ * library. -HB
*/
#include "private/gc_priv.h"
-# if defined(GC_PTHREADS) || defined(GC_SOLARIS_THREADS)
+# if (defined(GC_PTHREADS) && !defined(GC_DARWIN_THREADS)) \
+ || defined(GC_SOLARIS_THREADS)
# if defined(dlopen) && !defined(GC_USE_LD_WRAP)
/* To support various threads pkgs, gc.h interposes on dlopen by */
@@ -44,19 +46,14 @@
/* calls in either a multithreaded environment, or if the library */
/* initialization code allocates substantial amounts of GC'ed memory. */
/* But I don't know of a better solution. */
- /* This can still deadlock if the client explicitly starts a GC */
- /* during the dlopen. He shouldn't do that. */
- static GC_bool disable_gc_for_dlopen()
+ static void disable_gc_for_dlopen()
{
- GC_bool result;
LOCK();
- result = GC_dont_gc;
while (GC_incremental && GC_collection_in_progress()) {
GC_collect_a_little_inner(1000);
}
- GC_dont_gc = TRUE;
+ ++GC_dont_gc;
UNLOCK();
- return(result);
}
/* Redefine dlopen to guarantee mutual exclusion with */
@@ -74,10 +71,9 @@
#endif
{
void * result;
- GC_bool dont_gc_save;
# ifndef USE_PROC_FOR_LIBRARIES
- dont_gc_save = disable_gc_for_dlopen();
+ disable_gc_for_dlopen();
# endif
# ifdef GC_USE_LD_WRAP
result = (void *)__real_dlopen(path, mode);
@@ -85,7 +81,7 @@
result = dlopen(path, mode);
# endif
# ifndef USE_PROC_FOR_LIBRARIES
- GC_dont_gc = dont_gc_save;
+ GC_enable(); /* undoes disable_gc_for_dlopen */
# endif
return(result);
}
diff --git a/boehm-gc/gcj_mlc.c b/boehm-gc/gcj_mlc.c
index 89f0d728a57..a10a66f926e 100644
--- a/boehm-gc/gcj_mlc.c
+++ b/boehm-gc/gcj_mlc.c
@@ -157,6 +157,7 @@ DCL_LOCK_STATE;
GC_words_allocd += lw;
}
*(void **)op = ptr_to_struct_containing_descr;
+ GC_ASSERT(((void **)op)[1] == 0);
UNLOCK();
} else {
LOCK();
diff --git a/boehm-gc/if_mach.c b/boehm-gc/if_mach.c
index fd6009e1c35..3dcccf21f5a 100644
--- a/boehm-gc/if_mach.c
+++ b/boehm-gc/if_mach.c
@@ -14,7 +14,7 @@ char ** envp;
if (strcmp(MACH_TYPE, argv[1]) != 0) return(0);
if (strcmp(OS_TYPE, "") != 0 && strcmp(argv[2], "") != 0
&& strcmp(OS_TYPE, argv[2]) != 0) return(0);
- printf("^^^^Starting command^^^^\n");
+ fprintf(stderr, "^^^^Starting command^^^^\n");
fflush(stdout);
execvp(argv[3], argv+3);
perror("Couldn't execute");
diff --git a/boehm-gc/include/Makefile.in b/boehm-gc/include/Makefile.in
index 65bd34e2e33..94ece1a258a 100644
--- a/boehm-gc/include/Makefile.in
+++ b/boehm-gc/include/Makefile.in
@@ -1,6 +1,6 @@
-# Makefile.in generated automatically by automake 1.4 from Makefile.am
+# Makefile.in generated automatically by automake 1.4-p5 from Makefile.am
-# Copyright (C) 1994, 1995-8, 1999 Free Software Foundation, Inc.
+# Copyright (C) 1994, 1995-8, 1999, 2001 Free Software Foundation, Inc.
# This Makefile.in is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
# with or without modifications, as long as this notice is preserved.
@@ -66,9 +66,11 @@ target_triplet = @target@
AR = @AR@
AS = @AS@
CC = @CC@
+CFLAGS = @CFLAGS@
CPP = @CPP@
CXX = @CXX@
CXXCPP = @CXXCPP@
+CXXFLAGS = @CXXFLAGS@
CXXINCLUDES = @CXXINCLUDES@
DLLTOOL = @DLLTOOL@
EXEEXT = @EXEEXT@
@@ -89,10 +91,15 @@ RANLIB = @RANLIB@
STRIP = @STRIP@
THREADLIBS = @THREADLIBS@
VERSION = @VERSION@
+addincludes = @addincludes@
+addlibs = @addlibs@
addobjs = @addobjs@
+addtests = @addtests@
gc_basedir = @gc_basedir@
mkinstalldirs = @mkinstalldirs@
target_all = @target_all@
+toolexecdir = @toolexecdir@
+toolexeclibdir = @toolexeclibdir@
AUTOMAKE_OPTIONS = foreign
diff --git a/boehm-gc/include/gc.h b/boehm-gc/include/gc.h
index 69075b0669e..d49cd9d60b1 100644
--- a/boehm-gc/include/gc.h
+++ b/boehm-gc/include/gc.h
@@ -30,91 +30,7 @@
# define _GC_H
-/*
- * Some tests for old macros. These violate our namespace rules and will
- * disappear shortly. Use the GC_ names.
- */
-#if defined(SOLARIS_THREADS) || defined(_SOLARIS_THREADS)
-# define GC_SOLARIS_THREADS
-#endif
-#if defined(_SOLARIS_PTHREADS)
-# define GC_SOLARIS_PTHREADS
-#endif
-#if defined(IRIX_THREADS)
-# define GC_IRIX_THREADS
-#endif
-#if defined(HPUX_THREADS)
-# define GC_HPUX_THREADS
-#endif
-#if defined(OSF1_THREADS)
-# define GC_OSF1_THREADS
-#endif
-#if defined(LINUX_THREADS)
-# define GC_LINUX_THREADS
-#endif
-#if defined(WIN32_THREADS)
-# define GC_WIN32_THREADS
-#endif
-#if defined(USE_LD_WRAP)
-# define GC_USE_LD_WRAP
-#endif
-
-#if !defined(_REENTRANT) && (defined(GC_SOLARIS_THREADS) \
- || defined(GC_SOLARIS_PTHREADS) \
- || defined(GC_HPUX_THREADS) \
- || defined(GC_LINUX_THREADS))
-# define _REENTRANT
- /* Better late than never. This fails if system headers that */
- /* depend on this were previously included. */
-#endif
-
-#if defined(GC_SOLARIS_PTHREADS) && !defined(GC_SOLARIS_THREADS)
-# define GC_SOLARIS_THREADS
-#endif
-
-# if defined(GC_SOLARIS_PTHREADS) || defined(GC_FREEBSD_THREADS) || \
- defined(GC_IRIX_THREADS) || defined(GC_LINUX_THREADS) || \
- defined(GC_HPUX_THREADS) || defined(GC_OSF1_THREADS)
-# define GC_PTHREADS
-# endif
-
-# define __GC
-# include <stddef.h>
-# ifdef _WIN32_WCE
-/* Yet more kluges for WinCE */
-# include <stdlib.h> /* size_t is defined here */
- typedef long ptrdiff_t; /* ptrdiff_t is not defined */
-# endif
-
-#if defined(__MINGW32__) &&defined(_DLL) && !defined(GC_NOT_DLL)
-# ifdef GC_BUILD
-# define GC_API __declspec(dllexport)
-# else
-# define GC_API __declspec(dllimport)
-# endif
-#endif
-
-#if (defined(__DMC__) || defined(_MSC_VER)) \
- && (defined(_DLL) && !defined(GC_NOT_DLL) \
- || defined(GC_DLL))
-# ifdef GC_BUILD
-# define GC_API extern __declspec(dllexport)
-# else
-# define GC_API __declspec(dllimport)
-# endif
-#endif
-
-#if defined(__WATCOMC__) && defined(GC_DLL)
-# ifdef GC_BUILD
-# define GC_API extern __declspec(dllexport)
-# else
-# define GC_API extern __declspec(dllimport)
-# endif
-#endif
-
-#ifndef GC_API
-#define GC_API extern
-#endif
+# include "gc_config_macros.h"
# if defined(__STDC__) || defined(__cplusplus)
# define GC_PROTO(args) args
@@ -154,7 +70,7 @@ GC_API int GC_parallel; /* GC is parallelized for performance on */
/* Env variable GC_NPROC is set to > 1, or */
/* GC_NPROC is not set and this is an MP. */
/* If GC_parallel is set, incremental */
- /* collection is aonly partially functional, */
+ /* collection is only partially functional, */
/* and may not be desirable. */
@@ -215,8 +131,14 @@ GC_API void (* GC_finalizer_notifier)();
/* thread, which will call GC_invoke_finalizers */
/* in response. */
-GC_API int GC_dont_gc; /* Dont collect unless explicitly requested, e.g. */
- /* because it's not safe. */
+GC_API int GC_dont_gc; /* != 0 ==> Dont collect. In versions 6.2a1+, */
+ /* this overrides explicit GC_gcollect() calls. */
+ /* Used as a counter, so that nested enabling */
+ /* and disabling work correctly. Should */
+ /* normally be updated with GC_enable() and */
+ /* GC_disable() calls. */
+ /* Direct assignment to GC_dont_gc is */
+ /* deprecated. */
GC_API int GC_dont_expand;
/* Dont expand heap unless explicitly requested */
@@ -316,9 +238,18 @@ GC_API unsigned long GC_time_limit;
/* enabled. */
# define GC_TIME_UNLIMITED 999999
/* Setting GC_time_limit to this value */
- /* will disable the "pause time exceeded */
+ /* will disable the "pause time exceeded"*/
/* tests. */
+/* Public procedures */
+
+/* Initialize the collector. This is only required when using thread-local
+ * allocation, since unlike the regular allocation routines, GC_local_malloc
+ * is not self-initializing. If you use GC_local_malloc you should arrange
+ * to call this somehow (e.g. from a constructor) before doing any allocation.
+ */
+GC_API void GC_init GC_PROTO((void));
+
/*
* general purpose allocation routines, with roughly malloc calling conv.
* The atomic versions promise that no relevant pointers are contained
@@ -419,17 +350,21 @@ GC_API void GC_clear_roots GC_PROTO((void));
GC_API void GC_add_roots GC_PROTO((char * low_address,
char * high_address_plus_1));
+/* Remove a root segment. Wizards only. */
+GC_API void GC_remove_roots GC_PROTO((char * low_address,
+ char * high_address_plus_1));
+
/* Add a displacement to the set of those considered valid by the */
/* collector. GC_register_displacement(n) means that if p was returned */
/* by GC_malloc, then (char *)p + n will be considered to be a valid */
-/* pointer to n. N must be small and less than the size of p. */
+/* pointer to p. N must be small and less than the size of p. */
/* (All pointers to the interior of objects from the stack are */
/* considered valid in any case. This applies to heap objects and */
/* static data.) */
/* Preferably, this should be called before any other GC procedures. */
/* Calling it later adds to the probability of excess memory */
/* retention. */
-/* This is a no-op if the collector was compiled with recognition of */
+/* This is a no-op if the collector has recognition of */
/* arbitrary interior pointers enabled, which is now the default. */
GC_API void GC_register_displacement GC_PROTO((GC_word n));
@@ -464,9 +399,18 @@ GC_API size_t GC_get_free_bytes GC_PROTO((void));
GC_API size_t GC_get_bytes_since_gc GC_PROTO((void));
/* Return the total number of bytes allocated in this process. */
-/* Never decreases. */
+/* Never decreases, except due to wrapping. */
GC_API size_t GC_get_total_bytes GC_PROTO((void));
+/* Disable garbage collection. Even GC_gcollect calls will be */
+/* ineffective. */
+GC_API void GC_disable GC_PROTO((void));
+
+/* Reenable garbage collection. GC_disable() and GC_enable() calls */
+/* nest. Garbage collection is enabled if the number of calls to both */
+/* both functions is equal. */
+GC_API void GC_enable GC_PROTO((void));
+
/* Enable incremental/generational collection. */
/* Not advisable unless dirty bits are */
/* available or most heap objects are */
@@ -474,7 +418,11 @@ GC_API size_t GC_get_total_bytes GC_PROTO((void));
/* Don't use in leak finding mode. */
/* Ignored if GC_dont_gc is true. */
/* Only the generational piece of this is */
-/* functional if GC_parallel is TRUE. */
+/* functional if GC_parallel is TRUE */
+/* or if GC_time_limit is GC_TIME_UNLIMITED. */
+/* Causes GC_local_gcj_malloc() to revert to */
+/* locked allocation. Must be called */
+/* before any GC_local_gcj_malloc() calls. */
GC_API void GC_enable_incremental GC_PROTO((void));
/* Does incremental mode write-protect pages? Returns zero or */
@@ -518,6 +466,42 @@ GC_API GC_PTR GC_malloc_atomic_ignore_off_page GC_PROTO((size_t lb));
# define GC_RETURN_ADDR (GC_word)__return_address
#endif
+#ifdef __linux__
+# include <features.h>
+# if (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 1 || __GLIBC__ > 2) \
+ && !defined(__ia64__)
+# define GC_HAVE_BUILTIN_BACKTRACE
+# define GC_CAN_SAVE_CALL_STACKS
+# endif
+# if defined(__i386__) || defined(__x86_64__)
+# define GC_CAN_SAVE_CALL_STACKS
+# endif
+#endif
+
+#if defined(__sparc__)
+# define GC_CAN_SAVE_CALL_STACKS
+#endif
+
+/* If we're on an a platform on which we can't save call stacks, but */
+/* gcc is normally used, we go ahead and define GC_ADD_CALLER. */
+/* We make this decision independent of whether gcc is actually being */
+/* used, in order to keep the interface consistent, and allow mixing */
+/* of compilers. */
+/* This may also be desirable if it is possible but expensive to */
+/* retrieve the call chain. */
+#if (defined(__linux__) || defined(__NetBSD__) || defined(__OpenBSD__) \
+ || defined(__FreeBSD__)) & !defined(GC_CAN_SAVE_CALL_STACKS)
+# define GC_ADD_CALLER
+# if __GNUC__ >= 3 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 95)
+ /* gcc knows how to retrieve return address, but we don't know */
+ /* how to generate call stacks. */
+# define GC_RETURN_ADDR (GC_word)__builtin_return_address(0)
+# else
+ /* Just pass 0 for gcc compatibility. */
+# define GC_RETURN_ADDR 0
+# endif
+#endif
+
#ifdef GC_ADD_CALLER
# define GC_EXTRAS GC_RETURN_ADDR, __FILE__, __LINE__
# define GC_EXTRA_PARAMS GC_word ra, GC_CONST char * s, int i
@@ -536,18 +520,42 @@ GC_API GC_PTR GC_debug_malloc_uncollectable
GC_PROTO((size_t size_in_bytes, GC_EXTRA_PARAMS));
GC_API GC_PTR GC_debug_malloc_stubborn
GC_PROTO((size_t size_in_bytes, GC_EXTRA_PARAMS));
+GC_API GC_PTR GC_debug_malloc_ignore_off_page
+ GC_PROTO((size_t size_in_bytes, GC_EXTRA_PARAMS));
+GC_API GC_PTR GC_debug_malloc_atomic_ignore_off_page
+ GC_PROTO((size_t size_in_bytes, GC_EXTRA_PARAMS));
GC_API void GC_debug_free GC_PROTO((GC_PTR object_addr));
GC_API GC_PTR GC_debug_realloc
GC_PROTO((GC_PTR old_object, size_t new_size_in_bytes,
GC_EXTRA_PARAMS));
-
GC_API void GC_debug_change_stubborn GC_PROTO((GC_PTR));
GC_API void GC_debug_end_stubborn_change GC_PROTO((GC_PTR));
+
+/* Routines that allocate objects with debug information (like the */
+/* above), but just fill in dummy file and line number information. */
+/* Thus they can serve as drop-in malloc/realloc replacements. This */
+/* can be useful for two reasons: */
+/* 1) It allows the collector to be built with DBG_HDRS_ALL defined */
+/* even if some allocation calls come from 3rd party libraries */
+/* that can't be recompiled. */
+/* 2) On some platforms, the file and line information is redundant, */
+/* since it can be reconstructed from a stack trace. On such */
+/* platforms it may be more convenient not to recompile, e.g. for */
+/* leak detection. This can be accomplished by instructing the */
+/* linker to replace malloc/realloc with these. */
+GC_API GC_PTR GC_debug_malloc_replacement GC_PROTO((size_t size_in_bytes));
+GC_API GC_PTR GC_debug_realloc_replacement
+ GC_PROTO((GC_PTR object_addr, size_t size_in_bytes));
+
# ifdef GC_DEBUG
# define GC_MALLOC(sz) GC_debug_malloc(sz, GC_EXTRAS)
# define GC_MALLOC_ATOMIC(sz) GC_debug_malloc_atomic(sz, GC_EXTRAS)
-# define GC_MALLOC_UNCOLLECTABLE(sz) GC_debug_malloc_uncollectable(sz, \
- GC_EXTRAS)
+# define GC_MALLOC_UNCOLLECTABLE(sz) \
+ GC_debug_malloc_uncollectable(sz, GC_EXTRAS)
+# define GC_MALLOC_IGNORE_OFF_PAGE(sz) \
+ GC_debug_malloc_ignore_off_page(sz, GC_EXTRAS)
+# define GC_MALLOC_ATOMIC_IGNORE_OFF_PAGE(sz) \
+ GC_debug_malloc_atomic_ignore_off_page(sz, GC_EXTRAS)
# define GC_REALLOC(old, sz) GC_debug_realloc(old, sz, GC_EXTRAS)
# define GC_FREE(p) GC_debug_free(p)
# define GC_REGISTER_FINALIZER(p, f, d, of, od) \
@@ -566,6 +574,10 @@ GC_API void GC_debug_end_stubborn_change GC_PROTO((GC_PTR));
# define GC_MALLOC(sz) GC_malloc(sz)
# define GC_MALLOC_ATOMIC(sz) GC_malloc_atomic(sz)
# define GC_MALLOC_UNCOLLECTABLE(sz) GC_malloc_uncollectable(sz)
+# define GC_MALLOC_IGNORE_OFF_PAGE(sz) \
+ GC_malloc_ignore_off_page(sz)
+# define GC_MALLOC_ATOMIC_IGNORE_OFF_PAGE(sz) \
+ GC_malloc_atomic_ignore_off_page(sz)
# define GC_REALLOC(old, sz) GC_realloc(old, sz)
# define GC_FREE(p) GC_free(p)
# define GC_REGISTER_FINALIZER(p, f, d, of, od) \
@@ -644,7 +656,8 @@ GC_API void GC_debug_register_finalizer
/* itself. There is a stylistic argument that this is wrong, */
/* but it's unavoidable for C++, since the compiler may */
/* silently introduce these. It's also benign in that specific */
-/* case. */
+/* case. And it helps if finalizable objects are split to */
+/* avoid cycles. */
/* Note that cd will still be viewed as accessible, even if it */
/* refers to the object itself. */
GC_API void GC_register_finalizer_ignore_self
@@ -717,11 +730,6 @@ GC_API int GC_unregister_disappearing_link GC_PROTO((GC_PTR * /* link */));
/* Undoes a registration by either of the above two */
/* routines. */
-/* Auxiliary fns to make finalization work correctly with displaced */
-/* pointers introduced by the debugging allocators. */
-GC_API GC_PTR GC_make_closure GC_PROTO((GC_finalization_proc fn, GC_PTR data));
-GC_API void GC_debug_invoke_finalizer GC_PROTO((GC_PTR obj, GC_PTR data));
-
/* Returns !=0 if GC_invoke_finalizers has something to do. */
GC_API int GC_should_invoke_finalizers GC_PROTO((void));
@@ -738,6 +746,10 @@ GC_API int GC_invoke_finalizers GC_PROTO((void));
typedef void (*GC_warn_proc) GC_PROTO((char *msg, GC_word arg));
GC_API GC_warn_proc GC_set_warn_proc GC_PROTO((GC_warn_proc p));
/* Returns old warning procedure. */
+
+GC_API GC_word GC_set_free_space_divisor GC_PROTO((GC_word value));
+ /* Set free_space_divisor. See above for definition. */
+ /* Returns old value. */
/* The following is intended to be used by a higher level */
/* (e.g. Java-like) finalization facility. It is expected */
@@ -873,14 +885,17 @@ extern void GC_thr_init(); /* Needed for Solaris/X86 */
#endif /* THREADS && !SRC_M3 */
-#if defined(GC_WIN32_THREADS)
+#if defined(GC_WIN32_THREADS) && !defined(__CYGWIN32__) && !defined(__CYGWIN__)
# include <windows.h>
/*
* All threads must be created using GC_CreateThread, so that they will be
- * recorded in the thread table.
+ * recorded in the thread table. For backwards compatibility, this is not
+ * technically true if the GC is built as a dynamic library, since it can
+ * and does then use DllMain to keep track of thread creations. But new code
+ * should be built to call GC_CreateThread.
*/
- HANDLE WINAPI GC_CreateThread(
+ GC_API HANDLE GC_CreateThread(
LPSECURITY_ATTRIBUTES lpThreadAttributes,
DWORD dwStackSize, LPTHREAD_START_ROUTINE lpStartAddress,
LPVOID lpParameter, DWORD dwCreationFlags, LPDWORD lpThreadId );
@@ -902,7 +917,7 @@ extern void GC_thr_init(); /* Needed for Solaris/X86 */
# endif
# endif /* defined(_WIN32_WCE) */
-#endif /* defined(GC_WIN32_THREADS) */
+#endif /* defined(GC_WIN32_THREADS) && !cygwin */
/*
* If you are planning on putting
@@ -914,13 +929,18 @@ extern void GC_thr_init(); /* Needed for Solaris/X86 */
# define GC_INIT() { extern end, etext; \
GC_noop(&end, &etext); }
#else
-# if (defined(__CYGWIN32__) && defined(GC_USE_DLL)) || defined (_AIX)
+# if defined(__CYGWIN32__) && defined(GC_DLL) || defined (_AIX)
/*
- * Similarly gnu-win32 DLLs need explicit initialization
+ * Similarly gnu-win32 DLLs need explicit initialization from
+ * the main program, as does AIX.
*/
# define GC_INIT() { GC_add_roots(DATASTART, DATAEND); }
# else
+# if defined(__APPLE__) && defined(__MACH__)
+# define GC_INIT() { GC_init(); }
+# else
# define GC_INIT()
+# endif
# endif
#endif
diff --git a/boehm-gc/include/gc_cpp.h b/boehm-gc/include/gc_cpp.h
index ceb73f50a65..d789a3731e3 100644
--- a/boehm-gc/include/gc_cpp.h
+++ b/boehm-gc/include/gc_cpp.h
@@ -134,7 +134,9 @@ by UseGC. GC is an alias for UseGC, unless GC_NAME_CONFLICT is defined.
#include "gc.h"
#ifndef THINK_CPLUS
-#define _cdecl
+# define GC_cdecl
+#else
+# define GC_cdecl _cdecl
#endif
#if ! defined( GC_NO_OPERATOR_NEW_ARRAY ) \
@@ -159,12 +161,22 @@ enum GCPlacement {UseGC,
class gc {public:
inline void* operator new( size_t size );
inline void* operator new( size_t size, GCPlacement gcp );
+ inline void* operator new( size_t size, void *p );
+ /* Must be redefined here, since the other overloadings */
+ /* hide the global definition. */
inline void operator delete( void* obj );
+# ifndef __BORLANDC__ /* Confuses the Borland compiler. */
+ inline void operator delete( void*, void* );
+# endif
#ifdef GC_OPERATOR_NEW_ARRAY
inline void* operator new[]( size_t size );
inline void* operator new[]( size_t size, GCPlacement gcp );
+ inline void* operator new[]( size_t size, void *p );
inline void operator delete[]( void* obj );
+# ifndef __BORLANDC__
+ inline void gc::operator delete[]( void*, void* );
+# endif
#endif /* GC_OPERATOR_NEW_ARRAY */
};
/*
@@ -176,7 +188,7 @@ class gc_cleanup: virtual public gc {public:
inline gc_cleanup();
inline virtual ~gc_cleanup();
private:
- inline static void _cdecl cleanup( void* obj, void* clientData );};
+ inline static void GC_cdecl cleanup( void* obj, void* clientData );};
/*
Instances of classes derived from "gc_cleanup" will be allocated
in the collected heap by default. When the collector discovers an
@@ -211,7 +223,6 @@ inline void* operator new(
classes derived from "gc_cleanup" or containing members derived
from "gc_cleanup". */
-#ifdef GC_OPERATOR_NEW_ARRAY
#ifdef _MSC_VER
/** This ensures that the system default operator new[] doesn't get
@@ -220,42 +231,24 @@ inline void* operator new(
* There seems to be really redirect new in this environment without
* including this everywhere.
*/
- inline void *operator new[]( size_t size )
- {
- return GC_MALLOC_UNCOLLECTABLE( size );
- }
-
- inline void operator delete[](void* obj)
- {
- GC_FREE(obj);
- };
-
- inline void* operator new( size_t size)
- {
- return GC_MALLOC_UNCOLLECTABLE( size);
- };
+ void *operator new[]( size_t size );
+
+ void operator delete[](void* obj);
- inline void operator delete(void* obj)
- {
- GC_FREE(obj);
- };
+ void* operator new( size_t size);
+ void operator delete(void* obj);
-// This new operator is used by VC++ in case of Debug builds !
- inline void* operator new( size_t size,
+ // This new operator is used by VC++ in case of Debug builds !
+ void* operator new( size_t size,
int ,//nBlockUse,
const char * szFileName,
- int nLine
- ) {
-# ifndef GC_DEBUG
- return GC_malloc_uncollectable( size );
-# else
- return GC_debug_malloc_uncollectable(size, szFileName, nLine);
-# endif
- }
-
+ int nLine );
#endif /* _MSC_VER */
+
+#ifdef GC_OPERATOR_NEW_ARRAY
+
inline void* operator new[](
size_t size,
GCPlacement gcp,
@@ -283,9 +276,15 @@ inline void* gc::operator new( size_t size, GCPlacement gcp ) {
else
return GC_MALLOC_UNCOLLECTABLE( size );}
+inline void* gc::operator new( size_t size, void *p ) {
+ return p;}
+
inline void gc::operator delete( void* obj ) {
GC_FREE( obj );}
+#ifndef __BORLANDC__
+ inline void gc::operator delete( void*, void* ) {}
+#endif
#ifdef GC_OPERATOR_NEW_ARRAY
@@ -295,14 +294,21 @@ inline void* gc::operator new[]( size_t size ) {
inline void* gc::operator new[]( size_t size, GCPlacement gcp ) {
return gc::operator new( size, gcp );}
+inline void* gc::operator new[]( size_t size, void *p ) {
+ return p;}
+
inline void gc::operator delete[]( void* obj ) {
gc::operator delete( obj );}
+
+#ifndef __BORLANDC__
+ inline void gc::operator delete[]( void*, void* ) {}
+#endif
#endif /* GC_OPERATOR_NEW_ARRAY */
inline gc_cleanup::~gc_cleanup() {
- GC_REGISTER_FINALIZER_IGNORE_SELF( GC_base(this), 0, 0, 0, 0 );}
+ GC_register_finalizer_ignore_self( GC_base(this), 0, 0, 0, 0 );}
inline void gc_cleanup::cleanup( void* obj, void* displ ) {
((gc_cleanup*) ((char*) obj + (ptrdiff_t) displ))->~gc_cleanup();}
diff --git a/boehm-gc/include/gc_local_alloc.h b/boehm-gc/include/gc_local_alloc.h
index 1e58730cfe8..88e29e9a11f 100644
--- a/boehm-gc/include/gc_local_alloc.h
+++ b/boehm-gc/include/gc_local_alloc.h
@@ -33,6 +33,9 @@
* -DTHREAD_LOCAL_ALLOC, which is currently supported only on Linux.
*
* The debugging allocators use standard, not thread-local allocation.
+ *
+ * These routines normally require an explicit call to GC_init(), though
+ * that may be done from a constructor function.
*/
#ifndef GC_LOCAL_ALLOC_H
diff --git a/boehm-gc/include/gc_mark.h b/boehm-gc/include/gc_mark.h
index 0856d16fdae..9ddba2ca527 100644
--- a/boehm-gc/include/gc_mark.h
+++ b/boehm-gc/include/gc_mark.h
@@ -129,7 +129,9 @@ extern GC_PTR GC_greatest_plausible_heap_addr;
/* be reserved for exceptional cases. That will ensure that */
/* performance of this call is not extremely performance critical. */
/* (Otherwise we would need to inline GC_mark_and_push completely, */
-/* which would tie the client code to a fixed colllector version.) */
+/* which would tie the client code to a fixed collector version.) */
+/* Note that mark procedures should explicitly call FIXUP_POINTER() */
+/* if required. */
struct GC_ms_entry *GC_mark_and_push
GC_PROTO((GC_PTR obj,
struct GC_ms_entry * mark_stack_ptr,
diff --git a/boehm-gc/include/gc_pthread_redirects.h b/boehm-gc/include/gc_pthread_redirects.h
index 47284fbc97a..842518cfcc4 100644
--- a/boehm-gc/include/gc_pthread_redirects.h
+++ b/boehm-gc/include/gc_pthread_redirects.h
@@ -52,15 +52,30 @@
int GC_pthread_create(pthread_t *new_thread,
const pthread_attr_t *attr,
void *(*start_routine)(void *), void *arg);
+#ifndef GC_DARWIN_THREADS
int GC_pthread_sigmask(int how, const sigset_t *set, sigset_t *oset);
+#endif
int GC_pthread_join(pthread_t thread, void **retval);
int GC_pthread_detach(pthread_t thread);
+#if defined(GC_OSF1_THREADS) \
+ && defined(_PTHREAD_USE_MANGLED_NAMES_) && !defined(_PTHREAD_USE_PTDNAM_)
+/* Unless the compiler supports #pragma extern_prefix, the Tru64 UNIX
+ <pthread.h> redefines some POSIX thread functions to use mangled names.
+ If so, undef them before redefining. */
+# undef pthread_create
+# undef pthread_join
+# undef pthread_detach
+#endif
+
# define pthread_create GC_pthread_create
-# define pthread_sigmask GC_pthread_sigmask
# define pthread_join GC_pthread_join
# define pthread_detach GC_pthread_detach
+
+#ifndef GC_DARWIN_THREADS
+# define pthread_sigmask GC_pthread_sigmask
# define dlopen GC_dlopen
+#endif
#endif /* GC_xxxxx_THREADS */
diff --git a/boehm-gc/include/gc_typed.h b/boehm-gc/include/gc_typed.h
index 2e0598f204c..905734b8da0 100644
--- a/boehm-gc/include/gc_typed.h
+++ b/boehm-gc/include/gc_typed.h
@@ -29,14 +29,21 @@
# include "gc.h"
# endif
+#ifdef __cplusplus
+ extern "C" {
+#endif
typedef GC_word * GC_bitmap;
/* The least significant bit of the first word is one if */
/* the first word in the object may be a pointer. */
+# define GC_WORDSZ (8*sizeof(GC_word))
# define GC_get_bit(bm, index) \
- (((bm)[divWORDSZ(index)] >> modWORDSZ(index)) & 1)
+ (((bm)[index/GC_WORDSZ] >> (index%GC_WORDSZ)) & 1)
# define GC_set_bit(bm, index) \
- (bm)[divWORDSZ(index)] |= (word)1 << modWORDSZ(index)
+ (bm)[index/GC_WORDSZ] |= ((GC_word)1 << (index%GC_WORDSZ))
+# define GC_WORD_OFFSET(t, f) (offsetof(t,f)/sizeof(GC_word))
+# define GC_WORD_LEN(t) (sizeof(t)/ sizeof(GC_word))
+# define GC_BITMAP_SIZE(t) ((GC_WORD_LEN(t) + GC_WORDSZ-1)/GC_WORDSZ)
typedef GC_word GC_descr;
@@ -57,6 +64,16 @@ GC_API GC_descr GC_make_descriptor GC_PROTO((GC_bitmap bm, size_t len));
/* is intended to be called once per type, not once */
/* per allocation. */
+/* It is possible to generate a descriptor for a C type T with */
+/* word aligned pointer fields f1, f2, ... as follows: */
+/* */
+/* GC_descr T_descr; */
+/* GC_word T_bitmap[GC_BITMAP_SIZE(T)] = {0}; */
+/* GC_set_bit(T_bitmap, GC_WORD_OFFSET(T,f1)); */
+/* GC_set_bit(T_bitmap, GC_WORD_OFFSET(T,f2)); */
+/* ... */
+/* T_descr = GC_make_descriptor(T_bitmap, GC_WORD_LEN(T)); */
+
GC_API GC_PTR GC_malloc_explicitly_typed
GC_PROTO((size_t size_in_bytes, GC_descr d));
/* Allocate an object whose layout is described by d. */
@@ -79,15 +96,18 @@ GC_API GC_PTR GC_calloc_explicitly_typed
/* Returned object is cleared. */
#ifdef GC_DEBUG
-# define GC_MALLOC_EXPLICTLY_TYPED(bytes, d) GC_MALLOC(bytes)
-# define GC_CALLOC_EXPLICTLY_TYPED(n, bytes, d) GC_MALLOC(n*bytes)
+# define GC_MALLOC_EXPLICITLY_TYPED(bytes, d) GC_MALLOC(bytes)
+# define GC_CALLOC_EXPLICITLY_TYPED(n, bytes, d) GC_MALLOC(n*bytes)
#else
-# define GC_MALLOC_EXPLICTLY_TYPED(bytes, d) \
+# define GC_MALLOC_EXPLICITLY_TYPED(bytes, d) \
GC_malloc_explicitly_typed(bytes, d)
-# define GC_CALLOC_EXPLICTLY_TYPED(n, bytes, d) \
+# define GC_CALLOC_EXPLICITLY_TYPED(n, bytes, d) \
GC_calloc_explicitly_typed(n, bytes, d)
#endif /* !GC_DEBUG */
+#ifdef __cplusplus
+ } /* matches extern "C" */
+#endif
#endif /* _GC_TYPED_H */
diff --git a/boehm-gc/include/new_gc_alloc.h b/boehm-gc/include/new_gc_alloc.h
index aad9446543e..20a2fabf83c 100644
--- a/boehm-gc/include/new_gc_alloc.h
+++ b/boehm-gc/include/new_gc_alloc.h
@@ -64,6 +64,14 @@
#endif
#endif
+/* A hack to deal with gcc 3.1. If you are using gcc3.1 and later, */
+/* you should probably really use gc_allocator.h instead. */
+#if defined (__GNUC__) && \
+ (__GNUC > 3 || (__GNUC__ == 3 && (__GNUC_MINOR__ >= 1)))
+# define simple_alloc __simple_alloc
+#endif
+
+
#define GC_ALLOC_H
diff --git a/boehm-gc/include/private/dbg_mlc.h b/boehm-gc/include/private/dbg_mlc.h
index 5378835811c..e2003e6c44f 100644
--- a/boehm-gc/include/private/dbg_mlc.h
+++ b/boehm-gc/include/private/dbg_mlc.h
@@ -115,16 +115,24 @@ typedef struct {
#ifdef SHORT_DBG_HDRS
# define DEBUG_BYTES (sizeof (oh))
+# define UNCOLLECTABLE_DEBUG_BYTES DEBUG_BYTES
#else
/* Add space for END_FLAG, but use any extra space that was already */
/* added to catch off-the-end pointers. */
-# define DEBUG_BYTES (sizeof (oh) + sizeof (word) - EXTRA_BYTES)
+ /* For uncollectable objects, the extra byte is not added. */
+# define UNCOLLECTABLE_DEBUG_BYTES (sizeof (oh) + sizeof (word))
+# define DEBUG_BYTES (UNCOLLECTABLE_DEBUG_BYTES - EXTRA_BYTES)
#endif
#define USR_PTR_FROM_BASE(p) ((ptr_t)(p) + sizeof(oh))
/* Round bytes to words without adding extra byte at end. */
#define SIMPLE_ROUNDED_UP_WORDS(n) BYTES_TO_WORDS((n) + WORDS_TO_BYTES(1) - 1)
+/* ADD_CALL_CHAIN stores a (partial) call chain into an object */
+/* header. It may be called with or without the allocation */
+/* lock. */
+/* PRINT_CALL_CHAIN prints the call chain stored in an object */
+/* to stderr. It requires that we do not hold the lock. */
#ifdef SAVE_CALL_CHAIN
# define ADD_CALL_CHAIN(base, ra) GC_save_callers(((oh *)(base)) -> oh_ci)
# define PRINT_CALL_CHAIN(base) GC_print_callers(((oh *)(base)) -> oh_ci)
diff --git a/boehm-gc/include/private/gc_hdrs.h b/boehm-gc/include/private/gc_hdrs.h
index dd615455f3b..96749ab1bf0 100644
--- a/boehm-gc/include/private/gc_hdrs.h
+++ b/boehm-gc/include/private/gc_hdrs.h
@@ -70,7 +70,7 @@ extern hdr * GC_invalid_header; /* header for an imaginary block */
#define ADVANCE(p, hhdr, source) \
{ \
hdr * new_hdr = GC_invalid_header; \
- p = GC_FIND_START(p, hhdr, &new_hdr, (word)source); \
+ p = GC_find_start(p, hhdr, &new_hdr); \
hhdr = new_hdr; \
}
diff --git a/boehm-gc/include/private/gc_locks.h b/boehm-gc/include/private/gc_locks.h
index 9b91ada917a..775176b3151 100644
--- a/boehm-gc/include/private/gc_locks.h
+++ b/boehm-gc/include/private/gc_locks.h
@@ -141,23 +141,24 @@
# if defined(POWERPC)
inline static int GC_test_and_set(volatile unsigned int *addr) {
int oldval;
- int temp = 1; // locked value
+ int temp = 1; /* locked value */
__asm__ __volatile__(
- "1:\tlwarx %0,0,%3\n" // load and reserve
- "\tcmpwi %0, 0\n" // if load is
- "\tbne 2f\n" // non-zero, return already set
- "\tstwcx. %2,0,%1\n" // else store conditional
- "\tbne- 1b\n" // retry if lost reservation
- "2:\t\n" // oldval is zero if we set
+ "1:\tlwarx %0,0,%3\n" /* load and reserve */
+ "\tcmpwi %0, 0\n" /* if load is */
+ "\tbne 2f\n" /* non-zero, return already set */
+ "\tstwcx. %2,0,%1\n" /* else store conditional */
+ "\tbne- 1b\n" /* retry if lost reservation */
+ "\tsync\n" /* import barrier */
+ "2:\t\n" /* oldval is zero if we set */
: "=&r"(oldval), "=p"(addr)
: "r"(temp), "1"(addr)
- : "memory");
- return (int)oldval;
+ : "cr0","memory");
+ return oldval;
}
# define GC_TEST_AND_SET_DEFINED
inline static void GC_clear(volatile unsigned int *addr) {
- __asm__ __volatile__("eieio" ::: "memory");
+ __asm__ __volatile__("eieio" : : : "memory");
*(addr) = 0;
}
# define GC_CLEAR_DEFINED
@@ -174,12 +175,18 @@
" bne %2,2f\n"
" xor %0,%3,%0\n"
" stl_c %0,%1\n"
+# ifdef __ELF__
" beq %0,3f\n"
+# else
+ " beq %0,1b\n"
+# endif
" mb\n"
"2:\n"
+# ifdef __ELF__
".section .text2,\"ax\"\n"
"3: br 1b\n"
".previous"
+# endif
:"=&r" (temp), "=m" (*addr), "=&r" (oldvalue)
:"Ir" (1), "m" (*addr)
:"memory");
@@ -187,8 +194,11 @@
return oldvalue;
}
# define GC_TEST_AND_SET_DEFINED
- /* Should probably also define GC_clear, since it needs */
- /* a memory barrier ?? */
+ inline static void GC_clear(volatile unsigned int *addr) {
+ __asm__ __volatile__("mb" : : : "memory");
+ *(addr) = 0;
+ }
+# define GC_CLEAR_DEFINED
# endif /* ALPHA */
# ifdef ARM32
inline static int GC_test_and_set(volatile unsigned int *addr) {
@@ -206,22 +216,30 @@
# define GC_TEST_AND_SET_DEFINED
# endif /* ARM32 */
# ifdef S390
- inline static int GC_test_and_set(volatile unsigned int *addr) {
- int ret;
- __asm__ __volatile__ (
- " l %0,0(%2)\n"
- "0: cs %0,%1,0(%2)\n"
- " jl 0b"
- : "=&d" (ret)
- : "d" (1), "a" (addr)
- : "cc", "memory");
- return ret;
- }
+ inline static int GC_test_and_set(volatile unsigned int *addr) {
+ int ret;
+ __asm__ __volatile__ (
+ " l %0,0(%2)\n"
+ "0: cs %0,%1,0(%2)\n"
+ " jl 0b"
+ : "=&d" (ret)
+ : "d" (1), "a" (addr)
+ : "cc", "memory");
+ return ret;
+ }
# endif
# endif /* __GNUC__ */
# if (defined(ALPHA) && !defined(__GNUC__))
-# define GC_test_and_set(addr) __cxx_test_and_set_atomic(addr, 1)
+# ifndef OSF1
+ --> We currently assume that if gcc is not used, we are
+ --> running under Tru64.
+# endif
+# include <machine/builtins.h>
+# include <c_asm.h>
+# define GC_test_and_set(addr) __ATOMIC_EXCH_LONG(addr, 1)
# define GC_TEST_AND_SET_DEFINED
+# define GC_clear(addr) { asm("mb"); *(volatile unsigned *)addr = 0; }
+# define GC_CLEAR_DEFINED
# endif
# if defined(MSWIN32)
# define GC_test_and_set(addr) InterlockedExchange((LPLONG)addr,1)
@@ -234,14 +252,51 @@
# define GC_TEST_AND_SET_DEFINED
# elif __mips < 3 || !(defined (_ABIN32) || defined(_ABI64)) \
|| !defined(_COMPILER_VERSION) || _COMPILER_VERSION < 700
-# define GC_test_and_set(addr) test_and_set(addr, 1)
+# ifdef __GNUC__
+# define GC_test_and_set(addr) _test_and_set((void *)addr,1)
+# else
+# define GC_test_and_set(addr) test_and_set((void *)addr,1)
+# endif
# else
-# define GC_test_and_set(addr) __test_and_set(addr,1)
+# define GC_test_and_set(addr) __test_and_set32((void *)addr,1)
# define GC_clear(addr) __lock_release(addr);
# define GC_CLEAR_DEFINED
# endif
# define GC_TEST_AND_SET_DEFINED
# endif /* MIPS */
+# if defined(_AIX)
+# include <sys/atomic_op.h>
+# if (defined(_POWER) || defined(_POWERPC))
+# if defined(__GNUC__)
+ inline static void GC_memsync() {
+ __asm__ __volatile__ ("sync" : : : "memory");
+ }
+# else
+# ifndef inline
+# define inline __inline
+# endif
+# pragma mc_func GC_memsync { \
+ "7c0004ac" /* sync (same opcode used for dcs)*/ \
+ }
+# endif
+# else
+# error dont know how to memsync
+# endif
+ inline static int GC_test_and_set(volatile unsigned int * addr) {
+ int oldvalue = 0;
+ if (compare_and_swap((void *)addr, &oldvalue, 1)) {
+ GC_memsync();
+ return 0;
+ } else return 1;
+ }
+# define GC_TEST_AND_SET_DEFINED
+ inline static void GC_clear(volatile unsigned int *addr) {
+ GC_memsync();
+ *(addr) = 0;
+ }
+# define GC_CLEAR_DEFINED
+
+# endif
# if 0 /* defined(HP_PA) */
/* The official recommendation seems to be to not use ldcw from */
/* user mode. Since multithreaded incremental collection doesn't */
@@ -275,7 +330,7 @@
# endif
# if defined(GC_PTHREADS) && !defined(GC_SOLARIS_THREADS) \
- && !defined(GC_IRIX_THREADS)
+ && !defined(GC_IRIX_THREADS) && !defined(GC_WIN32_THREADS)
# define NO_THREAD (pthread_t)(-1)
# include <pthread.h>
# if defined(PARALLEL_MARK)
@@ -306,12 +361,12 @@
{
char result;
__asm__ __volatile__("lock; cmpxchgl %2, %0; setz %1"
- : "=m"(*(addr)), "=r"(result)
- : "r" (new_val), "0"(*(addr)), "a"(old) : "memory");
+ : "+m"(*(addr)), "=r"(result)
+ : "r" (new_val), "a"(old) : "memory");
return (GC_bool) result;
}
# endif /* !GENERIC_COMPARE_AND_SWAP */
- inline static void GC_memory_write_barrier()
+ inline static void GC_memory_barrier()
{
/* We believe the processor ensures at least processor */
/* consistent ordering. Thus a compiler barrier */
@@ -319,6 +374,37 @@
__asm__ __volatile__("" : : : "memory");
}
# endif /* I386 */
+
+# if defined(POWERPC)
+# if !defined(GENERIC_COMPARE_AND_SWAP)
+ /* Returns TRUE if the comparison succeeded. */
+ inline static GC_bool GC_compare_and_exchange(volatile GC_word *addr,
+ GC_word old, GC_word new_val)
+ {
+ int result, dummy;
+ __asm__ __volatile__(
+ "1:\tlwarx %0,0,%5\n"
+ "\tcmpw %0,%4\n"
+ "\tbne 2f\n"
+ "\tstwcx. %3,0,%2\n"
+ "\tbne- 1b\n"
+ "\tsync\n"
+ "\tli %1, 1\n"
+ "\tb 3f\n"
+ "2:\tli %1, 0\n"
+ "3:\t\n"
+ : "=&r" (dummy), "=r" (result), "=p" (addr)
+ : "r" (new_val), "r" (old), "2"(addr)
+ : "cr0","memory");
+ return (GC_bool) result;
+ }
+# endif /* !GENERIC_COMPARE_AND_SWAP */
+ inline static void GC_memory_barrier()
+ {
+ __asm__ __volatile__("sync" : : : "memory");
+ }
+# endif /* POWERPC */
+
# if defined(IA64)
# if !defined(GENERIC_COMPARE_AND_SWAP)
inline static GC_bool GC_compare_and_exchange(volatile GC_word *addr,
@@ -330,31 +416,71 @@
# endif /* !GENERIC_COMPARE_AND_SWAP */
# if 0
/* Shouldn't be needed; we use volatile stores instead. */
- inline static void GC_memory_write_barrier()
+ inline static void GC_memory_barrier()
{
__sync_synchronize ();
}
# endif /* 0 */
# endif /* IA64 */
+# if defined(ALPHA)
+# if !defined(GENERIC_COMPARE_AND_SWAP)
+# if defined(__GNUC__)
+ inline static GC_bool GC_compare_and_exchange(volatile GC_word *addr,
+ GC_word old, GC_word new_val)
+ {
+ unsigned long was_equal;
+ unsigned long temp;
+
+ __asm__ __volatile__(
+ "1: ldq_l %0,%1\n"
+ " cmpeq %0,%4,%2\n"
+ " mov %3,%0\n"
+ " beq %2,2f\n"
+ " stq_c %0,%1\n"
+ " beq %0,1b\n"
+ "2:\n"
+ " mb\n"
+ :"=&r" (temp), "=m" (*addr), "=&r" (was_equal)
+ : "r" (new_val), "Ir" (old)
+ :"memory");
+ return was_equal;
+ }
+# else /* !__GNUC__ */
+ inline static GC_bool GC_compare_and_exchange(volatile GC_word *addr,
+ GC_word old, GC_word new_val)
+ {
+ return __CMP_STORE_QUAD(addr, old, new_val, addr);
+ }
+# endif /* !__GNUC__ */
+# endif /* !GENERIC_COMPARE_AND_SWAP */
+# ifdef __GNUC__
+ inline static void GC_memory_barrier()
+ {
+ __asm__ __volatile__("mb" : : : "memory");
+ }
+# else
+# define GC_memory_barrier() asm("mb")
+# endif /* !__GNUC__ */
+# endif /* ALPHA */
# if defined(S390)
# if !defined(GENERIC_COMPARE_AND_SWAP)
- inline static GC_bool GC_compare_and_exchange(volatile C_word *addr,
- GC_word old, GC_word new_val)
- {
- int retval;
- __asm__ __volatile__ (
-# ifndef __s390x__
- " cs %1,%2,0(%3)\n"
-# else
- " csg %1,%2,0(%3)\n"
-# endif
- " ipm %0\n"
- " srl %0,28\n"
- : "=&d" (retval), "+d" (old)
- : "d" (new_val), "a" (addr)
- : "cc", "memory");
- return retval == 0;
- }
+ inline static GC_bool GC_compare_and_exchange(volatile C_word *addr,
+ GC_word old, GC_word new_val)
+ {
+ int retval;
+ __asm__ __volatile__ (
+# ifndef __s390x__
+ " cs %1,%2,0(%3)\n"
+# else
+ " csg %1,%2,0(%3)\n"
+# endif
+ " ipm %0\n"
+ " srl %0,28\n"
+ : "=&d" (retval), "+d" (old)
+ : "d" (new_val), "a" (addr)
+ : "cc", "memory");
+ return retval == 0;
+ }
# endif
# endif
# if !defined(GENERIC_COMPARE_AND_SWAP)
@@ -427,8 +553,12 @@
{ GC_ASSERT(I_HOLD_LOCK()); UNSET_LOCK_HOLDER(); \
pthread_mutex_unlock(&GC_allocate_ml); }
# else /* !GC_ASSERTIONS */
+# if defined(NO_PTHREAD_TRYLOCK)
+# define LOCK() GC_lock();
+# else /* !defined(NO_PTHREAD_TRYLOCK) */
# define LOCK() \
{ if (0 != pthread_mutex_trylock(&GC_allocate_ml)) GC_lock(); }
+# endif
# define UNLOCK() pthread_mutex_unlock(&GC_allocate_ml)
# endif /* !GC_ASSERTIONS */
# endif /* USE_PTHREAD_LOCKS */
@@ -450,7 +580,7 @@
/* on Irix anymore. */
# include <mutex.h>
- extern unsigned long GC_allocate_lock;
+ extern volatile unsigned int GC_allocate_lock;
/* This is not a mutex because mutexes that obey the (optional) */
/* POSIX scheduling rules are subject to convoys in high contention */
/* applications. This is basically a spin lock. */
@@ -471,11 +601,18 @@
}
# define EXIT_GC() GC_collecting = 0;
# endif /* GC_IRIX_THREADS */
-# ifdef GC_WIN32_THREADS
-# include <windows.h>
- GC_API CRITICAL_SECTION GC_allocate_ml;
-# define LOCK() EnterCriticalSection(&GC_allocate_ml);
-# define UNLOCK() LeaveCriticalSection(&GC_allocate_ml);
+# if defined(GC_WIN32_THREADS)
+# if defined(GC_PTHREADS)
+# include <pthread.h>
+ extern pthread_mutex_t GC_allocate_ml;
+# define LOCK() pthread_mutex_lock(&GC_allocate_ml)
+# define UNLOCK() pthread_mutex_unlock(&GC_allocate_ml)
+# else
+# include <windows.h>
+ GC_API CRITICAL_SECTION GC_allocate_ml;
+# define LOCK() EnterCriticalSection(&GC_allocate_ml);
+# define UNLOCK() LeaveCriticalSection(&GC_allocate_ml);
+# endif
# endif
# ifndef SET_LOCK_HOLDER
# define SET_LOCK_HOLDER()
diff --git a/boehm-gc/include/private/gc_pmark.h b/boehm-gc/include/private/gc_pmark.h
index 872065702f0..c109738203a 100644
--- a/boehm-gc/include/private/gc_pmark.h
+++ b/boehm-gc/include/private/gc_pmark.h
@@ -137,7 +137,7 @@ extern mse * GC_mark_stack;
#ifdef __STDC__
# ifdef PRINT_BLACK_LIST
ptr_t GC_find_start(ptr_t current, hdr *hhdr, hdr **new_hdr_p,
- ptr_t source);
+ word source);
# else
ptr_t GC_find_start(ptr_t current, hdr *hhdr, hdr **new_hdr_p);
# endif
@@ -145,7 +145,7 @@ extern mse * GC_mark_stack;
ptr_t GC_find_start();
#endif
-mse *GC_signal_mark_stack_overflow(mse *msp);
+mse * GC_signal_mark_stack_overflow GC_PROTO((mse *msp));
# ifdef GATHERSTATS
# define ADD_TO_ATOMIC(sz) GC_atomic_in_use += (sz)
@@ -174,14 +174,6 @@ mse *GC_signal_mark_stack_overflow(mse *msp);
} \
}
-#ifdef PRINT_BLACK_LIST
-# define GC_FIND_START(current, hhdr, new_hdr_p, source) \
- GC_find_start(current, hhdr, new_hdr_p, source)
-#else
-# define GC_FIND_START(current, hhdr, new_hdr_p, source) \
- GC_find_start(current, hhdr, new_hdr_p)
-#endif
-
/* Push the contents of current onto the mark stack if it is a valid */
/* ptr to a currently unmarked object. Mark it. */
/* If we assumed a standard-conforming compiler, we could probably */
@@ -195,8 +187,7 @@ mse *GC_signal_mark_stack_overflow(mse *msp);
GET_HDR(my_current, my_hhdr); \
if (IS_FORWARDING_ADDR_OR_NIL(my_hhdr)) { \
hdr * new_hdr = GC_invalid_header; \
- my_current = GC_FIND_START(my_current, my_hhdr, \
- &new_hdr, (word)source); \
+ my_current = GC_find_start(my_current, my_hhdr, &new_hdr); \
my_hhdr = new_hdr; \
} \
PUSH_CONTENTS_HDR(my_current, mark_stack_top, mark_stack_limit, \
@@ -290,21 +281,39 @@ exit_label: ; \
/*
* Push a single value onto mark stack. Mark from the object pointed to by p.
+ * Invoke FIXUP_POINTER(p) before any further processing.
* P is considered valid even if it is an interior pointer.
* Previously marked objects are not pushed. Hence we make progress even
* if the mark stack overflows.
*/
-# define GC_PUSH_ONE_STACK(p, source) \
- if ((ptr_t)(p) >= (ptr_t)GC_least_plausible_heap_addr \
+
+# if NEED_FIXUP_POINTER
+ /* Try both the raw version and the fixed up one. */
+# define GC_PUSH_ONE_STACK(p, source) \
+ if ((ptr_t)(p) >= (ptr_t)GC_least_plausible_heap_addr \
&& (ptr_t)(p) < (ptr_t)GC_greatest_plausible_heap_addr) { \
PUSH_ONE_CHECKED_STACK(p, source); \
- }
+ } \
+ FIXUP_POINTER(p); \
+ if ((ptr_t)(p) >= (ptr_t)GC_least_plausible_heap_addr \
+ && (ptr_t)(p) < (ptr_t)GC_greatest_plausible_heap_addr) { \
+ PUSH_ONE_CHECKED_STACK(p, source); \
+ }
+# else /* !NEED_FIXUP_POINTER */
+# define GC_PUSH_ONE_STACK(p, source) \
+ if ((ptr_t)(p) >= (ptr_t)GC_least_plausible_heap_addr \
+ && (ptr_t)(p) < (ptr_t)GC_greatest_plausible_heap_addr) { \
+ PUSH_ONE_CHECKED_STACK(p, source); \
+ }
+# endif
+
/*
* As above, but interior pointer recognition as for
* normal for heap pointers.
*/
# define GC_PUSH_ONE_HEAP(p,source) \
+ FIXUP_POINTER(p); \
if ((ptr_t)(p) >= (ptr_t)GC_least_plausible_heap_addr \
&& (ptr_t)(p) < (ptr_t)GC_greatest_plausible_heap_addr) { \
GC_mark_stack_top = GC_mark_and_push( \
diff --git a/boehm-gc/include/private/gc_priv.h b/boehm-gc/include/private/gc_priv.h
index b09c4840945..ffa398b308b 100644
--- a/boehm-gc/include/private/gc_priv.h
+++ b/boehm-gc/include/private/gc_priv.h
@@ -30,14 +30,20 @@
# define BSD_TIME
#endif
+#ifdef DGUX
+# include <sys/types.h>
+# include <sys/time.h>
+# include <sys/resource.h>
+#endif /* DGUX */
+
#ifdef BSD_TIME
# include <sys/types.h>
# include <sys/time.h>
# include <sys/resource.h>
#endif /* BSD_TIME */
-# ifndef GC_H
-# include "gc.h"
+# ifndef _GC_H
+# include "../gc.h"
# endif
# ifndef GC_MARK_H
@@ -206,11 +212,10 @@ typedef char * ptr_t; /* A generic pointer to which we can add */
#endif
#if defined(GC_GCJ_SUPPORT) && ALIGNMENT < 8 && !defined(ALIGN_DOUBLE)
- /* GCJ's Hashtable synchronization code requires 64-bit alignment. */
+ /* GCJ's Hashtable synchronization code requires 64-bit alignment. */
# define ALIGN_DOUBLE
#endif
-
/* ALIGN_DOUBLE requires MERGE_SIZES at present. */
# if defined(ALIGN_DOUBLE) && !defined(MERGE_SIZES)
# define MERGE_SIZES
@@ -347,7 +352,8 @@ void GC_print_callers GC_PROTO((struct callinfo info[NFRAMES]));
# include <string.h>
# define BCOPY_EXISTS
# endif
-# if defined(MACOSX)
+# if defined(DARWIN)
+# include <string.h>
# define BCOPY_EXISTS
# endif
@@ -360,68 +366,6 @@ void GC_print_callers GC_PROTO((struct callinfo info[NFRAMES]));
# define BZERO(x,n) bzero((char *)(x),(int)(n))
# endif
-/* HBLKSIZE aligned allocation. 0 is taken to mean failure */
-/* space is assumed to be cleared. */
-/* In the case os USE_MMAP, the argument must also be a */
-/* physical page size. */
-/* GET_MEM is currently not assumed to retrieve 0 filled space, */
-/* though we should perhaps take advantage of the case in which */
-/* does. */
-struct hblk; /* See below. */
-# ifdef PCR
- char * real_malloc();
-# define GET_MEM(bytes) HBLKPTR(real_malloc((size_t)bytes + GC_page_size) \
- + GC_page_size-1)
-# else
-# ifdef OS2
- void * os2_alloc(size_t bytes);
-# define GET_MEM(bytes) HBLKPTR((ptr_t)os2_alloc((size_t)bytes \
- + GC_page_size) \
- + GC_page_size-1)
-# else
-# if defined(NEXT) || defined(MACOSX) || defined(DOS4GW) || \
- (defined(AMIGA) && !defined(GC_AMIGA_FASTALLOC)) || \
- (defined(SUNOS5) && !defined(USE_MMAP))
-# define GET_MEM(bytes) HBLKPTR((size_t) \
- calloc(1, (size_t)bytes + GC_page_size) \
- + GC_page_size-1)
-# else
-# ifdef MSWIN32
- extern ptr_t GC_win32_get_mem();
-# define GET_MEM(bytes) (struct hblk *)GC_win32_get_mem(bytes)
-# else
-# ifdef MACOS
-# if defined(USE_TEMPORARY_MEMORY)
- extern Ptr GC_MacTemporaryNewPtr(size_t size,
- Boolean clearMemory);
-# define GET_MEM(bytes) HBLKPTR( \
- GC_MacTemporaryNewPtr(bytes + GC_page_size, true) \
- + GC_page_size-1)
-# else
-# define GET_MEM(bytes) HBLKPTR( \
- NewPtrClear(bytes + GC_page_size) + GC_page_size-1)
-# endif
-# else
-# ifdef MSWINCE
- extern ptr_t GC_wince_get_mem();
-# define GET_MEM(bytes) (struct hblk *)GC_wince_get_mem(bytes)
-# else
-# if defined(AMIGA) && defined(GC_AMIGA_FASTALLOC)
- extern void *GC_amiga_get_mem(size_t size);
- define GET_MEM(bytes) HBLKPTR((size_t) \
- GC_amiga_get_mem((size_t)bytes + GC_page_size) \
- + GC_page_size-1)
-# else
- extern ptr_t GC_unix_get_mem();
-# define GET_MEM(bytes) (struct hblk *)GC_unix_get_mem(bytes)
-# endif
-# endif
-# endif
-# endif
-# endif
-# endif
-# endif
-
/* Delay any interrupts or signals that may abort this thread. Data */
/* structures are in a consistent state outside this pair of calls. */
/* ANSI C allows both to be empty (though the standard isn't very */
@@ -486,7 +430,7 @@ struct hblk; /* See below. */
# ifdef SMALL_CONFIG
# define ABORT(msg) abort();
# else
- GC_API void GC_abort();
+ GC_API void GC_abort GC_PROTO((GC_CONST char * msg));
# define ABORT(msg) GC_abort(msg);
# endif
# endif
@@ -646,9 +590,10 @@ extern GC_warn_proc GC_current_warn_proc;
*/
# ifdef LARGE_CONFIG
-# define LOG_PHT_ENTRIES 19 /* Collisions likely at 512K blocks, */
- /* which is >= 2GB. Each table takes */
- /* 64KB. */
+# define LOG_PHT_ENTRIES 20 /* Collisions likely at 1M blocks, */
+ /* which is >= 4GB. Each table takes */
+ /* 128KB, some of which may never be */
+ /* touched. */
# else
# ifdef SMALL_CONFIG
# define LOG_PHT_ENTRIES 14 /* Collisions are likely if heap grows */
@@ -656,7 +601,7 @@ extern GC_warn_proc GC_current_warn_proc;
/* Each hash table occupies 2K bytes. */
# else /* default "medium" configuration */
# define LOG_PHT_ENTRIES 16 /* Collisions are likely if heap grows */
- /* to more than 16K hblks >= 256MB. */
+ /* to more than 64K hblks >= 256MB. */
/* Each hash table occupies 8K bytes. */
# endif
# endif
@@ -897,6 +842,10 @@ struct _GC_arrays {
word _mem_freed;
/* Number of explicitly deallocated words of memory */
/* since last collection. */
+ word _finalizer_mem_freed;
+ /* Words of memory explicitly deallocated while */
+ /* finalizers were running. Used to approximate mem. */
+ /* explicitly deallocated by finalizers. */
ptr_t _scratch_end_ptr;
ptr_t _scratch_last_end_ptr;
/* Used by headers.c, and can easily appear to point to */
@@ -957,7 +906,7 @@ struct _GC_arrays {
/* OFFSET_TOO_BIG if the value j would be too */
/* large to fit in the entry. (Note that the */
/* size of these entries matters, both for */
- /* space consumption and for cache utilization. */
+ /* space consumption and for cache utilization.) */
# define OFFSET_TOO_BIG 0xfe
# define OBJ_INVALID 0xff
# define MAP_ENTRY(map, bytes) (map)[bytes]
@@ -1067,6 +1016,7 @@ GC_API GC_FAR struct _GC_arrays GC_arrays;
# define GC_words_finalized GC_arrays._words_finalized
# define GC_non_gc_bytes_at_gc GC_arrays._non_gc_bytes_at_gc
# define GC_mem_freed GC_arrays._mem_freed
+# define GC_finalizer_mem_freed GC_arrays._finalizer_mem_freed
# define GC_scratch_end_ptr GC_arrays._scratch_end_ptr
# define GC_scratch_last_end_ptr GC_arrays._scratch_last_end_ptr
# define GC_mark_procs GC_arrays._mark_procs
@@ -1201,17 +1151,19 @@ extern struct hblk * GC_hblkfreelist[];
/* header structure associated with */
/* block. */
-extern GC_bool GC_is_initialized; /* GC_init() has been run. */
-
extern GC_bool GC_objects_are_marked; /* There are marked objects in */
/* the heap. */
#ifndef SMALL_CONFIG
extern GC_bool GC_incremental;
/* Using incremental/generational collection. */
+# define TRUE_INCREMENTAL \
+ (GC_incremental && GC_time_limit != GC_TIME_UNLIMITED)
+ /* True incremental, not just generational, mode */
#else
# define GC_incremental FALSE
/* Hopefully allow optimizer to remove some code. */
+# define TRUE_INCREMENTAL FALSE
#endif
extern GC_bool GC_dirty_maintained;
@@ -1229,6 +1181,10 @@ extern long GC_large_alloc_warn_interval;
extern long GC_large_alloc_warn_suppressed;
/* Number of warnings suppressed so far. */
+#ifdef THREADS
+ extern GC_bool GC_world_stopped;
+#endif
+
/* Operations */
# ifndef abs
# define abs(x) ((x) < 0? (-(x)) : (x))
@@ -1403,6 +1359,11 @@ extern void (*GC_start_call_back) GC_PROTO((void));
# else
void GC_push_regs GC_PROTO((void));
# endif
+# if defined(SPARC) || defined(IA64)
+ /* Cause all stacked registers to be saved in memory. Return a */
+ /* pointer to the top of the corresponding memory stack. */
+ word GC_save_regs_in_stack GC_PROTO((void));
+# endif
/* Push register contents onto mark stack. */
/* If NURSERY is defined, the default push */
/* action can be overridden with GC_push_proc */
@@ -1452,6 +1413,7 @@ void GC_set_fl_marks GC_PROTO((ptr_t p));
/* Set all mark bits associated with */
/* a free list. */
void GC_add_roots_inner GC_PROTO((char * b, char * e, GC_bool tmp));
+void GC_remove_roots_inner GC_PROTO((char * b, char * e));
GC_bool GC_is_static_root GC_PROTO((ptr_t p));
/* Is the address p in one of the registered static */
/* root sections? */
@@ -1462,11 +1424,10 @@ GC_bool GC_is_tmp_root GC_PROTO((ptr_t p));
# endif
void GC_register_dynamic_libraries GC_PROTO((void));
/* Add dynamic library data sections to the root set. */
-
GC_bool GC_register_main_static_data GC_PROTO((void));
- /* We need to register the main data segment. Returns */
- /* TRUE unless this is done implicitly as part of */
- /* dynamic library registration. */
+ /* We need to register the main data segment. Returns */
+ /* TRUE unless this is done implicitly as part of */
+ /* dynamic library registration. */
/* Machine dependent startup routines */
ptr_t GC_get_stack_base GC_PROTO((void)); /* Cold end of stack */
@@ -1624,6 +1585,8 @@ GC_bool GC_collect_or_expand GC_PROTO(( \
/* until the blocks are available or */
/* until it fails by returning FALSE. */
+extern GC_bool GC_is_initialized; /* GC_init() has been run. */
+
#if defined(MSWIN32) || defined(MSWINCE)
void GC_deinit GC_PROTO((void));
/* Free any resources allocated by */
@@ -1665,6 +1628,8 @@ ptr_t GC_allocobj GC_PROTO((word sz, int kind));
/* Make the indicated */
/* free list nonempty, and return its */
/* head. */
+
+void GC_free_inner(GC_PTR p);
void GC_init_headers GC_PROTO((void));
struct hblkhdr * GC_install_header GC_PROTO((struct hblk *h));
@@ -1694,6 +1659,12 @@ void GC_notify_or_invoke_finalizers GC_PROTO((void));
/* Call *GC_finalizer_notifier if there are */
/* finalizers to be run, and we haven't called */
/* this procedure yet this GC cycle. */
+
+GC_API GC_PTR GC_make_closure GC_PROTO((GC_finalization_proc fn, GC_PTR data));
+GC_API void GC_debug_invoke_finalizer GC_PROTO((GC_PTR obj, GC_PTR data));
+ /* Auxiliary fns to make finalization work */
+ /* correctly with displaced pointers introduced */
+ /* by the debugging allocators. */
void GC_add_to_heap GC_PROTO((struct hblk *p, word bytes));
/* Add a HBLKSIZE aligned chunk to the heap. */
@@ -1704,16 +1675,36 @@ void GC_print_obj GC_PROTO((ptr_t p));
/* description of the object to stderr. */
extern void (*GC_check_heap) GC_PROTO((void));
/* Check that all objects in the heap with */
- /* debugging info are intact. Print */
- /* descriptions of any that are not. */
+ /* debugging info are intact. */
+ /* Add any that are not to GC_smashed list. */
+extern void (*GC_print_all_smashed) GC_PROTO((void));
+ /* Print GC_smashed if it's not empty. */
+ /* Clear GC_smashed list. */
+extern void GC_print_all_errors GC_PROTO((void));
+ /* Print smashed and leaked objects, if any. */
+ /* Clear the lists of such objects. */
extern void (*GC_print_heap_obj) GC_PROTO((ptr_t p));
/* If possible print s followed by a more */
/* detailed description of the object */
/* referred to by p. */
+#if defined(LINUX) && defined(__ELF__) && !defined(SMALL_CONFIG)
+ void GC_print_address_map GC_PROTO((void));
+ /* Print an address map of the process. */
+#endif
+extern GC_bool GC_have_errors; /* We saw a smashed or leaked object. */
+ /* Call error printing routine */
+ /* occasionally. */
extern GC_bool GC_print_stats; /* Produce at least some logging output */
/* Set from environment variable. */
+#ifndef NO_DEBUGGING
+ extern GC_bool GC_dump_regularly; /* Generate regular debugging dumps. */
+# define COND_DUMP if (GC_dump_regularly) GC_dump();
+#else
+# define COND_DUMP
+#endif
+
/* Macros used for collector internal allocation. */
/* These assume the collector lock is held. */
#ifdef DBG_HDRS_ALL
@@ -1785,6 +1776,7 @@ void GC_print_block_list GC_PROTO((void));
void GC_print_hblkfreelist GC_PROTO((void));
void GC_print_heap_sects GC_PROTO((void));
void GC_print_static_roots GC_PROTO((void));
+void GC_print_finalization_stats GC_PROTO((void));
void GC_dump GC_PROTO((void));
#ifdef KEEP_BACK_PTRS
@@ -1866,6 +1858,16 @@ void GC_err_puts GC_PROTO((GC_CONST char *s));
# define GC_ASSERT(expr)
# endif
+/* Check a compile time assertion at compile time. The error */
+/* message for failure is a bit baroque, but ... */
+#if defined(mips) && !defined(__GNUC__)
+/* DOB: MIPSPro C gets an internal error taking the sizeof an array type.
+ This code works correctly (ugliness is to avoid "unused var" warnings) */
+# define GC_STATIC_ASSERT(expr) do { if (0) { char j[(expr)? 1 : -1]; j[0]='\0'; j[0]=j[0]; } } while(0)
+#else
+# define GC_STATIC_ASSERT(expr) sizeof(char[(expr)? 1 : -1])
+#endif
+
# if defined(PARALLEL_MARK) || defined(THREAD_LOCAL_ALLOC)
/* We need additional synchronization facilities from the thread */
/* support. We believe these are less performance critical */
@@ -1911,7 +1913,7 @@ void GC_err_puts GC_PROTO((GC_CONST char *s));
/* in Linux glibc, but it's not exported.) Thus we continue to use */
/* the same hard-coded signals we've always used. */
# if !defined(SIG_SUSPEND)
-# if defined(GC_LINUX_THREADS)
+# if defined(GC_LINUX_THREADS) || defined(GC_DGUX386_THREADS)
# if defined(SPARC) && !defined(SIGPWR)
/* SPARC/Linux doesn't properly define SIGPWR in <signal.h>.
* It is aliased to SIGLOST in asm/signal.h, though. */
diff --git a/boehm-gc/include/private/gcconfig.h b/boehm-gc/include/private/gcconfig.h
index 809887f8219..29dab213815 100644
--- a/boehm-gc/include/private/gcconfig.h
+++ b/boehm-gc/include/private/gcconfig.h
@@ -13,11 +13,25 @@
* provided the above notices are retained, and a notice that the code was
* modified is included with the above copyright notice.
*/
+
+/*
+ * This header is private to the gc. It is almost always included from
+ * gc_priv.h. However it is possible to include it by itself if just the
+ * configuration macros are needed. In that
+ * case, a few declarations relying on types declared in gc_priv.h will be
+ * omitted.
+ */
#ifndef GCCONFIG_H
# define GCCONFIG_H
+# ifndef GC_PRIVATE_H
+ /* Fake ptr_t declaration, just to avoid compilation errors. */
+ /* This avoids many instances if "ifndef GC_PRIVATE_H" below. */
+ typedef struct GC_undefined_struct * ptr_t;
+# endif
+
/* Machine dependent parameters. Some tuning parameters can be found */
/* near the top of gc_private.h. */
@@ -25,7 +39,9 @@
/* First a unified test for Linux: */
# if defined(linux) || defined(__linux__)
+# ifndef LINUX
# define LINUX
+# endif
# endif
/* And one for NetBSD: */
@@ -44,9 +60,9 @@
# endif
/* Determine the machine type: */
-# if defined(__arm__) || defined(__thumb__)
+# if defined(__XSCALE__)
# define ARM32
-# if !defined(LINUX) && !defined(NETBSD)
+# if !defined(LINUX)
# define NOSYS
# define mach_type_known
# endif
@@ -69,7 +85,7 @@
# define SPARC
# define mach_type_known
# endif
-# if defined(NETBSD) && defined(m68k)
+# if defined(NETBSD) && (defined(m68k) || defined(__m68k__))
# define M68K
# define mach_type_known
# endif
@@ -77,7 +93,7 @@
# define POWERPC
# define mach_type_known
# endif
-# if defined(NETBSD) && defined(__arm__)
+# if defined(NETBSD) && (defined(__arm32__) || defined(__arm__))
# define ARM32
# define mach_type_known
# endif
@@ -90,6 +106,10 @@
# endif
# define mach_type_known
# endif
+# if defined(__NetBSD__) && defined(__vax__)
+# define VAX
+# define mach_type_known
+# endif
# if defined(mips) || defined(__mips) || defined(_mips)
# define MIPS
# if defined(nec_ews) || defined(_nec_ews)
@@ -109,6 +129,13 @@
# endif /* !LINUX */
# define mach_type_known
# endif
+# if defined(DGUX) && (defined(i386) || defined(__i386__))
+# define I386
+# ifndef _USING_DGUX
+# define _USING_DGUX
+# endif
+# define mach_type_known
+# endif
# if defined(sequent) && (defined(i386) || defined(__i386__))
# define I386
# define SEQUENT
@@ -198,7 +225,11 @@
# define IA64
# define mach_type_known
# endif
-# if defined(LINUX) && (defined(powerpc) || defined(__powerpc__))
+# if defined(LINUX) && defined(__arm__)
+# define ARM32
+# define mach_type_known
+# endif
+# if defined(LINUX) && (defined(powerpc) || defined(__powerpc__) || defined(powerpc64) || defined(__powerpc64__))
# define POWERPC
# define mach_type_known
# endif
@@ -237,19 +268,19 @@
# define MACOS
# define mach_type_known
# endif
-# if defined(__MWERKS__) && defined(__powerc)
+# if defined(__MWERKS__) && defined(__powerc) && !defined(__MACH__)
# define POWERPC
# define MACOS
# define mach_type_known
# endif
# if defined(macosx) || \
defined(__APPLE__) && defined(__MACH__) && defined(__ppc__)
-# define MACOSX
+# define DARWIN
# define POWERPC
# define mach_type_known
# endif
# if defined(__APPLE__) && defined(__MACH__) && defined(__i386__)
-# define MACOSX
+# define DARWIN
# define I386
--> Not really supported, but at least we recognize it.
# endif
@@ -291,7 +322,7 @@
# define CX_UX
# define mach_type_known
# endif
-# if defined(DGUX)
+# if defined(DGUX) && defined(m88k)
# define M88K
/* DGUX defined */
# define mach_type_known
@@ -419,17 +450,18 @@
/* (CX_UX and DGUX) */
/* S370 ==> 370-like machine */
/* running Amdahl UTS4 */
- /* S390 ==> 390-like machine */
- /* running LINUX */
+ /* S390 ==> 390-like machine */
+ /* running LINUX */
/* ARM32 ==> Intel StrongARM */
/* IA64 ==> Intel IPF */
/* (e.g. Itanium) */
/* (LINUX and HPUX) */
- /* IA64_32 ==> IA64 w/32 bit ABI */
- /* (HPUX) */
/* SH ==> Hitachi SuperH */
/* (LINUX & MSWINCE) */
/* X86_64 ==> AMD x86-64 */
+ /* POWERPC ==> IBM/Apple PowerPC */
+ /* (MACOS(<=9),DARWIN(incl.MACOSX),*/
+ /* LINUX, NETBSD, NOSYS variants) */
/*
@@ -450,7 +482,12 @@
* defining it to be 1 will always work, but perform poorly.
*
* DATASTART is the beginning of the data segment.
- * On UNIX systems, the collector will scan the area between DATASTART
+ * On some platforms SEARCH_FOR_DATA_START is defined.
+ * SEARCH_FOR_DATASTART will cause GC_data_start to
+ * be set to an address determined by accessing data backwards from _end
+ * until an unmapped page is found. DATASTART will be defined to be
+ * GC_data_start.
+ * On UNIX-like systems, the collector will scan the area between DATASTART
* and DATAEND for root pointers.
*
* DATAEND, if not `end' where `end' is defined as ``extern int end[];''.
@@ -470,8 +507,13 @@
* 1) define STACK_GROWS_UP if the stack grows toward higher addresses, and
* 2) define exactly one of
* STACKBOTTOM (should be defined to be an expression)
+ * LINUX_STACKBOTTOM
* HEURISTIC1
* HEURISTIC2
+ * If STACKBOTTOM is defined, then it's value will be used directly as the
+ * stack base. If LINUX_STACKBOTTOM is defined, then it will be determined
+ * with a method appropriate for most Linux systems. Currently we look
+ * first for __libc_stack_end, and if that fails read it from /proc.
* If either of the last two macros are defined, then STACKBOTTOM is computed
* during collector startup using one of the following two heuristics:
* HEURISTIC1: Take an address inside GC_init's frame, and round it up to
@@ -536,6 +578,9 @@
* An architecture may also define CLEAR_DOUBLE(x) to be a fast way to
* clear the two words at GC_malloc-aligned address x. By default,
* word stores of 0 are used instead.
+ *
+ * HEAP_START may be defined as the initial address hint for mmap-based
+ * allocation.
*/
/* If we are using a recent version of gcc, we can use __builtin_unwind_init()
@@ -560,18 +605,25 @@
# ifdef NETBSD
# define OS_TYPE "NETBSD"
# define HEURISTIC2
- extern char etext[];
-# define DATASTART ((ptr_t)(etext))
+# ifdef __ELF__
+# define DATASTART GC_data_start
+# define DYNAMIC_LOADING
+# else
+ extern char etext[];
+# define DATASTART ((ptr_t)(etext))
+# endif
# endif
# ifdef LINUX
# define OS_TYPE "LINUX"
# define STACKBOTTOM ((ptr_t)0xf0000000)
+# define USE_GENERIC_PUSH_REGS
+ /* We never got around to the assembly version. */
/* # define MPROTECT_VDB - Reported to not work 9/17/01 */
# ifdef __ELF__
# define DYNAMIC_LOADING
# include <features.h>
# if defined(__GLIBC__)&& __GLIBC__>=2
-# define LINUX_DATA_START
+# define SEARCH_FOR_DATA_START
# else /* !GLIBC2 */
extern char **__environ;
# define DATASTART ((ptr_t)(&__environ))
@@ -666,26 +718,49 @@
# define DATAEND /* not needed */
# endif
# ifdef LINUX
-# define ALIGNMENT 4 /* Guess. Can someone verify? */
+# if (defined (powerpc64) || defined(__powerpc64__))
+# define ALIGNMENT 8
+# define CPP_WORDSZ 64
+# else
+# define ALIGNMENT 4 /* Guess. Can someone verify? */
/* This was 2, but that didn't sound right. */
+# endif
# define OS_TYPE "LINUX"
-# define DYNAMIC_LOADING
+ /* HEURISTIC1 has been reliably reported to fail for a 32-bit */
+ /* executable on a 64 bit kernel. */
# define LINUX_STACKBOTTOM
- /* Stack usually starts at 0x80000000 */
-# define LINUX_DATA_START
+# define DYNAMIC_LOADING
+# define SEARCH_FOR_DATA_START
extern int _end[];
# define DATAEND (_end)
# endif
-# ifdef MACOSX
- /* There are reasons to suspect this may not be reliable. */
+# ifdef DARWIN
# define ALIGNMENT 4
-# define OS_TYPE "MACOSX"
+# define OS_TYPE "DARWIN"
+# define DYNAMIC_LOADING
+ /* XXX: see get_end(3), get_etext() and get_end() should not be used.
+ These aren't used when dyld support is enabled (it is by default) */
# define DATASTART ((ptr_t) get_etext())
+# define DATAEND ((ptr_t) get_end())
# define STACKBOTTOM ((ptr_t) 0xc0000000)
-# define DATAEND /* not needed */
-# undef MPROTECT_VDB
+# define USE_MMAP
+# define USE_MMAP_ANON
+# define USE_ASM_PUSH_REGS
+ /* This is potentially buggy. It needs more testing. See the comments in
+ os_dep.c */
+# define MPROTECT_VDB
# include <unistd.h>
# define GETPAGESIZE() getpagesize()
+# if defined(USE_PPC_PREFETCH) && defined(__GNUC__)
+ /* The performance impact of prefetches is untested */
+# define PREFETCH(x) \
+ __asm__ __volatile__ ("dcbt 0,%0" : : "r" ((const void *) (x)))
+# define PREFETCH_FOR_WRITE(x) \
+ __asm__ __volatile__ ("dcbtst 0,%0" : : "r" ((const void *) (x)))
+# endif
+ /* There seems to be some issues with trylock hanging on darwin. This
+ should be looked into some more */
+# define NO_PTHREAD_TRYLOCK
# endif
# ifdef NETBSD
# define ALIGNMENT 4
@@ -746,8 +821,8 @@
# define OS_TYPE "SUNOS5"
extern int _etext[];
extern int _end[];
- extern char * GC_SysVGetDataStart();
-# define DATASTART (ptr_t)GC_SysVGetDataStart(0x10000, _etext)
+ extern ptr_t GC_SysVGetDataStart();
+# define DATASTART GC_SysVGetDataStart(0x10000, _etext)
# define DATAEND (_end)
# if !defined(USE_MMAP) && defined(REDIRECT_MALLOC)
# define USE_MMAP
@@ -801,9 +876,9 @@
# endif
# ifdef DRSNX
# define OS_TYPE "DRSNX"
- extern char * GC_SysVGetDataStart();
+ extern ptr_t GC_SysVGetDataStart();
extern int etext[];
-# define DATASTART (ptr_t)GC_SysVGetDataStart(0x10000, etext)
+# define DATASTART GC_SysVGetDataStart(0x10000, etext)
# define MPROTECT_VDB
# define STACKBOTTOM ((ptr_t) 0xdfff0000)
# define DYNAMIC_LOADING
@@ -819,13 +894,14 @@
extern int _etext[];
# define DATAEND (_end)
# define SVR4
+ extern ptr_t GC_SysVGetDataStart();
# ifdef __arch64__
+# define DATASTART GC_SysVGetDataStart(0x100000, _etext)
/* libc_stack_end is not set reliably for sparc64 */
-# define STACKBOTTOM ((ptr_t) 0x80000000000)
-# define DATASTART (ptr_t)GC_SysVGetDataStart(0x100000, _etext)
+# define STACKBOTTOM ((ptr_t) 0x80000000000ULL)
# else
-# define LINUX_STACKBOTTOM
-# define DATASTART (ptr_t)GC_SysVGetDataStart(0x10000, _etext)
+# define DATASTART GC_SysVGetDataStart(0x10000, _etext)
+# define LINUX_STACKBOTTOM
# endif
# endif
# ifdef OPENBSD
@@ -876,7 +952,7 @@
# ifdef SUNOS5
# define OS_TYPE "SUNOS5"
extern int _etext[], _end[];
- extern char * GC_SysVGetDataStart();
+ extern ptr_t GC_SysVGetDataStart();
# define DATASTART GC_SysVGetDataStart(0x1000, _etext)
# define DATAEND (_end)
/* # define STACKBOTTOM ((ptr_t)(_start)) worked through 2.7, */
@@ -921,6 +997,28 @@
# define DYNAMIC_LOADING
# define ELF_CLASS ELFCLASS32
# endif
+# ifdef DGUX
+# define OS_TYPE "DGUX"
+ extern int _etext, _end;
+ extern ptr_t GC_SysVGetDataStart();
+# define DATASTART GC_SysVGetDataStart(0x1000, &_etext)
+# define DATAEND (&_end)
+# define STACK_GROWS_DOWN
+# define HEURISTIC2
+# include <unistd.h>
+# define GETPAGESIZE() sysconf(_SC_PAGESIZE)
+# define DYNAMIC_LOADING
+# ifndef USE_MMAP
+# define USE_MMAP
+# endif /* USE_MMAP */
+# define MAP_FAILED (void *) -1
+# ifdef USE_MMAP
+# define HEAP_START (ptr_t)0x40000000
+# else /* USE_MMAP */
+# define HEAP_START DATAEND
+# endif /* USE_MMAP */
+# endif /* DGUX */
+
# ifdef LINUX
# ifndef __GNUC__
/* The Intel compiler doesn't like inline assembly */
@@ -944,6 +1042,9 @@
/* possibly because Linux threads is itself a malloc client */
/* and can't deal with the signals. */
# endif
+# define HEAP_START 0x1000
+ /* This encourages mmap to give us low addresses, */
+ /* thus allowing the heap to grow to ~3GB */
# ifdef __ELF__
# define DYNAMIC_LOADING
# ifdef UNDEFINED /* includes ro data */
@@ -952,7 +1053,7 @@
# endif
# include <features.h>
# if defined(__GLIBC__) && __GLIBC__ >= 2
-# define LINUX_DATA_START
+# define SEARCH_FOR_DATA_START
# else
extern char **__environ;
# define DATASTART ((ptr_t)(&__environ))
@@ -1006,8 +1107,12 @@
/* DATAEND = _data_end__ */
/* To get it right for both, we take the */
/* minumum/maximum of the two. */
+# ifndef MAX
# define MAX(x,y) ((x) > (y) ? (x) : (y))
+# endif
+# ifndef MIN
# define MIN(x,y) ((x) < (y) ? (x) : (y))
+# endif
# define DATASTART ((ptr_t) MIN(_data_start__, _bss_start__))
# define DATAEND ((ptr_t) MAX(_data_end__, _bss_end__))
# undef STACK_GRAN
@@ -1061,16 +1166,9 @@
# ifdef __ELF__
# define DYNAMIC_LOADING
# endif
-/* Handle unmapped hole i386*-*-freebsd[45]* may put between etext and edata. */
extern char etext[];
- extern char edata[];
- extern char end[];
-# define NEED_FIND_LIMIT
-# define DATASTART ((ptr_t)(etext))
-# define MIN(x,y) ((x) < (y) ? (x) : (y))
-# define DATAEND (MIN (GC_find_limit (DATASTART, TRUE), DATASTART2))
-# define DATASTART2 ((ptr_t)(edata))
-# define DATAEND2 ((ptr_t)(end))
+ extern char * GC_FreeBSDGetDataStart();
+# define DATASTART GC_FreeBSDGetDataStart(0x1000, &etext)
# endif
# ifdef NETBSD
# define OS_TYPE "NETBSD"
@@ -1149,7 +1247,11 @@
# define DATASTART ((ptr_t)(__data_start))
# define ALIGNMENT 4
# define USE_GENERIC_PUSH_REGS
-# define LINUX_STACKBOTTOM
+# if __GLIBC__ == 2 && __GLIBC_MINOR__ >= 2 || __GLIBC__ > 2
+# define LINUX_STACKBOTTOM
+# else
+# define STACKBOTTOM 0x80000000
+# endif
# endif /* Linux */
# ifdef EWS4800
# define HEURISTIC2
@@ -1203,7 +1305,8 @@
/* heap sections so they're not */
/* considered as roots. */
# define OS_TYPE "IRIX5"
-# define MPROTECT_VDB
+/*# define MPROTECT_VDB DOB: this should work, but there is evidence */
+/* of recent breakage. */
# ifdef _MIPS_SZPTR
# define CPP_WORDSZ _MIPS_SZPTR
# define ALIGNMENT (_MIPS_SZPTR/8)
@@ -1226,28 +1329,46 @@
# define ALIGNMENT 4
# define HEURISTIC2
# define USE_GENERIC_PUSH_REGS
- extern int _fdata[];
-# define DATASTART ((ptr_t)(_fdata))
- extern int _end[];
-# define DATAEND ((ptr_t)(_end))
-# define DYNAMIC_LOADING
+# ifdef __ELF__
+ extern int etext[];
+# define DATASTART GC_data_start
+# define NEED_FIND_LIMIT
+# define DYNAMIC_LOADING
+# else
+# define DATASTART ((ptr_t) 0x10000000)
+# define STACKBOTTOM ((ptr_t) 0x7ffff000)
+# endif /* _ELF_ */
# endif
# endif
# ifdef RS6000
# define MACH_TYPE "RS6000"
+# ifdef ALIGNMENT
+# undef ALIGNMENT
+# endif
+# ifdef IA64
+# undef IA64 /* DOB: some AIX installs stupidly define IA64 in /usr/include/sys/systemcfg.h */
+# endif
# ifdef __64BIT__
# define ALIGNMENT 8
# define CPP_WORDSZ 64
+# define STACKBOTTOM ((ptr_t)0x1000000000000000)
# else
# define ALIGNMENT 4
# define CPP_WORDSZ 32
-# endif
+# define STACKBOTTOM ((ptr_t)((ulong)&errno))
+# endif
+ /* From AIX linker man page:
+ _text Specifies the first location of the program.
+ _etext Specifies the first location after the program.
+ _data Specifies the first location of the data.
+ _edata Specifies the first location after the initialized data
+ _end or end Specifies the first location after all data.
+ */
extern int _data[], _end[];
# define DATASTART ((ptr_t)((ulong)_data))
# define DATAEND ((ptr_t)((ulong)_end))
extern int errno;
-# define STACKBOTTOM ((ptr_t)((ulong)&errno))
# define USE_GENERIC_PUSH_REGS
# define DYNAMIC_LOADING
/* For really old versions of AIX, this may have to be removed. */
@@ -1311,15 +1432,23 @@
# define OS_TYPE "LINUX"
# define LINUX_STACKBOTTOM
# define DYNAMIC_LOADING
-# define LINUX_DATA_START
+# define SEARCH_FOR_DATA_START
extern int _end[];
-# define DATAEND (_end)
+# define DATAEND (&_end)
# endif /* LINUX */
# endif /* HP_PA */
# ifdef ALPHA
# define MACH_TYPE "ALPHA"
# define ALIGNMENT 8
+# define CPP_WORDSZ 64
+# ifndef LINUX
+# define USE_GENERIC_PUSH_REGS
+ /* Gcc and probably the DEC/Compaq compiler spill pointers to preserved */
+ /* fp registers in some cases when the target is a 21264. The assembly */
+ /* code doesn't handle that yet, and version dependencies make that a */
+ /* bit tricky. Do the easy thing for now. */
+# endif
# ifdef NETBSD
# define OS_TYPE "NETBSD"
# define HEURISTIC2
@@ -1327,13 +1456,11 @@
# define ELFCLASS32 32
# define ELFCLASS64 64
# define ELF_CLASS ELFCLASS64
-# define CPP_WORDSZ 64
# define DYNAMIC_LOADING
# endif
# ifdef OPENBSD
# define OS_TYPE "OPENBSD"
# define HEURISTIC2
-# define CPP_WORDSZ 64
# ifdef __ELF__ /* since OpenBSD/Alpha 2.9 */
# define DATASTART GC_data_start
# define ELFCLASS32 32
@@ -1357,17 +1484,16 @@
extern char edata[];
extern char end[];
# define NEED_FIND_LIMIT
-# define DATASTART ((ptr_t)(etext))
+# define DATASTART ((ptr_t)(&etext))
# define DATAEND (GC_find_limit (DATASTART, TRUE))
-# define DATASTART2 ((ptr_t)(edata))
-# define DATAEND2 ((ptr_t)(end))
-# define CPP_WORDSZ 64
+# define DATASTART2 ((ptr_t)(&edata))
+# define DATAEND2 ((ptr_t)(&end))
# endif
# ifdef OSF1
# define OS_TYPE "OSF1"
# define DATASTART ((ptr_t) 0x140000000)
extern int _end[];
-# define DATAEND ((ptr_t) _end)
+# define DATAEND ((ptr_t) &_end)
extern char ** environ;
/* round up from the value of environ to the nearest page boundary */
/* Probably breaks if putenv is called before collector */
@@ -1378,19 +1504,19 @@
/* the text segment immediately follows the stack. */
/* Hence we give an upper pound. */
/* This is currently unused, since we disabled HEURISTIC2 */
- extern int __start[];
+ extern int __start[];
# define HEURISTIC2_LIMIT ((ptr_t)((word)(__start) & ~(getpagesize()-1)))
-# define CPP_WORDSZ 64
-# define MPROTECT_VDB
+# ifndef GC_OSF1_THREADS
+ /* Unresolved signal issues with threads. */
+# define MPROTECT_VDB
+# endif
# define DYNAMIC_LOADING
# endif
# ifdef LINUX
# define OS_TYPE "LINUX"
-# define CPP_WORDSZ 64
# define STACKBOTTOM ((ptr_t) 0x120000000)
# ifdef __ELF__
# define SEARCH_FOR_DATA_START
-# define DATASTART GC_data_start
# define DYNAMIC_LOADING
# else
# define DATASTART ((ptr_t) 0x140000000)
@@ -1468,7 +1594,6 @@
extern char * GC_register_stackbottom;
# define BACKING_STORE_BASE ((ptr_t)GC_register_stackbottom)
# define SEARCH_FOR_DATA_START
-# define DATASTART GC_data_start
# ifdef __GNUC__
# define DYNAMIC_LOADING
# else
@@ -1502,23 +1627,25 @@
# endif
# ifdef DGUX
# define OS_TYPE "DGUX"
- extern char * GC_SysVGetDataStart();
-# define DATASTART (ptr_t)GC_SysVGetDataStart(0x10000, etext)
+ extern ptr_t GC_SysVGetDataStart();
+# define DATASTART GC_SysVGetDataStart(0x10000, etext)
# endif
# define STACKBOTTOM ((char*)0xf0000000) /* determined empirically */
# endif
# ifdef S370
+ /* If this still works, and if anyone cares, this should probably */
+ /* be moved to the S390 category. */
# define MACH_TYPE "S370"
# define ALIGNMENT 4 /* Required by hardware */
# define USE_GENERIC_PUSH_REGS
# ifdef UTS4
# define OS_TYPE "UTS4"
- extern int etext[];
+ extern int etext[];
extern int _etext[];
extern int _end[];
- extern char * GC_SysVGetDataStart();
-# define DATASTART (ptr_t)GC_SysVGetDataStart(0x10000, _etext)
+ extern ptr_t GC_SysVGetDataStart();
+# define DATASTART GC_SysVGetDataStart(0x10000, _etext)
# define DATAEND (_end)
# define HEURISTIC2
# endif
@@ -1528,23 +1655,23 @@
# define MACH_TYPE "S390"
# define USE_GENERIC_PUSH_REGS
# ifndef __s390x__
-# define ALIGNMENT 4
-# define CPP_WORDSZ 32
+# define ALIGNMENT 4
+# define CPP_WORDSZ 32
# else
-# define ALIGNMENT 8
-# define CPP_WORDSZ 64
-# define HBLKSIZE 4096
+# define ALIGNMENT 8
+# define CPP_WORDSZ 64
+# define HBLKSIZE 4096
# endif
# ifdef LINUX
# define OS_TYPE "LINUX"
# define LINUX_STACKBOTTOM
# define DYNAMIC_LOADING
- extern int __data_start[];
+ extern int __data_start[];
# define DATASTART ((ptr_t)(__data_start))
- extern int _end[];
-# define DATAEND (_end)
-# define CACHE_LINE_SIZE 256
-# define GETPAGESIZE() 4096
+ extern int _end[];
+# define DATAEND (_end)
+# define CACHE_LINE_SIZE 256
+# define GETPAGESIZE() 4096
# endif
# endif
@@ -1562,13 +1689,8 @@
# ifdef NETBSD
# define OS_TYPE "NETBSD"
# define HEURISTIC2
-# ifdef __ELF__
-# define DATASTART GC_data_start
-# define DYNAMIC_LOADING
-# else
- extern char etext[];
-# define DATASTART ((ptr_t)(etext))
-# endif
+ extern char etext[];
+# define DATASTART ((ptr_t)(etext))
# define USE_GENERIC_PUSH_REGS
# endif
# ifdef LINUX
@@ -1581,7 +1703,7 @@
# define DYNAMIC_LOADING
# include <features.h>
# if defined(__GLIBC__) && __GLIBC__ >= 2
-# define LINUX_DATA_START
+# define SEARCH_FOR_DATA_START
# else
extern char **__environ;
# define DATASTART ((ptr_t)(&__environ))
@@ -1628,7 +1750,7 @@
# define STACKBOTTOM ((ptr_t) 0x7c000000)
# define USE_GENERIC_PUSH_REGS
# define DYNAMIC_LOADING
-# define LINUX_DATA_START
+# define SEARCH_FOR_DATA_START
extern int _end[];
# define DATAEND (_end)
# endif
@@ -1645,7 +1767,9 @@
# define MACH_TYPE "X86_64"
# define ALIGNMENT 8
# define CPP_WORDSZ 64
-# define HBLKSIZE 4096
+# ifndef HBLKSIZE
+# define HBLKSIZE 4096
+# endif
# define CACHE_LINE_SIZE 64
# define USE_GENERIC_PUSH_REGS
# ifdef LINUX
@@ -1665,7 +1789,7 @@
# define DATASTART ((ptr_t)((((word) (_etext)) + 0xfff) & ~0xfff))
# endif
# include <features.h>
-# define LINUX_DATA_START
+# define SEARCH_FOR_DATA_START
extern int _end[];
# define DATAEND (_end)
# else
@@ -1679,19 +1803,6 @@
# endif
# endif
-#ifdef LINUX_DATA_START
- /* Some Linux distributions arrange to define __data_start. Some */
- /* define data_start as a weak symbol. The latter is technically */
- /* broken, since the user program may define data_start, in which */
- /* case we lose. Nonetheless, we try both, prefering __data_start. */
- /* We assume gcc. */
-# pragma weak __data_start
- extern int __data_start[];
-# pragma weak data_start
- extern int data_start[];
-# define DATASTART ((ptr_t)(__data_start != 0? __data_start : data_start))
-#endif
-
#if defined(LINUX) && defined(REDIRECT_MALLOC)
/* Rld appears to allocate some memory with its own allocator, and */
/* some through malloc, which might be redirected. To make this */
@@ -1730,15 +1841,15 @@
# endif
# if defined(SUNOS5) || defined(DRSNX) || defined(UTS4)
- /* OS has SVR4 generic features. Probably others also qualify. */
+ /* OS has SVR4 generic features. Probably others also qualify. */
# define SVR4
# endif
# if defined(SUNOS5) || defined(DRSNX)
- /* OS has SUNOS5 style semi-undocumented interface to dynamic */
- /* loader. */
+ /* OS has SUNOS5 style semi-undocumented interface to dynamic */
+ /* loader. */
# define SUNOS5DL
- /* OS has SUNOS5 style signal handlers. */
+ /* OS has SUNOS5 style signal handlers. */
# define SUNOS5SIGS
# endif
@@ -1747,13 +1858,14 @@
# endif
# if defined(SVR4) || defined(LINUX) || defined(IRIX) || defined(HPUX) \
- || defined(OPENBSD) || defined(NETBSD) || defined(FREEBSD) \
- || defined(BSD) || defined(_AIX) || defined(MACOSX) || defined(OSF1)
+ || defined(OPENBSD) || defined(NETBSD) || defined(FREEBSD) \
+ || defined(DGUX) || defined(BSD) \
+ || defined(_AIX) || defined(DARWIN) || defined(OSF1)
# define UNIX_LIKE /* Basic Unix-like system calls work. */
# endif
# if CPP_WORDSZ != 32 && CPP_WORDSZ != 64
- -> bad word size
+ -> bad word size
# endif
# ifdef PCR
@@ -1767,13 +1879,13 @@
# endif
# ifdef SRC_M3
-/* Postponed for now. */
+ /* Postponed for now. */
# undef PROC_VDB
# undef MPROTECT_VDB
# endif
# ifdef SMALL_CONFIG
-/* Presumably not worth the space it takes. */
+ /* Presumably not worth the space it takes. */
# undef PROC_VDB
# undef MPROTECT_VDB
# endif
@@ -1813,49 +1925,50 @@
/* platforms as well, though it should be avoided in win32. */
# endif /* LINUX */
-# if defined(SEARCH_FOR_DATA_START) && defined(GC_PRIVATE_H)
+# if defined(SEARCH_FOR_DATA_START)
extern ptr_t GC_data_start;
+# define DATASTART GC_data_start
# endif
# ifndef CLEAR_DOUBLE
# define CLEAR_DOUBLE(x) \
- ((word*)x)[0] = 0; \
- ((word*)x)[1] = 0;
+ ((word*)x)[0] = 0; \
+ ((word*)x)[1] = 0;
# endif /* CLEAR_DOUBLE */
-/* Internally we use GC_SOLARIS_THREADS to test for either old or pthreads. */
+ /* Internally we use GC_SOLARIS_THREADS to test for either old or pthreads. */
# if defined(GC_SOLARIS_PTHREADS) && !defined(GC_SOLARIS_THREADS)
# define GC_SOLARIS_THREADS
# endif
# if defined(GC_IRIX_THREADS) && !defined(IRIX5)
---> inconsistent configuration
+ --> inconsistent configuration
# endif
# if defined(GC_LINUX_THREADS) && !defined(LINUX)
---> inconsistent configuration
+ --> inconsistent configuration
# endif
# if defined(GC_SOLARIS_THREADS) && !defined(SUNOS5)
---> inconsistent configuration
+ --> inconsistent configuration
# endif
# if defined(GC_HPUX_THREADS) && !defined(HPUX)
---> inconsistent configuration
+ --> inconsistent configuration
+# endif
+# if defined(GC_AIX_THREADS) && !defined(_AIX)
+ --> inconsistent configuration
# endif
-# if defined(GC_WIN32_THREADS) && !defined(MSWIN32)
- /* Ideally CYGWIN32 should work, in addition to MSWIN32. I suspect */
- /* the necessary code is mostly there, but nobody has actually made */
- /* sure the right combination of pieces is compiled in, etc. */
---> inconsistent configuration
+# if defined(GC_WIN32_THREADS) && !defined(MSWIN32) && !defined(CYGWIN32)
+ --> inconsistent configuration
# endif
# if defined(PCR) || defined(SRC_M3) || \
- defined(GC_SOLARIS_THREADS) || defined(GC_WIN32_THREADS) || \
- defined(GC_PTHREADS)
+ defined(GC_SOLARIS_THREADS) || defined(GC_WIN32_THREADS) || \
+ defined(GC_PTHREADS)
# define THREADS
# endif
-# if defined(HP_PA) || defined(M88K) || defined(POWERPC) && !defined(MACOSX) \
- || defined(LINT) || defined(MSWINCE) \
- || (defined(I386) && defined(__LCC__))
+# if defined(HP_PA) || defined(M88K) || defined(POWERPC) && !defined(DARWIN) \
+ || defined(LINT) || defined(MSWINCE) || defined(ARM32) \
+ || (defined(I386) && defined(__LCC__))
/* Use setjmp based hack to mark from callee-save registers. */
/* The define should move to the individual platform */
/* descriptions. */
@@ -1867,36 +1980,26 @@
/* include assembly code to do it well. */
# endif
-/* Can we save call chain in objects for debugging? */
-/* SET NFRAMES (# of saved frames) and NARGS (#of args for each frame) */
-/* to reasonable values for the platform. */
-/* Set SAVE_CALL_CHAIN if we can. SAVE_CALL_COUNT can be specified at */
-/* build time, though we feel free to adjust it slightly. */
-/* Define NEED_CALLINFO if we either save the call stack or */
-/* GC_ADD_CALLER is defined. */
-#ifdef LINUX
-# include <features.h>
-# if __GLIBC__ == 2 && __GLIBC_MINOR__ >= 1 || __GLIBC__ > 2
-# define HAVE_BUILTIN_BACKTRACE
-# endif
-#endif
+ /* Can we save call chain in objects for debugging? */
+ /* SET NFRAMES (# of saved frames) and NARGS (#of args for each */
+ /* frame) to reasonable values for the platform. */
+ /* Set SAVE_CALL_CHAIN if we can. SAVE_CALL_COUNT can be specified */
+ /* at build time, though we feel free to adjust it slightly. */
+ /* Define NEED_CALLINFO if we either save the call stack or */
+ /* GC_ADD_CALLER is defined. */
+ /* GC_CAN_SAVE_CALL_STACKS is set in gc.h. */
#if defined(SPARC)
-# define CAN_SAVE_CALL_STACKS
# define CAN_SAVE_CALL_ARGS
#endif
#if (defined(I386) || defined(X86_64)) && defined(LINUX)
- /* SAVE_CALL_CHAIN is supported if the code is compiled to save */
- /* frame pointers by default, i.e. no -fomit-frame-pointer flag. */
-# define CAN_SAVE_CALL_STACKS
+ /* SAVE_CALL_CHAIN is supported if the code is compiled to save */
+ /* frame pointers by default, i.e. no -fomit-frame-pointer flag. */
# define CAN_SAVE_CALL_ARGS
#endif
-#if defined(HAVE_BUILTIN_BACKTRACE) && !defined(CAN_SAVE_CALL_STACKS)
-# define CAN_SAVE_CALL_STACKS
-#endif
# if defined(SAVE_CALL_COUNT) && !defined(GC_ADD_CALLER) \
- && defined(CAN_SAVE_CALL_STACKS)
+ && defined(GC_CAN_SAVE_CALL_STACKS)
# define SAVE_CALL_CHAIN
# endif
# ifdef SAVE_CALL_CHAIN
@@ -1909,7 +2012,7 @@
# ifdef SAVE_CALL_CHAIN
# ifndef SAVE_CALL_COUNT
# define NFRAMES 6 /* Number of frames to save. Even for */
- /* alignment reasons. */
+ /* alignment reasons. */
# else
# define NFRAMES ((SAVE_CALL_COUNT + 1) & ~1)
# endif
@@ -1925,4 +2028,96 @@
# define DBG_HDRS_ALL
# endif
+# if defined(POINTER_MASK) && !defined(POINTER_SHIFT)
+# define POINTER_SHIFT 0
+# endif
+
+# if defined(POINTER_SHIFT) && !defined(POINTER_MASK)
+# define POINTER_MASK ((GC_word)(-1))
+# endif
+
+# if !defined(FIXUP_POINTER) && defined(POINTER_MASK)
+# define FIXUP_POINTER(p) (p) = ((p) & (POINTER_MASK) << POINTER_SHIFT)
+# endif
+
+# if defined(FIXUP_POINTER)
+# define NEED_FIXUP_POINTER 1
+# else
+# define NEED_FIXUP_POINTER 0
+# define FIXUP_POINTER(p)
+# endif
+
+#ifdef GC_PRIVATE_H
+ /* This relies on some type definitions from gc_priv.h, from */
+ /* where it's normally included. */
+ /* */
+ /* How to get heap memory from the OS: */
+ /* Note that sbrk()-like allocation is preferred, since it */
+ /* usually makes it possible to merge consecutively allocated */
+ /* chunks. It also avoids unintented recursion with */
+ /* -DREDIRECT_MALLOC. */
+ /* GET_MEM() returns a HLKSIZE aligned chunk. */
+ /* 0 is taken to mean failure. */
+ /* In the case os USE_MMAP, the argument must also be a */
+ /* physical page size. */
+ /* GET_MEM is currently not assumed to retrieve 0 filled space, */
+ /* though we should perhaps take advantage of the case in which */
+ /* does. */
+ struct hblk; /* See gc_priv.h. */
+# ifdef PCR
+ char * real_malloc();
+# define GET_MEM(bytes) HBLKPTR(real_malloc((size_t)bytes + GC_page_size) \
+ + GC_page_size-1)
+# else
+# ifdef OS2
+ void * os2_alloc(size_t bytes);
+# define GET_MEM(bytes) HBLKPTR((ptr_t)os2_alloc((size_t)bytes \
+ + GC_page_size) \
+ + GC_page_size-1)
+# else
+# if defined(NEXT) || defined(DOS4GW) || \
+ (defined(AMIGA) && !defined(GC_AMIGA_FASTALLOC)) || \
+ (defined(SUNOS5) && !defined(USE_MMAP))
+# define GET_MEM(bytes) HBLKPTR((size_t) \
+ calloc(1, (size_t)bytes + GC_page_size) \
+ + GC_page_size-1)
+# else
+# ifdef MSWIN32
+ extern ptr_t GC_win32_get_mem();
+# define GET_MEM(bytes) (struct hblk *)GC_win32_get_mem(bytes)
+# else
+# ifdef MACOS
+# if defined(USE_TEMPORARY_MEMORY)
+ extern Ptr GC_MacTemporaryNewPtr(size_t size,
+ Boolean clearMemory);
+# define GET_MEM(bytes) HBLKPTR( \
+ GC_MacTemporaryNewPtr(bytes + GC_page_size, true) \
+ + GC_page_size-1)
+# else
+# define GET_MEM(bytes) HBLKPTR( \
+ NewPtrClear(bytes + GC_page_size) + GC_page_size-1)
+# endif
+# else
+# ifdef MSWINCE
+ extern ptr_t GC_wince_get_mem();
+# define GET_MEM(bytes) (struct hblk *)GC_wince_get_mem(bytes)
+# else
+# if defined(AMIGA) && defined(GC_AMIGA_FASTALLOC)
+ extern void *GC_amiga_get_mem(size_t size);
+# define GET_MEM(bytes) HBLKPTR((size_t) \
+ GC_amiga_get_mem((size_t)bytes + GC_page_size) \
+ + GC_page_size-1)
+# else
+ extern ptr_t GC_unix_get_mem();
+# define GET_MEM(bytes) (struct hblk *)GC_unix_get_mem(bytes)
+# endif
+# endif
+# endif
+# endif
+# endif
+# endif
+# endif
+
+#endif /* GC_PRIVATE_H */
+
# endif /* GCCONFIG_H */
diff --git a/boehm-gc/include/private/solaris_threads.h b/boehm-gc/include/private/solaris_threads.h
index 1464bc14fd7..7d49c2987e0 100644
--- a/boehm-gc/include/private/solaris_threads.h
+++ b/boehm-gc/include/private/solaris_threads.h
@@ -16,7 +16,8 @@
# define DETACHED 2 /* Thread is intended to be detached. */
# define CLIENT_OWNS_STACK 4
/* Stack was supplied by client. */
-# define SUSPENDED 8 /* Currently suspended. */
+# define SUSPNDED 8 /* Currently suspended. */
+ /* SUSPENDED is used insystem header. */
ptr_t stack;
size_t stack_size;
cond_t join_cv;
diff --git a/boehm-gc/include/private/specific.h b/boehm-gc/include/private/specific.h
index 399f84f58d6..a0e6ae0ebc1 100644
--- a/boehm-gc/include/private/specific.h
+++ b/boehm-gc/include/private/specific.h
@@ -85,7 +85,7 @@ static __inline__ void * PREFIXED(getspecific) (tsd * key) {
unsigned hash_val = CACHE_HASH(qtid);
tse * volatile * entry_ptr = key -> cache + hash_val;
tse * entry = *entry_ptr; /* Must be loaded only once. */
- if (entry -> qtid == qtid) {
+ if (EXPECT(entry -> qtid == qtid, 1)) {
GC_ASSERT(entry -> thread == pthread_self());
return entry -> value;
}
diff --git a/boehm-gc/irix_threads.c b/boehm-gc/irix_threads.c
deleted file mode 100644
index 75b7c63125e..00000000000
--- a/boehm-gc/irix_threads.c
+++ /dev/null
@@ -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 */
-
diff --git a/boehm-gc/linux_threads.c b/boehm-gc/linux_threads.c
deleted file mode 100644
index c968e7cbfd4..00000000000
--- a/boehm-gc/linux_threads.c
+++ /dev/null
@@ -1,1735 +0,0 @@
-/*
- * Copyright (c) 1994 by Xerox Corporation. All rights reserved.
- * Copyright (c) 1996 by Silicon Graphics. All rights reserved.
- * Copyright (c) 1998 by Fergus Henderson. All rights reserved.
- * Copyright (c) 2000-2001 by Hewlett-Packard Company. All rights reserved.
- *
- * 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 LinuxThreads, the clone()-based kernel
- * thread package for Linux which is included in libc6.
- *
- * This code relies on implementation details of LinuxThreads,
- * (i.e. properties not guaranteed by the Pthread standard),
- * though this version now does less of that than the other Pthreads
- * support code.
- *
- * Note that there is a lot of code duplication between linux_threads.c
- * and thread support for some of the other Posix platforms; any changes
- * made here may need to be reflected there too.
- */
-/*
- * Linux_threads.c now also includes some code to support HPUX and
- * OSF1 (Compaq Tru64 Unix, really). The OSF1 support is not yet
- * functional. The OSF1 code is based on Eric Benson's
- * patch, though that was originally against hpux_irix_threads. The code
- * here is completely untested. With 0.0000001% probability, it might
- * actually work.
- *
- * Eric also suggested an alternate basis for a lock implementation in
- * his code:
- * + #elif defined(OSF1)
- * + unsigned long GC_allocate_lock = 0;
- * + msemaphore GC_allocate_semaphore;
- * + # define GC_TRY_LOCK() \
- * + ((msem_lock(&GC_allocate_semaphore, MSEM_IF_NOWAIT) == 0) \
- * + ? (GC_allocate_lock = 1) \
- * + : 0)
- * + # define GC_LOCK_TAKEN GC_allocate_lock
- */
-
-/* #define DEBUG_THREADS 1 */
-
-/* ANSI C requires that a compilation unit contains something */
-
-# include "gc.h"
-
-# if defined(GC_PTHREADS) && !defined(GC_SOLARIS_THREADS) \
- && !defined(GC_IRIX_THREADS)
-
-# include "private/gc_priv.h"
-
-# if defined(GC_HPUX_THREADS) && !defined(USE_PTHREAD_SPECIFIC) \
- && !defined(USE_HPUX_TLS)
-# define USE_HPUX_TLS
-# endif
-
-# ifdef THREAD_LOCAL_ALLOC
-# if !defined(USE_PTHREAD_SPECIFIC) && !defined(USE_HPUX_TLS)
-# include "private/specific.h"
-# endif
-# if defined(USE_PTHREAD_SPECIFIC)
-# define GC_getspecific pthread_getspecific
-# define GC_setspecific pthread_setspecific
-# define GC_key_create pthread_key_create
- typedef pthread_key_t GC_key_t;
-# endif
-# if defined(USE_HPUX_TLS)
-# define GC_getspecific(x) (x)
-# define GC_setspecific(key, v) ((key) = (v), 0)
-# define GC_key_create(key, d) 0
- typedef void * GC_key_t;
-# endif
-# endif
-# include <stdlib.h>
-# include <pthread.h>
-# include <sched.h>
-# include <time.h>
-# include <errno.h>
-# include <unistd.h>
-# include <sys/mman.h>
-# include <sys/time.h>
-# include <semaphore.h>
-# include <signal.h>
-# include <sys/types.h>
-# include <sys/stat.h>
-# include <fcntl.h>
-
-#ifndef __GNUC__
-# define __inline__
-#endif
-
-#ifdef GC_USE_LD_WRAP
-# define WRAP_FUNC(f) __wrap_##f
-# define REAL_FUNC(f) __real_##f
-#else
-# define WRAP_FUNC(f) GC_##f
-# define REAL_FUNC(f) f
-# undef pthread_create
-# undef pthread_sigmask
-# undef pthread_join
-# undef pthread_detach
-#endif
-
-
-void GC_thr_init();
-
-#if 0
-void GC_print_sig_mask()
-{
- sigset_t blocked;
- int i;
-
- if (pthread_sigmask(SIG_BLOCK, NULL, &blocked) != 0)
- ABORT("pthread_sigmask");
- GC_printf0("Blocked: ");
- for (i = 1; i <= MAXSIG; i++) {
- if (sigismember(&blocked, i)) { GC_printf1("%ld ",(long) i); }
- }
- GC_printf0("\n");
-}
-#endif
-
-
-/* We use the allocation lock to protect thread-related data structures. */
-
-/* The set of all known threads. We intercept thread creation and */
-/* joins. */
-/* Protected by allocation/GC lock. */
-/* Some of this should be declared volatile, but that's inconsistent */
-/* 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;
- short flags;
-# define FINISHED 1 /* Thread has exited. */
-# define DETACHED 2 /* Thread is intended to be detached. */
-# define MAIN_THREAD 4 /* True for the original thread only. */
- short thread_blocked; /* Protected by GC lock. */
- /* Treated as a boolean value. If set, */
- /* thread will acquire GC lock before */
- /* doing any pointer manipulations, and */
- /* has set its sp value. Thus it does */
- /* not need to be sent a signal to stop */
- /* it. */
- ptr_t stack_end; /* Cold end of the stack. */
- ptr_t stack_ptr; /* Valid only when stopped. */
-# ifdef IA64
- ptr_t backing_store_end;
- ptr_t backing_store_ptr;
-# endif
- int signal;
- void * status; /* The value returned from the thread. */
- /* Used only to avoid premature */
- /* reclamation of any data it might */
- /* reference. */
-# ifdef THREAD_LOCAL_ALLOC
-# if CPP_WORDSZ == 64 && defined(ALIGN_DOUBLE)
-# define GRANULARITY 16
-# define NFREELISTS 49
-# else
-# define GRANULARITY 8
-# define NFREELISTS 65
-# endif
- /* The ith free list corresponds to size i*GRANULARITY */
-# define INDEX_FROM_BYTES(n) ((ADD_SLOP(n) + GRANULARITY - 1)/GRANULARITY)
-# define BYTES_FROM_INDEX(i) ((i) * GRANULARITY - EXTRA_BYTES)
-# define SMALL_ENOUGH(bytes) (ADD_SLOP(bytes) <= \
- (NFREELISTS-1)*GRANULARITY)
- ptr_t ptrfree_freelists[NFREELISTS];
- ptr_t normal_freelists[NFREELISTS];
-# ifdef GC_GCJ_SUPPORT
- ptr_t gcj_freelists[NFREELISTS];
-# endif
- /* Free lists contain either a pointer or a small count */
- /* reflecting the number of granules allocated at that */
- /* size. */
- /* 0 ==> thread-local allocation in use, free list */
- /* empty. */
- /* > 0, <= DIRECT_GRANULES ==> Using global allocation, */
- /* too few objects of this size have been */
- /* allocated by this thread. */
- /* >= HBLKSIZE => pointer to nonempty free list. */
- /* > DIRECT_GRANULES, < HBLKSIZE ==> transition to */
- /* local alloc, equivalent to 0. */
-# define DIRECT_GRANULES (HBLKSIZE/GRANULARITY)
- /* Don't use local free lists for up to this much */
- /* allocation. */
-# endif
-} * GC_thread;
-
-GC_thread GC_lookup_thread(pthread_t id);
-
-static GC_bool parallel_initialized = FALSE;
-
-void GC_init_parallel();
-
-# if defined(THREAD_LOCAL_ALLOC) && !defined(DBG_HDRS_ALL)
-
-/* We don't really support thread-local allocation with DBG_HDRS_ALL */
-
-#ifdef USE_HPUX_TLS
- __thread
-#endif
-GC_key_t GC_thread_key;
-
-static GC_bool keys_initialized;
-
-/* Recover the contents of the freelist array fl into the global one gfl.*/
-/* Note that the indexing scheme differs, in that gfl has finer size */
-/* resolution, even if not all entries are used. */
-/* We hold the allocator lock. */
-static void return_freelists(ptr_t *fl, ptr_t *gfl)
-{
- int i;
- ptr_t q, *qptr;
- size_t nwords;
-
- for (i = 1; i < NFREELISTS; ++i) {
- nwords = i * (GRANULARITY/sizeof(word));
- qptr = fl + i;
- q = *qptr;
- if ((word)q >= HBLKSIZE) {
- if (gfl[nwords] == 0) {
- gfl[nwords] = q;
- } else {
- /* Concatenate: */
- for (; (word)q >= HBLKSIZE; qptr = &(obj_link(q)), q = *qptr);
- GC_ASSERT(0 == q);
- *qptr = gfl[nwords];
- gfl[nwords] = fl[i];
- }
- }
- /* Clear fl[i], since the thread structure may hang around. */
- /* Do it in a way that is likely to trap if we access it. */
- fl[i] = (ptr_t)HBLKSIZE;
- }
-}
-
-/* We statically allocate a single "size 0" object. It is linked to */
-/* itself, and is thus repeatedly reused for all size 0 allocation */
-/* requests. (Size 0 gcj allocation requests are incorrect, and */
-/* we arrange for those to fault asap.) */
-static ptr_t size_zero_object = (ptr_t)(&size_zero_object);
-
-/* Each thread structure must be initialized. */
-/* This call must be made from the new thread. */
-/* Caller holds allocation lock. */
-void GC_init_thread_local(GC_thread p)
-{
- int i;
-
- if (!keys_initialized) {
- if (0 != GC_key_create(&GC_thread_key, 0)) {
- ABORT("Failed to create key for local allocator");
- }
- keys_initialized = TRUE;
- }
- if (0 != GC_setspecific(GC_thread_key, p)) {
- ABORT("Failed to set thread specific allocation pointers");
- }
- for (i = 1; i < NFREELISTS; ++i) {
- p -> ptrfree_freelists[i] = (ptr_t)1;
- p -> normal_freelists[i] = (ptr_t)1;
-# ifdef GC_GCJ_SUPPORT
- p -> gcj_freelists[i] = (ptr_t)1;
-# endif
- }
- /* Set up the size 0 free lists. */
- p -> ptrfree_freelists[0] = (ptr_t)(&size_zero_object);
- p -> normal_freelists[0] = (ptr_t)(&size_zero_object);
-# ifdef GC_GCJ_SUPPORT
- p -> gcj_freelists[0] = (ptr_t)(-1);
-# endif
-}
-
-#ifdef GC_GCJ_SUPPORT
- extern ptr_t * GC_gcjobjfreelist;
-#endif
-
-/* We hold the allocator lock. */
-void GC_destroy_thread_local(GC_thread p)
-{
- /* We currently only do this from the thread itself. */
- GC_ASSERT(GC_getspecific(GC_thread_key) == (void *)p);
- return_freelists(p -> ptrfree_freelists, GC_aobjfreelist);
- return_freelists(p -> normal_freelists, GC_objfreelist);
-# ifdef GC_GCJ_SUPPORT
- return_freelists(p -> gcj_freelists, GC_gcjobjfreelist);
-# endif
-}
-
-extern GC_PTR GC_generic_malloc_many();
-
-GC_PTR GC_local_malloc(size_t bytes)
-{
- if (EXPECT(!SMALL_ENOUGH(bytes),0)) {
- return(GC_malloc(bytes));
- } else {
- int index = INDEX_FROM_BYTES(bytes);
- ptr_t * my_fl;
- ptr_t my_entry;
- GC_key_t k = GC_thread_key;
- void * tsd;
-
-# if defined(REDIRECT_MALLOC) && !defined(USE_PTHREAD_SPECIFIC) \
- || !defined(__GNUC__)
- if (EXPECT(0 == k, 0)) {
- /* This can happen if we get called when the world is */
- /* being initialized. Whether we can actually complete */
- /* the initialization then is unclear. */
- GC_init_parallel();
- k = GC_thread_key;
- }
-# endif
- tsd = GC_getspecific(GC_thread_key);
-# ifdef GC_ASSERTIONS
- LOCK();
- GC_ASSERT(tsd == (void *)GC_lookup_thread(pthread_self()));
- UNLOCK();
-# endif
- my_fl = ((GC_thread)tsd) -> normal_freelists + index;
- my_entry = *my_fl;
- if (EXPECT((word)my_entry >= HBLKSIZE, 1)) {
- ptr_t next = obj_link(my_entry);
- GC_PTR result = (GC_PTR)my_entry;
- *my_fl = next;
- obj_link(my_entry) = 0;
- PREFETCH_FOR_WRITE(next);
- return result;
- } else if ((word)my_entry - 1 < DIRECT_GRANULES) {
- *my_fl = my_entry + index + 1;
- return GC_malloc(bytes);
- } else {
- GC_generic_malloc_many(BYTES_FROM_INDEX(index), NORMAL, my_fl);
- if (*my_fl == 0) return GC_oom_fn(bytes);
- return GC_local_malloc(bytes);
- }
- }
-}
-
-GC_PTR GC_local_malloc_atomic(size_t bytes)
-{
- if (EXPECT(!SMALL_ENOUGH(bytes), 0)) {
- return(GC_malloc_atomic(bytes));
- } else {
- int index = INDEX_FROM_BYTES(bytes);
- ptr_t * my_fl = ((GC_thread)GC_getspecific(GC_thread_key))
- -> ptrfree_freelists + index;
- ptr_t my_entry = *my_fl;
- if (EXPECT((word)my_entry >= HBLKSIZE, 1)) {
- GC_PTR result = (GC_PTR)my_entry;
- *my_fl = obj_link(my_entry);
- return result;
- } else if ((word)my_entry - 1 < DIRECT_GRANULES) {
- *my_fl = my_entry + index + 1;
- return GC_malloc_atomic(bytes);
- } else {
- GC_generic_malloc_many(BYTES_FROM_INDEX(index), PTRFREE, my_fl);
- /* *my_fl is updated while the collector is excluded; */
- /* the free list is always visible to the collector as */
- /* such. */
- if (*my_fl == 0) return GC_oom_fn(bytes);
- return GC_local_malloc_atomic(bytes);
- }
- }
-}
-
-#ifdef GC_GCJ_SUPPORT
-
-#include "include/gc_gcj.h"
-
-#ifdef GC_ASSERTIONS
- extern GC_bool GC_gcj_malloc_initialized;
-#endif
-
-extern int GC_gcj_kind;
-
-GC_PTR GC_local_gcj_malloc(size_t bytes,
- void * ptr_to_struct_containing_descr)
-{
- GC_ASSERT(GC_gcj_malloc_initialized);
- if (EXPECT(!SMALL_ENOUGH(bytes), 0)) {
- return GC_gcj_malloc(bytes, ptr_to_struct_containing_descr);
- } else {
- int index = INDEX_FROM_BYTES(bytes);
- ptr_t * my_fl = ((GC_thread)GC_getspecific(GC_thread_key))
- -> gcj_freelists + index;
- ptr_t my_entry = *my_fl;
- if (EXPECT((word)my_entry >= HBLKSIZE, 1)) {
- GC_PTR result = (GC_PTR)my_entry;
- GC_ASSERT(!GC_incremental);
- /* We assert that any concurrent marker will stop us. */
- /* Thus it is impossible for a mark procedure to see the */
- /* allocation of the next object, but to see this object */
- /* still containing a free list pointer. Otherwise the */
- /* marker might find a random "mark descriptor". */
- *(volatile ptr_t *)my_fl = obj_link(my_entry);
- /* We must update the freelist before we store the pointer. */
- /* Otherwise a GC at this point would see a corrupted */
- /* free list. */
- /* A memory barrier is probably never needed, since the */
- /* action of stopping this thread will cause prior writes */
- /* to complete. */
- GC_ASSERT(((void * volatile *)result)[1] == 0);
- *(void * volatile *)result = ptr_to_struct_containing_descr;
- return result;
- } else if ((word)my_entry - 1 < DIRECT_GRANULES) {
- *my_fl = my_entry + index + 1;
- return GC_gcj_malloc(bytes, ptr_to_struct_containing_descr);
- } else {
- GC_generic_malloc_many(BYTES_FROM_INDEX(index), GC_gcj_kind, my_fl);
- if (*my_fl == 0) return GC_oom_fn(bytes);
- return GC_local_gcj_malloc(bytes, ptr_to_struct_containing_descr);
- }
- }
-}
-
-#endif /* GC_GCJ_SUPPORT */
-
-# else /* !THREAD_LOCAL_ALLOC && !DBG_HDRS_ALL */
-
-# define GC_destroy_thread_local(t)
-
-# endif /* !THREAD_LOCAL_ALLOC */
-
-/*
- * We use signals to stop threads during GC.
- *
- * Suspended threads wait in signal handler for SIG_THR_RESTART.
- * That's more portable than semaphores or condition variables.
- * (We do use sem_post from a signal handler, but that should be portable.)
- *
- * The thread suspension signal SIG_SUSPEND is now defined in gc_priv.h.
- * Note that we can't just stop a thread; we need it to save its stack
- * pointer(s) and acknowledge.
- */
-
-#ifndef SIG_THR_RESTART
-# if defined(GC_HPUX_THREADS) || defined(GC_OSF1_THREADS)
-# define SIG_THR_RESTART _SIGRTMIN + 5
-# else
-# define SIG_THR_RESTART SIGXCPU
-# endif
-#endif
-
-sem_t GC_suspend_ack_sem;
-
-#if 0
-/*
-To make sure that we're using LinuxThreads and not some other thread
-package, we generate a dummy reference to `pthread_kill_other_threads_np'
-(was `__pthread_initial_thread_bos' but that disappeared),
-which is a symbol defined in LinuxThreads, but (hopefully) not in other
-thread packages.
-
-We no longer do this, since this code is now portable enough that it might
-actually work for something else.
-*/
-void (*dummy_var_to_force_linux_threads)() = pthread_kill_other_threads_np;
-#endif /* 0 */
-
-#if defined(SPARC) || defined(IA64)
- extern word GC_save_regs_in_stack();
-#endif
-
-long GC_nprocs = 1; /* Number of processors. We may not have */
- /* access to all of them, but this is as good */
- /* a guess as any ... */
-
-#ifdef PARALLEL_MARK
-
-# ifndef MAX_MARKERS
-# define MAX_MARKERS 16
-# endif
-
-static ptr_t marker_sp[MAX_MARKERS] = {0};
-
-void * GC_mark_thread(void * id)
-{
- word my_mark_no = 0;
-
- marker_sp[(word)id] = GC_approx_sp();
- for (;; ++my_mark_no) {
- /* GC_mark_no is passed only to allow GC_help_marker to terminate */
- /* promptly. This is important if it were called from the signal */
- /* handler or from the GC lock acquisition code. Under Linux, it's */
- /* not safe to call it from a signal handler, since it uses mutexes */
- /* and condition variables. Since it is called only here, the */
- /* argument is unnecessary. */
- if (my_mark_no < GC_mark_no || my_mark_no > GC_mark_no + 2) {
- /* resynchronize if we get far off, e.g. because GC_mark_no */
- /* wrapped. */
- my_mark_no = GC_mark_no;
- }
-# ifdef DEBUG_THREADS
- GC_printf1("Starting mark helper for mark number %ld\n", my_mark_no);
-# endif
- GC_help_marker(my_mark_no);
- }
-}
-
-extern long GC_markers; /* Number of mark threads we would */
- /* like to have. Includes the */
- /* initiating thread. */
-
-pthread_t GC_mark_threads[MAX_MARKERS];
-
-#define PTHREAD_CREATE REAL_FUNC(pthread_create)
-
-static void start_mark_threads()
-{
- unsigned i;
- pthread_attr_t attr;
-
- if (GC_markers > MAX_MARKERS) {
- WARN("Limiting number of mark threads\n", 0);
- GC_markers = MAX_MARKERS;
- }
- if (0 != pthread_attr_init(&attr)) ABORT("pthread_attr_init failed");
-
- if (0 != pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED))
- ABORT("pthread_attr_setdetachstate failed");
-
-# ifdef HPUX
- /* Default stack size is usually too small: fix it. */
- /* Otherwise marker threads or GC may run out of */
- /* space. */
-# define MIN_STACK_SIZE (8*HBLKSIZE*sizeof(word))
- {
- size_t old_size;
- int code;
-
- if (pthread_attr_getstacksize(&attr, &old_size) != 0)
- ABORT("pthread_attr_getstacksize failed\n");
- if (old_size < MIN_STACK_SIZE) {
- if (pthread_attr_setstacksize(&attr, MIN_STACK_SIZE) != 0)
- ABORT("pthread_attr_setstacksize failed\n");
- }
- }
-# endif /* HPUX */
-# ifdef CONDPRINT
- if (GC_print_stats) {
- GC_printf1("Starting %ld marker threads\n", GC_markers - 1);
- }
-# endif
- for (i = 0; i < GC_markers - 1; ++i) {
- if (0 != PTHREAD_CREATE(GC_mark_threads + i, &attr,
- GC_mark_thread, (void *)(word)i)) {
- WARN("Marker thread creation failed, errno = %ld.\n", errno);
- }
- }
-}
-
-#else /* !PARALLEL_MARK */
-
-static __inline__ void start_mark_threads()
-{
-}
-
-#endif /* !PARALLEL_MARK */
-
-void GC_suspend_handler(int sig)
-{
- int dummy;
- pthread_t my_thread = pthread_self();
- GC_thread me;
- sigset_t all_sigs;
- sigset_t old_sigs;
- int i;
- sigset_t mask;
-# ifdef PARALLEL_MARK
- word my_mark_no = GC_mark_no;
- /* Marker can't proceed until we acknowledge. Thus this is */
- /* guaranteed to be the mark_no correspending to our */
- /* suspension, i.e. the marker can't have incremented it yet. */
-# endif
-
- if (sig != SIG_SUSPEND) ABORT("Bad signal in suspend_handler");
-
-#if DEBUG_THREADS
- GC_printf1("Suspending 0x%x\n", my_thread);
-#endif
-
- me = GC_lookup_thread(my_thread);
- /* 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. */
-# ifdef SPARC
- me -> stack_ptr = (ptr_t)GC_save_regs_in_stack();
-# else
- me -> stack_ptr = (ptr_t)(&dummy);
-# endif
-# ifdef IA64
- me -> backing_store_ptr = (ptr_t)GC_save_regs_in_stack();
-# endif
-
- /* Tell the thread that wants to stop the world that this */
- /* thread has been stopped. Note that sem_post() is */
- /* the only async-signal-safe primitive in LinuxThreads. */
- sem_post(&GC_suspend_ack_sem);
-
- /* Wait until that thread tells us to restart by sending */
- /* this thread a SIG_THR_RESTART signal. */
- /* SIG_THR_RESTART should be masked at this point. Thus there */
- /* is no race. */
- if (sigfillset(&mask) != 0) ABORT("sigfillset() failed");
- if (sigdelset(&mask, SIG_THR_RESTART) != 0) ABORT("sigdelset() failed");
-# ifdef NO_SIGNALS
- if (sigdelset(&mask, SIGINT) != 0) ABORT("sigdelset() failed");
- if (sigdelset(&mask, SIGQUIT) != 0) ABORT("sigdelset() failed");
- if (sigdelset(&mask, SIGTERM) != 0) ABORT("sigdelset() failed");
- if (sigdelset(&mask, SIGABRT) != 0) ABORT("sigdelset() failed");
-# endif
- do {
- me->signal = 0;
- sigsuspend(&mask); /* Wait for signal */
- } while (me->signal != SIG_THR_RESTART);
-
-#if DEBUG_THREADS
- GC_printf1("Continuing 0x%x\n", my_thread);
-#endif
-}
-
-void GC_restart_handler(int sig)
-{
- GC_thread me;
-
- if (sig != SIG_THR_RESTART) ABORT("Bad signal in suspend_handler");
-
- /* Let the GC_suspend_handler() know that we got a SIG_THR_RESTART. */
- /* The lookup here is safe, since I'm doing this on behalf */
- /* of a thread which holds the allocation lock in order */
- /* to stop the world. Thus concurrent modification of the */
- /* data structure is impossible. */
- me = GC_lookup_thread(pthread_self());
- me->signal = SIG_THR_RESTART;
-
- /*
- ** Note: even if we didn't do anything useful here,
- ** it would still be necessary to have a signal handler,
- ** rather than ignoring the signals, otherwise
- ** the signals will not be delivered at all, and
- ** will thus not interrupt the sigsuspend() above.
- */
-
-#if DEBUG_THREADS
- GC_printf1("In GC_restart_handler for 0x%x\n", pthread_self());
-#endif
-}
-
-/* Defining INSTALL_LOOPING_SEGV_HANDLER causes SIGSEGV and SIGBUS to */
-/* result in an infinite loop in a signal handler. This can be very */
-/* useful for debugging, since (as of RH7) gdb still seems to have */
-/* serious problems with threads. */
-#ifdef INSTALL_LOOPING_SEGV_HANDLER
-void GC_looping_handler(int sig)
-{
- GC_printf3("Signal %ld in thread %lx, pid %ld\n",
- sig, pthread_self(), getpid());
- for (;;);
-}
-#endif
-
-GC_bool GC_thr_initialized = FALSE;
-
-# define THREAD_TABLE_SZ 128 /* Must be power of 2 */
-volatile GC_thread GC_threads[THREAD_TABLE_SZ];
-
-void GC_push_thread_structures GC_PROTO((void))
-{
- GC_push_all((ptr_t)(GC_threads), (ptr_t)(GC_threads)+sizeof(GC_threads));
-}
-
-#ifdef THREAD_LOCAL_ALLOC
-/* We must explicitly mark ptrfree and gcj free lists, since the free */
-/* list links wouldn't otherwise be found. We also set them in the */
-/* normal free lists, since that involves touching less memory than if */
-/* we scanned them normally. */
-void GC_mark_thread_local_free_lists(void)
-{
- int i, j;
- GC_thread p;
- ptr_t q;
-
- for (i = 0; i < THREAD_TABLE_SZ; ++i) {
- for (p = GC_threads[i]; 0 != p; p = p -> next) {
- for (j = 1; j < NFREELISTS; ++j) {
- q = p -> ptrfree_freelists[j];
- if ((word)q > HBLKSIZE) GC_set_fl_marks(q);
- q = p -> normal_freelists[j];
- if ((word)q > HBLKSIZE) GC_set_fl_marks(q);
-# ifdef GC_GCJ_SUPPORT
- q = p -> gcj_freelists[j];
- if ((word)q > HBLKSIZE) GC_set_fl_marks(q);
-# endif /* GC_GCJ_SUPPORT */
- }
- }
- }
-}
-#endif /* THREAD_LOCAL_ALLOC */
-
-/* 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;
- } 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;
- GC_ASSERT(result -> flags == 0 && result -> thread_blocked == 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;
- }
- GC_INTERNAL_FREE(p);
-}
-
-/* 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;
- }
- GC_INTERNAL_FREE(p);
-}
-
-/* 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);
-}
-
-/* There seems to be a very rare thread stopping problem. To help us */
-/* debug that, we save the ids of the stopping thread. */
-pthread_t GC_stopping_thread;
-int GC_stopping_pid;
-
-/* Caller holds allocation lock. */
-void GC_stop_world()
-{
- pthread_t my_thread = pthread_self();
- register int i;
- register GC_thread p;
- register int n_live_threads = 0;
- register int result;
-
- GC_stopping_thread = my_thread; /* debugging only. */
- GC_stopping_pid = getpid(); /* debugging only. */
- /* Make sure all free list construction has stopped before we start. */
- /* No new construction can start, since free list construction is */
- /* required to acquire and release the GC lock before it starts, */
- /* and we have the lock. */
-# ifdef PARALLEL_MARK
- GC_acquire_mark_lock();
- GC_ASSERT(GC_fl_builder_count == 0);
- /* We should have previously waited for it to become zero. */
-# endif /* PARALLEL_MARK */
- 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) continue;
- if (p -> thread_blocked) /* Will wait */ continue;
- n_live_threads++;
- #if DEBUG_THREADS
- GC_printf1("Sending suspend signal to 0x%x\n", p -> id);
- #endif
- result = pthread_kill(p -> id, SIG_SUSPEND);
- switch(result) {
- case ESRCH:
- /* Not really there anymore. Possible? */
- n_live_threads--;
- break;
- case 0:
- break;
- default:
- ABORT("pthread_kill failed");
- }
- }
- }
- }
- for (i = 0; i < n_live_threads; i++) {
- if (0 != sem_wait(&GC_suspend_ack_sem))
- ABORT("sem_wait in handler failed");
- }
-# ifdef PARALLEL_MARK
- GC_release_mark_lock();
-# endif
- #if DEBUG_THREADS
- GC_printf1("World stopped 0x%x\n", pthread_self());
- #endif
- GC_stopping_thread = 0; /* debugging only */
-}
-
-/* Caller holds allocation lock, and has held it continuously since */
-/* the world stopped. */
-void GC_start_world()
-{
- pthread_t my_thread = pthread_self();
- register int i;
- register GC_thread p;
- register int n_live_threads = 0;
- register int result;
-
-# if DEBUG_THREADS
- GC_printf0("World starting\n");
-# endif
-
- 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) continue;
- if (p -> thread_blocked) continue;
- n_live_threads++;
- #if DEBUG_THREADS
- GC_printf1("Sending restart signal to 0x%x\n", p -> id);
- #endif
- result = pthread_kill(p -> id, SIG_THR_RESTART);
- switch(result) {
- case ESRCH:
- /* Not really there anymore. Possible? */
- n_live_threads--;
- break;
- case 0:
- break;
- default:
- ABORT("pthread_kill failed");
- }
- }
- }
- }
- #if DEBUG_THREADS
- GC_printf0("World started\n");
- #endif
- GC_stopping_thread = 0; /* debugging only */
-}
-
-# ifdef IA64
-# define IF_IA64(x) x
-# else
-# define IF_IA64(x)
-# 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()
-{
- int i;
- GC_thread p;
- ptr_t sp = GC_approx_sp();
- ptr_t lo, hi;
- /* On IA64, we also need to scan the register backing store. */
- IF_IA64(ptr_t bs_lo; ptr_t bs_hi;)
- pthread_t me = pthread_self();
-
- if (!GC_thr_initialized) GC_thr_init();
- #if DEBUG_THREADS
- GC_printf1("Pushing stacks from thread 0x%lx\n", (unsigned long) me);
- #endif
- 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)) {
-# ifdef SPARC
- lo = (ptr_t)GC_save_regs_in_stack();
-# else
- lo = GC_approx_sp();
-# endif
- IF_IA64(bs_hi = (ptr_t)GC_save_regs_in_stack();)
- } else {
- lo = p -> stack_ptr;
- IF_IA64(bs_hi = p -> backing_store_ptr;)
- }
- if ((p -> flags & MAIN_THREAD) == 0) {
- hi = p -> stack_end;
- IF_IA64(bs_lo = p -> backing_store_end);
- } else {
- /* The original stack. */
- hi = GC_stackbottom;
- IF_IA64(bs_lo = BACKING_STORE_BASE;)
- }
- #if DEBUG_THREADS
- GC_printf3("Stack for thread 0x%lx = [%lx,%lx)\n",
- (unsigned long) p -> id,
- (unsigned long) lo, (unsigned long) hi);
- #endif
- if (0 == lo) ABORT("GC_push_all_stacks: sp not set!\n");
-# ifdef STACK_GROWS_UP
- /* We got them backwards! */
- GC_push_all_stack(hi, lo);
-# else
- GC_push_all_stack(lo, hi);
-# endif
-# ifdef IA64
- if (pthread_equal(p -> id, me)) {
- GC_push_all_eager(bs_lo, bs_hi);
- } else {
- GC_push_all_stack(bs_lo, bs_hi);
- }
-# endif
- }
- }
-}
-
-#ifdef USE_PROC_FOR_LIBRARIES
-int GC_segment_is_thread_stack(ptr_t lo, ptr_t hi)
-{
- int i;
- GC_thread p;
-
-# ifdef PARALLEL_MARK
- for (i = 0; i < GC_markers; ++i) {
- if (marker_sp[i] > lo & marker_sp[i] < hi) return 1;
- }
-# endif
- for (i = 0; i < THREAD_TABLE_SZ; i++) {
- for (p = GC_threads[i]; p != 0; p = p -> next) {
- if (0 != p -> stack_end) {
-# ifdef STACK_GROWS_UP
- if (p -> stack_end >= lo && p -> stack_end < hi) return 1;
-# else /* STACK_GROWS_DOWN */
- if (p -> stack_end > lo && p -> stack_end <= hi) return 1;
-# endif
- }
- }
- }
- return 0;
-}
-#endif /* USE_PROC_FOR_LIBRARIES */
-
-#ifdef GC_LINUX_THREADS
-/* Return the number of processors, or i<= 0 if it can't be determined. */
-int GC_get_nprocs()
-{
- /* Should be "return sysconf(_SC_NPROCESSORS_ONLN);" but that */
- /* appears to be buggy in many cases. */
- /* We look for lines "cpu<n>" in /proc/stat. */
-# define STAT_BUF_SIZE 4096
-# if defined(GC_USE_LD_WRAP)
-# define STAT_READ __real_read
-# else
-# define STAT_READ read
-# endif
- char stat_buf[STAT_BUF_SIZE];
- int f;
- char c;
- word result = 1;
- /* Some old kernels only have a single "cpu nnnn ..." */
- /* entry in /proc/stat. We identify those as */
- /* uniprocessors. */
- size_t i, len = 0;
-
- f = open("/proc/stat", O_RDONLY);
- if (f < 0 || (len = STAT_READ(f, stat_buf, STAT_BUF_SIZE)) < 100) {
- WARN("Couldn't read /proc/stat\n", 0);
- return -1;
- }
- close(f);
- for (i = 0; i < len - 100; ++i) {
- if (stat_buf[i] == '\n' && stat_buf[i+1] == 'c'
- && stat_buf[i+2] == 'p' && stat_buf[i+3] == 'u') {
- int cpu_no = atoi(stat_buf + i + 4);
- if (cpu_no >= result) result = cpu_no + 1;
- }
- }
- return result;
-}
-#endif /* GC_LINUX_THREADS */
-
-/* We hold the allocation lock. */
-void GC_thr_init()
-{
- int dummy;
- GC_thread t;
- struct sigaction act;
-
- if (GC_thr_initialized) return;
- GC_thr_initialized = TRUE;
-
- if (sem_init(&GC_suspend_ack_sem, 0, 0) != 0)
- ABORT("sem_init failed");
-
- act.sa_flags = SA_RESTART;
- if (sigfillset(&act.sa_mask) != 0) {
- ABORT("sigfillset() failed");
- }
-# ifdef NO_SIGNALS
- if (sigdelset(&act.sa_mask, SIGINT) != 0
- || sigdelset(&act.sa_mask, SIGQUIT != 0)
- || sigdelset(&act.sa_mask, SIGABRT != 0)
- || sigdelset(&act.sa_mask, SIGTERM != 0)) {
- ABORT("sigdelset() failed");
- }
-# endif
-
- /* SIG_THR_RESTART is unmasked by the handler when necessary. */
- act.sa_handler = GC_suspend_handler;
- if (sigaction(SIG_SUSPEND, &act, NULL) != 0) {
- ABORT("Cannot set SIG_SUSPEND handler");
- }
-
- act.sa_handler = GC_restart_handler;
- if (sigaction(SIG_THR_RESTART, &act, NULL) != 0) {
- ABORT("Cannot set SIG_THR_RESTART handler");
- }
-# ifdef INSTALL_LOOPING_SEGV_HANDLER
- act.sa_handler = GC_looping_handler;
- if (sigaction(SIGSEGV, &act, NULL) != 0
- || sigaction(SIGBUS, &act, NULL) != 0) {
- ABORT("Cannot set SIGSEGV or SIGBUS looping handler");
- }
-# endif /* INSTALL_LOOPING_SEGV_HANDLER */
-
- /* Add the initial thread, so we can stop it. */
- t = GC_new_thread(pthread_self());
- t -> stack_ptr = (ptr_t)(&dummy);
- t -> flags = DETACHED | MAIN_THREAD;
-
- /* Set GC_nprocs. */
- {
- char * nprocs_string = GETENV("GC_NPROCS");
- GC_nprocs = -1;
- if (nprocs_string != NULL) GC_nprocs = atoi(nprocs_string);
- }
- if (GC_nprocs <= 0) {
-# if defined(GC_HPUX_THREADS)
- GC_nprocs = pthread_num_processors_np();
-# endif
-# if defined(GC_OSF1_THREADS) || defined(GC_FREEBSD_THREADS)
- GC_nprocs = 1;
-# endif
-# if defined(GC_LINUX_THREADS)
- GC_nprocs = GC_get_nprocs();
-# endif
- }
- if (GC_nprocs <= 0) {
- WARN("GC_get_nprocs() returned %ld\n", GC_nprocs);
- GC_nprocs = 2;
-# ifdef PARALLEL_MARK
- GC_markers = 1;
-# endif
- } else {
-# ifdef PARALLEL_MARK
- GC_markers = GC_nprocs;
-# endif
- }
-# ifdef PARALLEL_MARK
-# ifdef CONDPRINT
- if (GC_print_stats) {
- GC_printf2("Number of processors = %ld, "
- "number of marker threads = %ld\n", GC_nprocs, GC_markers);
- }
-# endif
- if (GC_markers == 1) {
- GC_parallel = FALSE;
-# ifdef CONDPRINT
- if (GC_print_stats) {
- GC_printf0("Single marker thread, turning off parallel marking\n");
- }
-# endif
- } else {
- GC_parallel = TRUE;
- }
-# endif
-}
-
-
-/* Perform all initializations, including those that */
-/* may require allocation. */
-/* Called as constructor without allocation lock. */
-/* Must be called before a second thread is created. */
-/* Called without allocation lock. */
-void GC_init_parallel()
-{
- if (parallel_initialized) return;
- parallel_initialized = TRUE;
- /* GC_init() calls us back, so set flag first. */
- if (!GC_is_initialized) GC_init();
- /* If we are using a parallel marker, start the helper threads. */
-# ifdef PARALLEL_MARK
- if (GC_parallel) start_mark_threads();
-# endif
- /* Initialize thread local free lists if used. */
-# if defined(THREAD_LOCAL_ALLOC) && !defined(DBG_HDRS_ALL)
- LOCK();
- GC_init_thread_local(GC_lookup_thread(pthread_self()));
- UNLOCK();
-# endif
-}
-
-
-int WRAP_FUNC(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(REAL_FUNC(pthread_sigmask)(how, set, oset));
-}
-
-/* Wrappers for functions that are likely to block for an appreciable */
-/* length of time. Must be called in pairs, if at all. */
-/* Nothing much beyond the system call itself should be executed */
-/* between these. */
-
-void GC_start_blocking(void) {
-# define SP_SLOP 128
- GC_thread me;
- LOCK();
- me = GC_lookup_thread(pthread_self());
- GC_ASSERT(!(me -> thread_blocked));
-# ifdef SPARC
- me -> stack_ptr = (ptr_t)GC_save_regs_in_stack();
-# else
- me -> stack_ptr = (ptr_t)GC_approx_sp();
-# endif
-# ifdef IA64
- me -> backing_store_ptr = (ptr_t)GC_save_regs_in_stack() + SP_SLOP;
-# endif
- /* Add some slop to the stack pointer, since the wrapped call may */
- /* end up pushing more callee-save registers. */
-# ifdef STACK_GROWS_UP
- me -> stack_ptr += SP_SLOP;
-# else
- me -> stack_ptr -= SP_SLOP;
-# endif
- me -> thread_blocked = TRUE;
- UNLOCK();
-}
-
-GC_end_blocking(void) {
- GC_thread me;
- LOCK(); /* This will block if the world is stopped. */
- me = GC_lookup_thread(pthread_self());
- GC_ASSERT(me -> thread_blocked);
- me -> thread_blocked = FALSE;
- UNLOCK();
-}
-
-/* A wrapper for the standard C sleep function */
-int WRAP_FUNC(sleep) (unsigned int seconds)
-{
- int result;
-
- GC_start_blocking();
- result = REAL_FUNC(sleep)(seconds);
- GC_end_blocking();
- return result;
-}
-
-struct start_info {
- void *(*start_routine)(void *);
- void *arg;
- word flags;
- sem_t registered; /* 1 ==> in our thread table, but */
- /* parent hasn't yet noticed. */
-};
-
-/* Called at thread exit. */
-/* Never called for main thread. That's OK, since it */
-/* results in at most a tiny one-time leak. And */
-/* linuxthreads doesn't reclaim the main threads */
-/* resources or id anyway. */
-void GC_thread_exit_proc(void *arg)
-{
- GC_thread me;
-
- LOCK();
- me = GC_lookup_thread(pthread_self());
- GC_destroy_thread_local(me);
- if (me -> flags & DETACHED) {
- GC_delete_thread(pthread_self());
- } else {
- me -> flags |= FINISHED;
- }
-# if defined(THREAD_LOCAL_ALLOC) && !defined(USE_PTHREAD_SPECIFIC) \
- && !defined(USE_HPUX_TLS) && !defined(DBG_HDRS_ALL)
- GC_remove_specific(GC_thread_key);
-# endif
- if (GC_incremental && GC_collection_in_progress()) {
- int old_gc_no = GC_gc_no;
-
- /* Make sure that no part of our stack is still on the mark stack, */
- /* since it's about to be unmapped. */
- while (GC_incremental && GC_collection_in_progress()
- && old_gc_no == GC_gc_no) {
- ENTER_GC();
- GC_collect_a_little_inner(1);
- EXIT_GC();
- UNLOCK();
- sched_yield();
- LOCK();
- }
- }
- UNLOCK();
-}
-
-int WRAP_FUNC(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 = REAL_FUNC(pthread_join)(thread, retval);
-# if defined (GC_FREEBSD_THREADS)
- /* On FreeBSD, the wrapped pthread_join() sometimes returns (what
- appears to be) a spurious EINTR which caused the test and real code
- to gratuitously fail. Having looked at system pthread library source
- code, I see how this return code may be generated. In one path of
- code, pthread_join() just returns the errno setting of the thread
- being joined. This does not match the POSIX specification or the
- local man pages thus I have taken the liberty to catch this one
- spurious return value properly conditionalized on GC_FREEBSD_THREADS. */
- if (result == EINTR) result = 0;
-# endif
- 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
-WRAP_FUNC(pthread_detach)(pthread_t thread)
-{
- int result;
- GC_thread thread_gc_id;
-
- LOCK();
- thread_gc_id = GC_lookup_thread(thread);
- UNLOCK();
- result = REAL_FUNC(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)
-{
- int dummy;
- struct start_info * si = arg;
- void * result;
- GC_thread me;
- pthread_t my_pthread;
- void *(*start)(void *);
- void *start_arg;
-
- my_pthread = pthread_self();
-# ifdef DEBUG_THREADS
- GC_printf1("Starting thread 0x%lx\n", my_pthread);
- GC_printf1("pid = %ld\n", (long) getpid());
- GC_printf1("sp = 0x%lx\n", (long) &arg);
-# endif
- LOCK();
- me = GC_new_thread(my_pthread);
- me -> flags = si -> flags;
- me -> stack_ptr = 0;
- /* me -> stack_end = GC_linux_stack_base(); -- currently (11/99) */
- /* doesn't work because the stack base in /proc/self/stat is the */
- /* one for the main thread. There is a strong argument that that's */
- /* a kernel bug, but a pervasive one. */
-# ifdef STACK_GROWS_DOWN
- me -> stack_end = (ptr_t)(((word)(&dummy) + (GC_page_size - 1))
- & ~(GC_page_size - 1));
- me -> stack_ptr = me -> stack_end - 0x10;
- /* Needs to be plausible, since an asynchronous stack mark */
- /* should not crash. */
-# else
- me -> stack_end = (ptr_t)((word)(&dummy) & ~(GC_page_size - 1));
- me -> stack_ptr = me -> stack_end + 0x10;
-# endif
- /* This is dubious, since we may be more than a page into the stack, */
- /* and hence skip some of it, though it's not clear that matters. */
-# ifdef IA64
- me -> backing_store_end = (ptr_t)
- (GC_save_regs_in_stack() & ~(GC_page_size - 1));
- /* This is also < 100% convincing. We should also read this */
- /* from /proc, but the hook to do so isn't there yet. */
-# endif /* IA64 */
- UNLOCK();
- start = si -> start_routine;
-# ifdef DEBUG_THREADS
- GC_printf1("start_routine = 0x%lx\n", start);
-# endif
- start_arg = si -> arg;
-# ifdef DEBUG_THREADS
- GC_printf1("sem_post from 0x%lx\n", my_pthread);
-# endif
- sem_post(&(si -> registered)); /* Last action on si. */
- /* OK to deallocate. */
- pthread_cleanup_push(GC_thread_exit_proc, 0);
-# if defined(THREAD_LOCAL_ALLOC) && !defined(DBG_HDRS_ALL)
- LOCK();
- GC_init_thread_local(me);
- UNLOCK();
-# endif
- result = (*start)(start_arg);
-#if DEBUG_THREADS
- GC_printf1("Finishing thread 0x%x\n", pthread_self());
-#endif
- me -> status = result;
- me -> flags |= FINISHED;
- pthread_cleanup_pop(1);
- /* Cleanup acquires lock, ensuring that we can't exit */
- /* while a collection that thinks we're alive is trying to stop */
- /* us. */
- return(result);
-}
-
-int
-WRAP_FUNC(pthread_create)(pthread_t *new_thread,
- const pthread_attr_t *attr,
- void *(*start_routine)(void *), void *arg)
-{
- int result;
- GC_thread t;
- pthread_t my_new_thread;
- int detachstate;
- word my_flags = 0;
- struct start_info * si;
- /* This is otherwise saved only in an area mmapped by the thread */
- /* library, which isn't visible to the collector. */
-
- LOCK();
- si = (struct start_info *)GC_INTERNAL_MALLOC(sizeof(struct start_info), NORMAL);
- UNLOCK();
- if (!parallel_initialized) GC_init_parallel();
- if (0 == si) return(ENOMEM);
- sem_init(&(si -> registered), 0, 0);
- si -> start_routine = start_routine;
- si -> arg = arg;
- LOCK();
- if (!GC_thr_initialized) GC_thr_init();
- if (NULL == attr) {
- detachstate = PTHREAD_CREATE_JOINABLE;
- } else {
- pthread_attr_getdetachstate(attr, &detachstate);
- }
- if (PTHREAD_CREATE_DETACHED == detachstate) my_flags |= DETACHED;
- si -> flags = my_flags;
- UNLOCK();
-# ifdef DEBUG_THREADS
- GC_printf1("About to start new thread from thread 0x%X\n",
- pthread_self());
-# endif
- result = REAL_FUNC(pthread_create)(new_thread, attr, GC_start_routine, si);
-# ifdef DEBUG_THREADS
- GC_printf1("Started thread 0x%X\n", *new_thread);
-# endif
- /* 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 (EINTR != errno) ABORT("sem_wait failed");
- }
-# ifdef DEBUG_THREADS
- GC_printf1("sem_wait complete from thread 0x%X\n",
- pthread_self());
-# endif
- sem_destroy(&(si -> registered));
- LOCK();
- GC_INTERNAL_FREE(si);
- UNLOCK();
- return(result);
-}
-
-#ifdef GENERIC_COMPARE_AND_SWAP
- pthread_mutex_t GC_compare_and_swap_lock = PTHREAD_MUTEX_INITIALIZER;
-
- GC_bool GC_compare_and_exchange(volatile GC_word *addr,
- GC_word old, GC_word new_val)
- {
- GC_bool result;
- pthread_mutex_lock(&GC_compare_and_swap_lock);
- if (*addr == old) {
- *addr = new_val;
- result = TRUE;
- } else {
- result = FALSE;
- }
- pthread_mutex_unlock(&GC_compare_and_swap_lock);
- return result;
- }
-
- GC_word GC_atomic_add(volatile GC_word *addr, GC_word how_much)
- {
- GC_word old;
- pthread_mutex_lock(&GC_compare_and_swap_lock);
- old = *addr;
- *addr = old + how_much;
- pthread_mutex_unlock(&GC_compare_and_swap_lock);
- return old;
- }
-
-#endif /* GENERIC_COMPARE_AND_SWAP */
-/* Spend a few cycles in a way that can't introduce contention with */
-/* othre threads. */
-void GC_pause()
-{
- int i;
- volatile word dummy = 0;
-
- for (i = 0; i < 10; ++i) {
-# ifdef __GNUC__
- __asm__ __volatile__ (" " : : : "memory");
-# else
- /* Something that's unlikely to be optimized away. */
- GC_noop(++dummy);
-# endif
- }
-}
-
-#define SPIN_MAX 1024 /* Maximum number of calls to GC_pause before */
- /* give up. */
-
-VOLATILE GC_bool GC_collecting = 0;
- /* A hint that we're in the collector and */
- /* holding the allocation lock for an */
- /* extended period. */
-
-#if !defined(USE_SPIN_LOCK) || defined(PARALLEL_MARK)
-/* If we don't want to use the below spinlock implementation, either */
-/* because we don't have a GC_test_and_set implementation, or because */
-/* we don't want to risk sleeping, we can still try spinning on */
-/* pthread_mutex_trylock for a while. This appears to be very */
-/* beneficial in many cases. */
-/* I suspect that under high contention this is nearly always better */
-/* than the spin lock. But it's a bit slower on a uniprocessor. */
-/* Hence we still default to the spin lock. */
-/* This is also used to acquire the mark lock for the parallel */
-/* marker. */
-
-/* Here we use a strict exponential backoff scheme. I don't know */
-/* whether that's better or worse than the above. We eventually */
-/* yield by calling pthread_mutex_lock(); it never makes sense to */
-/* explicitly sleep. */
-
-void GC_generic_lock(pthread_mutex_t * lock)
-{
- unsigned pause_length = 1;
- unsigned i;
-
- if (0 == pthread_mutex_trylock(lock)) return;
- for (; pause_length <= SPIN_MAX; pause_length <<= 1) {
- for (i = 0; i < pause_length; ++i) {
- GC_pause();
- }
- switch(pthread_mutex_trylock(lock)) {
- case 0:
- return;
- case EBUSY:
- break;
- default:
- ABORT("Unexpected error from pthread_mutex_trylock");
- }
- }
- pthread_mutex_lock(lock);
-}
-
-#endif /* !USE_SPIN_LOCK || PARALLEL_MARK */
-
-#if defined(USE_SPIN_LOCK)
-
-/* Reasonably fast spin locks. Basically the same implementation */
-/* as STL alloc.h. This isn't really the right way to do this. */
-/* but until the POSIX scheduling mess gets straightened out ... */
-
-volatile unsigned int GC_allocate_lock = 0;
-
-
-void GC_lock()
-{
-# define low_spin_max 30 /* spin cycles if we suspect uniprocessor */
-# define high_spin_max SPIN_MAX /* spin cycles for multiprocessor */
- static unsigned spin_max = low_spin_max;
- unsigned my_spin_max;
- static unsigned last_spins = 0;
- unsigned my_last_spins;
- int i;
-
- if (!GC_test_and_set(&GC_allocate_lock)) {
- return;
- }
- my_spin_max = spin_max;
- my_last_spins = last_spins;
- for (i = 0; i < my_spin_max; i++) {
- if (GC_collecting || GC_nprocs == 1) goto yield;
- if (i < my_last_spins/2 || GC_allocate_lock) {
- GC_pause();
- continue;
- }
- if (!GC_test_and_set(&GC_allocate_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_test_and_set(&GC_allocate_lock)) {
- return;
- }
-# define SLEEP_THRESHOLD 12
- /* nanosleep(<= 2ms) just spins under Linux. We */
- /* want to be careful to avoid that behavior. */
- if (i < SLEEP_THRESHOLD) {
- sched_yield();
- } else {
- struct timespec ts;
-
- if (i > 24) i = 24;
- /* Don't wait for more than about 15msecs, even */
- /* under extreme contention. */
- ts.tv_sec = 0;
- ts.tv_nsec = 1 << i;
- nanosleep(&ts, 0);
- }
- }
-}
-
-#else /* !USE_SPINLOCK */
-
-void GC_lock()
-{
- if (1 == GC_nprocs || GC_collecting) {
- pthread_mutex_lock(&GC_allocate_ml);
- } else {
- GC_generic_lock(&GC_allocate_ml);
- }
-}
-
-#endif /* !USE_SPINLOCK */
-
-#if defined(PARALLEL_MARK) || defined(THREAD_LOCAL_ALLOC)
-
-#ifdef GC_ASSERTIONS
- pthread_t GC_mark_lock_holder = NO_THREAD;
-#endif
-
-#if 0
- /* Ugly workaround for a linux threads bug in the final versions */
- /* of glibc2.1. Pthread_mutex_trylock sets the mutex owner */
- /* field even when it fails to acquire the mutex. This causes */
- /* pthread_cond_wait to die. Remove for glibc2.2. */
- /* According to the man page, we should use */
- /* PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP, but that isn't actually */
- /* defined. */
- static pthread_mutex_t mark_mutex =
- {0, 0, 0, PTHREAD_MUTEX_ERRORCHECK_NP, {0, 0}};
-#else
- static pthread_mutex_t mark_mutex = PTHREAD_MUTEX_INITIALIZER;
-#endif
-
-static pthread_cond_t builder_cv = PTHREAD_COND_INITIALIZER;
-
-void GC_acquire_mark_lock()
-{
-/*
- if (pthread_mutex_lock(&mark_mutex) != 0) {
- ABORT("pthread_mutex_lock failed");
- }
-*/
- GC_generic_lock(&mark_mutex);
-# ifdef GC_ASSERTIONS
- GC_mark_lock_holder = pthread_self();
-# endif
-}
-
-void GC_release_mark_lock()
-{
- GC_ASSERT(GC_mark_lock_holder == pthread_self());
-# ifdef GC_ASSERTIONS
- GC_mark_lock_holder = NO_THREAD;
-# endif
- if (pthread_mutex_unlock(&mark_mutex) != 0) {
- ABORT("pthread_mutex_unlock failed");
- }
-}
-
-/* Collector must wait for a freelist builders for 2 reasons: */
-/* 1) Mark bits may still be getting examined without lock. */
-/* 2) Partial free lists referenced only by locals may not be scanned */
-/* correctly, e.g. if they contain "pointer-free" objects, since the */
-/* free-list link may be ignored. */
-void GC_wait_builder()
-{
- GC_ASSERT(GC_mark_lock_holder == pthread_self());
-# ifdef GC_ASSERTIONS
- GC_mark_lock_holder = NO_THREAD;
-# endif
- if (pthread_cond_wait(&builder_cv, &mark_mutex) != 0) {
- ABORT("pthread_cond_wait failed");
- }
- GC_ASSERT(GC_mark_lock_holder == NO_THREAD);
-# ifdef GC_ASSERTIONS
- GC_mark_lock_holder = pthread_self();
-# endif
-}
-
-void GC_wait_for_reclaim()
-{
- GC_acquire_mark_lock();
- while (GC_fl_builder_count > 0) {
- GC_wait_builder();
- }
- GC_release_mark_lock();
-}
-
-void GC_notify_all_builder()
-{
- GC_ASSERT(GC_mark_lock_holder == pthread_self());
- if (pthread_cond_broadcast(&builder_cv) != 0) {
- ABORT("pthread_cond_broadcast failed");
- }
-}
-
-#endif /* PARALLEL_MARK || THREAD_LOCAL_ALLOC */
-
-#ifdef PARALLEL_MARK
-
-static pthread_cond_t mark_cv = PTHREAD_COND_INITIALIZER;
-
-void GC_wait_marker()
-{
- GC_ASSERT(GC_mark_lock_holder == pthread_self());
-# ifdef GC_ASSERTIONS
- GC_mark_lock_holder = NO_THREAD;
-# endif
- if (pthread_cond_wait(&mark_cv, &mark_mutex) != 0) {
- ABORT("pthread_cond_wait failed");
- }
- GC_ASSERT(GC_mark_lock_holder == NO_THREAD);
-# ifdef GC_ASSERTIONS
- GC_mark_lock_holder = pthread_self();
-# endif
-}
-
-void GC_notify_all_marker()
-{
- if (pthread_cond_broadcast(&mark_cv) != 0) {
- ABORT("pthread_cond_broadcast failed");
- }
-}
-
-#endif /* PARALLEL_MARK */
-
-# endif /* GC_LINUX_THREADS and friends */
-
diff --git a/boehm-gc/mach_dep.c b/boehm-gc/mach_dep.c
index a741058d70e..3dc5f0b27b9 100644
--- a/boehm-gc/mach_dep.c
+++ b/boehm-gc/mach_dep.c
@@ -74,7 +74,8 @@ asm static void PushMacRegisters()
/* on your architecture. Run the test_setjmp program to see whether */
/* there is any chance it will work. */
-#ifndef USE_GENERIC_PUSH_REGS
+#if !defined(USE_GENERIC_PUSH_REGS) && !defined(USE_ASM_PUSH_REGS)
+#undef HAVE_PUSH_REGS
void GC_push_regs()
{
# ifdef RT
@@ -91,6 +92,7 @@ void GC_push_regs()
asm("pushl r8"); asm("calls $1,_GC_push_one");
asm("pushl r7"); asm("calls $1,_GC_push_one");
asm("pushl r6"); asm("calls $1,_GC_push_one");
+# define HAVE_PUSH_REGS
# endif
# if defined(M68K) && (defined(SUNOS4) || defined(NEXT))
/* M68K SUNOS - could be replaced by generic code */
@@ -113,6 +115,7 @@ void GC_push_regs()
asm("movl d7,sp@"); asm("jbsr _GC_push_one");
asm("addqw #0x4,sp"); /* put stack back where it was */
+# define HAVE_PUSH_REGS
# endif
# if defined(M68K) && defined(HP)
@@ -135,6 +138,7 @@ void GC_push_regs()
asm("mov.l %d7,(%sp)"); asm("jsr _GC_push_one");
asm("addq.w &0x4,%sp"); /* put stack back where it was */
+# define HAVE_PUSH_REGS
# endif /* M68K HP */
# if defined(M68K) && defined(AMIGA)
@@ -158,6 +162,7 @@ void GC_push_regs()
asm("mov.l %d7,(%sp)"); asm("jsr _GC_push_one");
asm("addq.w &0x4,%sp"); /* put stack back where it was */
+# define HAVE_PUSH_REGS
# else /* !__GNUC__ */
GC_push_one(getreg(REG_A2));
GC_push_one(getreg(REG_A3));
@@ -174,6 +179,7 @@ void GC_push_regs()
GC_push_one(getreg(REG_D5));
GC_push_one(getreg(REG_D6));
GC_push_one(getreg(REG_D7));
+# define HAVE_PUSH_REGS
# endif /* !__GNUC__ */
# endif /* AMIGA */
@@ -196,10 +202,12 @@ void GC_push_regs()
PushMacReg(d7);
add.w #4,sp ; fix stack.
}
+# define HAVE_PUSH_REGS
# undef PushMacReg
# endif /* THINK_C */
# if defined(__MWERKS__)
PushMacRegisters();
+# define HAVE_PUSH_REGS
# endif /* __MWERKS__ */
# endif /* MACOS */
@@ -222,13 +230,15 @@ void GC_push_regs()
asm("pushl %esi"); asm("call _GC_push_one"); asm("addl $4,%esp");
asm("pushl %edi"); asm("call _GC_push_one"); asm("addl $4,%esp");
asm("pushl %ebx"); asm("call _GC_push_one"); asm("addl $4,%esp");
+# define HAVE_PUSH_REGS
# endif
# if ( defined(I386) && defined(LINUX) && defined(__ELF__) ) \
|| ( defined(I386) && defined(FREEBSD) && defined(__ELF__) ) \
|| ( defined(I386) && defined(NETBSD) && defined(__ELF__) ) \
|| ( defined(I386) && defined(OPENBSD) && defined(__ELF__) ) \
- || ( defined(I386) && defined(HURD) && defined(__ELF__) )
+ || ( defined(I386) && defined(HURD) && defined(__ELF__) ) \
+ || ( defined(I386) && defined(DGUX) )
/* This is modified for Linux with ELF (Note: _ELF_ only) */
/* This section handles FreeBSD with ELF. */
@@ -243,6 +253,7 @@ void GC_push_regs()
asm("pushl %esi; call GC_push_one; addl $4,%esp");
asm("pushl %edi; call GC_push_one; addl $4,%esp");
asm("pushl %ebx; call GC_push_one; addl $4,%esp");
+# define HAVE_PUSH_REGS
# endif
# if ( defined(I386) && defined(BEOS) && defined(__ELF__) )
@@ -254,6 +265,7 @@ void GC_push_regs()
asm("pushl %esi; call GC_push_one; addl $4,%esp");
asm("pushl %edi; call GC_push_one; addl $4,%esp");
asm("pushl %ebx; call GC_push_one; addl $4,%esp");
+# define HAVE_PUSH_REGS
# endif
# if defined(I386) && defined(MSWIN32) && !defined(__MINGW32__) \
@@ -280,6 +292,7 @@ void GC_push_regs()
__asm push edi
__asm call GC_push_one
__asm add esp,4
+# define HAVE_PUSH_REGS
# endif
# if defined(I386) && (defined(SVR4) || defined(SCO) || defined(SCO_ELF))
@@ -291,6 +304,7 @@ void GC_push_regs()
asm("pushl %ebp"); asm("call GC_push_one"); asm("addl $4,%esp");
asm("pushl %esi"); asm("call GC_push_one"); asm("addl $4,%esp");
asm("pushl %edi"); asm("call GC_push_one"); asm("addl $4,%esp");
+# define HAVE_PUSH_REGS
# endif
# ifdef NS32K
@@ -299,14 +313,12 @@ void GC_push_regs()
asm ("movd r5, tos"); asm ("bsr ?_GC_push_one"); asm ("adjspb $-4");
asm ("movd r6, tos"); asm ("bsr ?_GC_push_one"); asm ("adjspb $-4");
asm ("movd r7, tos"); asm ("bsr ?_GC_push_one"); asm ("adjspb $-4");
+# define HAVE_PUSH_REGS
# endif
# if defined(SPARC)
- {
- word GC_save_regs_in_stack();
-
- GC_save_regs_ret_val = GC_save_regs_in_stack();
- }
+ GC_save_regs_ret_val = GC_save_regs_in_stack();
+# define HAVE_PUSH_REGS
# endif
# ifdef RT
@@ -322,6 +334,7 @@ void GC_push_regs()
asm("cas r11, r13, r0"); GC_push_one(TMP_SP); /* through */
asm("cas r11, r14, r0"); GC_push_one(TMP_SP); /* r15 */
asm("cas r11, r15, r0"); GC_push_one(TMP_SP);
+# define HAVE_PUSH_REGS
# endif
# if defined(M68K) && defined(SYSV)
@@ -345,6 +358,7 @@ void GC_push_regs()
asm("movl %d7,%sp@"); asm("jbsr GC_push_one");
asm("addqw #0x4,%sp"); /* put stack back where it was */
+# define HAVE_PUSH_REGS
# else /* !__GNUC__*/
asm("subq.w &0x4,%sp"); /* allocate word on top of stack */
@@ -362,6 +376,7 @@ void GC_push_regs()
asm("mov.l %d7,(%sp)"); asm("jsr GC_push_one");
asm("addq.w &0x4,%sp"); /* put stack back where it was */
+# define HAVE_PUSH_REGS
# endif /* !__GNUC__ */
# endif /* M68K/SYSV */
@@ -371,21 +386,19 @@ void GC_push_regs()
extern int *__libc_stack_end;
GC_push_all_stack (sp, __libc_stack_end);
+# define HAVE_PUSH_REGS
+ /* Isn't this redundant with the code to push the stack? */
}
# endif
/* other machines... */
-# if !defined(M68K) && !defined(VAX) && !defined(RT)
-# if !defined(SPARC) && !defined(I386) && !defined(NS32K)
-# if !defined(POWERPC) && !defined(UTS4)
-# if !defined(PJ) && !(defined(MIPS) && defined(LINUX))
- --> bad news <--
-# endif
-# endif
-# endif
+# if !defined(HAVE_PUSH_REGS)
+ --> We just generated an empty GC_push_regs, which
+ --> is almost certainly broken. Try defining
+ --> USE_GENERIC_PUSH_REGS instead.
# endif
}
-#endif /* !USE_GENERIC_PUSH_REGS */
+#endif /* !USE_GENERIC_PUSH_REGS && !USE_ASM_PUSH_REGS */
#if defined(USE_GENERIC_PUSH_REGS)
void GC_generic_push_regs(cold_gc_frame)
@@ -427,8 +440,6 @@ ptr_t cold_gc_frame;
/* needed on IA64, since some non-windowed registers are */
/* preserved. */
{
- word GC_save_regs_in_stack();
-
GC_save_regs_ret_val = GC_save_regs_in_stack();
/* On IA64 gcc, could use __builtin_ia64_flushrs() and */
/* __builtin_ia64_flushrs(). The latter will be done */
@@ -445,7 +456,7 @@ ptr_t cold_gc_frame;
/* the stack. Return sp. */
# ifdef SPARC
asm(" .seg \"text\"");
-# ifdef SVR4
+# if defined(SVR4) || defined(NETBSD)
asm(" .globl GC_save_regs_in_stack");
asm("GC_save_regs_in_stack:");
asm(" .type GC_save_regs_in_stack,#function");
diff --git a/boehm-gc/malloc.c b/boehm-gc/malloc.c
index 5ac21421bea..f5c8f06b0dd 100644
--- a/boehm-gc/malloc.c
+++ b/boehm-gc/malloc.c
@@ -182,6 +182,7 @@ register int k;
ptr_t result;
DCL_LOCK_STATE;
+ if (GC_have_errors) GC_print_all_errors();
GC_INVOKE_FINALIZERS();
if (SMALL_OBJ(lb)) {
DISABLE_SIGNALS();
@@ -294,6 +295,11 @@ DCL_LOCK_STATE;
return(GENERAL_MALLOC((word)lb, NORMAL));
}
/* See above comment on signals. */
+ GC_ASSERT(0 == obj_link(op)
+ || (word)obj_link(op)
+ <= (word)GC_greatest_plausible_heap_addr
+ && (word)obj_link(op)
+ >= (word)GC_least_plausible_heap_addr);
*opp = obj_link(op);
obj_link(op) = 0;
GC_words_allocd += lw;
@@ -338,6 +344,7 @@ DCL_LOCK_STATE;
return((GC_PTR)REDIRECT_MALLOC(n*lb));
}
+#ifndef strdup
# include <string.h>
# ifdef __STDC__
char *strdup(const char *s)
@@ -346,11 +353,16 @@ DCL_LOCK_STATE;
char *s;
# endif
{
- size_t len = strlen + 1;
+ size_t len = strlen(s) + 1;
char * result = ((char *)REDIRECT_MALLOC(len+1));
BCOPY(s, result, len+1);
return result;
}
+#endif /* !defined(strdup) */
+ /* If strdup is macro defined, we assume that it actually calls malloc, */
+ /* and thus the right thing will happen even without overriding it. */
+ /* This seems to be true on most Linux systems. */
+
# endif /* REDIRECT_MALLOC */
/* Explicitly deallocate an object p. */
@@ -373,6 +385,7 @@ DCL_LOCK_STATE;
/* Required by ANSI. It's not my fault ... */
h = HBLKPTR(p);
hhdr = HDR(h);
+ GC_ASSERT(GC_base(p) == p);
# if defined(REDIRECT_MALLOC) && \
(defined(GC_SOLARIS_THREADS) || defined(GC_LINUX_THREADS) \
|| defined(__MINGW32__)) /* Should this be MSWIN32 in general? */
@@ -454,7 +467,10 @@ void GC_free_inner(GC_PTR p)
}
#endif /* THREADS */
-# ifdef REDIRECT_MALLOC
+# if defined(REDIRECT_MALLOC) && !defined(REDIRECT_FREE)
+# define REDIRECT_FREE GC_free
+# endif
+# ifdef REDIRECT_FREE
# ifdef __STDC__
void free(GC_PTR p)
# else
@@ -463,7 +479,7 @@ void GC_free_inner(GC_PTR p)
# endif
{
# ifndef IGNORE_FREE
- GC_free(p);
+ REDIRECT_FREE(p);
# endif
}
# endif /* REDIRECT_MALLOC */
diff --git a/boehm-gc/mallocx.c b/boehm-gc/mallocx.c
index 031fcaf91a8..06f45622dfb 100644
--- a/boehm-gc/mallocx.c
+++ b/boehm-gc/mallocx.c
@@ -142,7 +142,11 @@ int obj_kind;
}
}
-# if defined(REDIRECT_MALLOC) || defined(REDIRECT_REALLOC)
+# if defined(REDIRECT_MALLOC) && !defined(REDIRECT_REALLOC)
+# define REDIRECT_REALLOC GC_realloc
+# endif
+
+# ifdef REDIRECT_REALLOC
# ifdef __STDC__
GC_PTR realloc(GC_PTR p, size_t lb)
# else
@@ -151,13 +155,9 @@ int obj_kind;
size_t lb;
# endif
{
-# ifdef REDIRECT_REALLOC
- return(REDIRECT_REALLOC(p, lb));
-# else
- return(GC_realloc(p, lb));
-# endif
+ return(REDIRECT_REALLOC(p, lb));
}
-# endif /* REDIRECT_MALLOC */
+# endif /* REDIRECT_REALLOC */
/* The same thing, except caller does not hold allocation lock. */
@@ -177,6 +177,7 @@ register int k;
lw = ROUNDED_UP_WORDS(lb);
n_blocks = OBJ_SZ_TO_BLOCKS(lw);
init = GC_obj_kinds[k].ok_init;
+ if (GC_have_errors) GC_print_all_errors();
GC_INVOKE_FINALIZERS();
DISABLE_SIGNALS();
LOCK();
@@ -286,6 +287,7 @@ register struct obj_kind * kind = GC_obj_kinds + k;
register ptr_t op;
DCL_LOCK_STATE;
+ if (GC_have_errors) GC_print_all_errors();
GC_INVOKE_FINALIZERS();
DISABLE_SIGNALS();
LOCK();
@@ -354,6 +356,7 @@ DCL_LOCK_STATE;
return;
}
lw = ALIGNED_WORDS(lb);
+ if (GC_have_errors) GC_print_all_errors();
GC_INVOKE_FINALIZERS();
DISABLE_SIGNALS();
LOCK();
@@ -375,6 +378,7 @@ DCL_LOCK_STATE;
while ((hbp = *rlh) != 0) {
hhdr = HDR(hbp);
*rlh = hhdr -> hb_next;
+ hhdr -> hb_last_reclaimed = (unsigned short) GC_gc_no;
# ifdef PARALLEL_MARK
{
signed_word my_words_allocd_tmp = GC_words_allocd_tmp;
@@ -575,6 +579,44 @@ DCL_LOCK_STATE;
}
}
+#ifdef __STDC__
+/* Not well tested nor integrated. */
+/* Debug version is tricky and currently missing. */
+#include <limits.h>
+
+GC_PTR GC_memalign(size_t align, size_t lb)
+{
+ size_t new_lb;
+ size_t offset;
+ ptr_t result;
+
+# ifdef ALIGN_DOUBLE
+ if (align <= WORDS_TO_BYTES(2) && lb > align) return GC_malloc(lb);
+# endif
+ if (align <= WORDS_TO_BYTES(1)) return GC_malloc(lb);
+ if (align >= HBLKSIZE/2 || lb >= HBLKSIZE/2) {
+ if (align > HBLKSIZE) return GC_oom_fn(LONG_MAX-1024) /* Fail */;
+ return GC_malloc(lb <= HBLKSIZE? HBLKSIZE : lb);
+ /* Will be HBLKSIZE aligned. */
+ }
+ /* We could also try to make sure that the real rounded-up object size */
+ /* is a multiple of align. That would be correct up to HBLKSIZE. */
+ new_lb = lb + align - 1;
+ result = GC_malloc(new_lb);
+ offset = (word)result % align;
+ if (offset != 0) {
+ offset = align - offset;
+ if (!GC_all_interior_pointers) {
+ if (offset >= VALID_OFFSET_SZ) return GC_malloc(HBLKSIZE);
+ GC_register_displacement(offset);
+ }
+ }
+ result = (GC_PTR) ((ptr_t)result + offset);
+ GC_ASSERT((word)result % align == 0);
+ return result;
+}
+#endif
+
# ifdef ATOMIC_UNCOLLECTABLE
/* Allocate lb bytes of pointerfree, untraced, uncollectable data */
/* This is normally roughly equivalent to the system malloc. */
diff --git a/boehm-gc/mark.c b/boehm-gc/mark.c
index eb5b9eeb34d..ca947290291 100644
--- a/boehm-gc/mark.c
+++ b/boehm-gc/mark.c
@@ -19,6 +19,10 @@
# include <stdio.h>
# include "private/gc_pmark.h"
+#if defined(MSWIN32) && defined(__GNUC__)
+# include <excpt.h>
+#endif
+
/* We put this here to minimize the risk of inlining. */
/*VARARGS*/
#ifdef __WATCOMC__
@@ -261,20 +265,20 @@ static void alloc_mark_stack();
/* remains valid until all marking is complete. */
/* A zero value indicates that it's OK to miss some */
/* register values. */
-GC_bool GC_mark_some(cold_gc_frame)
-ptr_t cold_gc_frame;
+/* We hold the allocation lock. In the case of */
+/* incremental collection, the world may not be stopped.*/
+#ifdef MSWIN32
+ /* For win32, this is called after we establish a structured */
+ /* exception handler, in case Windows unmaps one of our root */
+ /* segments. See below. In either case, we acquire the */
+ /* allocator lock long before we get here. */
+ GC_bool GC_mark_some_inner(cold_gc_frame)
+ ptr_t cold_gc_frame;
+#else
+ GC_bool GC_mark_some(cold_gc_frame)
+ ptr_t cold_gc_frame;
+#endif
{
-#if defined(MSWIN32) && !defined(__GNUC__)
- /* Windows 98 appears to asynchronously create and remove writable */
- /* memory mappings, for reasons we haven't yet understood. Since */
- /* we look for writable regions to determine the root set, we may */
- /* try to mark from an address range that disappeared since we */
- /* started the collection. Thus we have to recover from faults here. */
- /* This code does not appear to be necessary for Windows 95/NT/2000. */
- /* Note that this code should never generate an incremental GC write */
- /* fault. */
- __try {
-#endif /* defined(MSWIN32) && !defined(__GNUC__) */
switch(GC_mark_state) {
case MS_NONE:
return(FALSE);
@@ -395,23 +399,130 @@ ptr_t cold_gc_frame;
ABORT("GC_mark_some: bad state");
return(FALSE);
}
-#if defined(MSWIN32) && !defined(__GNUC__)
- } __except (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ?
- EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) {
-# ifdef CONDPRINT
- if (GC_print_stats) {
- GC_printf0("Caught ACCESS_VIOLATION in marker. "
- "Memory mapping disappeared.\n");
+}
+
+
+#ifdef MSWIN32
+
+# ifdef __GNUC__
+
+ typedef struct {
+ EXCEPTION_REGISTRATION ex_reg;
+ void *alt_path;
+ } ext_ex_regn;
+
+
+ static EXCEPTION_DISPOSITION mark_ex_handler(
+ struct _EXCEPTION_RECORD *ex_rec,
+ void *est_frame,
+ struct _CONTEXT *context,
+ void *disp_ctxt)
+ {
+ if (ex_rec->ExceptionCode == STATUS_ACCESS_VIOLATION) {
+ ext_ex_regn *xer = (ext_ex_regn *)est_frame;
+
+ /* Unwind from the inner function assuming the standard */
+ /* function prologue. */
+ /* Assumes code has not been compiled with */
+ /* -fomit-frame-pointer. */
+ context->Esp = context->Ebp;
+ context->Ebp = *((DWORD *)context->Esp);
+ context->Esp = context->Esp - 8;
+
+ /* Resume execution at the "real" handler within the */
+ /* wrapper function. */
+ context->Eip = (DWORD )(xer->alt_path);
+
+ return ExceptionContinueExecution;
+
+ } else {
+ return ExceptionContinueSearch;
+ }
+ }
+# endif /* __GNUC__ */
+
+
+ GC_bool GC_mark_some(cold_gc_frame)
+ ptr_t cold_gc_frame;
+ {
+ GC_bool ret_val;
+
+# ifndef __GNUC__
+ /* Windows 98 appears to asynchronously create and remove */
+ /* writable memory mappings, for reasons we haven't yet */
+ /* understood. Since we look for writable regions to */
+ /* determine the root set, we may try to mark from an */
+ /* address range that disappeared since we started the */
+ /* collection. Thus we have to recover from faults here. */
+ /* This code does not appear to be necessary for Windows */
+ /* 95/NT/2000. Note that this code should never generate */
+ /* an incremental GC write fault. */
+
+ __try {
+
+# else /* __GNUC__ */
+
+ /* Manually install an exception handler since GCC does */
+ /* not yet support Structured Exception Handling (SEH) on */
+ /* Win32. */
+
+ ext_ex_regn er;
+
+ er.alt_path = &&handle_ex;
+ er.ex_reg.handler = mark_ex_handler;
+ asm volatile ("movl %%fs:0, %0" : "=r" (er.ex_reg.prev));
+ asm volatile ("movl %0, %%fs:0" : : "r" (&er));
+
+# endif /* __GNUC__ */
+
+ ret_val = GC_mark_some_inner(cold_gc_frame);
+
+# ifndef __GNUC__
+
+ } __except (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ?
+ EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) {
+
+# else /* __GNUC__ */
+
+ /* Prevent GCC from considering the following code unreachable */
+ /* and thus eliminating it. */
+ if (er.alt_path != 0)
+ goto rm_handler;
+
+handle_ex:
+ /* Execution resumes from here on an access violation. */
+
+# endif /* __GNUC__ */
+
+# ifdef CONDPRINT
+ if (GC_print_stats) {
+ GC_printf0("Caught ACCESS_VIOLATION in marker. "
+ "Memory mapping disappeared.\n");
+ }
+# endif /* CONDPRINT */
+
+ /* We have bad roots on the stack. Discard mark stack. */
+ /* Rescan from marked objects. Redetermine roots. */
+ GC_invalidate_mark_state();
+ scan_ptr = 0;
+
+ ret_val = FALSE;
+
+# ifndef __GNUC__
+
}
-# endif /* CONDPRINT */
- /* We have bad roots on the stack. Discard mark stack. */
- /* Rescan from marked objects. Redetermine roots. */
- GC_invalidate_mark_state();
- scan_ptr = 0;
- return FALSE;
+
+# 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 /* defined(MSWIN32) && !defined(__GNUC__) */
-}
+#endif /* MSWIN32 */
GC_bool GC_mark_stack_empty()
@@ -434,13 +545,7 @@ GC_bool GC_mark_stack_empty()
/* for the large object. */
/* - just return current if it does not point to a large object. */
/*ARGSUSED*/
-# ifdef PRINT_BLACK_LIST
- ptr_t GC_find_start(current, hhdr, new_hdr_p, source)
- ptr_t source;
-# else
- ptr_t GC_find_start(current, hhdr, new_hdr_p)
-# define source 0
-# endif
+ptr_t GC_find_start(current, hhdr, new_hdr_p)
register ptr_t current;
register hdr *hhdr, **new_hdr_p;
{
@@ -468,7 +573,6 @@ register hdr *hhdr, **new_hdr_p;
} else {
return(current);
}
-# undef source
}
void GC_invalidate_mark_state()
@@ -546,8 +650,8 @@ mse * mark_stack_limit;
/* Large length. */
/* Process part of the range to avoid pushing too much on the */
/* stack. */
- GC_ASSERT(descr < GC_greatest_plausible_heap_addr
- - GC_least_plausible_heap_addr);
+ GC_ASSERT(descr < (word)GC_greatest_plausible_heap_addr
+ - (word)GC_least_plausible_heap_addr);
# ifdef PARALLEL_MARK
# define SHARE_BYTES 2048
if (descr > SHARE_BYTES && GC_parallel
@@ -578,6 +682,7 @@ mse * mark_stack_limit;
while (descr != 0) {
if ((signed_word)descr < 0) {
current = *current_p;
+ FIXUP_POINTER(current);
if ((ptr_t)current >= least_ha && (ptr_t)current < greatest_ha) {
PREFETCH(current);
HC_PUSH_CONTENTS((ptr_t)current, mark_stack_top,
@@ -652,6 +757,7 @@ mse * mark_stack_limit;
PREFETCH((ptr_t)limit - PREF_DIST*CACHE_LINE_SIZE);
GC_ASSERT(limit >= current_p);
deferred = *limit;
+ FIXUP_POINTER(deferred);
limit = (word *)((char *)limit - ALIGNMENT);
if ((ptr_t)deferred >= least_ha && (ptr_t)deferred < greatest_ha) {
PREFETCH(deferred);
@@ -661,6 +767,7 @@ mse * mark_stack_limit;
/* Unroll once, so we don't do too many of the prefetches */
/* based on limit. */
deferred = *limit;
+ FIXUP_POINTER(deferred);
limit = (word *)((char *)limit - ALIGNMENT);
if ((ptr_t)deferred >= least_ha && (ptr_t)deferred < greatest_ha) {
PREFETCH(deferred);
@@ -675,6 +782,7 @@ mse * mark_stack_limit;
/* Since HC_PUSH_CONTENTS expands to a lot of code, */
/* we don't. */
current = *current_p;
+ FIXUP_POINTER(current);
PREFETCH((ptr_t)current_p + PREF_DIST*CACHE_LINE_SIZE);
if ((ptr_t)current >= least_ha && (ptr_t)current < greatest_ha) {
/* Prefetch the contents of the object we just pushed. It's */
@@ -726,22 +834,33 @@ mse * GC_steal_mark_stack(mse * low, mse * high, mse * local,
mse *top = local - 1;
unsigned i = 0;
+ /* Make sure that prior writes to the mark stack are visible. */
+ /* On some architectures, the fact that the reads are */
+ /* volatile should suffice. */
+# if !defined(IA64) && !defined(HP_PA) && !defined(I386)
+ GC_memory_barrier();
+# endif
GC_ASSERT(high >= low-1 && high - low + 1 <= GC_mark_stack_size);
for (p = low; p <= high && i <= max; ++p) {
word descr = *(volatile word *) &(p -> mse_descr);
+ /* In the IA64 memory model, the following volatile store is */
+ /* ordered after this read of descr. Thus a thread must read */
+ /* the original nonzero value. HP_PA appears to be similar, */
+ /* and if I'm reading the P4 spec correctly, X86 is probably */
+ /* also OK. In some other cases we need a barrier. */
+# if !defined(IA64) && !defined(HP_PA) && !defined(I386)
+ GC_memory_barrier();
+# endif
if (descr != 0) {
*(volatile word *) &(p -> mse_descr) = 0;
+ /* More than one thread may get this entry, but that's only */
+ /* a minor performance problem. */
++top;
top -> mse_descr = descr;
top -> mse_start = p -> mse_start;
GC_ASSERT( top -> mse_descr & GC_DS_TAGS != GC_DS_LENGTH ||
top -> mse_descr < GC_greatest_plausible_heap_addr
- GC_least_plausible_heap_addr);
- /* There is no synchronization here. We assume that at */
- /* least one thread will see the original descriptor. */
- /* Otherwise we need a barrier. */
- /* More than one thread may get this entry, but that's only */
- /* a minor performance problem. */
/* If this is a big object, count it as */
/* size/256 + 1 objects. */
++i;
@@ -778,7 +897,7 @@ void GC_return_mark_stack(mse * low, mse * high)
BCOPY(low, my_start, stack_size * sizeof(mse));
GC_ASSERT(GC_mark_stack_top = my_top);
# if !defined(IA64) && !defined(HP_PA)
- GC_memory_write_barrier();
+ GC_memory_barrier();
# endif
/* On IA64, the volatile write acts as a release barrier. */
GC_mark_stack_top = my_top + stack_size;
@@ -1342,8 +1461,8 @@ ptr_t top;
# define GC_least_plausible_heap_addr least_ha
if (top == 0) return;
- /* check all pointers in range and put in push if they appear */
- /* to be valid. */
+ /* check all pointers in range and push if they appear */
+ /* to be valid. */
lim = t - 1 /* longword */;
for (p = b; p <= lim; p = (word *)(((char *)p) + ALIGNMENT)) {
q = *p;
@@ -1366,7 +1485,7 @@ ptr_t bottom;
ptr_t top;
ptr_t cold_gc_frame;
{
- if (GC_all_interior_pointers) {
+ if (!NEED_FIXUP_POINTER && GC_all_interior_pointers) {
# define EAGER_BYTES 1024
/* Push the hot end of the stack eagerly, so that register values */
/* saved inside GC frames are marked before they disappear. */
@@ -1375,6 +1494,7 @@ ptr_t cold_gc_frame;
GC_push_all_stack(bottom, top);
return;
}
+ GC_ASSERT(bottom <= cold_gc_frame && cold_gc_frame <= top);
# ifdef STACK_GROWS_DOWN
GC_push_all(cold_gc_frame - sizeof(ptr_t), top);
GC_push_all_eager(bottom, cold_gc_frame);
@@ -1395,7 +1515,7 @@ void GC_push_all_stack(bottom, top)
ptr_t bottom;
ptr_t top;
{
- if (GC_all_interior_pointers) {
+ if (!NEED_FIXUP_POINTER && GC_all_interior_pointers) {
GC_push_all(bottom, top);
} else {
GC_push_all_eager(bottom, top);
diff --git a/boehm-gc/mark_rts.c b/boehm-gc/mark_rts.c
index f663dcd55c3..55eb5d54339 100644
--- a/boehm-gc/mark_rts.c
+++ b/boehm-gc/mark_rts.c
@@ -275,33 +275,72 @@ void GC_clear_roots GC_PROTO((void))
}
/* Internal use only; lock held. */
+static void GC_remove_root_at_pos(i)
+int i;
+{
+ GC_root_size -= (GC_static_roots[i].r_end - GC_static_roots[i].r_start);
+ GC_static_roots[i].r_start = GC_static_roots[n_root_sets-1].r_start;
+ GC_static_roots[i].r_end = GC_static_roots[n_root_sets-1].r_end;
+ GC_static_roots[i].r_tmp = GC_static_roots[n_root_sets-1].r_tmp;
+ n_root_sets--;
+}
+
+#if !defined(MSWIN32) && !defined(MSWINCE)
+static void GC_rebuild_root_index()
+{
+ register int i;
+
+ for (i = 0; i < RT_SIZE; i++) GC_root_index[i] = 0;
+ for (i = 0; i < n_root_sets; i++)
+ add_roots_to_index(GC_static_roots + i);
+}
+#endif
+
+/* Internal use only; lock held. */
void GC_remove_tmp_roots()
{
register int i;
for (i = 0; i < n_root_sets; ) {
if (GC_static_roots[i].r_tmp) {
- GC_root_size -=
- (GC_static_roots[i].r_end - GC_static_roots[i].r_start);
- GC_static_roots[i].r_start = GC_static_roots[n_root_sets-1].r_start;
- GC_static_roots[i].r_end = GC_static_roots[n_root_sets-1].r_end;
- GC_static_roots[i].r_tmp = GC_static_roots[n_root_sets-1].r_tmp;
- n_root_sets--;
+ GC_remove_root_at_pos(i);
} else {
i++;
- }
}
-# if !defined(MSWIN32) && !defined(MSWINCE)
- {
- register int i;
-
- for (i = 0; i < RT_SIZE; i++) GC_root_index[i] = 0;
- for (i = 0; i < n_root_sets; i++)
- add_roots_to_index(GC_static_roots + i);
}
-# endif
+ #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)
/* Workaround for the OS mapping and unmapping behind our back: */
@@ -573,8 +612,11 @@ ptr_t cold_gc_frame;
/* Mark thread local free lists, even if their mark */
/* descriptor excludes the link field. */
+ /* If the world is not stopped, this is unsafe. It is */
+ /* also unnecessary, since we will do this again with the */
+ /* world stopped. */
# ifdef THREAD_LOCAL_ALLOC
- GC_mark_thread_local_free_lists();
+ if (GC_world_stopped) GC_mark_thread_local_free_lists();
# endif
/*
diff --git a/boehm-gc/mips_sgi_mach_dep.S b/boehm-gc/mips_sgi_mach_dep.s
index bae9b5ebfe4..56390280a71 100644
--- a/boehm-gc/mips_sgi_mach_dep.S
+++ b/boehm-gc/mips_sgi_mach_dep.s
@@ -1,5 +1,10 @@
#include <sys/regdef.h>
#include <sys/asm.h>
+/* This file must be preprocessed. But the SGI assembler always does */
+/* that. Furthermore, a generic preprocessor won't do, since some of */
+/* the SGI-supplied include files rely on behavior of the MIPS */
+/* assembler. Hence we treat and name this file as though it required */
+/* no preprocessing. */
# define call_push(x) move $4,x; jal GC_push_one
diff --git a/boehm-gc/misc.c b/boehm-gc/misc.c
index 8f83ff3ab53..814fa41ab24 100644
--- a/boehm-gc/misc.c
+++ b/boehm-gc/misc.c
@@ -46,8 +46,10 @@
# ifdef GC_SOLARIS_THREADS
mutex_t GC_allocate_ml; /* Implicitly initialized. */
# else
-# ifdef GC_WIN32_THREADS
-# if !defined(GC_NOT_DLL) && (defined(_DLL) || defined(GC_DLL))
+# if defined(GC_WIN32_THREADS)
+# if defined(GC_PTHREADS)
+ pthread_mutex_t GC_allocate_ml = PTHREAD_MUTEX_INITIALIZER;
+# elif defined(GC_DLL)
__declspec(dllexport) CRITICAL_SECTION GC_allocate_ml;
# else
CRITICAL_SECTION GC_allocate_ml;
@@ -75,8 +77,8 @@
#undef STACKBASE
#endif
-/* Dont unnecessarily call GC_register_main_static_data() in case */
-/* dyn_load.c isn't linked in. */
+/* Dont unnecessarily call GC_register_main_static_data() in case */
+/* dyn_load.c isn't linked in. */
#ifdef DYNAMIC_LOADING
# define GC_REGISTER_MAIN_STATIC_DATA() GC_register_main_static_data()
#else
@@ -90,6 +92,7 @@ GC_bool GC_debugging_started = FALSE;
/* defined here so we don't have to load debug_malloc.o */
void (*GC_check_heap) GC_PROTO((void)) = (void (*) GC_PROTO((void)))0;
+void (*GC_print_all_smashed) GC_PROTO((void)) = (void (*) GC_PROTO((void)))0;
void (*GC_start_call_back) GC_PROTO((void)) = (void (*) GC_PROTO((void)))0;
@@ -109,6 +112,10 @@ GC_bool GC_print_stats = 0;
GC_bool GC_print_back_height = 0;
+#ifndef NO_DEBUGGING
+ GC_bool GC_dump_regularly = 0; /* Generate regular debugging dumps. */
+#endif
+
#ifdef FIND_LEAK
int GC_find_leak = 1;
#else
@@ -137,6 +144,13 @@ GC_PTR (*GC_oom_fn) GC_PROTO((size_t bytes_requested)) = GC_default_oom_fn;
extern signed_word GC_mem_found;
+void * GC_project2(arg1, arg2)
+void *arg1;
+void *arg2;
+{
+ return arg2;
+}
+
# ifdef MERGE_SIZES
/* Set things up so that GC_size_map[i] >= words(i), */
/* but not too much bigger */
@@ -455,7 +469,7 @@ void GC_init()
DISABLE_SIGNALS();
-#ifdef MSWIN32
+#if defined(GC_WIN32_THREADS) && !defined(GC_PTHREADS)
if (!GC_is_initialized) InitializeCriticalSection(&GC_allocate_ml);
#endif /* MSWIN32 */
@@ -473,6 +487,15 @@ void GC_init()
GC_init_parallel();
}
# endif /* PARALLEL_MARK || THREAD_LOCAL_ALLOC */
+
+# if defined(DYNAMIC_LOADING) && defined(DARWIN)
+ {
+ /* This must be called WITHOUT the allocation lock held
+ and before any threads are created */
+ extern void GC_init_dyld();
+ GC_init_dyld();
+ }
+# endif
}
#if defined(MSWIN32) || defined(MSWINCE)
@@ -485,6 +508,22 @@ void GC_init()
extern void GC_setpagesize();
+
+#ifdef MSWIN32
+extern GC_bool GC_no_win32_dlls;
+#else
+# define GC_no_win32_dlls FALSE
+#endif
+
+void GC_exit_check GC_PROTO((void))
+{
+ GC_gcollect();
+}
+
+#ifdef SEARCH_FOR_DATA_START
+ extern void GC_init_linux_data_start GC_PROTO((void));
+#endif
+
#ifdef UNIX_LIKE
extern void GC_set_and_save_fault_handler GC_PROTO((void (*handler)(int)));
@@ -495,12 +534,23 @@ int sig;
GC_err_printf1("Caught signal %d: looping in handler\n", sig);
for(;;);
}
-#endif
-#ifdef MSWIN32
-extern GC_bool GC_no_win32_dlls;
-#else
-# define GC_no_win32_dlls FALSE
+static GC_bool installed_looping_handler = FALSE;
+
+void maybe_install_looping_handler()
+{
+ /* Install looping handler before the write fault handler, so we */
+ /* handle write faults correctly. */
+ if (!installed_looping_handler && 0 != GETENV("GC_LOOP_ON_ABORT")) {
+ GC_set_and_save_fault_handler(looping_handler);
+ installed_looping_handler = TRUE;
+ }
+}
+
+#else /* !UNIX_LIKE */
+
+# define maybe_install_looping_handler()
+
#endif
void GC_init_inner()
@@ -515,14 +565,21 @@ void GC_init_inner()
GC_print_stats = 1;
# endif
# if defined(MSWIN32) || defined(MSWINCE)
- InitializeCriticalSection(&GC_write_cs);
+ InitializeCriticalSection(&GC_write_cs);
# endif
-
if (0 != GETENV("GC_PRINT_STATS")) {
GC_print_stats = 1;
}
+# ifndef NO_DEBUGGING
+ if (0 != GETENV("GC_DUMP_REGULARLY")) {
+ GC_dump_regularly = 1;
+ }
+# endif
if (0 != GETENV("GC_FIND_LEAK")) {
GC_find_leak = 1;
+# ifdef __STDC__
+ atexit(GC_exit_check);
+# endif
}
if (0 != GETENV("GC_ALL_INTERIOR_POINTERS")) {
GC_all_interior_pointers = 1;
@@ -560,11 +617,7 @@ void GC_init_inner()
}
}
}
-# ifdef UNIX_LIKE
- if (0 != GETENV("GC_LOOP_ON_ABORT")) {
- GC_set_and_save_fault_handler(looping_handler);
- }
-# endif
+ maybe_install_looping_handler();
/* Adjust normal object descriptor for extra allocation. */
if (ALIGNMENT > GC_DS_TAGS && EXTRA_BYTES != 0) {
GC_obj_kinds[NORMAL].ok_descriptor = ((word)(-ALIGNMENT) | GC_DS_LENGTH);
@@ -599,11 +652,21 @@ void GC_init_inner()
# if defined(LINUX) && defined(IA64)
GC_register_stackbottom = GC_get_register_stack_base();
# endif
+ } else {
+# if defined(LINUX) && defined(IA64)
+ if (GC_register_stackbottom == 0) {
+ WARN("GC_register_stackbottom should be set with GC_stackbottom", 0);
+ /* The following is likely to fail, since we rely on */
+ /* alignment properties that may not hold with a user set */
+ /* GC_stackbottom. */
+ GC_register_stackbottom = GC_get_register_stack_base();
+ }
+# endif
}
# endif
- GC_ASSERT(sizeof (ptr_t) == sizeof(word));
- GC_ASSERT(sizeof (signed_word) == sizeof(word));
- GC_ASSERT(sizeof (struct hblk) == HBLKSIZE);
+ GC_STATIC_ASSERT(sizeof (ptr_t) == sizeof(word));
+ GC_STATIC_ASSERT(sizeof (signed_word) == sizeof(word));
+ GC_STATIC_ASSERT(sizeof (struct hblk) == HBLKSIZE);
# ifndef THREADS
# if defined(STACK_GROWS_UP) && defined(STACK_GROWS_DOWN)
ABORT(
@@ -642,6 +705,18 @@ void GC_init_inner()
initial_heap_sz = divHBLKSZ(initial_heap_sz);
}
}
+ {
+ char * sz_str = GETENV("GC_MAXIMUM_HEAP_SIZE");
+ if (sz_str != NULL) {
+ word max_heap_sz = (word)atol(sz_str);
+ if (max_heap_sz < initial_heap_sz * HBLKSIZE) {
+ WARN("Bad maximum heap size %s - ignoring it.\n",
+ sz_str);
+ }
+ if (0 == GC_max_retries) GC_max_retries = 2;
+ GC_set_max_heap_size(max_heap_sz);
+ }
+ }
if (!GC_expand_hp_inner(initial_heap_sz)) {
GC_err_printf0("Can't start up: not enough memory\n");
EXIT();
@@ -677,6 +752,7 @@ void GC_init_inner()
GC_incremental = TRUE;
}
# endif /* !SMALL_CONFIG */
+ COND_DUMP;
/* Get black list set up and/or incrmental GC started */
if (!GC_dont_precollect || GC_incremental) GC_gcollect_inner();
GC_is_initialized = TRUE;
@@ -712,8 +788,9 @@ void GC_enable_incremental GC_PROTO(())
if (GC_incremental) goto out;
GC_setpagesize();
if (GC_no_win32_dlls) goto out;
-# ifndef GC_SOLARIS_THREADS
- GC_dirty_init();
+# ifndef GC_SOLARIS_THREADS
+ maybe_install_looping_handler(); /* Before write fault handler! */
+ GC_dirty_init();
# endif
if (!GC_is_initialized) {
GC_init_inner();
@@ -932,6 +1009,17 @@ GC_warn_proc GC_current_warn_proc = GC_default_warn_proc;
return(result);
}
+# if defined(__STDC__) || defined(__cplusplus)
+ GC_word GC_set_free_space_divisor (GC_word value)
+# else
+ GC_word GC_set_free_space_divisor (value)
+ GC_word value;
+# endif
+{
+ GC_word old = GC_free_space_divisor;
+ GC_free_space_divisor = value;
+ return old;
+}
#ifndef PCR
void GC_abort(msg)
@@ -958,122 +1046,18 @@ GC_CONST char * msg;
}
#endif
-#ifdef NEED_CALLINFO
-
-#ifdef HAVE_BUILTIN_BACKTRACE
-# include <execinfo.h>
-# ifdef LINUX
-# include <unistd.h>
-# endif
-#endif
-
-void GC_print_callers (info)
-struct callinfo info[NFRAMES];
-{
- register int i;
-
-# if NFRAMES == 1
- GC_err_printf0("\tCaller at allocation:\n");
-# else
- GC_err_printf0("\tCall chain at allocation:\n");
-# endif
- for (i = 0; i < NFRAMES; i++) {
- if (info[i].ci_pc == 0) break;
-# if NARGS > 0
- {
- int j;
-
- GC_err_printf0("\t\targs: ");
- for (j = 0; j < NARGS; j++) {
- if (j != 0) GC_err_printf0(", ");
- GC_err_printf2("%d (0x%X)", ~(info[i].ci_arg[j]),
- ~(info[i].ci_arg[j]));
- }
- GC_err_printf0("\n");
- }
-# endif
-# if defined(HAVE_BUILTIN_BACKTRACE) && !defined(REDIRECT_MALLOC)
- /* Unfortunately backtrace_symbols calls malloc, which makes */
- /* it dangersous if that has been redirected. */
- {
- char **sym_name =
- backtrace_symbols((void **)(&(info[i].ci_pc)), 1);
- char *name = sym_name[0];
- GC_bool found_it = (strchr(name, '(') != 0);
- FILE *pipe;
-# ifdef LINUX
- if (!found_it) {
-# define EXE_SZ 100
- static char exe_name[EXE_SZ];
-# define CMD_SZ 200
- char cmd_buf[CMD_SZ];
-# define RESULT_SZ 200
- static char result_buf[RESULT_SZ];
- size_t result_len;
- static GC_bool found_exe_name = FALSE;
- static GC_bool will_fail = FALSE;
- int ret_code;
- /* Unfortunately, this is the common case for the */
- /* main executable. */
- /* Try to get it via a hairy and expensive scheme. */
- /* First we get the name of the executable: */
- if (will_fail) goto out;
- if (!found_exe_name) {
- ret_code = readlink("/proc/self/exe", exe_name, EXE_SZ);
- if (ret_code < 0 || ret_code >= EXE_SZ || exe_name[0] != '/') {
- will_fail = TRUE; /* Dont try again. */
- goto out;
- }
- exe_name[ret_code] = '\0';
- found_exe_name = TRUE;
- }
- /* Then we use popen to start addr2line -e <exe> <addr> */
- /* There are faster ways to do this, but hopefully this */
- /* isn't time critical. */
- sprintf(cmd_buf, "/usr/bin/addr2line -e %s 0x%lx", exe_name,
- (unsigned long)info[i].ci_pc);
- pipe = popen(cmd_buf, "r");
- if (pipe < 0 || fgets(result_buf, RESULT_SZ, pipe) == 0) {
- will_fail = TRUE;
- goto out;
- }
- result_len = strlen(result_buf);
- if (result_buf[result_len - 1] == '\n') --result_len;
- if (result_buf[0] == '?'
- || result_buf[result_len-2] == ':'
- && result_buf[result_len-1] == '0')
- goto out;
- if (result_len < RESULT_SZ - 25) {
- /* Add in hex address */
- sprintf(result_buf + result_len, " [0x%lx]",
- (unsigned long)info[i].ci_pc);
- }
- name = result_buf;
- pclose(pipe);
- out:
- }
-# endif
- GC_err_printf1("\t\t%s\n", name);
- free(sym_name);
- }
-# else
- GC_err_printf1("\t\t##PC##= 0x%lx\n", info[i].ci_pc);
-# endif
- }
-}
-
-#endif /* SAVE_CALL_CHAIN */
-
-/* Needed by SRC_M3, gcj, and should perhaps be the official interface */
-/* to GC_dont_gc. */
void GC_enable()
{
+ LOCK();
GC_dont_gc--;
+ UNLOCK();
}
void GC_disable()
{
+ LOCK();
GC_dont_gc++;
+ UNLOCK();
}
#if !defined(NO_DEBUGGING)
@@ -1088,6 +1072,8 @@ void GC_dump()
GC_print_hblkfreelist();
GC_printf0("\n***Blocks in use:\n");
GC_print_block_list();
+ GC_printf0("\n***Finalization statistics:\n");
+ GC_print_finalization_stats();
}
#endif /* NO_DEBUGGING */
diff --git a/boehm-gc/missing b/boehm-gc/missing
deleted file mode 100755
index dd583709f53..00000000000
--- a/boehm-gc/missing
+++ /dev/null
@@ -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
diff --git a/boehm-gc/os_dep.c b/boehm-gc/os_dep.c
index 82386ec4fba..fecda89db77 100644
--- a/boehm-gc/os_dep.c
+++ b/boehm-gc/os_dep.c
@@ -80,6 +80,13 @@
# define NEED_FIND_LIMIT
# endif
+#if defined(FREEBSD) && defined(I386)
+# include <machine/trap.h>
+# if !defined(PCR)
+# define NEED_FIND_LIMIT
+# endif
+#endif
+
#ifdef NEED_FIND_LIMIT
# include <setjmp.h>
#endif
@@ -129,6 +136,11 @@
# define jmp_buf sigjmp_buf
#endif
+#ifdef DARWIN
+/* for get_etext and friends */
+#include <mach-o/getsect.h>
+#endif
+
#ifdef DJGPP
/* Apparently necessary for djgpp 2.01. May cause problems with */
/* other versions. */
@@ -147,6 +159,156 @@
# define OPT_PROT_EXEC 0
#endif
+#if defined(LINUX) && \
+ (defined(USE_PROC_FOR_LIBRARIES) || defined(IA64) || !defined(SMALL_CONFIG))
+
+/* We need to parse /proc/self/maps, either to find dynamic libraries, */
+/* and/or to find the register backing store base (IA64). Do it once */
+/* here. */
+
+#define READ read
+
+/* Repeatedly perform a read call until the buffer is filled or */
+/* we encounter EOF. */
+ssize_t GC_repeat_read(int fd, char *buf, size_t count)
+{
+ ssize_t num_read = 0;
+ ssize_t result;
+
+ while (num_read < count) {
+ result = READ(fd, buf + num_read, count - num_read);
+ if (result < 0) return result;
+ if (result == 0) break;
+ num_read += result;
+ }
+ return num_read;
+}
+
+/*
+ * Apply fn to a buffer containing the contents of /proc/self/maps.
+ * Return the result of fn or, if we failed, 0.
+ */
+
+word GC_apply_to_maps(word (*fn)(char *))
+{
+ int f;
+ int result;
+ int maps_size;
+ char maps_temp[32768];
+ char *maps_buf;
+
+ /* Read /proc/self/maps */
+ /* Note that we may not allocate, and thus can't use stdio. */
+ f = open("/proc/self/maps", O_RDONLY);
+ if (-1 == f) return 0;
+ /* 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) return 0;
+ 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) return 0;
+ maps_buf = alloca(maps_size);
+ if (NULL == maps_buf) return 0;
+ result = GC_repeat_read(f, maps_buf, maps_size);
+ if (result <= 0) return 0;
+ } else {
+ /* Otherwise use the fixed size buffer */
+ maps_buf = maps_temp;
+ }
+
+ close(f);
+ maps_buf[result] = '\0';
+
+ /* Apply fn to result. */
+ return fn(maps_buf);
+}
+
+#endif /* Need GC_apply_to_maps */
+
+#if defined(LINUX) && (defined(USE_PROC_FOR_LIBRARIES) || defined(IA64))
+//
+// GC_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
+//
+// For 64 bit ABIs:
+// 0 17 34 56
+//
+// The parser is called with a pointer to the entry and the return value
+// is either NULL or is advanced to the next entry(the byte after the
+// trailing '\n'.)
+//
+#if CPP_WORDSZ == 32
+# define OFFSET_MAP_START 0
+# define OFFSET_MAP_END 9
+# define OFFSET_MAP_PROT 18
+# define OFFSET_MAP_MAJDEV 32
+# define ADDR_WIDTH 8
+#endif
+
+#if CPP_WORDSZ == 64
+# define OFFSET_MAP_START 0
+# define OFFSET_MAP_END 17
+# define OFFSET_MAP_PROT 34
+# define OFFSET_MAP_MAJDEV 56
+# define ADDR_WIDTH 16
+#endif
+
+/*
+ * Assign various fields of the first line in buf_ptr to *start, *end,
+ * *prot_buf and *maj_dev. Only *prot_buf may be set for unwritable maps.
+ */
+char *GC_parse_map_entry(char *buf_ptr, word *start, word *end,
+ char *prot_buf, unsigned int *maj_dev)
+{
+ int i;
+ 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+ADDR_WIDTH] = '\0';
+ *start = strtoul(tok, NULL, 16);
+
+ tok = buf_ptr+OFFSET_MAP_END;
+ buf_ptr[OFFSET_MAP_END+ADDR_WIDTH] = '\0';
+ *end = strtoul(tok, NULL, 16);
+
+ buf_ptr += OFFSET_MAP_MAJDEV;
+ tok = buf_ptr;
+ while (*buf_ptr != ':') buf_ptr++;
+ *buf_ptr++ = '\0';
+ *maj_dev = strtoul(tok, NULL, 16);
+ }
+
+ while (*buf_ptr && *buf_ptr++ != '\n');
+
+ return buf_ptr;
+}
+
+#endif /* Need to parse /proc/self/maps. */
+
#if defined(SEARCH_FOR_DATA_START)
/* The I386 case can be handled without a search. The Alpha case */
/* used to be handled differently as well, but the rules changed */
@@ -154,6 +316,11 @@
/* cover all versions. */
# ifdef LINUX
+ /* 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-compatible pragmas. */
# pragma weak __data_start
extern int __data_start[];
# pragma weak data_start
@@ -169,16 +336,16 @@
# ifdef LINUX
/* Try the easy approaches first: */
- if (__data_start != 0) {
- GC_data_start = (ptr_t)__data_start;
+ if ((ptr_t)__data_start != 0) {
+ GC_data_start = (ptr_t)(__data_start);
return;
}
- if (data_start != 0) {
- GC_data_start = (ptr_t)data_start;
+ if ((ptr_t)data_start != 0) {
+ GC_data_start = (ptr_t)(data_start);
return;
}
# endif /* LINUX */
- GC_data_start = GC_find_limit((ptr_t)_end, FALSE);
+ GC_data_start = GC_find_limit((ptr_t)(_end), FALSE);
}
#endif
@@ -617,7 +784,8 @@ ptr_t GC_get_stack_base()
}
/* Return the first nonaddressible location > p (up) or */
- /* the smallest location q s.t. [q,p] is addressible (!up). */
+ /* the smallest location q s.t. [q,p) is addressable (!up). */
+ /* We assume that p (up) or p-1 (!up) is addressable. */
ptr_t GC_find_limit(p, up)
ptr_t p;
GC_bool up;
@@ -650,18 +818,18 @@ ptr_t GC_get_stack_base()
}
# endif
-# if defined(ECOS) || defined(NOSYS)
-ptr_t GC_get_stack_base()
-{
- return STACKBOTTOM;
-}
-
-#else
+#if defined(ECOS) || defined(NOSYS)
+ ptr_t GC_get_stack_base()
+ {
+ return STACKBOTTOM;
+ }
+#endif
#ifdef LINUX_STACKBOTTOM
#include <sys/types.h>
#include <sys/stat.h>
+#include <ctype.h>
# define STAT_SKIP 27 /* Number of fields preceding startstack */
/* field in /proc/self/stat */
@@ -670,6 +838,33 @@ ptr_t GC_get_stack_base()
extern ptr_t __libc_stack_end;
# ifdef IA64
+ /* Try to read the backing store base from /proc/self/maps. */
+ /* We look for the writable mapping with a 0 major device, */
+ /* which is as close to our frame as possible, but below it.*/
+ static word backing_store_base_from_maps(char *maps)
+ {
+ char prot_buf[5];
+ char *buf_ptr = maps;
+ word start, end;
+ unsigned int maj_dev;
+ word current_best = 0;
+ word dummy;
+
+ for (;;) {
+ buf_ptr = GC_parse_map_entry(buf_ptr, &start, &end, prot_buf, &maj_dev);
+ if (buf_ptr == NULL) return current_best;
+ if (prot_buf[1] == 'w' && maj_dev == 0) {
+ if (end < (word)(&dummy) && start > current_best) current_best = start;
+ }
+ }
+ return current_best;
+ }
+
+ static word backing_store_base_from_proc(void)
+ {
+ return GC_apply_to_maps(backing_store_base_from_maps);
+ }
+
# pragma weak __libc_ia64_register_backing_store_base
extern ptr_t __libc_ia64_register_backing_store_base;
@@ -679,13 +874,19 @@ ptr_t GC_get_stack_base()
&& 0 != __libc_ia64_register_backing_store_base) {
/* Glibc 2.2.4 has a bug such that for dynamically linked */
/* executables __libc_ia64_register_backing_store_base is */
- /* defined but ininitialized during constructor calls. */
+ /* defined but uninitialized during constructor calls. */
/* Hence we check for both nonzero address and value. */
return __libc_ia64_register_backing_store_base;
} else {
- word result = (word)GC_stackbottom - BACKING_STORE_DISPLACEMENT;
- result += BACKING_STORE_ALIGNMENT - 1;
- result &= ~(BACKING_STORE_ALIGNMENT - 1);
+ word result = backing_store_base_from_proc();
+ if (0 == result) {
+ /* Use dumb heuristics. Works only for default configuration. */
+ result = (word)GC_stackbottom - BACKING_STORE_DISPLACEMENT;
+ result += BACKING_STORE_ALIGNMENT - 1;
+ result &= ~(BACKING_STORE_ALIGNMENT - 1);
+ /* Verify that it's at least readable. If not, we goofed. */
+ GC_noop1(*(word *)result);
+ }
return (ptr_t)result;
}
}
@@ -697,11 +898,8 @@ ptr_t GC_get_stack_base()
/* using direct I/O system calls in order to avoid calling malloc */
/* in case REDIRECT_MALLOC is defined. */
# define STAT_BUF_SIZE 4096
-# if defined(GC_USE_LD_WRAP)
-# define STAT_READ __real_read
-# else
-# define STAT_READ read
-# endif
+# define STAT_READ read
+ /* Should probably call the real read, if read is wrapped. */
char stat_buf[STAT_BUF_SIZE];
int f;
char c;
@@ -710,7 +908,16 @@ ptr_t GC_get_stack_base()
/* First try the easy way. This should work for glibc 2.2 */
if (0 != &__libc_stack_end) {
- return __libc_stack_end;
+# ifdef IA64
+ /* Some versions of glibc set the address 16 bytes too */
+ /* low while the initialization code is running. */
+ if (((word)__libc_stack_end & 0xfff) + 0x10 < 0x1000) {
+ return __libc_stack_end + 0x10;
+ } /* Otherwise it's not safe to add 16 bytes and we fall */
+ /* back to using /proc. */
+# else
+ return __libc_stack_end;
+# endif
}
f = open("/proc/self/stat", O_RDONLY);
if (f < 0 || STAT_READ(f, stat_buf, STAT_BUF_SIZE) < 2 * STAT_SKIP) {
@@ -764,8 +971,11 @@ ptr_t GC_get_stack_base()
ptr_t GC_get_stack_base()
{
+# if defined(HEURISTIC1) || defined(HEURISTIC2) || \
+ defined(LINUX_STACKBOTTOM) || defined(FREEBSD_STACKBOTTOM)
word dummy;
ptr_t result;
+# endif
# define STACKBOTTOM_ALIGNMENT_M1 ((word)STACK_GRAN - 1)
@@ -814,7 +1024,6 @@ ptr_t GC_get_stack_base()
return(result);
# endif /* STACKBOTTOM */
}
-# endif /* NOSYS ECOS */
# endif /* ! AMIGA, !OS 2, ! MS Windows, !BEOS */
@@ -924,15 +1133,14 @@ void GC_register_data_segments()
/* Unfortunately, we have to handle win32s very differently from NT, */
/* Since VirtualQuery has very different semantics. In particular, */
/* under win32s a VirtualQuery call on an unmapped page returns an */
- /* invalid result. Under GC_register_data_segments is a noop and */
+ /* invalid result. Under NT, GC_register_data_segments is a noop and */
/* all real work is done by GC_register_dynamic_libraries. Under */
/* win32s, we cannot find the data segments associated with dll's. */
- /* We rgister the main data segment here. */
-# ifdef __GCC__
- GC_bool GC_no_win32_dlls = TRUE; /* GCC can't do SEH, so we can't use VirtualQuery */
-# else
+ /* We register the main data segment here. */
GC_bool GC_no_win32_dlls = FALSE;
-# endif
+ /* This used to be set for gcc, to avoid dealing with */
+ /* the structured exception handling issues. But we now have */
+ /* assembly code to do that right. */
void GC_init_win32()
{
@@ -964,36 +1172,102 @@ void GC_register_data_segments()
return(p);
}
# endif
+
+# ifndef REDIRECT_MALLOC
+ /* We maintain a linked list of AllocationBase values that we know */
+ /* correspond to malloc heap sections. Currently this is only called */
+ /* during a GC. But there is some hope that for long running */
+ /* programs we will eventually see most heap sections. */
+
+ /* In the long run, it would be more reliable to occasionally walk */
+ /* the malloc heap with HeapWalk on the default heap. But that */
+ /* apparently works only for NT-based Windows. */
+
+ /* In the long run, a better data structure would also be nice ... */
+ struct GC_malloc_heap_list {
+ void * allocation_base;
+ struct GC_malloc_heap_list *next;
+ } *GC_malloc_heap_l = 0;
+
+ /* Is p the base of one of the malloc heap sections we already know */
+ /* about? */
+ GC_bool GC_is_malloc_heap_base(ptr_t p)
+ {
+ struct GC_malloc_heap_list *q = GC_malloc_heap_l;
+
+ while (0 != q) {
+ if (q -> allocation_base == p) return TRUE;
+ q = q -> next;
+ }
+ return FALSE;
+ }
+
+ void *GC_get_allocation_base(void *p)
+ {
+ MEMORY_BASIC_INFORMATION buf;
+ DWORD result = VirtualQuery(p, &buf, sizeof(buf));
+ if (result != sizeof(buf)) {
+ ABORT("Weird VirtualQuery result");
+ }
+ return buf.AllocationBase;
+ }
+
+ size_t GC_max_root_size = 100000; /* Appr. largest root size. */
+
+ void GC_add_current_malloc_heap()
+ {
+ struct GC_malloc_heap_list *new_l =
+ malloc(sizeof(struct GC_malloc_heap_list));
+ void * candidate = GC_get_allocation_base(new_l);
+
+ if (new_l == 0) return;
+ if (GC_is_malloc_heap_base(candidate)) {
+ /* Try a little harder to find malloc heap. */
+ size_t req_size = 10000;
+ do {
+ void *p = malloc(req_size);
+ if (0 == p) { free(new_l); return; }
+ candidate = GC_get_allocation_base(p);
+ free(p);
+ req_size *= 2;
+ } while (GC_is_malloc_heap_base(candidate)
+ && req_size < GC_max_root_size/10 && req_size < 500000);
+ if (GC_is_malloc_heap_base(candidate)) {
+ free(new_l); return;
+ }
+ }
+# ifdef CONDPRINT
+ if (GC_print_stats)
+ GC_printf1("Found new system malloc AllocationBase at 0x%lx\n",
+ candidate);
+# endif
+ new_l -> allocation_base = candidate;
+ new_l -> next = GC_malloc_heap_l;
+ GC_malloc_heap_l = new_l;
+ }
+# endif /* REDIRECT_MALLOC */
/* Is p the start of either the malloc heap, or of one of our */
/* heap sections? */
GC_bool GC_is_heap_base (ptr_t p)
{
- register unsigned i;
+ unsigned i;
# ifndef REDIRECT_MALLOC
- static ptr_t malloc_heap_pointer = 0;
+ static word last_gc_no = -1;
- if (0 == malloc_heap_pointer) {
- MEMORY_BASIC_INFORMATION buf;
- void *pTemp = malloc( 1 );
- register DWORD result = VirtualQuery(pTemp, &buf, sizeof(buf));
-
- free( pTemp );
-
-
- if (result != sizeof(buf)) {
- ABORT("Weird VirtualQuery result");
- }
- malloc_heap_pointer = (ptr_t)(buf.AllocationBase);
+ if (last_gc_no != GC_gc_no) {
+ GC_add_current_malloc_heap();
+ last_gc_no = GC_gc_no;
}
- if (p == malloc_heap_pointer) return(TRUE);
+ if (GC_root_size > GC_max_root_size) GC_max_root_size = GC_root_size;
+ if (GC_is_malloc_heap_base(p)) return TRUE;
# endif
for (i = 0; i < GC_n_heap_bases; i++) {
- if (GC_heap_bases[i] == p) return(TRUE);
+ if (GC_heap_bases[i] == p) return TRUE;
}
- return(FALSE);
+ return FALSE ;
}
# ifdef MSWIN32
@@ -1043,7 +1317,7 @@ void GC_register_data_segments()
# if (defined(SVR4) || defined(AUX) || defined(DGUX) \
|| (defined(LINUX) && defined(SPARC))) && !defined(PCR)
-char * GC_SysVGetDataStart(max_page_size, etext_addr)
+ptr_t GC_SysVGetDataStart(max_page_size, etext_addr)
int max_page_size;
int * etext_addr;
{
@@ -1069,12 +1343,45 @@ int * etext_addr;
/* string constants in the text segment, but after etext. */
/* Use plan B. Note that we now know there is a gap between */
/* text and data segments, so plan A bought us something. */
- result = (char *)GC_find_limit((ptr_t)(DATAEND) - MIN_PAGE_SIZE, FALSE);
+ result = (char *)GC_find_limit((ptr_t)(DATAEND), FALSE);
}
- return((char *)result);
+ return((ptr_t)result);
}
# endif
+# if defined(FREEBSD) && defined(I386) && !defined(PCR)
+/* Its unclear whether this should be identical to the above, or */
+/* whether it should apply to non-X86 architectures. */
+/* For now we don't assume that there is always an empty page after */
+/* etext. But in some cases there actually seems to be slightly more. */
+/* This also deals with holes between read-only data and writable data. */
+ptr_t GC_FreeBSDGetDataStart(max_page_size, etext_addr)
+int max_page_size;
+int * etext_addr;
+{
+ word text_end = ((word)(etext_addr) + sizeof(word) - 1)
+ & ~(sizeof(word) - 1);
+ /* etext rounded to word boundary */
+ VOLATILE word next_page = (text_end + (word)max_page_size - 1)
+ & ~((word)max_page_size - 1);
+ VOLATILE ptr_t result = (ptr_t)text_end;
+ GC_setup_temporary_fault_handler();
+ if (setjmp(GC_jmp_buf) == 0) {
+ /* Try reading at the address. */
+ /* This should happen before there is another thread. */
+ for (; next_page < (word)(DATAEND); next_page += (word)max_page_size)
+ *(VOLATILE char *)next_page;
+ GC_reset_fault_handler();
+ } else {
+ GC_reset_fault_handler();
+ /* As above, we go to plan B */
+ result = GC_find_limit((ptr_t)(DATAEND), FALSE);
+ }
+ return(result);
+}
+
+# endif
+
#ifdef AMIGA
@@ -1086,8 +1393,7 @@ int * etext_addr;
void GC_register_data_segments()
{
-# if !defined(PCR) && !defined(SRC_M3) && !defined(NEXT) && !defined(MACOS) \
- && !defined(MACOSX)
+# if !defined(PCR) && !defined(SRC_M3) && !defined(MACOS)
# if defined(REDIRECT_MALLOC) && defined(GC_SOLARIS_THREADS)
/* As of Solaris 2.3, the Solaris threads implementation */
/* allocates the data structure for the initial thread with */
@@ -1104,9 +1410,6 @@ void GC_register_data_segments()
# endif
# endif
# endif
-# if !defined(PCR) && (defined(NEXT) || defined(MACOSX))
- GC_add_roots_inner(DATASTART, (char *) get_end(), FALSE);
-# endif
# if defined(MACOS)
{
# if defined(THINK_C)
@@ -1216,18 +1519,28 @@ word bytes;
ptr_t GC_unix_get_mem(bytes)
word bytes;
{
- static GC_bool initialized = FALSE;
- static int fd;
void *result;
static ptr_t last_addr = HEAP_START;
- if (!initialized) {
- fd = open("/dev/zero", O_RDONLY);
- initialized = TRUE;
- }
+# ifndef USE_MMAP_ANON
+ static GC_bool initialized = FALSE;
+ static int fd;
+
+ if (!initialized) {
+ fd = open("/dev/zero", O_RDONLY);
+ fcntl(fd, F_SETFD, FD_CLOEXEC);
+ initialized = TRUE;
+ }
+# endif
+
if (bytes & (GC_page_size -1)) ABORT("Bad GET_MEM arg");
- result = mmap(last_addr, bytes, PROT_READ | PROT_WRITE | OPT_PROT_EXEC,
- GC_MMAP_FLAGS, fd, 0/* offset */);
+# ifdef USE_MMAP_ANON
+ result = mmap(last_addr, bytes, PROT_READ | PROT_WRITE | OPT_PROT_EXEC,
+ GC_MMAP_FLAGS | MAP_ANON, -1, 0/* offset */);
+# else
+ result = mmap(last_addr, bytes, PROT_READ | PROT_WRITE | OPT_PROT_EXEC,
+ GC_MMAP_FLAGS, fd, 0/* offset */);
+# endif
if (result == MAP_FAILED) return(0);
last_addr = (ptr_t)result + bytes + GC_page_size - 1;
last_addr = (ptr_t)((word)last_addr & ~(GC_page_size - 1));
@@ -1322,7 +1635,15 @@ word bytes;
result = (ptr_t) GlobalAlloc(0, bytes + HBLKSIZE);
result = (ptr_t)(((word)result + HBLKSIZE) & ~(HBLKSIZE-1));
} else {
- result = (ptr_t) VirtualAlloc(NULL, bytes,
+ /* VirtualProtect only works on regions returned by a */
+ /* single VirtualAlloc call. Thus we allocate one */
+ /* extra page, which will prevent merging of blocks */
+ /* in separate regions, and eliminate any temptation */
+ /* to call VirtualProtect on a range spanning regions. */
+ /* This wastes a small amount of memory, and risks */
+ /* increased fragmentation. But better alternatives */
+ /* would require effort. */
+ result = (ptr_t) VirtualAlloc(NULL, bytes + 1,
MEM_COMMIT | MEM_RESERVE,
PAGE_EXECUTE_READWRITE);
}
@@ -1378,6 +1699,10 @@ word bytes;
/* Reserve more pages */
word res_bytes = (bytes + GC_sysinfo.dwAllocationGranularity-1)
& ~(GC_sysinfo.dwAllocationGranularity-1);
+ /* If we ever support MPROTECT_VDB here, we will probably need to */
+ /* ensure that res_bytes is strictly > bytes, so that VirtualProtect */
+ /* never spans regions. It seems to be OK for a VirtualFree argument */
+ /* to span regions, so we should be OK for now. */
result = (ptr_t) VirtualAlloc(NULL, res_bytes,
MEM_RESERVE | MEM_TOP_DOWN,
PAGE_EXECUTE_READWRITE);
@@ -1508,6 +1833,7 @@ void GC_remap(ptr_t start, word bytes)
}
# else
if (-1 == zero_descr) zero_descr = open("/dev/zero", O_RDWR);
+ fcntl(zero_descr, F_SETFD, FD_CLOEXEC);
if (0 == start_addr) return;
result = mmap(start_addr, len, PROT_READ | PROT_WRITE | OPT_PROT_EXEC,
MAP_FIXED | MAP_PRIVATE, zero_descr, 0);
@@ -1694,7 +2020,6 @@ void (*GC_push_other_roots) GC_PROTO((void)) = GC_default_push_other_roots;
* make sure that other system calls are similarly protected
* or write only to the stack.
*/
-
GC_bool GC_dirty_maintained = FALSE;
# ifdef DEFAULT_VDB
@@ -1708,6 +2033,9 @@ GC_bool GC_dirty_maintained = FALSE;
/* Initialize virtual dirty bit implementation. */
void GC_dirty_init()
{
+# ifdef PRINTSTATS
+ GC_printf0("Initializing DEFAULT_VDB...\n");
+# endif
GC_dirty_maintained = TRUE;
}
@@ -1776,17 +2104,21 @@ GC_bool is_ptrfree;
/*
* This implementation maintains dirty bits itself by catching write
* faults and keeping track of them. We assume nobody else catches
- * SIGBUS or SIGSEGV. We assume no write faults occur in system calls
- * except as a result of a read system call. This means clients must
- * either ensure that system calls do not touch the heap, or must
- * provide their own wrappers analogous to the one for read.
+ * SIGBUS or SIGSEGV. We assume no write faults occur in system calls.
+ * This means that clients must ensure that system calls don't write
+ * to the write-protected heap. Probably the best way to do this is to
+ * ensure that system calls write at most to POINTERFREE objects in the
+ * heap, and do even that only if we are on a platform on which those
+ * are not protected. Another alternative is to wrap system calls
+ * (see example for read below), but the current implementation holds
+ * a lock across blocking calls, making it problematic for multithreaded
+ * applications.
* We assume the page size is a multiple of HBLKSIZE.
- * This implementation is currently SunOS 4.X and IRIX 5.X specific, though we
- * tried to use portable code where easily possible. It is known
- * not to work under a number of other systems.
+ * We prefer them to be the same. We avoid protecting POINTERFREE
+ * objects only if they are the same.
*/
-# if !defined(MSWIN32) && !defined(MSWINCE)
+# if !defined(MSWIN32) && !defined(MSWINCE) && !defined(DARWIN)
# include <sys/mman.h>
# include <signal.h>
@@ -1805,6 +2137,23 @@ GC_bool is_ptrfree;
# else
+# ifdef DARWIN
+ /* Using vm_protect (mach syscall) over mprotect (BSD syscall) seems to
+ decrease the likelihood of some of the problems described below. */
+ #include <mach/vm_map.h>
+ extern mach_port_t GC_task_self;
+ #define PROTECT(addr,len) \
+ if(vm_protect(GC_task_self,(vm_address_t)(addr),(vm_size_t)(len), \
+ FALSE,VM_PROT_READ) != KERN_SUCCESS) { \
+ ABORT("vm_portect failed"); \
+ }
+ #define UNPROTECT(addr,len) \
+ if(vm_protect(GC_task_self,(vm_address_t)(addr),(vm_size_t)(len), \
+ FALSE,VM_PROT_READ|VM_PROT_WRITE) != KERN_SUCCESS) { \
+ ABORT("vm_portect failed"); \
+ }
+# else
+
# ifndef MSWINCE
# include <signal.h>
# endif
@@ -1822,20 +2171,22 @@ GC_bool is_ptrfree;
&protect_junk)) { \
ABORT("un-VirtualProtect failed"); \
}
-
-# endif
+# endif /* !DARWIN */
+# endif /* MSWIN32 || MSWINCE || DARWIN */
#if defined(SUNOS4) || defined(FREEBSD)
typedef void (* SIG_PF)();
-#endif
+#endif /* SUNOS4 || FREEBSD */
+
#if defined(SUNOS5SIGS) || defined(OSF1) || defined(LINUX) \
- || defined(MACOSX) || defined(HURD)
+ || defined(HURD)
# ifdef __STDC__
typedef void (* SIG_PF)(int);
# else
typedef void (* SIG_PF)();
# endif
-#endif
+#endif /* SUNOS5SIGS || OSF1 || LINUX || HURD */
+
#if defined(MSWIN32)
typedef LPTOP_LEVEL_EXCEPTION_FILTER SIG_PF;
# undef SIG_DFL
@@ -1849,7 +2200,8 @@ GC_bool is_ptrfree;
#if defined(IRIX5) || defined(OSF1) || defined(HURD)
typedef void (* REAL_SIG_PF)(int, int, struct sigcontext *);
-#endif
+#endif /* IRIX5 || OSF1 || HURD */
+
#if defined(SUNOS5SIGS)
# ifdef HPUX
# define SIGINFO __siginfo
@@ -1861,13 +2213,14 @@ GC_bool is_ptrfree;
# else
typedef void (* REAL_SIG_PF)();
# endif
-#endif
+#endif /* SUNOS5SIGS */
+
#if defined(LINUX)
# if __GLIBC__ > 2 || __GLIBC__ == 2 && __GLIBC_MINOR__ >= 2
typedef struct sigcontext s_c;
# else /* glibc < 2.2 */
# include <linux/version.h>
-# if (LINUX_VERSION_CODE >= 0x20100) && !defined(M68K) || defined(ALPHA)
+# if (LINUX_VERSION_CODE >= 0x20100) && !defined(M68K) || defined(ALPHA) || defined(ARM32)
typedef struct sigcontext s_c;
# else
typedef struct sigcontext_struct s_c;
@@ -1895,139 +2248,14 @@ GC_bool is_ptrfree;
return (char *)faultaddr;
}
# endif /* !ALPHA */
-# endif
-
-# if defined(MACOSX) /* Should also test for PowerPC? */
- typedef void (* REAL_SIG_PF)(int, int, struct sigcontext *);
-
-/* Decodes the machine instruction which was responsible for the sending of the
- SIGBUS signal. Sadly this is the only way to find the faulting address because
- the signal handler doesn't get it directly from the kernel (although it is
- available on the Mach level, but droppped by the BSD personality before it
- calls our signal handler...)
- This code should be able to deal correctly with all PPCs starting from the
- 601 up to and including the G4s (including Velocity Engine). */
-#define EXTRACT_OP1(iw) (((iw) & 0xFC000000) >> 26)
-#define EXTRACT_OP2(iw) (((iw) & 0x000007FE) >> 1)
-#define EXTRACT_REGA(iw) (((iw) & 0x001F0000) >> 16)
-#define EXTRACT_REGB(iw) (((iw) & 0x03E00000) >> 21)
-#define EXTRACT_REGC(iw) (((iw) & 0x0000F800) >> 11)
-#define EXTRACT_DISP(iw) ((short *) &(iw))[1]
-
-static char *get_fault_addr(struct sigcontext *scp)
-{
- unsigned int instr = *((unsigned int *) scp->sc_ir);
- unsigned int * regs = &((unsigned int *) scp->sc_regs)[2];
- int disp = 0, tmp;
- unsigned int baseA = 0, baseB = 0;
- unsigned int addr, alignmask = 0xFFFFFFFF;
-
-#ifdef GC_DEBUG_DECODER
- GC_err_printf1("Instruction: 0x%lx\n", instr);
- GC_err_printf1("Opcode 1: d\n", (int)EXTRACT_OP1(instr));
-#endif
- switch(EXTRACT_OP1(instr)) {
- case 38: /* stb */
- case 39: /* stbu */
- case 54: /* stfd */
- case 55: /* stfdu */
- case 52: /* stfs */
- case 53: /* stfsu */
- case 44: /* sth */
- case 45: /* sthu */
- case 47: /* stmw */
- case 36: /* stw */
- case 37: /* stwu */
- tmp = EXTRACT_REGA(instr);
- if(tmp > 0)
- baseA = regs[tmp];
- disp = EXTRACT_DISP(instr);
- break;
- case 31:
-#ifdef GC_DEBUG_DECODER
- GC_err_printf1("Opcode 2: %d\n", (int)EXTRACT_OP2(instr));
-#endif
- switch(EXTRACT_OP2(instr)) {
- case 86: /* dcbf */
- case 54: /* dcbst */
- case 1014: /* dcbz */
- case 247: /* stbux */
- case 215: /* stbx */
- case 759: /* stfdux */
- case 727: /* stfdx */
- case 983: /* stfiwx */
- case 695: /* stfsux */
- case 663: /* stfsx */
- case 918: /* sthbrx */
- case 439: /* sthux */
- case 407: /* sthx */
- case 661: /* stswx */
- case 662: /* stwbrx */
- case 150: /* stwcx. */
- case 183: /* stwux */
- case 151: /* stwx */
- case 135: /* stvebx */
- case 167: /* stvehx */
- case 199: /* stvewx */
- case 231: /* stvx */
- case 487: /* stvxl */
- tmp = EXTRACT_REGA(instr);
- if(tmp > 0)
- baseA = regs[tmp];
- baseB = regs[EXTRACT_REGC(instr)];
- /* determine Altivec alignment mask */
- switch(EXTRACT_OP2(instr)) {
- case 167: /* stvehx */
- alignmask = 0xFFFFFFFE;
- break;
- case 199: /* stvewx */
- alignmask = 0xFFFFFFFC;
- break;
- case 231: /* stvx */
- alignmask = 0xFFFFFFF0;
- break;
- case 487: /* stvxl */
- alignmask = 0xFFFFFFF0;
- break;
- }
- break;
- case 725: /* stswi */
- tmp = EXTRACT_REGA(instr);
- if(tmp > 0)
- baseA = regs[tmp];
- break;
- default: /* ignore instruction */
-#ifdef GC_DEBUG_DECODER
- GC_err_printf("Ignored by inner handler\n");
-#endif
- return NULL;
- break;
- }
- break;
- default: /* ignore instruction */
-#ifdef GC_DEBUG_DECODER
- GC_err_printf("Ignored by main handler\n");
-#endif
- return NULL;
- break;
- }
-
- addr = (baseA + baseB) + disp;
- addr &= alignmask;
-#ifdef GC_DEBUG_DECODER
- GC_err_printf1("BaseA: %d\n", baseA);
- GC_err_printf1("BaseB: %d\n", baseB);
- GC_err_printf1("Disp: %d\n", disp);
- GC_err_printf1("Address: %d\n", addr);
-#endif
- return (char *)addr;
-}
-#endif /* MACOSX */
+# endif /* LINUX */
+#ifndef DARWIN
SIG_PF GC_old_bus_handler;
SIG_PF GC_old_segv_handler; /* Also old MSWIN32 ACCESS_VIOLATION filter */
+#endif /* !DARWIN */
-#ifdef THREADS
+#if defined(THREADS)
/* We need to lock around the bitmap update in the write fault handler */
/* in order to avoid the risk of losing a bit. We do this with a */
/* test-and-set spin lock if we know how to do that. Otherwise we */
@@ -2076,6 +2304,7 @@ SIG_PF GC_old_segv_handler; /* Also old MSWIN32 ACCESS_VIOLATION filter */
#endif /* !THREADS */
/*ARGSUSED*/
+#if !defined(DARWIN)
# if defined (SUNOS4) || defined(FREEBSD)
void GC_write_fault_handler(sig, code, scp, addr)
int sig, code;
@@ -2091,7 +2320,8 @@ SIG_PF GC_old_segv_handler; /* Also old MSWIN32 ACCESS_VIOLATION filter */
# define SIG_OK (sig == SIGBUS)
# define CODE_OK (code == BUS_PAGE_FAULT)
# endif
-# endif
+# endif /* SUNOS4 || FREEBSD */
+
# if defined(IRIX5) || defined(OSF1) || defined(HURD)
# include <errno.h>
void GC_write_fault_handler(int sig, int code, struct sigcontext *scp)
@@ -2107,7 +2337,8 @@ SIG_PF GC_old_segv_handler; /* Also old MSWIN32 ACCESS_VIOLATION filter */
# define SIG_OK (sig == SIGBUS || sig == SIGSEGV)
# define CODE_OK TRUE
# endif
-# endif
+# endif /* IRIX5 || OSF1 || HURD */
+
# if defined(LINUX)
# if defined(ALPHA) || defined(M68K)
void GC_write_fault_handler(int sig, int code, s_c * sc)
@@ -2115,7 +2346,11 @@ SIG_PF GC_old_segv_handler; /* Also old MSWIN32 ACCESS_VIOLATION filter */
# if defined(IA64) || defined(HP_PA)
void GC_write_fault_handler(int sig, siginfo_t * si, s_c * scp)
# else
- void GC_write_fault_handler(int sig, s_c sc)
+# if defined(ARM32)
+ void GC_write_fault_handler(int sig, int a2, int a3, int a4, s_c sc)
+# else
+ void GC_write_fault_handler(int sig, s_c sc)
+# endif
# endif
# endif
# define SIG_OK (sig == SIGSEGV)
@@ -2123,7 +2358,8 @@ SIG_PF GC_old_segv_handler; /* Also old MSWIN32 ACCESS_VIOLATION filter */
/* Empirically c.trapno == 14, on IA32, but is that useful? */
/* Should probably consider alignment issues on other */
/* architectures. */
-# endif
+# endif /* LINUX */
+
# if defined(SUNOS5SIGS)
# ifdef __STDC__
void GC_write_fault_handler(int sig, struct SIGINFO *scp, void * context)
@@ -2144,13 +2380,7 @@ SIG_PF GC_old_segv_handler; /* Also old MSWIN32 ACCESS_VIOLATION filter */
# define SIG_OK (sig == SIGSEGV)
# define CODE_OK (scp -> si_code == SEGV_ACCERR)
# endif
-# endif
-
-# if defined(MACOSX)
- void GC_write_fault_handler(int sig, int code, struct sigcontext *scp)
-# define SIG_OK (sig == SIGBUS)
-# define CODE_OK (code == 0 /* experimentally determined */)
-# endif
+# endif /* SUNOS5SIGS */
# if defined(MSWIN32) || defined(MSWINCE)
LONG WINAPI GC_write_fault_handler(struct _EXCEPTION_POINTERS *exc_info)
@@ -2158,7 +2388,7 @@ SIG_PF GC_old_segv_handler; /* Also old MSWIN32 ACCESS_VIOLATION filter */
STATUS_ACCESS_VIOLATION)
# define CODE_OK (exc_info -> ExceptionRecord -> ExceptionInformation[0] == 1)
/* Write fault */
-# endif
+# endif /* MSWIN32 || MSWINCE */
{
register unsigned i;
# if defined(HURD)
@@ -2218,16 +2448,17 @@ SIG_PF GC_old_segv_handler; /* Also old MSWIN32 ACCESS_VIOLATION filter */
# if defined(POWERPC)
char * addr = (char *) (sc.regs->dar);
# else
- --> architecture not supported
+# if defined(ARM32)
+ char * addr = (char *)sc.fault_address;
+# else
+ --> architecture not supported
+# endif
# endif
# endif
# endif
# endif
# endif
# endif
-# if defined(MACOSX)
- char * addr = get_fault_addr(scp);
-# endif
# if defined(MSWIN32) || defined(MSWINCE)
char * addr = (char *) (exc_info -> ExceptionRecord
-> ExceptionInformation[1]);
@@ -2291,9 +2522,6 @@ SIG_PF GC_old_segv_handler; /* Also old MSWIN32 ACCESS_VIOLATION filter */
(*(REAL_SIG_PF)old_handler) (sig, code, scp);
return;
# endif
-# ifdef MACOSX
- (*(REAL_SIG_PF)old_handler) (sig, code, scp);
-# endif
# ifdef MSWIN32
return((*old_handler)(exc_info));
# endif
@@ -2335,10 +2563,11 @@ SIG_PF GC_old_segv_handler; /* Also old MSWIN32 ACCESS_VIOLATION filter */
ABORT("Unexpected bus error or segmentation fault");
#endif
}
+#endif /* !DARWIN */
/*
* We hold the allocation lock. We expect block h to be written
- * shortly. Ensure that all pages cvontaining any part of the n hblks
+ * shortly. Ensure that all pages containing any part of the n hblks
* starting at h are no longer protected. If is_ptrfree is false,
* also ensure that they will subsequently appear to be dirty.
*/
@@ -2367,6 +2596,7 @@ GC_bool is_ptrfree;
UNPROTECT(h_trunc, (ptr_t)h_end - (ptr_t)h_trunc);
}
+#if !defined(DARWIN)
void GC_dirty_init()
{
# if defined(SUNOS5SIGS) || defined(IRIX5) || defined(LINUX) || \
@@ -2389,13 +2619,6 @@ void GC_dirty_init()
(void)sigaddset(&act.sa_mask, SIG_SUSPEND);
# endif /* SIG_SUSPEND */
# endif
-# if defined(MACOSX)
- struct sigaction act, oldact;
-
- act.sa_flags = SA_RESTART;
- act.sa_handler = GC_write_fault_handler;
- sigemptyset(&act.sa_mask);
-# endif
# ifdef PRINTSTATS
GC_printf0("Inititalizing mprotect virtual dirty bit implementation\n");
# endif
@@ -2435,9 +2658,12 @@ void GC_dirty_init()
sigaction(SIGSEGV, 0, &oldact);
sigaction(SIGSEGV, &act, 0);
# else
- sigaction(SIGSEGV, &act, &oldact);
+ {
+ int res = sigaction(SIGSEGV, &act, &oldact);
+ if (res != 0) ABORT("Sigaction failed");
+ }
# endif
-# if defined(_sigargs) || defined(HURD)
+# if defined(_sigargs) || defined(HURD) || !defined(SA_SIGINFO)
/* This is Irix 5.x, not 6.x. Irix 5.x does not have */
/* sa_sigaction. */
GC_old_segv_handler = oldact.sa_handler;
@@ -2458,7 +2684,7 @@ void GC_dirty_init()
# endif
}
# endif
-# if defined(MACOSX) || defined(HPUX) || defined(LINUX) || defined(HURD)
+# if defined(HPUX) || defined(LINUX) || defined(HURD)
sigaction(SIGBUS, &act, &oldact);
GC_old_bus_handler = oldact.sa_handler;
if (GC_old_bus_handler == SIG_IGN) {
@@ -2470,7 +2696,7 @@ void GC_dirty_init()
GC_err_printf0("Replaced other SIGBUS handler\n");
# endif
}
-# endif /* MACOS || HPUX || LINUX */
+# endif /* HPUX || LINUX || HURD */
# if defined(MSWIN32)
GC_old_segv_handler = SetUnhandledExceptionFilter(GC_write_fault_handler);
if (GC_old_segv_handler != NULL) {
@@ -2482,6 +2708,7 @@ void GC_dirty_init()
}
# endif
}
+#endif /* !DARWIN */
int GC_incremental_protection_needs()
{
@@ -2628,15 +2855,23 @@ word len;
((ptr_t)end_block - (ptr_t)start_block) + HBLKSIZE);
}
-#if !defined(MSWIN32) && !defined(MSWINCE) && !defined(THREADS) \
- && !defined(GC_USE_LD_WRAP)
-/* Replacement for UNIX system call. */
-/* Other calls that write to the heap should be handled similarly. */
-/* Note that this doesn't work well for blocking reads: It will hold */
-/* tha allocation lock for the entur duration of the call. Multithreaded */
-/* clients should really ensure that it won't block, either by setting */
-/* the descriptor nonblocking, or by calling select or poll first, to */
-/* make sure that input is available. */
+#if 0
+
+/* We no longer wrap read by default, since that was causing too many */
+/* problems. It is preferred that the client instead avoids writing */
+/* to the write-protected heap with a system call. */
+/* This still serves as sample code if you do want to wrap system calls.*/
+
+#if !defined(MSWIN32) && !defined(MSWINCE) && !defined(GC_USE_LD_WRAP)
+/* Replacement for UNIX system call. */
+/* Other calls that write to the heap should be handled similarly. */
+/* Note that this doesn't work well for blocking reads: It will hold */
+/* the allocation lock for the entire duration of the call. Multithreaded */
+/* clients should really ensure that it won't block, either by setting */
+/* the descriptor nonblocking, or by calling select or poll first, to */
+/* make sure that input is available. */
+/* Another, preferred alternative is to ensure that system calls never */
+/* write to the protected heap (see above). */
# if defined(__STDC__) && !defined(SUNOS4)
# include <unistd.h>
# include <sys/uio.h>
@@ -2706,6 +2941,8 @@ word len;
/* actually calls. */
#endif
+#endif /* 0 */
+
/*ARGSUSED*/
GC_bool GC_page_was_ever_dirty(h)
struct hblk *h;
@@ -2721,13 +2958,6 @@ word n;
{
}
-# else /* !MPROTECT_VDB */
-
-# ifdef GC_USE_LD_WRAP
- ssize_t __wrap_read(int fd, void *buf, size_t nbyte)
- { return __real_read(fd, buf, nbyte); }
-# endif
-
# endif /* MPROTECT_VDB */
# ifdef PROC_VDB
@@ -2806,6 +3036,7 @@ void GC_dirty_init()
}
GC_proc_fd = syscall(SYS_ioctl, fd, PIOCOPENPD, 0);
close(fd);
+ syscall(SYS_fcntl, GC_proc_fd, F_SETFD, FD_CLOEXEC);
if (GC_proc_fd < 0) {
ABORT("/proc ioctl failed");
}
@@ -3045,6 +3276,552 @@ GC_bool is_ptrfree;
# endif /* PCR_VDB */
+#if defined(MPROTECT_VDB) && defined(DARWIN)
+/* The following sources were used as a *reference* for this exception handling
+ code:
+ 1. Apple's mach/xnu documentation
+ 2. Timothy J. Wood's "Mach Exception Handlers 101" post to the
+ omnigroup's macosx-dev list.
+ www.omnigroup.com/mailman/archive/macosx-dev/2000-June/002030.html
+ 3. macosx-nat.c from Apple's GDB source code.
+*/
+
+/* The bug that caused all this trouble should now be fixed. This should
+ eventually be removed if all goes well. */
+/* define BROKEN_EXCEPTION_HANDLING */
+
+#include <mach/mach.h>
+#include <mach/mach_error.h>
+#include <mach/thread_status.h>
+#include <mach/exception.h>
+#include <mach/task.h>
+#include <pthread.h>
+
+/* These are not defined in any header, although they are documented */
+extern boolean_t exc_server(mach_msg_header_t *,mach_msg_header_t *);
+extern kern_return_t exception_raise(
+ mach_port_t,mach_port_t,mach_port_t,
+ exception_type_t,exception_data_t,mach_msg_type_number_t);
+extern kern_return_t exception_raise_state(
+ mach_port_t,mach_port_t,mach_port_t,
+ exception_type_t,exception_data_t,mach_msg_type_number_t,
+ thread_state_flavor_t*,thread_state_t,mach_msg_type_number_t,
+ thread_state_t,mach_msg_type_number_t*);
+extern kern_return_t exception_raise_state_identity(
+ mach_port_t,mach_port_t,mach_port_t,
+ exception_type_t,exception_data_t,mach_msg_type_number_t,
+ thread_state_flavor_t*,thread_state_t,mach_msg_type_number_t,
+ thread_state_t,mach_msg_type_number_t*);
+
+
+#define MAX_EXCEPTION_PORTS 16
+
+static mach_port_t GC_task_self;
+
+static struct {
+ mach_msg_type_number_t count;
+ exception_mask_t masks[MAX_EXCEPTION_PORTS];
+ exception_handler_t ports[MAX_EXCEPTION_PORTS];
+ exception_behavior_t behaviors[MAX_EXCEPTION_PORTS];
+ thread_state_flavor_t flavors[MAX_EXCEPTION_PORTS];
+} GC_old_exc_ports;
+
+static struct {
+ mach_port_t exception;
+#if defined(THREADS)
+ mach_port_t reply;
+#endif
+} GC_ports;
+
+typedef struct {
+ mach_msg_header_t head;
+} GC_msg_t;
+
+typedef enum {
+ GC_MP_NORMAL, GC_MP_DISCARDING, GC_MP_STOPPED
+} GC_mprotect_state_t;
+
+/* FIXME: 1 and 2 seem to be safe to use in the msgh_id field,
+ but it isn't documented. Use the source and see if they
+ should be ok. */
+#define ID_STOP 1
+#define ID_RESUME 2
+
+/* These values are only used on the reply port */
+#define ID_ACK 3
+
+#if defined(THREADS)
+
+GC_mprotect_state_t GC_mprotect_state;
+
+/* The following should ONLY be called when the world is stopped */
+static void GC_mprotect_thread_notify(mach_msg_id_t id) {
+ struct {
+ GC_msg_t msg;
+ mach_msg_trailer_t trailer;
+ } buf;
+ mach_msg_return_t r;
+ /* remote, local */
+ buf.msg.head.msgh_bits =
+ MACH_MSGH_BITS(MACH_MSG_TYPE_MAKE_SEND,0);
+ buf.msg.head.msgh_size = sizeof(buf.msg);
+ buf.msg.head.msgh_remote_port = GC_ports.exception;
+ buf.msg.head.msgh_local_port = MACH_PORT_NULL;
+ buf.msg.head.msgh_id = id;
+
+ r = mach_msg(
+ &buf.msg.head,
+ MACH_SEND_MSG|MACH_RCV_MSG|MACH_RCV_LARGE,
+ sizeof(buf.msg),
+ sizeof(buf),
+ GC_ports.reply,
+ MACH_MSG_TIMEOUT_NONE,
+ MACH_PORT_NULL);
+ if(r != MACH_MSG_SUCCESS)
+ ABORT("mach_msg failed in GC_mprotect_thread_notify");
+ if(buf.msg.head.msgh_id != ID_ACK)
+ ABORT("invalid ack in GC_mprotect_thread_notify");
+}
+
+/* Should only be called by the mprotect thread */
+static void GC_mprotect_thread_reply() {
+ GC_msg_t msg;
+ mach_msg_return_t r;
+ /* remote, local */
+ msg.head.msgh_bits =
+ MACH_MSGH_BITS(MACH_MSG_TYPE_MAKE_SEND,0);
+ msg.head.msgh_size = sizeof(msg);
+ msg.head.msgh_remote_port = GC_ports.reply;
+ msg.head.msgh_local_port = MACH_PORT_NULL;
+ msg.head.msgh_id = ID_ACK;
+
+ r = mach_msg(
+ &msg.head,
+ MACH_SEND_MSG,
+ sizeof(msg),
+ 0,
+ MACH_PORT_NULL,
+ MACH_MSG_TIMEOUT_NONE,
+ MACH_PORT_NULL);
+ if(r != MACH_MSG_SUCCESS)
+ ABORT("mach_msg failed in GC_mprotect_thread_reply");
+}
+
+void GC_mprotect_stop() {
+ GC_mprotect_thread_notify(ID_STOP);
+}
+void GC_mprotect_resume() {
+ GC_mprotect_thread_notify(ID_RESUME);
+}
+
+#else /* !THREADS */
+/* The compiler should optimize away any GC_mprotect_state computations */
+#define GC_mprotect_state GC_MP_NORMAL
+#endif
+
+static void *GC_mprotect_thread(void *arg) {
+ mach_msg_return_t r;
+ /* These two structures contain some private kernel data. We don't need to
+ access any of it so we don't bother defining a proper struct. The
+ correct definitions are in the xnu source code. */
+ struct {
+ mach_msg_header_t head;
+ char data[256];
+ } reply;
+ struct {
+ mach_msg_header_t head;
+ mach_msg_body_t msgh_body;
+ char data[1024];
+ } msg;
+
+ mach_msg_id_t id;
+
+ for(;;) {
+ r = mach_msg(
+ &msg.head,
+ MACH_RCV_MSG|MACH_RCV_LARGE|
+ (GC_mprotect_state == GC_MP_DISCARDING ? MACH_RCV_TIMEOUT : 0),
+ 0,
+ sizeof(msg),
+ GC_ports.exception,
+ GC_mprotect_state == GC_MP_DISCARDING ? 0 : MACH_MSG_TIMEOUT_NONE,
+ MACH_PORT_NULL);
+
+ id = r == MACH_MSG_SUCCESS ? msg.head.msgh_id : -1;
+
+#if defined(THREADS)
+ if(GC_mprotect_state == GC_MP_DISCARDING) {
+ if(r == MACH_RCV_TIMED_OUT) {
+ GC_mprotect_state = GC_MP_STOPPED;
+ GC_mprotect_thread_reply();
+ continue;
+ }
+ if(r == MACH_MSG_SUCCESS && (id == ID_STOP || id == ID_RESUME))
+ ABORT("out of order mprotect thread request");
+ }
+#endif
+
+ if(r != MACH_MSG_SUCCESS) {
+ GC_err_printf2("mach_msg failed with %d %s\n",
+ (int)r,mach_error_string(r));
+ ABORT("mach_msg failed");
+ }
+
+ switch(id) {
+#if defined(THREADS)
+ case ID_STOP:
+ if(GC_mprotect_state != GC_MP_NORMAL)
+ ABORT("Called mprotect_stop when state wasn't normal");
+ GC_mprotect_state = GC_MP_DISCARDING;
+ break;
+ case ID_RESUME:
+ if(GC_mprotect_state != GC_MP_STOPPED)
+ ABORT("Called mprotect_resume when state wasn't stopped");
+ GC_mprotect_state = GC_MP_NORMAL;
+ GC_mprotect_thread_reply();
+ break;
+#endif /* THREADS */
+ default:
+ /* Handle the message (calls catch_exception_raise) */
+ if(!exc_server(&msg.head,&reply.head))
+ ABORT("exc_server failed");
+ /* Send the reply */
+ r = mach_msg(
+ &reply.head,
+ MACH_SEND_MSG,
+ reply.head.msgh_size,
+ 0,
+ MACH_PORT_NULL,
+ MACH_MSG_TIMEOUT_NONE,
+ MACH_PORT_NULL);
+ if(r != MACH_MSG_SUCCESS) {
+ /* This will fail if the thread dies, but the thread shouldn't
+ die... */
+ #ifdef BROKEN_EXCEPTION_HANDLING
+ GC_err_printf2(
+ "mach_msg failed with %d %s while sending exc reply\n",
+ (int)r,mach_error_string(r));
+ #else
+ ABORT("mach_msg failed while sending exception reply");
+ #endif
+ }
+ } /* switch */
+ } /* for(;;) */
+ /* NOT REACHED */
+ return NULL;
+}
+
+/* All this SIGBUS code shouldn't be necessary. All protection faults should
+ be going throught the mach exception handler. However, it seems a SIGBUS is
+ occasionally sent for some unknown reason. Even more odd, it seems to be
+ meaningless and safe to ignore. */
+#ifdef BROKEN_EXCEPTION_HANDLING
+
+typedef void (* SIG_PF)();
+static SIG_PF GC_old_bus_handler;
+
+/* Updates to this aren't atomic, but the SIGBUSs seem pretty rare.
+ Even if this doesn't get updated property, it isn't really a problem */
+static int GC_sigbus_count;
+
+static void GC_darwin_sigbus(int num,siginfo_t *sip,void *context) {
+ if(num != SIGBUS) ABORT("Got a non-sigbus signal in the sigbus handler");
+
+ /* Ugh... some seem safe to ignore, but too many in a row probably means
+ trouble. GC_sigbus_count is reset for each mach exception that is
+ handled */
+ if(GC_sigbus_count >= 8) {
+ ABORT("Got more than 8 SIGBUSs in a row!");
+ } else {
+ GC_sigbus_count++;
+ GC_err_printf0("GC: WARNING: Ignoring SIGBUS.\n");
+ }
+}
+#endif /* BROKEN_EXCEPTION_HANDLING */
+
+void GC_dirty_init() {
+ kern_return_t r;
+ mach_port_t me;
+ pthread_t thread;
+ pthread_attr_t attr;
+ exception_mask_t mask;
+
+# ifdef PRINTSTATS
+ GC_printf0("Inititalizing mach/darwin mprotect virtual dirty bit "
+ "implementation\n");
+# endif
+# ifdef BROKEN_EXCEPTION_HANDLING
+ GC_err_printf0("GC: WARNING: Enabling workarounds for various darwin "
+ "exception handling bugs.\n");
+# endif
+ GC_dirty_maintained = TRUE;
+ if (GC_page_size % HBLKSIZE != 0) {
+ GC_err_printf0("Page size not multiple of HBLKSIZE\n");
+ ABORT("Page size not multiple of HBLKSIZE");
+ }
+
+ GC_task_self = me = mach_task_self();
+
+ r = mach_port_allocate(me,MACH_PORT_RIGHT_RECEIVE,&GC_ports.exception);
+ if(r != KERN_SUCCESS) ABORT("mach_port_allocate failed (exception port)");
+
+ r = mach_port_insert_right(me,GC_ports.exception,GC_ports.exception,
+ MACH_MSG_TYPE_MAKE_SEND);
+ if(r != KERN_SUCCESS)
+ ABORT("mach_port_insert_right failed (exception port)");
+
+ #if defined(THREADS)
+ r = mach_port_allocate(me,MACH_PORT_RIGHT_RECEIVE,&GC_ports.reply);
+ if(r != KERN_SUCCESS) ABORT("mach_port_allocate failed (reply port)");
+ #endif
+
+ /* The exceptions we want to catch */
+ mask = EXC_MASK_BAD_ACCESS;
+
+ r = task_get_exception_ports(
+ me,
+ mask,
+ GC_old_exc_ports.masks,
+ &GC_old_exc_ports.count,
+ GC_old_exc_ports.ports,
+ GC_old_exc_ports.behaviors,
+ GC_old_exc_ports.flavors
+ );
+ if(r != KERN_SUCCESS) ABORT("task_get_exception_ports failed");
+
+ r = task_set_exception_ports(
+ me,
+ mask,
+ GC_ports.exception,
+ EXCEPTION_DEFAULT,
+ MACHINE_THREAD_STATE
+ );
+ if(r != KERN_SUCCESS) ABORT("task_set_exception_ports failed");
+
+ if(pthread_attr_init(&attr) != 0) ABORT("pthread_attr_init failed");
+ if(pthread_attr_setdetachstate(&attr,PTHREAD_CREATE_DETACHED) != 0)
+ ABORT("pthread_attr_setdetachedstate failed");
+
+# undef pthread_create
+ /* This will call the real pthread function, not our wrapper */
+ if(pthread_create(&thread,&attr,GC_mprotect_thread,NULL) != 0)
+ ABORT("pthread_create failed");
+ pthread_attr_destroy(&attr);
+
+ /* Setup the sigbus handler for ignoring the meaningless SIGBUSs */
+ #ifdef BROKEN_EXCEPTION_HANDLING
+ {
+ struct sigaction sa, oldsa;
+ sa.sa_handler = (SIG_PF)GC_darwin_sigbus;
+ sigemptyset(&sa.sa_mask);
+ sa.sa_flags = SA_RESTART|SA_SIGINFO;
+ if(sigaction(SIGBUS,&sa,&oldsa) < 0) ABORT("sigaction");
+ GC_old_bus_handler = (SIG_PF)oldsa.sa_handler;
+ if (GC_old_bus_handler != SIG_DFL) {
+# ifdef PRINTSTATS
+ GC_err_printf0("Replaced other SIGBUS handler\n");
+# endif
+ }
+ }
+ #endif /* BROKEN_EXCEPTION_HANDLING */
+}
+
+/* The source code for Apple's GDB was used as a reference for the exception
+ forwarding code. This code is similar to be GDB code only because there is
+ only one way to do it. */
+static kern_return_t GC_forward_exception(
+ mach_port_t thread,
+ mach_port_t task,
+ exception_type_t exception,
+ exception_data_t data,
+ mach_msg_type_number_t data_count
+) {
+ int i;
+ kern_return_t r;
+ mach_port_t port;
+ exception_behavior_t behavior;
+ thread_state_flavor_t flavor;
+
+ thread_state_data_t thread_state;
+ mach_msg_type_number_t thread_state_count = THREAD_STATE_MAX;
+
+ for(i=0;i<GC_old_exc_ports.count;i++)
+ if(GC_old_exc_ports.masks[i] & (1 << exception))
+ break;
+ if(i==GC_old_exc_ports.count) ABORT("No handler for exception!");
+
+ port = GC_old_exc_ports.ports[i];
+ behavior = GC_old_exc_ports.behaviors[i];
+ flavor = GC_old_exc_ports.flavors[i];
+
+ if(behavior != EXCEPTION_DEFAULT) {
+ r = thread_get_state(thread,flavor,thread_state,&thread_state_count);
+ if(r != KERN_SUCCESS)
+ ABORT("thread_get_state failed in forward_exception");
+ }
+
+ switch(behavior) {
+ case EXCEPTION_DEFAULT:
+ r = exception_raise(port,thread,task,exception,data,data_count);
+ break;
+ case EXCEPTION_STATE:
+ r = exception_raise_state(port,thread,task,exception,data,
+ data_count,&flavor,thread_state,thread_state_count,
+ thread_state,&thread_state_count);
+ break;
+ case EXCEPTION_STATE_IDENTITY:
+ r = exception_raise_state_identity(port,thread,task,exception,data,
+ data_count,&flavor,thread_state,thread_state_count,
+ thread_state,&thread_state_count);
+ break;
+ default:
+ r = KERN_FAILURE; /* make gcc happy */
+ ABORT("forward_exception: unknown behavior");
+ break;
+ }
+
+ if(behavior != EXCEPTION_DEFAULT) {
+ r = thread_set_state(thread,flavor,thread_state,thread_state_count);
+ if(r != KERN_SUCCESS)
+ ABORT("thread_set_state failed in forward_exception");
+ }
+
+ return r;
+}
+
+#define FWD() GC_forward_exception(thread,task,exception,code,code_count)
+
+/* This violates the namespace rules but there isn't anything that can be done
+ about it. The exception handling stuff is hard coded to call this */
+kern_return_t
+catch_exception_raise(
+ mach_port_t exception_port,mach_port_t thread,mach_port_t task,
+ exception_type_t exception,exception_data_t code,
+ mach_msg_type_number_t code_count
+) {
+ kern_return_t r;
+ char *addr;
+ struct hblk *h;
+ int i;
+#ifdef POWERPC
+ thread_state_flavor_t flavor = PPC_EXCEPTION_STATE;
+ mach_msg_type_number_t exc_state_count = PPC_EXCEPTION_STATE_COUNT;
+ ppc_exception_state_t exc_state;
+#else
+# error FIXME for non-ppc darwin
+#endif
+
+
+ if(exception != EXC_BAD_ACCESS || code[0] != KERN_PROTECTION_FAILURE) {
+ #ifdef DEBUG_EXCEPTION_HANDLING
+ /* We aren't interested, pass it on to the old handler */
+ GC_printf3("Exception: 0x%x Code: 0x%x 0x%x in catch....\n",
+ exception,
+ code_count > 0 ? code[0] : -1,
+ code_count > 1 ? code[1] : -1);
+ #endif
+ return FWD();
+ }
+
+ r = thread_get_state(thread,flavor,
+ (natural_t*)&exc_state,&exc_state_count);
+ if(r != KERN_SUCCESS) {
+ /* The thread is supposed to be suspended while the exception handler
+ is called. This shouldn't fail. */
+ #ifdef BROKEN_EXCEPTION_HANDLING
+ GC_err_printf0("thread_get_state failed in "
+ "catch_exception_raise\n");
+ return KERN_SUCCESS;
+ #else
+ ABORT("thread_get_state failed in catch_exception_raise");
+ #endif
+ }
+
+ /* This is the address that caused the fault */
+ addr = (char*) exc_state.dar;
+
+ if((HDR(addr)) == 0) {
+ /* Ugh... just like the SIGBUS problem above, it seems we get a bogus
+ KERN_PROTECTION_FAILURE every once and a while. We wait till we get
+ a bunch in a row before doing anything about it. If a "real" fault
+ ever occurres it'll just keep faulting over and over and we'll hit
+ the limit pretty quickly. */
+ #ifdef BROKEN_EXCEPTION_HANDLING
+ static char *last_fault;
+ static int last_fault_count;
+
+ if(addr != last_fault) {
+ last_fault = addr;
+ last_fault_count = 0;
+ }
+ if(++last_fault_count < 32) {
+ if(last_fault_count == 1)
+ GC_err_printf1(
+ "GC: WARNING: Ignoring KERN_PROTECTION_FAILURE at %p\n",
+ addr);
+ return KERN_SUCCESS;
+ }
+
+ GC_err_printf1("Unexpected KERN_PROTECTION_FAILURE at %p\n",addr);
+ /* Can't pass it along to the signal handler because that is
+ ignoring SIGBUS signals. We also shouldn't call ABORT here as
+ signals don't always work too well from the exception handler. */
+ GC_err_printf0("Aborting\n");
+ exit(EXIT_FAILURE);
+ #else /* BROKEN_EXCEPTION_HANDLING */
+ /* Pass it along to the next exception handler
+ (which should call SIGBUS/SIGSEGV) */
+ return FWD();
+ #endif /* !BROKEN_EXCEPTION_HANDLING */
+ }
+
+ #ifdef BROKEN_EXCEPTION_HANDLING
+ /* Reset the number of consecutive SIGBUSs */
+ GC_sigbus_count = 0;
+ #endif
+
+ if(GC_mprotect_state == GC_MP_NORMAL) { /* common case */
+ h = (struct hblk*)((word)addr & ~(GC_page_size-1));
+ UNPROTECT(h, GC_page_size);
+ for (i = 0; i < divHBLKSZ(GC_page_size); i++) {
+ register int index = PHT_HASH(h+i);
+ async_set_pht_entry_from_index(GC_dirty_pages, index);
+ }
+ } else if(GC_mprotect_state == GC_MP_DISCARDING) {
+ /* Lie to the thread for now. No sense UNPROTECT()ing the memory
+ when we're just going to PROTECT() it again later. The thread
+ will just fault again once it resumes */
+ } else {
+ /* Shouldn't happen, i don't think */
+ GC_printf0("KERN_PROTECTION_FAILURE while world is stopped\n");
+ return FWD();
+ }
+ return KERN_SUCCESS;
+}
+#undef FWD
+
+/* These should never be called, but just in case... */
+kern_return_t catch_exception_raise_state(mach_port_name_t exception_port,
+ int exception, exception_data_t code, mach_msg_type_number_t codeCnt,
+ int flavor, thread_state_t old_state, int old_stateCnt,
+ thread_state_t new_state, int new_stateCnt)
+{
+ ABORT("catch_exception_raise_state");
+ return(KERN_INVALID_ARGUMENT);
+}
+kern_return_t catch_exception_raise_state_identity(
+ mach_port_name_t exception_port, mach_port_t thread, mach_port_t task,
+ int exception, exception_data_t code, mach_msg_type_number_t codeCnt,
+ int flavor, thread_state_t old_state, int old_stateCnt,
+ thread_state_t new_state, int new_stateCnt)
+{
+ ABORT("catch_exception_raise_state_identity");
+ return(KERN_INVALID_ARGUMENT);
+}
+
+
+#endif /* DARWIN && MPROTECT_VDB */
+
# ifndef HAVE_INCREMENTAL_PROTECTION_NEEDS
int GC_incremental_protection_needs()
{
@@ -3105,19 +3882,20 @@ GC_bool is_ptrfree;
# endif
#endif /* SPARC */
-#ifdef SAVE_CALL_CHAIN
+#ifdef NEED_CALLINFO
/* Fill in the pc and argument information for up to NFRAMES of my */
/* callers. Ignore my frame and my callers frame. */
#ifdef LINUX
-# include <features.h>
-# if __GLIBC__ == 2 && __GLIBC_MINOR__ >= 1 || __GLIBC__ > 2
-# define HAVE_BUILTIN_BACKTRACE
-# endif
+# include <unistd.h>
#endif
+#endif /* NEED_CALLINFO */
+
+#ifdef SAVE_CALL_CHAIN
+
#if NARGS == 0 && NFRAMES % 2 == 0 /* No padding */ \
- && defined(HAVE_BUILTIN_BACKTRACE)
+ && defined(GC_HAVE_BUILTIN_BACKTRACE)
#include <execinfo.h>
@@ -3163,8 +3941,6 @@ struct callinfo info[NFRAMES];
asm("movl %%ebp,%0" : "=r"(frame));
fp = frame;
# else
- word GC_save_regs_in_stack();
-
frame = (struct frame *) GC_save_regs_in_stack ();
fp = (struct frame *)((long) frame -> FR_SAVFP + BIAS);
#endif
@@ -3188,31 +3964,139 @@ struct callinfo info[NFRAMES];
#endif /* SAVE_CALL_CHAIN */
-#if defined(LINUX) && defined(__ELF__) && \
- (!defined(SMALL_CONFIG) || defined(USE_PROC_FOR_LIBRARIES))
-#ifdef GC_USE_LD_WRAP
-# define READ __real_read
-#else
-# define READ read
-#endif
-
+#ifdef NEED_CALLINFO
-/* Repeatedly perform a read call until the buffer is filled or */
-/* we encounter EOF. */
-ssize_t GC_repeat_read(int fd, char *buf, size_t count)
+/* Print info to stderr. We do NOT hold the allocation lock */
+void GC_print_callers (info)
+struct callinfo info[NFRAMES];
{
- ssize_t num_read = 0;
- ssize_t result;
+ register int i;
+ static int reentry_count = 0;
+ GC_bool stop = FALSE;
+
+ LOCK();
+ ++reentry_count;
+ UNLOCK();
- while (num_read < count) {
- result = READ(fd, buf + num_read, count - num_read);
- if (result < 0) return result;
- if (result == 0) break;
- num_read += result;
+# 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 && !stop ; 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 (reentry_count > 1) {
+ /* We were called during an allocation during */
+ /* a previous GC_print_callers call; punt. */
+ GC_err_printf1("\t\t##PC##= 0x%lx\n", info[i].ci_pc);
+ continue;
+ }
+ {
+# ifdef LINUX
+ FILE *pipe;
+# endif
+# if defined(GC_HAVE_BUILTIN_BACKTRACE)
+ char **sym_name =
+ backtrace_symbols((void **)(&(info[i].ci_pc)), 1);
+ char *name = sym_name[0];
+# else
+ char buf[40];
+ char *name = buf;
+ sprintf(buf, "##PC##= 0x%lx", info[i].ci_pc);
+# endif
+# if defined(LINUX) && !defined(SMALL_CONFIG)
+ /* Try for a line number. */
+ {
+# 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;
+ /* 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 -f -e %s 0x%lx", exe_name,
+ (unsigned long)info[i].ci_pc);
+ pipe = popen(cmd_buf, "r");
+ if (pipe == NULL
+ || (result_len = fread(result_buf, 1, RESULT_SZ - 1, pipe))
+ == 0) {
+ if (pipe != NULL) pclose(pipe);
+ will_fail = TRUE;
+ goto out;
+ }
+ if (result_buf[result_len - 1] == '\n') --result_len;
+ result_buf[result_len] = 0;
+ if (result_buf[0] == '?'
+ || result_buf[result_len-2] == ':'
+ && result_buf[result_len-1] == '0') {
+ pclose(pipe);
+ goto out;
+ }
+ /* Get rid of embedded newline, if any. Test for "main" */
+ {
+ char * nl = strchr(result_buf, '\n');
+ if (nl != NULL && nl < result_buf + result_len) {
+ *nl = ':';
+ }
+ if (strncmp(result_buf, "main", nl - result_buf) == 0) {
+ stop = TRUE;
+ }
+ }
+ 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 /* LINUX */
+ GC_err_printf1("\t\t%s\n", name);
+# if defined(GC_HAVE_BUILTIN_BACKTRACE)
+ free(sym_name); /* May call GC_free; that's OK */
+# endif
+ }
}
- return num_read;
+ LOCK();
+ --reentry_count;
+ UNLOCK();
}
-#endif /* LINUX && ... */
+
+#endif /* NEED_CALLINFO */
+
#if defined(LINUX) && defined(__ELF__) && !defined(SMALL_CONFIG)
@@ -3220,20 +4104,16 @@ ssize_t GC_repeat_read(int fd, char *buf, size_t count)
/* Dump /proc/self/maps to GC_stderr, to enable looking up names for
addresses in FIND_LEAK output. */
+static word dump_maps(char *maps)
+{
+ GC_err_write(maps, strlen(maps));
+ return 1;
+}
+
void GC_print_address_map()
{
- int f;
- int result;
- char maps_temp[32768];
GC_err_printf0("---------- Begin address map ----------\n");
- f = open("/proc/self/maps", O_RDONLY);
- if (-1 == f) ABORT("Couldn't open /proc/self/maps");
- do {
- result = GC_repeat_read(f, maps_temp, sizeof(maps_temp));
- if (result <= 0) ABORT("Couldn't read /proc/self/maps");
- GC_err_write(maps_temp, result);
- } while (result == sizeof(maps_temp));
-
+ GC_apply_to_maps(dump_maps);
GC_err_printf0("---------- End address map ----------\n");
}
diff --git a/boehm-gc/powerpc_macosx_mach_dep.s b/boehm-gc/powerpc_macosx_mach_dep.s
deleted file mode 100644
index 92f06286e73..00000000000
--- a/boehm-gc/powerpc_macosx_mach_dep.s
+++ /dev/null
@@ -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
-
-
-
-
diff --git a/boehm-gc/ptr_chck.c b/boehm-gc/ptr_chck.c
index af49d5f5b79..d83d730d343 100644
--- a/boehm-gc/ptr_chck.c
+++ b/boehm-gc/ptr_chck.c
@@ -79,7 +79,7 @@ void (*GC_same_obj_print_proc) GC_PROTO((GC_PTR, GC_PTR))
return(p);
}
sz = WORDS_TO_BYTES(hhdr -> hb_sz);
- if (sz > WORDS_TO_BYTES(MAXOBJSZ)) {
+ if (sz > MAXOBJBYTES) {
base = (ptr_t)HBLKPTR(p);
limit = base + sz;
if ((ptr_t)p >= limit) {
@@ -165,7 +165,7 @@ void (*GC_is_valid_displacement_print_proc) GC_PROTO((GC_PTR)) =
pdispl = HBLKDISPL(p);
map_entry = MAP_ENTRY((hhdr -> hb_map), pdispl);
if (map_entry == OBJ_INVALID
- || sz > MAXOBJSZ && (ptr_t)p >= (ptr_t)h + sz) {
+ || sz > MAXOBJBYTES && (ptr_t)p >= (ptr_t)h + sz) {
goto fail;
}
return(p);
diff --git a/boehm-gc/reclaim.c b/boehm-gc/reclaim.c
index 0418e9dea65..323d420fa40 100644
--- a/boehm-gc/reclaim.c
+++ b/boehm-gc/reclaim.c
@@ -27,23 +27,61 @@ signed_word GC_mem_found = 0;
/* nonzero. */
#endif /* PARALLEL_MARK */
-static void report_leak(p, sz)
-ptr_t p;
-word sz;
+/* We defer printing of leaked objects until we're done with the GC */
+/* cycle, since the routine for printing objects needs to run outside */
+/* the collector, e.g. without the allocation lock. */
+#define MAX_LEAKED 40
+ptr_t GC_leaked[MAX_LEAKED];
+unsigned GC_n_leaked = 0;
+
+GC_bool GC_have_errors = FALSE;
+
+void GC_add_leaked(leaked)
+ptr_t leaked;
{
- if (HDR(p) -> hb_obj_kind == PTRFREE) {
- GC_err_printf0("Leaked atomic object at ");
- } else {
- GC_err_printf0("Leaked composite object at ");
+ if (GC_n_leaked < MAX_LEAKED) {
+ GC_have_errors = TRUE;
+ GC_leaked[GC_n_leaked++] = leaked;
+ /* Make sure it's not reclaimed this cycle */
+ GC_set_mark_bit(leaked);
}
- GC_print_heap_obj(p);
- GC_err_printf0("\n");
}
+static GC_bool printing_errors = FALSE;
+/* Print all objects on the list after printing any smashed objs. */
+/* Clear both lists. */
+void GC_print_all_errors ()
+{
+ unsigned i;
+
+ LOCK();
+ if (printing_errors) {
+ UNLOCK();
+ return;
+ }
+ printing_errors = TRUE;
+ UNLOCK();
+ if (GC_debugging_started) GC_print_all_smashed();
+ for (i = 0; i < GC_n_leaked; ++i) {
+ ptr_t p = GC_leaked[i];
+ if (HDR(p) -> hb_obj_kind == PTRFREE) {
+ GC_err_printf0("Leaked atomic object at ");
+ } else {
+ GC_err_printf0("Leaked composite object at ");
+ }
+ GC_print_heap_obj(p);
+ GC_err_printf0("\n");
+ GC_free(p);
+ GC_leaked[i] = 0;
+ }
+ GC_n_leaked = 0;
+ printing_errors = FALSE;
+}
+
+
# define FOUND_FREE(hblk, word_no) \
{ \
- report_leak((ptr_t)hblk + WORDS_TO_BYTES(word_no), \
- HDR(hblk) -> hb_sz); \
+ GC_add_leaked((ptr_t)hblk + WORDS_TO_BYTES(word_no)); \
}
/*
@@ -866,7 +904,7 @@ void GC_print_block_list()
* Clear *flp.
* This must be done before dropping a list of free gcj-style objects,
* since may otherwise end up with dangling "descriptor" pointers.
- * It may help for other pointer-containg objects.
+ * It may help for other pointer-containing objects.
*/
void GC_clear_fl_links(flp)
ptr_t *flp;
diff --git a/boehm-gc/solaris_pthreads.c b/boehm-gc/solaris_pthreads.c
index bd63e6c612c..bae77193593 100644
--- a/boehm-gc/solaris_pthreads.c
+++ b/boehm-gc/solaris_pthreads.c
@@ -13,9 +13,8 @@
/*
* Support code for Solaris threads. Provides functionality we wish Sun
* had provided. Relies on some information we probably shouldn't rely on.
- * Modified Peter C. for Solaris Posix Threads.
+ * Modified by Peter C. for Solaris Posix Threads.
*/
-/* Boehm, September 14, 1994 4:44 pm PDT */
# if defined(GC_SOLARIS_PTHREADS)
# include "private/gc_priv.h"
diff --git a/boehm-gc/solaris_threads.c b/boehm-gc/solaris_threads.c
index 2b520d3d085..5f05b19e008 100644
--- a/boehm-gc/solaris_threads.c
+++ b/boehm-gc/solaris_threads.c
@@ -37,6 +37,10 @@
# include <unistd.h>
# include <errno.h>
+#ifdef HANDLE_FORK
+ --> Not yet supported. Try porting the code from linux_threads.c.
+#endif
+
/*
* This is the default size of the LWP arrays. If there are more LWPs
* than this when a stop-the-world GC happens, set_max_lwps will be
@@ -361,7 +365,7 @@ static void restart_all_lwps()
sizeof (prgregset_t)) != 0) {
int j;
- for(j = 0; j < NGREG; j++)
+ for(j = 0; j < NPRGREG; j++)
{
GC_printf3("%i: %x -> %x\n", j,
GC_lwp_registers[i][j],
@@ -821,7 +825,7 @@ int GC_thr_suspend(thread_t target_thread)
if (result == 0) {
t = GC_lookup_thread(target_thread);
if (t == 0) ABORT("thread unknown to GC");
- t -> flags |= SUSPENDED;
+ t -> flags |= SUSPNDED;
}
UNLOCK();
return(result);
@@ -837,7 +841,7 @@ int GC_thr_continue(thread_t target_thread)
if (result == 0) {
t = GC_lookup_thread(target_thread);
if (t == 0) ABORT("thread unknown to GC");
- t -> flags &= ~SUSPENDED;
+ t -> flags &= ~SUSPNDED;
}
UNLOCK();
return(result);
@@ -923,7 +927,7 @@ GC_thr_create(void *stack_base, size_t stack_size,
my_flags |= CLIENT_OWNS_STACK;
}
if (flags & THR_DETACHED) my_flags |= DETACHED;
- if (flags & THR_SUSPENDED) my_flags |= SUSPENDED;
+ if (flags & THR_SUSPENDED) my_flags |= SUSPNDED;
result = thr_create(stack, stack_size, start_routine,
arg, flags & ~THR_DETACHED, &my_new_thread);
if (result == 0) {
diff --git a/boehm-gc/sparc_mach_dep.S b/boehm-gc/sparc_mach_dep.S
index 860eeb666f3..06a0f3b4673 100644
--- a/boehm-gc/sparc_mach_dep.S
+++ b/boehm-gc/sparc_mach_dep.S
@@ -37,7 +37,7 @@ loop:
stx %g0,[%o3] ! *(long *)p = 0
cmp %o3,%o1
bgu,pt %xcc, loop ! if (p > limit) goto loop
- add %o3,-8,%o3 ! p -= 8 (delay slot)
+ add %o3,-8,%o3 ! p -= 8 (delay slot)
retl
mov %o2,%sp ! Restore sp., delay slot
#else /* 32 bit SPARC */
diff --git a/boehm-gc/tests/test.c b/boehm-gc/tests/test.c
index 7cb4d0c768f..cfe23c0efde 100644
--- a/boehm-gc/tests/test.c
+++ b/boehm-gc/tests/test.c
@@ -43,7 +43,7 @@
# include "gc_local_alloc.h"
# endif
# include "private/gc_priv.h" /* For output, locking, MIN_WORDS, */
- /* and some statistics. */
+ /* and some statistics. */
# include "private/gcconfig.h"
# if defined(MSWIN32) || defined(MSWINCE)
@@ -68,14 +68,14 @@
# include <pthread.h>
# endif
-# ifdef GC_WIN32_THREADS
-# ifndef MSWINCE
-# include <process.h>
-# define GC_CreateThread(a,b,c,d,e,f) ((HANDLE) _beginthreadex(a,b,c,d,e,f))
-# endif
+# if defined(GC_WIN32_THREADS) && !defined(GC_PTHREADS)
static CRITICAL_SECTION incr_cs;
# endif
+#ifdef __STDC__
+# include <stdarg.h>
+#endif
+
/* Allocation Statistics */
int stubborn_count = 0;
@@ -205,40 +205,6 @@ sexpr y;
}
# endif
-sexpr small_cons (x, y)
-sexpr x;
-sexpr y;
-{
- register sexpr r;
-
- collectable_count++;
- r = (sexpr) GC_MALLOC(sizeof(struct SEXPR));
- if (r == 0) {
- (void)GC_printf0("Out of memory\n");
- exit(1);
- }
- r -> sexpr_car = x;
- r -> sexpr_cdr = y;
- return(r);
-}
-
-sexpr small_cons_uncollectable (x, y)
-sexpr x;
-sexpr y;
-{
- register sexpr r;
-
- uncollectable_count++;
- r = (sexpr) GC_MALLOC_UNCOLLECTABLE(sizeof(struct SEXPR));
- if (r == 0) {
- (void)GC_printf0("Out of memory\n");
- exit(1);
- }
- r -> sexpr_car = x;
- r -> sexpr_cdr = (sexpr)(~(unsigned long)y);
- return(r);
-}
-
#ifdef GC_GCJ_SUPPORT
#include "gc_mark.h"
@@ -279,6 +245,93 @@ struct GC_ms_entry * fake_gcj_mark_proc(word * addr,
return(mark_stack_ptr);
}
+#endif /* GC_GCJ_SUPPORT */
+
+#ifdef THREAD_LOCAL_ALLOC
+
+#undef GC_REDIRECT_TO_LOCAL
+#include "gc_local_alloc.h"
+
+sexpr local_cons (x, y)
+sexpr x;
+sexpr y;
+{
+ register sexpr r;
+ register int *p;
+ register int my_extra = extra_count;
+ static int my_random = 0;
+
+ collectable_count++;
+ r = (sexpr) GC_LOCAL_MALLOC(sizeof(struct SEXPR) + my_extra);
+# ifdef GC_GCJ_SUPPORT
+ if (collectable_count % 2 == 0) {
+ r = (sexpr) GC_LOCAL_GCJ_MALLOC(sizeof(struct SEXPR) + sizeof(GC_word) + my_extra,
+ &gcj_class_struct1);
+ r = (sexpr) ((GC_word *)r + 1);
+ }
+# endif
+ if (r == 0) {
+ (void)GC_printf0("Out of memory\n");
+ exit(1);
+ }
+ for (p = (int *)r;
+ ((char *)p) < ((char *)r) + my_extra + sizeof(struct SEXPR); p++) {
+ if (*p) {
+ (void)GC_printf1("Found nonzero at 0x%lx (local) - allocator is broken\n",
+ (unsigned long)p);
+ FAIL;
+ }
+ *p = 13;
+ }
+ r -> sexpr_car = x;
+ r -> sexpr_cdr = y;
+ my_extra++;
+ if ( my_extra >= 5000 || my_extra == 200 && ++my_random % 37 != 0) {
+ extra_count = 0;
+ } else {
+ extra_count = my_extra;
+ }
+ return(r);
+}
+#endif /* THREAD_LOCAL_ALLOC */
+
+sexpr small_cons (x, y)
+sexpr x;
+sexpr y;
+{
+ register sexpr r;
+
+ collectable_count++;
+ r = (sexpr) GC_MALLOC(sizeof(struct SEXPR));
+ if (r == 0) {
+ (void)GC_printf0("Out of memory\n");
+ exit(1);
+ }
+ r -> sexpr_car = x;
+ r -> sexpr_cdr = y;
+ return(r);
+}
+
+sexpr small_cons_uncollectable (x, y)
+sexpr x;
+sexpr y;
+{
+ register sexpr r;
+
+ uncollectable_count++;
+ r = (sexpr) GC_MALLOC_UNCOLLECTABLE(sizeof(struct SEXPR));
+ if (r == 0) {
+ (void)GC_printf0("Out of memory\n");
+ exit(1);
+ }
+ r -> sexpr_car = x;
+ r -> sexpr_cdr = (sexpr)(~(unsigned long)y);
+ return(r);
+}
+
+#ifdef GC_GCJ_SUPPORT
+
+
sexpr gcj_cons(x, y)
sexpr x;
sexpr y;
@@ -323,6 +376,9 @@ sexpr x, y;
sexpr reverse(x)
sexpr x;
{
+# ifdef TEST_WITH_SYSTEM_MALLOC
+ malloc(100000);
+# endif
return( reverse1(x, nil) );
}
@@ -365,6 +421,35 @@ int low, up;
}
#endif /* GC_GCJ_SUPPORT */
+#ifdef THREAD_LOCAL_ALLOC
+/* Return reverse(x) concatenated with y */
+sexpr local_reverse1(x, y)
+sexpr x, y;
+{
+ if (is_nil(x)) {
+ return(y);
+ } else {
+ return( local_reverse1(cdr(x), local_cons(car(x), y)) );
+ }
+}
+
+sexpr local_reverse(x)
+sexpr x;
+{
+ return( local_reverse1(x, nil) );
+}
+
+sexpr local_ints(low, up)
+int low, up;
+{
+ if (low > up) {
+ return(nil);
+ } else {
+ return(local_cons(local_cons(INT_TO_SEXPR(low), nil), local_ints(low+1, up)));
+ }
+}
+#endif /* THREAD_LOCAL_ALLOC */
+
/* To check uncollectable allocation we build lists with disguised cdr */
/* pointers, and make sure they don't go away. */
sexpr uncollectable_ints(low, up)
@@ -435,25 +520,24 @@ sexpr x;
}
}
-/* Try to force a to be strangely aligned */
-struct {
- char dummy;
- sexpr aa;
-} A;
-#define a A.aa
-
/*
* A tiny list reversal test to check thread creation.
*/
#ifdef THREADS
-# ifdef GC_WIN32_THREADS
- unsigned __stdcall tiny_reverse_test(void * arg)
+# if defined(GC_WIN32_THREADS) && !defined(CYGWIN32)
+ DWORD __stdcall tiny_reverse_test(void * arg)
# else
void * tiny_reverse_test(void * arg)
# endif
{
- check_ints(reverse(reverse(ints(1,10))), 1, 10);
+ int i;
+ for (i = 0; i < 5; ++i) {
+ check_ints(reverse(reverse(ints(1,10))), 1, 10);
+# ifdef THREAD_LOCAL_ALLOC
+ check_ints(local_reverse(local_reverse(local_ints(1,10))), 1, 10);
+# endif
+ }
return 0;
}
@@ -477,7 +561,7 @@ struct {
# elif defined(GC_WIN32_THREADS)
void fork_a_thread()
{
- unsigned thread_id;
+ DWORD thread_id;
HANDLE h;
h = GC_CreateThread(NULL, 0, tiny_reverse_test, 0, 0, &thread_id);
if (h == (HANDLE)NULL) {
@@ -506,6 +590,13 @@ struct {
#endif
+/* Try to force a to be strangely aligned */
+struct {
+ char dummy;
+ sexpr aa;
+} A;
+#define a A.aa
+
/*
* Repeatedly reverse lists built out of very different sized cons cells.
* Check that we didn't lose anything.
@@ -563,7 +654,9 @@ void reverse_test()
h = (sexpr *)GC_REALLOC((GC_PTR)h, 2000 * sizeof(sexpr));
# ifdef GC_GCJ_SUPPORT
h[1999] = gcj_ints(1,200);
- h[1999] = gcj_reverse(h[1999]);
+ for (i = 0; i < 51; ++i)
+ h[1999] = gcj_reverse(h[1999]);
+ /* Leave it as the reveresed list for now. */
# else
h[1999] = ints(1,200);
# endif
@@ -594,6 +687,9 @@ void reverse_test()
/* 49 integers. Thus this is thread safe without locks, */
/* assuming atomic pointer assignments. */
a = reverse(reverse(a));
+# ifdef THREAD_LOCAL_ALLOC
+ a = local_reverse(local_reverse(a));
+# endif
# if !defined(AT_END) && !defined(THREADS)
/* This is not thread safe, since realloc explicitly deallocates */
if (i & 1) {
@@ -621,6 +717,8 @@ void reverse_test()
b = c = 0;
}
+#undef a
+
/*
* The rest of this builds balanced binary trees, checks that they don't
* disappear, and tests finalization.
@@ -655,15 +753,17 @@ VOLATILE int dropped_something = 0;
# if defined(GC_PTHREADS)
static pthread_mutex_t incr_lock = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_lock(&incr_lock);
-# endif
-# ifdef GC_WIN32_THREADS
- EnterCriticalSection(&incr_cs);
+# else
+# ifdef GC_WIN32_THREADS
+ EnterCriticalSection(&incr_cs);
+# endif
# endif
if ((int)(GC_word)client_data != t -> level) {
(void)GC_printf0("Wrong finalization data - collector is broken\n");
FAIL;
}
finalized_count++;
+ t -> level = -1; /* detect duplicate finalization immediately */
# ifdef PCR
PCR_ThCrSec_ExitSys();
# endif
@@ -672,9 +772,10 @@ VOLATILE int dropped_something = 0;
# endif
# if defined(GC_PTHREADS)
pthread_mutex_unlock(&incr_lock);
-# endif
-# ifdef GC_WIN32_THREADS
- LeaveCriticalSection(&incr_cs);
+# else
+# ifdef GC_WIN32_THREADS
+ LeaveCriticalSection(&incr_cs);
+# endif
# endif
}
@@ -746,9 +847,10 @@ int n;
# if defined(GC_PTHREADS)
static pthread_mutex_t incr_lock = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_lock(&incr_lock);
-# endif
-# ifdef GC_WIN32_THREADS
- EnterCriticalSection(&incr_cs);
+# else
+# ifdef GC_WIN32_THREADS
+ EnterCriticalSection(&incr_cs);
+# endif
# endif
/* Losing a count here causes erroneous report of failure. */
finalizable_count++;
@@ -761,9 +863,10 @@ int n;
# endif
# if defined(GC_PTHREADS)
pthread_mutex_unlock(&incr_lock);
-# endif
-# ifdef GC_WIN32_THREADS
- LeaveCriticalSection(&incr_cs);
+# else
+# ifdef GC_WIN32_THREADS
+ LeaveCriticalSection(&incr_cs);
+# endif
# endif
}
@@ -1068,6 +1171,25 @@ void fail_proc1(GC_PTR x)
fail_count++;
}
+static void uniq(void *p, ...) {
+ va_list a;
+ void *q[100];
+ int n = 0, i, j;
+ q[n++] = p;
+ va_start(a,p);
+ for (;(q[n] = va_arg(a,void *));n++) ;
+ va_end(a);
+ for (i=0; i<n; i++)
+ for (j=0; j<i; j++)
+ if (q[i] == q[j]) {
+ GC_printf0(
+ "Apparently failed to mark form some function arguments.\n"
+ "Perhaps GC_push_regs was configured incorrectly?\n"
+ );
+ FAIL;
+ }
+}
+
#endif /* __STDC__ */
#ifdef THREADS
@@ -1148,6 +1270,19 @@ void run_one_test()
"GC_is_valid_displacement produced incorrect result\n");
FAIL;
}
+# if defined(__STDC__) && !defined(MSWIN32) && !defined(MSWINCE)
+ /* Harder to test under Windows without a gc.h declaration. */
+ {
+ size_t i;
+ extern void *GC_memalign();
+
+ GC_malloc(17);
+ for (i = sizeof(GC_word); i < 512; i *= 2) {
+ GC_word result = (GC_word) GC_memalign(i, 17);
+ if (result % i != 0 || result == 0 || *(int *)result != 0) FAIL;
+ }
+ }
+# endif
# ifndef ALL_INTERIOR_POINTERS
# if defined(RS6000) || defined(POWERPC)
if (!TEST_FAIL_COUNT(1)) {
@@ -1168,6 +1303,21 @@ void run_one_test()
GC_REGISTER_DISPLACEMENT(sizeof(struct fake_vtable *));
GC_init_gcj_malloc(0, (void *)fake_gcj_mark_proc);
# endif
+ /* Make sure that fn arguments are visible to the collector. */
+# ifdef __STDC__
+ uniq(
+ GC_malloc(12), GC_malloc(12), GC_malloc(12),
+ (GC_gcollect(),GC_malloc(12)),
+ GC_malloc(12), GC_malloc(12), GC_malloc(12),
+ (GC_gcollect(),GC_malloc(12)),
+ GC_malloc(12), GC_malloc(12), GC_malloc(12),
+ (GC_gcollect(),GC_malloc(12)),
+ GC_malloc(12), GC_malloc(12), GC_malloc(12),
+ (GC_gcollect(),GC_malloc(12)),
+ GC_malloc(12), GC_malloc(12), GC_malloc(12),
+ (GC_gcollect(),GC_malloc(12)),
+ (void *)0);
+# endif
/* Repeated list reversal test. */
reverse_test();
# ifdef PRINTSTATS
@@ -1183,6 +1333,15 @@ void run_one_test()
LOCK();
n_tests++;
UNLOCK();
+# if defined(THREADS) && defined(HANDLE_FORK)
+ if (fork() == 0) {
+ GC_gcollect();
+ tiny_reverse_test(0);
+ GC_gcollect();
+ GC_printf0("Finished a child process\n");
+ exit(0);
+ }
+# endif
/* GC_printf1("Finished %x\n", pthread_self()); */
}
@@ -1202,7 +1361,7 @@ void check_heap_stats()
}
# else
if (sizeof(char *) > 4) {
- max_heap_sz = 15000000;
+ max_heap_sz = 19000000;
} else {
max_heap_sz = 11000000;
}
@@ -1212,7 +1371,7 @@ void check_heap_stats()
# ifdef SAVE_CALL_CHAIN
max_heap_sz *= 3;
# ifdef SAVE_CALL_COUNT
- max_heap_sz *= SAVE_CALL_COUNT/4;
+ max_heap_sz += max_heap_sz * SAVE_CALL_COUNT/4;
# endif
# endif
# endif
@@ -1327,6 +1486,10 @@ void SetMinimumStack(long minSize)
# endif
n_tests = 0;
+#if defined(__APPLE__) && defined(__MACH__)
+ GC_INIT();
+#endif
+
# if defined(DJGPP)
/* No good way to determine stack base from library; do it */
/* manually on this platform. */
@@ -1340,13 +1503,18 @@ void SetMinimumStack(long minSize)
# endif
GC_INIT(); /* Only needed if gc is dynamic library. */
(void) GC_set_warn_proc(warn_proc);
-# if (defined(MPROTECT_VDB) || defined(PROC_VDB)) && !defined(MAKE_BACK_GRAPH)
+# if (defined(MPROTECT_VDB) || defined(PROC_VDB)) \
+ && !defined(MAKE_BACK_GRAPH)
GC_enable_incremental();
(void) GC_printf0("Switched to incremental mode\n");
# if defined(MPROTECT_VDB)
(void)GC_printf0("Emulating dirty bits with mprotect/signals\n");
# else
+# ifdef PROC_VDB
(void)GC_printf0("Reading dirty bits from /proc\n");
+# else
+ (void)GC_printf0("Using DEFAULT_VDB dirty bit implementation\n");
+# endif
# endif
# endif
run_one_test();
@@ -1378,9 +1546,9 @@ void SetMinimumStack(long minSize)
}
# endif
-#ifdef GC_WIN32_THREADS
+#if defined(GC_WIN32_THREADS) && !defined(CYGWIN32)
-unsigned __stdcall thr_run_one_test(void *arg)
+DWORD __stdcall thr_run_one_test(void *arg)
{
run_one_test();
return 0;
@@ -1412,7 +1580,7 @@ LRESULT CALLBACK window_proc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
return ret;
}
-unsigned __stdcall thr_window(void *arg)
+DWORD __stdcall thr_window(void *arg)
{
WNDCLASS win_class = {
CS_NOCLOSE,
@@ -1474,10 +1642,11 @@ int APIENTRY WinMain(HINSTANCE instance, HINSTANCE prev, LPSTR cmd, int n)
# ifdef MSWINCE
HANDLE win_thr_h;
# endif
- unsigned thread_id;
+ DWORD thread_id;
# if 0
GC_enable_incremental();
# endif
+ GC_init();
InitializeCriticalSection(&incr_cs);
(void) GC_set_warn_proc(warn_proc);
# ifdef MSWINCE
@@ -1625,15 +1794,30 @@ main()
(void)GC_printf0("pthread_default_stacksize_np failed.\n");
}
# endif /* GC_HPUX_THREADS */
+# if defined(__APPLE__) && defined(__MACH__)
+ GC_INIT();
+# endif
+
pthread_attr_init(&attr);
-# if defined(GC_IRIX_THREADS) || defined(GC_FREEBSD_THREADS)
+# if defined(GC_IRIX_THREADS) || defined(GC_FREEBSD_THREADS) \
+ || defined(GC_DARWIN_THREADS) || defined(GC_AIX_THREADS)
pthread_attr_setstacksize(&attr, 1000000);
# endif
n_tests = 0;
-# if defined(MPROTECT_VDB) && !defined(PARALLEL_MARK) &&!defined(REDIRECT_MALLOC) && !defined(MAKE_BACK_GRAPH)
+# if (defined(MPROTECT_VDB)) \
+ && !defined(PARALLEL_MARK) &&!defined(REDIRECT_MALLOC) \
+ && !defined(MAKE_BACK_GRAPH)
GC_enable_incremental();
(void) GC_printf0("Switched to incremental mode\n");
- (void) GC_printf0("Emulating dirty bits with mprotect/signals\n");
+# if defined(MPROTECT_VDB)
+ (void)GC_printf0("Emulating dirty bits with mprotect/signals\n");
+# else
+# ifdef PROC_VDB
+ (void)GC_printf0("Reading dirty bits from /proc\n");
+# else
+ (void)GC_printf0("Using DEFAULT_VDB dirty bit implementation\n");
+# endif
+# endif
# endif
(void) GC_set_warn_proc(warn_proc);
if ((code = pthread_key_create(&fl_key, 0)) != 0) {
diff --git a/boehm-gc/tests/test_cpp.cc b/boehm-gc/tests/test_cpp.cc
index 75fd3668605..7e50e8aa0fd 100644
--- a/boehm-gc/tests/test_cpp.cc
+++ b/boehm-gc/tests/test_cpp.cc
@@ -28,7 +28,10 @@ few minutes to complete.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
-#ifdef __GNUC__
+#define USE_STD_ALLOCATOR
+#ifdef USE_STD_ALLOCATOR
+# include "gc_allocator.h"
+#elif __GNUC__
# include "new_gc_alloc.h"
#else
# include "gc_alloc.h"
@@ -189,25 +192,32 @@ int APIENTRY WinMain(
# endif
#endif
+ GC_init();
+
# if defined(MACOS) // MacOS
char* argv_[] = {"test_cpp", "10"}; // doesn't
argv = argv_; // have a
argc = sizeof(argv_)/sizeof(argv_[0]); // commandline
# endif
int i, iters, n;
-# if !defined(MACOS)
+# ifdef USE_STD_ALLOCATOR
+ int *x = gc_allocator<int>().allocate(1);
+ int **xptr = traceable_allocator<int *>().allocate(1);
+# else
# ifdef __GNUC__
- int *x = (int *)gc_alloc::allocate(sizeof(int));
+ int *x = (int *)gc_alloc::allocate(sizeof(int));
# else
- int *x = (int *)alloc::allocate(sizeof(int));
+ int *x = (int *)alloc::allocate(sizeof(int));
# endif
-
- *x = 29;
- x -= 3;
+# endif
+ *x = 29;
+# ifdef USE_STD_ALLOCATOR
+ *xptr = x;
+ x = 0;
# endif
if (argc != 2 || (0 >= (n = atoi( argv[ 1 ] )))) {
- GC_printf0( "usage: test_cpp number-of-iterations\n" );
- exit( 1 );}
+ GC_printf0( "usage: test_cpp number-of-iterations\nAssuming 10 iters\n" );
+ n = 10;}
for (iters = 1; iters <= n; iters++) {
GC_printf1( "Starting iteration %d\n", iters );
@@ -268,9 +278,10 @@ int APIENTRY WinMain(
D::Test();
F::Test();}
-# if !defined(__GNUC__) && !defined(MACOS)
- my_assert (29 == x[3]);
+# ifdef USE_STD_ALLOCATOR
+ x = *xptr;
# endif
+ my_assert (29 == x[0]);
GC_printf0( "The test appears to have succeeded.\n" );
return( 0 );}
diff --git a/boehm-gc/threadlibs.c b/boehm-gc/threadlibs.c
index 99968a94a6c..247d3c652ec 100644
--- a/boehm-gc/threadlibs.c
+++ b/boehm-gc/threadlibs.c
@@ -4,13 +4,14 @@
int main()
{
# if defined(GC_USE_LD_WRAP)
- printf("-Wl,--wrap -Wl,read -Wl,--wrap -Wl,dlopen "
+ printf("-Wl,--wrap -Wl,dlopen "
"-Wl,--wrap -Wl,pthread_create -Wl,--wrap -Wl,pthread_join "
"-Wl,--wrap -Wl,pthread_detach "
"-Wl,--wrap -Wl,pthread_sigmask -Wl,--wrap -Wl,sleep\n");
# endif
# if defined(GC_LINUX_THREADS) || defined(GC_IRIX_THREADS) \
- || defined(GC_FREEBSD_THREADS) || defined(GC_SOLARIS_PTHREADS)
+ || defined(GC_FREEBSD_THREADS) || defined(GC_SOLARIS_PTHREADS) \
+ || defined(GC_DARWIN_THREADS) || defined(GC_AIX_THREADS)
printf("-lpthread\n");
# endif
# if defined(GC_HPUX_THREADS) || defined(GC_OSF1_THREADS)
@@ -19,6 +20,17 @@ int main()
# if defined(GC_SOLARIS_THREADS) && !defined(GC_SOLARIS_PTHREADS)
printf("-lthread -ldl\n");
# endif
+# if defined(GC_WIN32_THREADS) && defined(CYGWIN32)
+ printf("-lpthread\n");
+# endif
+# if defined(GC_OSF1_THREADS)
+ printf("-pthread -lrt"); /* DOB: must be -pthread, not -lpthread */
+# endif
+ /* You need GCC 3.0.3 to build this one! */
+ /* DG/UX native gcc doesnt know what "-pthread" is */
+# if defined(GC_DGUX386_THREADS)
+ printf("-ldl -pthread\n");
+# endif
return 0;
}
diff --git a/boehm-gc/typd_mlc.c b/boehm-gc/typd_mlc.c
index 07717001e9d..a081c9797c3 100644
--- a/boehm-gc/typd_mlc.c
+++ b/boehm-gc/typd_mlc.c
@@ -437,6 +437,7 @@ void GC_init_explicit_typing()
for (; bm != 0; bm >>= 1, current_p++) {
if (bm & 1) {
current = *current_p;
+ FIXUP_POINTER(current);
if ((ptr_t)current >= least_ha && (ptr_t)current <= greatest_ha) {
PUSH_CONTENTS((ptr_t)current, mark_stack_ptr,
mark_stack_limit, current_p, exit1);
@@ -674,9 +675,9 @@ DCL_LOCK_STATE;
if( !FASTLOCK_SUCCEEDED() || (op = *opp) == 0 ) {
FASTUNLOCK();
op = (ptr_t)GENERAL_MALLOC((word)lb, GC_explicit_kind);
- if (0 == op) return(0);
+ if (0 == op) return 0;
# ifdef MERGE_SIZES
- lw = GC_size_map[lb]; /* May have been uninitialized. */
+ lw = GC_size_map[lb]; /* May have been uninitialized. */
# endif
} else {
*opp = obj_link(op);
@@ -720,7 +721,7 @@ DCL_LOCK_STATE;
FASTUNLOCK();
op = (ptr_t)GENERAL_MALLOC_IOP(lb, GC_explicit_kind);
# ifdef MERGE_SIZES
- lw = GC_size_map[lb]; /* May have been uninitialized. */
+ lw = GC_size_map[lb]; /* May have been uninitialized. */
# endif
} else {
*opp = obj_link(op);
diff --git a/boehm-gc/version.h b/boehm-gc/version.h
index 96b7e64cbbe..9d858b2aaa6 100644
--- a/boehm-gc/version.h
+++ b/boehm-gc/version.h
@@ -1,11 +1,30 @@
-#define GC_VERSION_MAJOR 6
-#define GC_VERSION_MINOR 1
-#define GC_ALPHA_VERSION 3
+/* The version here should match that in configure/configure.in */
+/* Eventually this one may become unnecessary. For now we need */
+/* it to keep the old-style build process working. */
+#define GC_TMP_VERSION_MAJOR 6
+#define GC_TMP_VERSION_MINOR 3
+#define GC_TMP_ALPHA_VERSION 1
+#ifndef GC_NOT_ALPHA
# define GC_NOT_ALPHA 0xff
+#endif
+
+#if defined(GC_VERSION_MAJOR)
+# if GC_TMP_VERSION_MAJOR != GC_VERSION_MAJOR || \
+ GC_TMP_VERSION_MINOR != GC_VERSION_MINOR || \
+ defined(GC_ALPHA_VERSION) != (GC_TMP_ALPHA_VERSION != GC_NOT_ALPHA) || \
+ defined(GC_ALPHA_VERSION) && GC_TMP_ALPHA_VERSION != GC_ALPHA_VERSION
+# error Inconsistent version info. Check version.h and configure.in.
+# endif
+#else
+# define GC_VERSION_MAJOR GC_TMP_VERSION_MAJOR
+# define GC_VERSION_MINOR GC_TMP_VERSION_MINOR
+# define GC_ALPHA_VERSION GC_TMP_ALPHA_VERSION
+#endif
+
#ifndef GC_NO_VERSION_VAR
-unsigned GC_version = ((GC_VERSION_MAJOR << 16) | (GC_VERSION_MINOR << 8) | GC_ALPHA_VERSION);
+unsigned GC_version = ((GC_VERSION_MAJOR << 16) | (GC_VERSION_MINOR << 8) | GC_TMP_ALPHA_VERSION);
#endif /* GC_NO_VERSION_VAR */
diff --git a/boehm-gc/win32_threads.c b/boehm-gc/win32_threads.c
index 954b18d7018..ff1d06625f8 100644
--- a/boehm-gc/win32_threads.c
+++ b/boehm-gc/win32_threads.c
@@ -1,13 +1,28 @@
-#if defined(GC_WIN32_THREADS)
+#if defined(GC_WIN32_THREADS)
#include "private/gc_priv.h"
-
-#if 0
-#define STRICT
#include <windows.h>
+
+#ifdef CYGWIN32
+# include <errno.h>
+
+ /* Cygwin-specific forward decls */
+# undef pthread_create
+# undef pthread_sigmask
+# undef pthread_join
+# undef dlopen
+
+# define DEBUG_CYGWIN_THREADS 0
+
+ GC_bool GC_thr_initialized = FALSE;
+ void * GC_start_routine(void * arg);
+ void GC_thread_exit_proc(void *arg);
+
#endif
-#define MAX_THREADS 64
+#ifndef MAX_THREADS
+# define MAX_THREADS 64
+#endif
struct thread_entry {
LONG in_use;
@@ -18,6 +33,12 @@ struct thread_entry {
/* !in_use ==> stack == 0 */
CONTEXT context;
GC_bool suspended;
+
+# ifdef CYGWIN32
+ void *status; /* hold exit value until join in case it's a pointer */
+ pthread_t pthread_id;
+# endif
+
};
volatile GC_bool GC_please_stop = FALSE;
@@ -29,6 +50,12 @@ void GC_push_thread_structures GC_PROTO((void))
/* Unlike the other threads implementations, the thread table here */
/* contains no pointers to the collectable heap. Thus we have */
/* no private structures we need to preserve. */
+# ifdef CYGWIN32
+ { int i; /* pthreads may keep a pointer in the thread exit value */
+ for (i = 0; i < MAX_THREADS; i++)
+ if (thread_table[i].in_use) GC_push_all((ptr_t)&(thread_table[i].status),(ptr_t)(&(thread_table[i].status)+1));
+ }
+# endif
}
void GC_stop_world()
@@ -36,6 +63,10 @@ void GC_stop_world()
DWORD thread_id = GetCurrentThreadId();
int i;
+#ifdef CYGWIN32
+ if (!GC_thr_initialized) ABORT("GC_stop_world() called before GC_thr_init()");
+#endif
+
GC_please_stop = TRUE;
for (i = 0; i < MAX_THREADS; i++)
if (thread_table[i].stack != 0
@@ -53,11 +84,15 @@ void GC_stop_world()
DWORD exitCode;
if (GetExitCodeThread(thread_table[i].handle,&exitCode) &&
exitCode != STILL_ACTIVE) {
- thread_table[i].stack = 0;
+ thread_table[i].stack = 0; /* prevent stack from being pushed */
+# ifndef CYGWIN32
+ /* this breaks pthread_join on Cygwin, which is guaranteed to */
+ /* only see user pthreads */
thread_table[i].in_use = FALSE;
CloseHandle(thread_table[i].handle);
BZERO((void *)(&thread_table[i].context), sizeof(CONTEXT));
- continue;
+# endif
+ continue;
}
if (SuspendThread(thread_table[i].handle) == (DWORD)-1)
ABORT("SuspendThread failed");
@@ -335,9 +370,13 @@ void GC_get_next_stack(char *start, char **lo, char **hi)
if (*lo < start) *lo = start;
}
-#if !defined(MSWINCE) && !(defined(__MINGW32__) && !defined(_DLL))
+#if !defined(CYGWIN32)
-HANDLE WINAPI GC_CreateThread(
+#if !defined(MSWINCE) && defined(GC_DLL)
+
+/* We register threads from DllMain */
+
+GC_API HANDLE GC_CreateThread(
LPSECURITY_ATTRIBUTES lpThreadAttributes,
DWORD dwStackSize, LPTHREAD_START_ROUTINE lpStartAddress,
LPVOID lpParameter, DWORD dwCreationFlags, LPDWORD lpThreadId )
@@ -346,7 +385,10 @@ HANDLE WINAPI GC_CreateThread(
lpParameter, dwCreationFlags, lpThreadId);
}
-#else /* !defined(MSWINCE) && !(defined(__MINGW32__) && !defined(_DLL)) */
+#else /* defined(MSWINCE) || !defined(GC_DLL)) */
+
+/* We have no DllMain to take care of new threads. Thus we */
+/* must properly intercept thread creation. */
typedef struct {
HANDLE child_ready_h, parent_ready_h;
@@ -400,7 +442,17 @@ HANDLE WINAPI GC_CreateThread(
/* fill in ID and handle; tell child this is done */
thread_table[i].id = *lpThreadId;
- thread_table[i].handle = thread_h;
+ if (!DuplicateHandle(GetCurrentProcess(),
+ thread_h,
+ GetCurrentProcess(),
+ &thread_table[i].handle,
+ 0,
+ 0,
+ DUPLICATE_SAME_ACCESS)) {
+ DWORD last_error = GetLastError();
+ GC_printf1("Last error code: %lx\n", last_error);
+ ABORT("DuplicateHandle failed");
+ }
SetEvent (parent_ready_h);
/* wait for child to fill in stack and copy args */
@@ -470,7 +522,9 @@ static DWORD WINAPI thread_start(LPVOID arg)
return ret;
}
-#endif /* !defined(MSWINCE) && !(defined(__MINGW32__) && !defined(_DLL)) */
+#endif /* !defined(MSWINCE) && !(defined(__MINGW32__) && !defined(_DLL)) */
+
+#endif /* !CYGWIN32 */
#ifdef MSWINCE
@@ -527,13 +581,255 @@ DWORD WINAPI main_thread_start(LPVOID arg)
LONG WINAPI GC_write_fault_handler(struct _EXCEPTION_POINTERS *exc_info);
-#ifdef GC_DLL
+/* threadAttach/threadDetach routines used by both CYGWIN and DLL
+ * implementation, since both recieve explicit notification on thread
+ * creation/destruction.
+ */
+static void threadAttach() {
+ int i;
+ /* It appears to be unsafe to acquire a lock here, since this */
+ /* code is apparently not preeemptible on some systems. */
+ /* (This is based on complaints, not on Microsoft's official */
+ /* documentation, which says this should perform "only simple */
+ /* inititalization tasks".) */
+ /* Hence we make do with nonblocking synchronization. */
+
+ /* The following should be a noop according to the win32 */
+ /* documentation. There is empirical evidence that it */
+ /* isn't. - HB */
+# if defined(MPROTECT_VDB)
+ if (GC_incremental) SetUnhandledExceptionFilter(GC_write_fault_handler);
+# endif
+ /* cast away volatile qualifier */
+ for (i = 0; InterlockedExchange((LONG*)&thread_table[i].in_use,1) != 0; i++) {
+ /* Compare-and-swap would make this cleaner, but that's not */
+ /* supported before Windows 98 and NT 4.0. In Windows 2000, */
+ /* InterlockedExchange is supposed to be replaced by */
+ /* InterlockedExchangePointer, but that's not really what I */
+ /* want here. */
+ if (i == MAX_THREADS - 1)
+ ABORT("too many threads");
+ }
+ thread_table[i].id = GetCurrentThreadId();
+# ifdef CYGWIN32
+ thread_table[i].pthread_id = pthread_self();
+# endif
+ if (!DuplicateHandle(GetCurrentProcess(),
+ GetCurrentThread(),
+ GetCurrentProcess(),
+ (HANDLE*)&thread_table[i].handle,
+ 0,
+ 0,
+ DUPLICATE_SAME_ACCESS)) {
+ DWORD last_error = GetLastError();
+ GC_printf1("Last error code: %lx\n", last_error);
+ ABORT("DuplicateHandle failed");
+ }
+ thread_table[i].stack = GC_get_stack_base();
+ if (thread_table[i].stack == NULL)
+ ABORT("Failed to find stack base in threadAttach");
+ /* If this thread is being created while we are trying to stop */
+ /* the world, wait here. Hopefully this can't happen on any */
+ /* systems that don't allow us to block here. */
+ while (GC_please_stop) Sleep(20);
+}
+
+static void threadDetach(DWORD thread_id) {
+ int i;
+
+ LOCK();
+ for (i = 0;
+ i < MAX_THREADS &&
+ (!thread_table[i].in_use || thread_table[i].id != thread_id);
+ i++) {}
+ if (i >= MAX_THREADS ) {
+ WARN("thread %ld not found on detach", (GC_word)thread_id);
+ } else {
+ thread_table[i].stack = 0;
+ thread_table[i].in_use = FALSE;
+ CloseHandle(thread_table[i].handle);
+ /* cast away volatile qualifier */
+ BZERO((void *)&thread_table[i].context, sizeof(CONTEXT));
+ }
+ UNLOCK();
+}
+
+#ifdef CYGWIN32
+
+/* Called by GC_init() - we hold the allocation lock. */
+void GC_thr_init() {
+ if (GC_thr_initialized) return;
+ GC_thr_initialized = TRUE;
+
+#if 0
+ /* this might already be handled in GC_init... */
+ InitializeCriticalSection(&GC_allocate_ml);
+#endif
+
+ /* Add the initial thread, so we can stop it. */
+ threadAttach();
+}
+
+struct start_info {
+ void *(*start_routine)(void *);
+ void *arg;
+};
+
+int GC_pthread_join(pthread_t pthread_id, void **retval) {
+ int result;
+ int i;
+
+# if DEBUG_CYGWIN_THREADS
+ GC_printf3("thread 0x%x(0x%x) is joining thread 0x%x.\n",(int)pthread_self(),
+ GetCurrentThreadId(), (int)pthread_id);
+# endif
+
+ /* Can't do any table lookups here, because thread being joined
+ might not have registered itself yet */
+
+ result = pthread_join(pthread_id, retval);
+
+ LOCK();
+ for (i = 0; !thread_table[i].in_use || thread_table[i].pthread_id != pthread_id;
+ i++) {
+ if (i == MAX_THREADS - 1) {
+ GC_printf1("Failed to find thread 0x%x in pthread_join()\n", pthread_id);
+ ABORT("thread not found on detach");
+ }
+ }
+ UNLOCK();
+ threadDetach(thread_table[i].id);
+
+# if DEBUG_CYGWIN_THREADS
+ GC_printf3("thread 0x%x(0x%x) completed join with thread 0x%x.\n",
+ (int)pthread_self(), GetCurrentThreadId(), (int)pthread_id);
+# endif
+
+ return result;
+}
+
+/* Cygwin-pthreads calls CreateThread internally, but it's not
+ * easily interceptible by us..
+ * so intercept pthread_create instead
+ */
+int
+GC_pthread_create(pthread_t *new_thread,
+ const pthread_attr_t *attr,
+ void *(*start_routine)(void *), void *arg) {
+ int result;
+ struct start_info * si;
+
+ if (!GC_is_initialized) GC_init();
+ /* make sure GC is initialized (i.e. main thread is attached) */
+
+ /* This is otherwise saved only in an area mmapped by the thread */
+ /* library, which isn't visible to the collector. */
+ si = GC_malloc_uncollectable(sizeof(struct start_info));
+ if (0 == si) return(EAGAIN);
+
+ si -> start_routine = start_routine;
+ si -> arg = arg;
+
+# if DEBUG_CYGWIN_THREADS
+ GC_printf2("About to create a thread from 0x%x(0x%x)\n",(int)pthread_self(),
+ GetCurrentThreadId);
+# endif
+ result = pthread_create(new_thread, attr, GC_start_routine, si);
+
+ if (result) { /* failure */
+ GC_free(si);
+ }
+
+ return(result);
+}
+
+void * GC_start_routine(void * arg)
+{
+ struct start_info * si = arg;
+ void * result;
+ void *(*start)(void *);
+ void *start_arg;
+ pthread_t pthread_id;
+ int i;
+
+# if DEBUG_CYGWIN_THREADS
+ GC_printf2("thread 0x%x(0x%x) starting...\n",(int)pthread_self(),
+ GetCurrentThreadId());
+# endif
+
+ /* If a GC occurs before the thread is registered, that GC will */
+ /* ignore this thread. That's fine, since it will block trying to */
+ /* acquire the allocation lock, and won't yet hold interesting */
+ /* pointers. */
+ LOCK();
+ /* We register the thread here instead of in the parent, so that */
+ /* we don't need to hold the allocation lock during pthread_create. */
+ threadAttach();
+ UNLOCK();
+
+ start = si -> start_routine;
+ start_arg = si -> arg;
+ pthread_id = pthread_self();
+
+ GC_free(si); /* was allocated uncollectable */
+
+ pthread_cleanup_push(GC_thread_exit_proc, pthread_id);
+ result = (*start)(start_arg);
+ pthread_cleanup_pop(0);
+
+# if DEBUG_CYGWIN_THREADS
+ GC_printf2("thread 0x%x(0x%x) returned from start routine.\n",
+ (int)pthread_self(),GetCurrentThreadId());
+# endif
+
+ LOCK();
+ for (i = 0; thread_table[i].pthread_id != pthread_id; i++) {
+ if (i == MAX_THREADS - 1)
+ ABORT("thread not found on exit");
+ }
+ thread_table[i].status = result;
+ UNLOCK();
+
+ return(result);
+}
+
+void GC_thread_exit_proc(void *arg)
+{
+ pthread_t pthread_id = (pthread_t)arg;
+ int i;
+
+# if DEBUG_CYGWIN_THREADS
+ GC_printf2("thread 0x%x(0x%x) called pthread_exit().\n",
+ (int)pthread_self(),GetCurrentThreadId());
+# endif
+
+ LOCK();
+ for (i = 0; thread_table[i].pthread_id != pthread_id; i++) {
+ if (i == MAX_THREADS - 1)
+ ABORT("thread not found on exit");
+ }
+ UNLOCK();
+
+#if 0
+ /* TODO: we need a way to get the exit value after a pthread_exit so we can stash it safely away */
+ thread_table[i].status = ???
+#endif
+}
+
+/* nothing required here... */
+int GC_pthread_sigmask(int how, const sigset_t *set, sigset_t *oset) {
+ return pthread_sigmask(how, set, oset);
+}
+int GC_pthread_detach(pthread_t thread) {
+ return pthread_detach(thread);
+}
+#else /* !CYGWIN32 */
/*
- * This isn't generally safe, since DllMain is not premptible.
- * If another thread holds the lock while this runs we're in trouble.
+ * We avoid acquiring locks here, since this doesn't seem to be preemptable.
* Pontus Rydin suggests wrapping the thread start routine instead.
*/
+#ifdef GC_DLL
BOOL WINAPI DllMain(HINSTANCE inst, ULONG reason, LPVOID reserved)
{
switch (reason) {
@@ -542,75 +838,13 @@ BOOL WINAPI DllMain(HINSTANCE inst, ULONG reason, LPVOID reserved)
GC_init(); /* Force initialization before thread attach. */
/* fall through */
case DLL_THREAD_ATTACH:
- {
- int i;
- /* It appears to be unsafe to acquire a lock here, since this */
- /* code is apparently not preeemptible on some systems. */
- /* (This is based on complaints, not on Microsoft's official */
- /* documentation, which says this should perform "only simple */
- /* inititalization tasks".) */
- /* Hence we make do with nonblocking synchronization. */
-
- /* The following should be a noop according to the win32 */
- /* documentation. There is empirical evidence that it */
- /* isn't. - HB */
-# ifdef MPROTECT_VDB
- if (GC_incremental) SetUnhandledExceptionFilter(GC_write_fault_handler);
-# endif
-
- for (i = 0;
- /* cast away volatile qualifier */
- InterlockedExchange((LPLONG) &thread_table[i].in_use, 1) != 0;
- i++) {
- /* Compare-and-swap would make this cleaner, but that's not */
- /* supported before Windows 98 and NT 4.0. In Windows 2000, */
- /* InterlockedExchange is supposed to be replaced by */
- /* InterlockedExchangePointer, but that's not really what I */
- /* want here. */
- if (i == MAX_THREADS - 1)
- ABORT("too many threads");
- }
- thread_table[i].id = GetCurrentThreadId();
- if (!DuplicateHandle(GetCurrentProcess(),
- GetCurrentThread(),
- GetCurrentProcess(),
- /* cast away volatile qualifier */
- (HANDLE *) &thread_table[i].handle,
- 0,
- 0,
- DUPLICATE_SAME_ACCESS)) {
- DWORD last_error = GetLastError();
- GC_printf1("Last error code: %lx\n", last_error);
- ABORT("DuplicateHandle failed");
- }
- thread_table[i].stack = GC_get_stack_base();
- /* If this thread is being created while we are trying to stop */
- /* the world, wait here. Hopefully this can't happen on any */
- /* systems that don't allow us to block here. */
- while (GC_please_stop) Sleep(20);
- }
+ threadAttach();
break;
+
case DLL_THREAD_DETACH:
- {
- int i;
- DWORD thread_id = GetCurrentThreadId();
- LOCK();
- for (i = 0;
- i < MAX_THREADS &&
- (thread_table[i].stack == 0 || thread_table[i].id != thread_id);
- i++) {}
- if (i >= MAX_THREADS) {
- WARN("thread %ld not found on detach", (GC_word)thread_id);
- } else {
- thread_table[i].stack = 0;
- thread_table[i].in_use = FALSE;
- CloseHandle(thread_table[i].handle);
- /* cast away volatile qualifier */
- BZERO((void *) &thread_table[i].context, sizeof(CONTEXT));
- }
- UNLOCK();
- }
+ threadDetach(GetCurrentThreadId());
break;
+
case DLL_PROCESS_DETACH:
{
int i;
@@ -636,8 +870,8 @@ BOOL WINAPI DllMain(HINSTANCE inst, ULONG reason, LPVOID reserved)
}
return TRUE;
}
-
-# endif /* GC_DLL */
+#endif /* GC_DLL */
+#endif /* !CYGWIN32 */
# endif /* !MSWINCE */
OpenPOWER on IntegriCloud