summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile8
-rw-r--r--Makefile.am10
-rw-r--r--Makefile.direct8
-rw-r--r--Makefile.in11
-rw-r--r--NT_MAKEFILE5
-rw-r--r--NT_STATIC_THREADS_MAKEFILE5
-rw-r--r--allchblk.c15
-rw-r--r--alloc.c33
-rwxr-xr-xconfigure101
-rw-r--r--configure.in15
-rw-r--r--cord/cordtest.c2
-rw-r--r--cord/cordxtra.c4
-rw-r--r--cord/de.c2
-rw-r--r--dbg_mlc.c88
-rw-r--r--doc/Makefile.in1
-rw-r--r--doc/README4
-rw-r--r--doc/README.changes69
-rw-r--r--doc/README.environment29
-rw-r--r--doc/README.macros5
-rw-r--r--doc/README.win3214
-rw-r--r--doc/gc.man11
-rw-r--r--doc/gcdescr.html60
-rw-r--r--dyn_load.c73
-rw-r--r--finalize.c29
-rw-r--r--gcj_mlc.c78
-rw-r--r--include/Makefile.in1
-rw-r--r--include/gc.h52
-rw-r--r--include/gc_config_macros.h5
-rw-r--r--include/gc_cpp.h13
-rw-r--r--include/gc_gcj.h13
-rw-r--r--include/gc_local_alloc.h1
-rw-r--r--include/gc_mark.h64
-rw-r--r--include/javaxfc.h20
-rw-r--r--include/private/dbg_mlc.h1
-rw-r--r--include/private/gc_priv.h11
-rw-r--r--include/private/gcconfig.h33
-rw-r--r--include/private/pthread_support.h6
-rw-r--r--malloc.c4
-rw-r--r--mallocx.c2
-rw-r--r--misc.c86
-rw-r--r--os_dep.c57
-rw-r--r--pthread_support.c46
-rw-r--r--tests/test.c13
-rw-r--r--tests/test_cpp.cc2
-rw-r--r--typd_mlc.c48
-rw-r--r--version.h4
-rwxr-xr-xwin32_threads.c2
47 files changed, 892 insertions, 272 deletions
diff --git a/Makefile b/Makefile
index 2158847..74929c1 100644
--- a/Makefile
+++ b/Makefile
@@ -36,7 +36,7 @@ CFLAGS= -O -I$(srcdir)/include -DATOMIC_UNCOLLECTABLE -DNO_SIGNALS -DNO_EXECUTE_
# -DGC_LINUX_THREADS -DPARALLEL_MARK -DTHREAD_LOCAL_ALLOC
# To build the parallel collector in a static library on HP/UX,
# add to the above:
-# -DGC_HPUX_THREADS -DPARALLEL_MARK -DTHREAD_LOCAL_ALLOC -DUSE_HPUX_TLS -D_POSIX_C_SOURCE=199506L
+# -DGC_HPUX_THREADS -DPARALLEL_MARK -DTHREAD_LOCAL_ALLOC -D_POSIX_C_SOURCE=199506L
# To build the thread-safe collector on Tru64, add to the above:
# -pthread -DGC_OSF1_THREADS
@@ -182,7 +182,7 @@ HOSTCFLAGS=$(CFLAGS)
# this facility is only used in a few places. It is intended primarily
# for debugging of the garbage collector itself, but could also
# -DDBG_HDRS_ALL Make sure that all objects have debug headers. Increases
-# the reliability (from 99.9999% to 100%) of some of the debugging
+# the reliability (from 99.9999% to 100% mod. bugs) of some of the debugging
# code (especially KEEP_BACK_PTRS). Makes -DSHORT_DBG_HDRS possible.
# Assumes that all client allocation is done through debugging
# allocators.
@@ -235,6 +235,10 @@ HOSTCFLAGS=$(CFLAGS)
# in a way that usually does not involve acquisition of a global lock.
# Currently requires -DGC_LINUX_THREADS, but should be easy to port to
# other pthreads environments. Recommended for multiprocessors.
+# -DUSE_COMPILER_TLS causes thread local allocation to use compiler-supported
+# "__thread" thread-local variables. This is the default in HP/UX. It
+# may help performance on recent Linux installations. (It failed for
+# me on RedHat 8, but appears to work on RedHat 9.)
# -DPARALLEL_MARK allows the marker to run in multiple threads. Recommended
# for multiprocessors. Currently requires Linux on X86 or IA64, though
# support for other Posix platforms should be fairly easy to add,
diff --git a/Makefile.am b/Makefile.am
index 645d465..ed24152 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -55,7 +55,7 @@ $(asm_libgc_sources)
# Include THREADLIBS here to ensure that the correct versions of
# linuxthread semaphore functions get linked:
-libgc_la_LIBADD = @addobjs@ $(THREADLIBS)
+libgc_la_LIBADD = @addobjs@ $(THREADLIBS) $(UNWINDLIBS)
libgc_la_DEPENDENCIES = @addobjs@
libgc_la_LDFLAGS = -version-info 1:2:0
@@ -65,7 +65,7 @@ EXTRA_libgc_la_SOURCES = alpha_mach_dep.S \
sparc_sunos4_mach_dep.s ia64_save_regs_in_stack.s
libgccpp_la_SOURCES = gc_cpp.cc
-libgccpp_la_LIBADD = $(THREADLIBS)
+libgccpp_la_LIBADD = $(THREADLIBS) $(UNWINDLIBS)
libgccpp_la_LDFLAGS = -version-info 1:2:0
EXTRA_DIST += alpha_mach_dep.S mips_sgi_mach_dep.s sparc_mach_dep.S
@@ -91,9 +91,9 @@ test_cpp.o: $(srcdir)/tests/test_cpp.cc
## are included in the distribution
# gctest_OBJECTS = test.o
gctest_SOURCES = tests/test.c
-gctest_LDADD = ./libgc.la $(THREADLIBS) $(EXTRA_TEST_LIBS)
+gctest_LDADD = ./libgc.la $(THREADLIBS) $(UNWINDLIBS) $(EXTRA_TEST_LIBS)
test_cpp_SOURCES = tests/test_cpp.cc
-test_cpp_LDADD = ./libgc.la ./libgccpp.la $(THREADLIBS) $(EXTRA_TEST_LIBS)
+test_cpp_LDADD = ./libgc.la ./libgccpp.la $(THREADLIBS) $(UNWINDLIBS) $(EXTRA_TEST_LIBS)
TESTS = gctest $(extra_checks)
@@ -175,8 +175,6 @@ CONFIG_STATUS_DEPENDENCIES = $(srcdir)/configure.host
#
EXTRA_DIST += libtool.m4
-MAKEOVERRIDES=
-
#
# :GOTCHA: GNU make rule for making .s out of .S is flawed,
# it will not remove dest if building fails
diff --git a/Makefile.direct b/Makefile.direct
index 2158847..74929c1 100644
--- a/Makefile.direct
+++ b/Makefile.direct
@@ -36,7 +36,7 @@ CFLAGS= -O -I$(srcdir)/include -DATOMIC_UNCOLLECTABLE -DNO_SIGNALS -DNO_EXECUTE_
# -DGC_LINUX_THREADS -DPARALLEL_MARK -DTHREAD_LOCAL_ALLOC
# To build the parallel collector in a static library on HP/UX,
# add to the above:
-# -DGC_HPUX_THREADS -DPARALLEL_MARK -DTHREAD_LOCAL_ALLOC -DUSE_HPUX_TLS -D_POSIX_C_SOURCE=199506L
+# -DGC_HPUX_THREADS -DPARALLEL_MARK -DTHREAD_LOCAL_ALLOC -D_POSIX_C_SOURCE=199506L
# To build the thread-safe collector on Tru64, add to the above:
# -pthread -DGC_OSF1_THREADS
@@ -182,7 +182,7 @@ HOSTCFLAGS=$(CFLAGS)
# this facility is only used in a few places. It is intended primarily
# for debugging of the garbage collector itself, but could also
# -DDBG_HDRS_ALL Make sure that all objects have debug headers. Increases
-# the reliability (from 99.9999% to 100%) of some of the debugging
+# the reliability (from 99.9999% to 100% mod. bugs) of some of the debugging
# code (especially KEEP_BACK_PTRS). Makes -DSHORT_DBG_HDRS possible.
# Assumes that all client allocation is done through debugging
# allocators.
@@ -235,6 +235,10 @@ HOSTCFLAGS=$(CFLAGS)
# in a way that usually does not involve acquisition of a global lock.
# Currently requires -DGC_LINUX_THREADS, but should be easy to port to
# other pthreads environments. Recommended for multiprocessors.
+# -DUSE_COMPILER_TLS causes thread local allocation to use compiler-supported
+# "__thread" thread-local variables. This is the default in HP/UX. It
+# may help performance on recent Linux installations. (It failed for
+# me on RedHat 8, but appears to work on RedHat 9.)
# -DPARALLEL_MARK allows the marker to run in multiple threads. Recommended
# for multiprocessors. Currently requires Linux on X86 or IA64, though
# support for other Posix platforms should be fairly easy to add,
diff --git a/Makefile.in b/Makefile.in
index 9c8ec41..2c7c1b7 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -109,6 +109,7 @@ PACKAGE = @PACKAGE@
RANLIB = @RANLIB@
STRIP = @STRIP@
THREADLIBS = @THREADLIBS@
+UNWINDLIBS = @UNWINDLIBS@
VERSION = @VERSION@
addincludes = @addincludes@
addlibs = @addlibs@
@@ -187,7 +188,7 @@ $(asm_libgc_sources)
# Include THREADLIBS here to ensure that the correct versions of
# linuxthread semaphore functions get linked:
-libgc_la_LIBADD = @addobjs@ $(THREADLIBS)
+libgc_la_LIBADD = @addobjs@ $(THREADLIBS) $(UNWINDLIBS)
libgc_la_DEPENDENCIES = @addobjs@
libgc_la_LDFLAGS = -version-info 1:2:0
@@ -198,7 +199,7 @@ EXTRA_libgc_la_SOURCES = alpha_mach_dep.S \
libgccpp_la_SOURCES = gc_cpp.cc
-libgccpp_la_LIBADD = $(THREADLIBS)
+libgccpp_la_LIBADD = $(THREADLIBS) $(UNWINDLIBS)
libgccpp_la_LDFLAGS = -version-info 1:2:0
AM_CXXFLAGS = @GC_CFLAGS@
@@ -211,9 +212,9 @@ check_PROGRAMS = gctest $(extra_checks)
# gctest_OBJECTS = test.o
gctest_SOURCES = tests/test.c
-gctest_LDADD = ./libgc.la $(THREADLIBS) $(EXTRA_TEST_LIBS)
+gctest_LDADD = ./libgc.la $(THREADLIBS) $(UNWINDLIBS) $(EXTRA_TEST_LIBS)
test_cpp_SOURCES = tests/test_cpp.cc
-test_cpp_LDADD = ./libgc.la ./libgccpp.la $(THREADLIBS) $(EXTRA_TEST_LIBS)
+test_cpp_LDADD = ./libgc.la ./libgccpp.la $(THREADLIBS) $(UNWINDLIBS) $(EXTRA_TEST_LIBS)
TESTS = gctest $(extra_checks)
@@ -235,8 +236,6 @@ dist_noinst_HEADERS = version.h
# this is an auxiliary shell file used by Makefile and Makefile.direct
#
CONFIG_STATUS_DEPENDENCIES = $(srcdir)/configure.host
-
-MAKEOVERRIDES =
subdir = .
ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs
diff --git a/NT_MAKEFILE b/NT_MAKEFILE
index 002f85c..d1b6a5d 100644
--- a/NT_MAKEFILE
+++ b/NT_MAKEFILE
@@ -2,7 +2,8 @@
# DLLs are included in the root set under NT, but not under win32S.
# Use "nmake nodebug=1 all" for optimized versions of library, gctest and editor.
-CPU= i386
+MY_CPU=X86
+CPU=$(MY_CPU)
!include <ntwin32.mak>
OBJS= alloc.obj reclaim.obj allchblk.obj misc.obj mach_dep.obj os_dep.obj mark_rts.obj headers.obj mark.obj obj_map.obj blacklst.obj finalize.obj new_hblk.obj dbg_mlc.obj malloc.obj stubborn.obj dyn_load.obj typd_mlc.obj ptr_chck.obj gc_cpp.obj mallocx.obj
@@ -30,7 +31,7 @@ gctest.exe: tests\test.obj gc.lib
# mapsympe -n -o gctest.sym gctest.exe
cord\de_win.rbj: cord\de_win.res
- cvtres -$(CPU) cord\de_win.res -o cord\de_win.rbj
+ cvtres /MACHINE:$(MY_CPU) /OUT:cord\de_win.rbj cord\de_win.res
cord\de.obj cord\de_win.obj: include\cord.h include\private\cord_pos.h cord\de_win.h cord\de_cmds.h
diff --git a/NT_STATIC_THREADS_MAKEFILE b/NT_STATIC_THREADS_MAKEFILE
index 2442117..7238c94 100644
--- a/NT_STATIC_THREADS_MAKEFILE
+++ b/NT_STATIC_THREADS_MAKEFILE
@@ -2,7 +2,8 @@
# DLLs are included in the root set under NT, but not under win32S.
# Use "nmake nodebug=1 all" for optimized versions of library, gctest and editor.
-CPU= i386
+MY_CPU=X86
+CPU=$(MY_CPU)
!include <ntwin32.mak>
OBJS= alloc.obj reclaim.obj allchblk.obj misc.obj mach_dep.obj os_dep.obj mark_rts.obj headers.obj mark.obj obj_map.obj blacklst.obj finalize.obj new_hblk.obj dbg_mlc.obj malloc.obj stubborn.obj dyn_load.obj typd_mlc.obj ptr_chck.obj gc_cpp.obj mallocx.obj win32_threads.obj
@@ -30,7 +31,7 @@ gctest.exe: tests\test.obj gc.lib
# mapsympe -n -o gctest.sym gctest.exe
cord\de_win.rbj: cord\de_win.res
- cvtres -$(CPU) cord\de_win.res -o cord\de_win.rbj
+ cvtres /MACHINE:$(MY_CPU) /OUT:cord\de_win.rbj cord\de_win.res
cord\de.obj cord\de_win.obj: include\cord.h include\private\cord_pos.h cord\de_win.h cord\de_cmds.h
diff --git a/allchblk.c b/allchblk.c
index 2b03939..1bd17da 100644
--- a/allchblk.c
+++ b/allchblk.c
@@ -375,9 +375,8 @@ void GC_unmap_old(void)
if (!IS_MAPPED(hhdr)) continue;
threshold = (unsigned short)(GC_gc_no - UNMAP_THRESHOLD);
last_rec = hhdr -> hb_last_reclaimed;
- if (last_rec > GC_gc_no
- || last_rec < threshold && threshold < GC_gc_no
- /* not recently wrapped */) {
+ if ((last_rec > GC_gc_no || last_rec < threshold)
+ && threshold < GC_gc_no /* not recently wrapped */) {
sz = hhdr -> hb_sz;
GC_unmap((ptr_t)h, sz);
hhdr -> hb_flags |= WAS_UNMAPPED;
@@ -422,6 +421,7 @@ void GC_merge_unmapped(void)
} else {
GC_remap((ptr_t)h, size);
hhdr -> hb_flags &= ~WAS_UNMAPPED;
+ hhdr -> hb_last_reclaimed = nexthdr -> hb_last_reclaimed;
}
} else {
/* Unmap any gap in the middle */
@@ -784,6 +784,9 @@ signed_word size;
size = HBLKSIZE * OBJ_SZ_TO_BLOCKS(size);
GC_remove_counts(hbp, (word)size);
hhdr->hb_sz = size;
+# ifdef USE_MUNMAP
+ hhdr -> hb_last_reclaimed = GC_gc_no;
+# endif
/* Check for duplicate deallocation in the easy case */
if (HBLK_IS_FREE(hhdr)) {
@@ -809,11 +812,17 @@ signed_word size;
if (IS_MAPPED(prevhdr)) {
GC_remove_from_fl(prevhdr, FL_UNKNOWN);
prevhdr -> hb_sz += hhdr -> hb_sz;
+# ifdef USE_MUNMAP
+ prevhdr -> hb_last_reclaimed = GC_gc_no;
+# endif
GC_remove_header(hbp);
hbp = prev;
hhdr = prevhdr;
}
}
+ /* FIXME: It is not clear we really always want to do these merges */
+ /* with -DUSE_MUNMAP, since it updates ages and hence prevents */
+ /* unmapping. */
GC_large_free_bytes += size;
GC_add_to_fl(hbp, hhdr);
diff --git a/alloc.c b/alloc.c
index d2b874f..aaf9124 100644
--- a/alloc.c
+++ b/alloc.c
@@ -228,10 +228,15 @@ void GC_clear_a_few_frames()
for (i = 0; i < NWORDS; i++) frames[i] = 0;
}
+/* Heap size at which we need a collection to avoid expanding past */
+/* limits used by blacklisting. */
+static word GC_collect_at_heapsize = (word)(-1);
+
/* Have we allocated enough to amortize a collection? */
GC_bool GC_should_collect()
{
- return(GC_adj_words_allocd() >= min_words_allocd());
+ return(GC_adj_words_allocd() >= min_words_allocd()
+ || GC_heapsize >= GC_collect_at_heapsize);
}
@@ -924,22 +929,32 @@ word n;
# endif
}
# endif
- expansion_slop = 8 * WORDS_TO_BYTES(min_words_allocd());
- if (5 * HBLKSIZE * MAXHINCR > expansion_slop) {
- expansion_slop = 5 * HBLKSIZE * MAXHINCR;
- }
+ expansion_slop = WORDS_TO_BYTES(min_words_allocd()) + 4*MAXHINCR*HBLKSIZE;
if (GC_last_heap_addr == 0 && !((word)space & SIGNB)
|| GC_last_heap_addr != 0 && GC_last_heap_addr < (ptr_t)space) {
/* Assume the heap is growing up */
GC_greatest_plausible_heap_addr =
- GC_max(GC_greatest_plausible_heap_addr,
- (ptr_t)space + bytes + expansion_slop);
+ (GC_PTR)GC_max((ptr_t)GC_greatest_plausible_heap_addr,
+ (ptr_t)space + bytes + expansion_slop);
} else {
/* Heap is growing down */
GC_least_plausible_heap_addr =
- GC_min(GC_least_plausible_heap_addr,
- (ptr_t)space - expansion_slop);
+ (GC_PTR)GC_min((ptr_t)GC_least_plausible_heap_addr,
+ (ptr_t)space - expansion_slop);
}
+ /* Force GC before we are likely to allocate past expansion_slop */
+ GC_collect_at_heapsize =
+ GC_heapsize + expansion_slop - 2*MAXHINCR*HBLKSIZE;
+# if defined(LARGE_CONFIG)
+ if (GC_collect_at_heapsize < GC_heapsize /* wrapped */)
+ GC_collect_at_heapsize = (word)(-1);
+ if (((ptr_t)GC_greatest_plausible_heap_addr <= (ptr_t)space + bytes
+ || (ptr_t)GC_least_plausible_heap_addr >= (ptr_t)space)
+ && GC_heapsize > 0) {
+ /* GC_add_to_heap will fix this, but ... */
+ WARN("Too close to address space limit: blacklisting ineffective\n", 0);
+ }
+# endif
GC_prev_heap_addr = GC_last_heap_addr;
GC_last_heap_addr = (ptr_t)space;
GC_add_to_heap(space, bytes);
diff --git a/configure b/configure
index 47982d9..3ede246 100755
--- a/configure
+++ b/configure
@@ -1,7 +1,7 @@
#! /bin/sh
# From configure.in Revision: 1.2 .
# Guess values for system-dependent variables and create Makefiles.
-# Generated by GNU Autoconf 2.53 for gc 6.3alpha4.
+# Generated by GNU Autoconf 2.53 for gc 6.3alpha5.
#
# Report bugs to <Hans.Boehm@hp.com>.
#
@@ -416,8 +416,8 @@ SHELL=${CONFIG_SHELL-/bin/sh}
# Identity of this package.
PACKAGE_NAME='gc'
PACKAGE_TARNAME='gc'
-PACKAGE_VERSION='6.3alpha4'
-PACKAGE_STRING='gc 6.3alpha4'
+PACKAGE_VERSION='6.3alpha5'
+PACKAGE_STRING='gc 6.3alpha5'
PACKAGE_BUGREPORT='Hans.Boehm@hp.com'
ac_unique_file="gcj_mlc.c"
@@ -930,7 +930,7 @@ if test "$ac_init_help" = "long"; then
# Omit some internal or obsolete options to make the list less imposing.
# This message is too long to be a string in the A/UX 3.1 sh.
cat <<_ACEOF
-\`configure' configures gc 6.3alpha4 to adapt to many kinds of systems.
+\`configure' configures gc 6.3alpha5 to adapt to many kinds of systems.
Usage: $0 [OPTION]... [VAR=VALUE]...
@@ -997,7 +997,7 @@ fi
if test -n "$ac_init_help"; then
case $ac_init_help in
- short | recursive ) echo "Configuration of gc 6.3alpha4:";;
+ short | recursive ) echo "Configuration of gc 6.3alpha5:";;
esac
cat <<\_ACEOF
@@ -1106,7 +1106,7 @@ fi
test -n "$ac_init_help" && exit 0
if $ac_init_version; then
cat <<\_ACEOF
-gc configure 6.3alpha4
+gc configure 6.3alpha5
generated by GNU Autoconf 2.53
Copyright 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001, 2002
@@ -1121,7 +1121,7 @@ cat >&5 <<_ACEOF
This file contains any messages produced by compilers while
running configure, to aid debugging if configure makes a mistake.
-It was created by gc $as_me 6.3alpha4, which was
+It was created by gc $as_me 6.3alpha5, which was
generated by GNU Autoconf 2.53. Invocation command line was
$ $0 $@
@@ -1782,7 +1782,7 @@ fi
# Define the identity of the package.
PACKAGE=gc
- VERSION=6.3alpha4
+ VERSION=6.3alpha5
cat >>confdefs.h <<_ACEOF
@@ -3670,7 +3670,7 @@ _ACEOF
;;
dgux386)
THREADS=dgux386
-echo "$as_me:$LINENO: result: $THREADLIBS" >&5
+ echo "$as_me:$LINENO: result: $THREADLIBS" >&5
echo "${ECHO_T}$THREADLIBS" >&6
# Use pthread GCC switch
THREADLIBS=-pthread
@@ -8786,12 +8786,13 @@ _ACEOF
fi
+UNWINDLIBS=
# Check whether --enable-full-debug or --disable-full-debug was given.
if test "${enable_full_debug+set}" = set; then
enableval="$enable_full_debug"
if test "$enable_full_debug" = "yes"; then
- { echo "$as_me:$LINENO: WARNING: \"Must define GC_DEBUG and use debug alloc. in clients.\"" >&5
-echo "$as_me: WARNING: \"Must define GC_DEBUG and use debug alloc. in clients.\"" >&2;}
+ { echo "$as_me:$LINENO: WARNING: \"Should define GC_DEBUG and use debug alloc. in clients.\"" >&5
+echo "$as_me: WARNING: \"Should define GC_DEBUG and use debug alloc. in clients.\"" >&2;}
cat >>confdefs.h <<\_ACEOF
#define KEEP_BACK_PTRS 1
_ACEOF
@@ -8806,6 +8807,77 @@ _ACEOF
#define MAKE_BACK_GRAPH 1
_ACEOF
+ cat >>confdefs.h <<\_ACEOF
+#define SAVE_CALL_COUNT 8
+_ACEOF
+
+ echo "$as_me:$LINENO: checking for backtrace in -lunwind" >&5
+echo $ECHO_N "checking for backtrace in -lunwind... $ECHO_C" >&6
+if test "${ac_cv_lib_unwind_backtrace+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lunwind $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+#include "confdefs.h"
+
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char backtrace ();
+#ifdef F77_DUMMY_MAIN
+# ifdef __cplusplus
+ extern "C"
+# endif
+ int F77_DUMMY_MAIN() { return 1; }
+#endif
+int
+main ()
+{
+backtrace ();
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_lib_unwind_backtrace=yes
+else
+ echo "$as_me: failed program was:" >&5
+cat conftest.$ac_ext >&5
+ac_cv_lib_unwind_backtrace=no
+fi
+rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_lib_unwind_backtrace" >&5
+echo "${ECHO_T}$ac_cv_lib_unwind_backtrace" >&6
+if test $ac_cv_lib_unwind_backtrace = yes; then
+
+ cat >>confdefs.h <<\_ACEOF
+#define GC_HAVE_BUILTIN_BACKTRACE 1
+_ACEOF
+
+ UNWINDLIBS=-lunwind
+ { echo "$as_me:$LINENO: WARNING: \"Client code may need to link against libunwind.\"" >&5
+echo "$as_me: WARNING: \"Client code may need to link against libunwind.\"" >&2;}
+
+fi
+
;;
x86-*-linux* | i586-*-linux* | i686-*-linux* | x86_64-*-linux* )
cat >>confdefs.h <<\_ACEOF
@@ -8829,6 +8901,8 @@ _ACEOF
fi
fi;
+
+
# Check whether --enable-redirect-malloc or --disable-redirect-malloc was given.
if test "${enable_redirect_malloc+set}" = set; then
enableval="$enable_redirect_malloc"
@@ -9273,7 +9347,7 @@ _ASBOX
} >&5
cat >&5 <<_CSEOF
-This file was extended by gc $as_me 6.3alpha4, which was
+This file was extended by gc $as_me 6.3alpha5, which was
generated by GNU Autoconf 2.53. Invocation command line was
CONFIG_FILES = $CONFIG_FILES
@@ -9330,7 +9404,7 @@ _ACEOF
cat >>$CONFIG_STATUS <<_ACEOF
ac_cs_version="\\
-gc config.status 6.3alpha4
+gc config.status 6.3alpha5
configured by $0, generated by GNU Autoconf 2.53,
with options \\"`echo "$ac_configure_args" | sed 's/[\\""\`\$]/\\\\&/g'`\\"
@@ -9592,6 +9666,7 @@ s,@ECHO@,$ECHO,;t t
s,@CPP@,$CPP,;t t
s,@LIBTOOL@,$LIBTOOL,;t t
s,@MY_CFLAGS@,$MY_CFLAGS,;t t
+s,@UNWINDLIBS@,$UNWINDLIBS,;t t
s,@USE_LIBDIR_TRUE@,$USE_LIBDIR_TRUE,;t t
s,@USE_LIBDIR_FALSE@,$USE_LIBDIR_FALSE,;t t
CEOF
diff --git a/configure.in b/configure.in
index 43c0d14..635742c 100644
--- a/configure.in
+++ b/configure.in
@@ -17,7 +17,7 @@ dnl Process this file with autoconf to produce configure.
# Initialization
# ==============
-AC_INIT(gc,6.3alpha4,Hans.Boehm@hp.com)
+AC_INIT(gc,6.3alpha5,Hans.Boehm@hp.com)
## version must conform to [0-9]+[.][0-9]+(alpha[0-9]+)?
AC_CONFIG_SRCDIR(gcj_mlc.c)
AC_CANONICAL_TARGET
@@ -146,7 +146,7 @@ case "$THREADS" in
;;
dgux386)
THREADS=dgux386
-AC_MSG_RESULT($THREADLIBS)
+ AC_MSG_RESULT($THREADLIBS)
# Use pthread GCC switch
THREADLIBS=-pthread
if test "${enable_parallel_mark}" = yes; then
@@ -397,15 +397,22 @@ if test -n "${with_cross_host}"; then
AC_DEFINE(NO_DEBUGGING)
fi
+UNWINDLIBS=
AC_ARG_ENABLE(full-debug,
[ --enable-full-debug include full support for pointer backtracing etc.],
[ if test "$enable_full_debug" = "yes"; then
- AC_MSG_WARN("Must define GC_DEBUG and use debug alloc. in clients.")
+ AC_MSG_WARN("Should define GC_DEBUG and use debug alloc. in clients.")
AC_DEFINE(KEEP_BACK_PTRS)
AC_DEFINE(DBG_HDRS_ALL)
case $host in
ia64-*-linux* )
AC_DEFINE(MAKE_BACK_GRAPH)
+ AC_DEFINE(SAVE_CALL_COUNT, 8)
+ AC_CHECK_LIB(unwind, backtrace, [
+ AC_DEFINE(GC_HAVE_BUILTIN_BACKTRACE)
+ UNWINDLIBS=-lunwind
+ AC_MSG_WARN("Client code may need to link against libunwind.")
+ ])
;;
x86-*-linux* | i586-*-linux* | i686-*-linux* | x86_64-*-linux* )
AC_DEFINE(MAKE_BACK_GRAPH)
@@ -418,6 +425,8 @@ AC_ARG_ENABLE(full-debug,
esac ]
fi)
+AC_SUBST(UNWINDLIBS)
+
AC_ARG_ENABLE(redirect-malloc,
[ --enable-redirect-malloc redirect malloc and friends to GC routines])
diff --git a/cord/cordtest.c b/cord/cordtest.c
index 0d06562..8f4836a 100644
--- a/cord/cordtest.c
+++ b/cord/cordtest.c
@@ -11,6 +11,7 @@
* modified is included with the above copyright notice.
*/
/* Boehm, August 24, 1994 11:58 am PDT */
+# include "gc.h" /* For GC_INIT() only */
# include "cord.h"
# include <string.h>
# include <stdio.h>
@@ -225,6 +226,7 @@ main()
# ifdef THINK_C
printf("cordtest:\n");
# endif
+ GC_INIT();
test_basics();
test_extras();
test_printf();
diff --git a/cord/cordxtra.c b/cord/cordxtra.c
index fe59e70..b0a7462 100644
--- a/cord/cordxtra.c
+++ b/cord/cordxtra.c
@@ -387,7 +387,7 @@ size_t CORD_str(CORD x, size_t start, CORD s)
s_buf <<= 8;
s_buf |= (unsigned char)s_start[i];
x_buf <<= 8;
- x_buf |= CORD_pos_fetch(xpos);
+ x_buf |= (unsigned char)CORD_pos_fetch(xpos);
CORD_next(xpos);
}
for (match_pos = start; ; match_pos++) {
@@ -402,7 +402,7 @@ size_t CORD_str(CORD x, size_t start, CORD s)
return(CORD_NOT_FOUND);
}
x_buf <<= 8;
- x_buf |= CORD_pos_fetch(xpos);
+ x_buf |= (unsigned char)CORD_pos_fetch(xpos);
CORD_next(xpos);
}
}
diff --git a/cord/de.c b/cord/de.c
index fda7142..989e19a 100644
--- a/cord/de.c
+++ b/cord/de.c
@@ -569,9 +569,9 @@ char ** argv;
#if defined(MACINTOSH)
console_options.title = "\pDumb Editor";
cshow(stdout);
- GC_init();
argc = ccommand(&argv);
#endif
+ GC_INIT();
if (argc != 2) goto usage;
arg_file_name = argv[1];
diff --git a/dbg_mlc.c b/dbg_mlc.c
index f640930..9daa0b0 100644
--- a/dbg_mlc.c
+++ b/dbg_mlc.c
@@ -2,7 +2,7 @@
* Copyright 1988, 1989 Hans-J. Boehm, Alan J. Demers
* Copyright (c) 1991-1995 by Xerox Corporation. All rights reserved.
* Copyright (c) 1997 by Silicon Graphics. All rights reserved.
- * Copyright (c) 1999-2000 by Hewlett-Packard Company. All rights reserved.
+ * Copyright (c) 1999-2004 Hewlett-Packard Development Company, L.P.
*
* THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
* OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
@@ -195,13 +195,13 @@ ptr_t p;
(unsigned long)i);
switch(source) {
case GC_REFD_FROM_ROOT:
- GC_err_printf1("root at 0x%lx\n", (unsigned long)base);
+ GC_err_printf1("root at 0x%lx\n\n", (unsigned long)base);
goto out;
case GC_REFD_FROM_REG:
- GC_err_printf0("root in register\n");
+ GC_err_printf0("root in register\n\n");
goto out;
case GC_FINALIZER_REFD:
- GC_err_printf0("list of finalizable objects\n");
+ GC_err_printf0("list of finalizable objects\n\n");
goto out;
case GC_REFD_FROM_HEAP:
GC_err_printf1("offset %ld in object:\n", (unsigned long)offset);
@@ -217,15 +217,20 @@ ptr_t p;
/* Force a garbage collection and generate a backtrace from a */
/* random heap address. */
- void GC_generate_random_backtrace(void)
+ void GC_generate_random_backtrace_no_gc(void)
{
void * current;
- GC_gcollect();
current = GC_generate_random_valid_address();
- GC_printf1("Chose address 0x%lx in object\n", (unsigned long)current);
+ GC_printf1("\n****Chose address 0x%lx in object\n", (unsigned long)current);
GC_print_backtrace(current);
}
+ void GC_generate_random_backtrace(void)
+ {
+ GC_gcollect();
+ GC_generate_random_backtrace_no_gc();
+ }
+
#endif /* KEEP_BACK_PTRS */
# define CROSSES_HBLK(p, sz) \
@@ -325,6 +330,58 @@ register oh * ohdr;
}
#endif /* !SHORT_DBG_HDRS */
+static GC_describe_type_fn GC_describe_type_fns[MAXOBJKINDS] = {0};
+
+void GC_register_describe_type_fn(kind, fn)
+int kind;
+GC_describe_type_fn fn;
+{
+ GC_describe_type_fns[kind] = fn;
+}
+
+/* Print a type description for the object whose client-visible address */
+/* is p. */
+void GC_print_type(p)
+ptr_t p;
+{
+ hdr * hhdr = GC_find_header(p);
+ char buffer[GC_TYPE_DESCR_LEN + 1];
+ int kind = hhdr -> hb_obj_kind;
+
+ if (0 != GC_describe_type_fns[kind] && GC_is_marked(GC_base(p))) {
+ /* This should preclude free list objects except with */
+ /* thread-local allocation. */
+ buffer[GC_TYPE_DESCR_LEN] = 0;
+ (GC_describe_type_fns[kind])(p, buffer);
+ GC_ASSERT(buffer[GC_TYPE_DESCR_LEN] == 0);
+ GC_err_puts(buffer);
+ } else {
+ switch(kind) {
+ case PTRFREE:
+ GC_err_puts("PTRFREE");
+ break;
+ case NORMAL:
+ GC_err_puts("NORMAL");
+ break;
+ case UNCOLLECTABLE:
+ GC_err_puts("UNCOLLECTABLE");
+ break;
+# ifdef ATOMIC_UNCOLLECTABLE
+ case AUNCOLLECTABLE:
+ GC_err_puts("ATOMIC UNCOLLECTABLE");
+ break;
+# endif
+ case STUBBORN:
+ GC_err_puts("STUBBORN");
+ break;
+ default:
+ GC_err_printf2("kind %ld, descr 0x%lx", kind, hhdr -> hb_descr);
+ }
+ }
+}
+
+
+
void GC_print_obj(p)
ptr_t p;
{
@@ -334,11 +391,13 @@ ptr_t p;
GC_err_printf1("0x%lx (", ((unsigned long)ohdr + sizeof(oh)));
GC_err_puts(ohdr -> oh_string);
# ifdef SHORT_DBG_HDRS
- GC_err_printf1(":%ld)\n", (unsigned long)(ohdr -> oh_int));
+ GC_err_printf1(":%ld, ", (unsigned long)(ohdr -> oh_int));
# else
- GC_err_printf2(":%ld, sz=%ld)\n", (unsigned long)(ohdr -> oh_int),
+ GC_err_printf2(":%ld, sz=%ld, ", (unsigned long)(ohdr -> oh_int),
(unsigned long)(ohdr -> oh_sz));
# endif
+ GC_print_type((ptr_t)(ohdr + 1));
+ GC_err_puts(")\n");
PRINT_CALL_CHAIN(ohdr);
}
@@ -403,6 +462,8 @@ void GC_start_debugging()
GC_register_displacement((word)sizeof(oh));
}
+size_t GC_debug_header_size = sizeof(oh);
+
# if defined(__STDC__) || defined(__cplusplus)
void GC_debug_register_displacement(GC_word offset)
# else
@@ -1013,7 +1074,8 @@ GC_PTR *ocd;
GC_finalization_proc my_old_fn;
GC_PTR my_old_cd;
ptr_t base = GC_base(obj);
- if (0 == base || (ptr_t)obj - base != sizeof(oh)) {
+ if (0 == base) return;
+ if ((ptr_t)obj - base != sizeof(oh)) {
GC_err_printf1(
"GC_debug_register_finalizer called with non-base-pointer 0x%lx\n",
obj);
@@ -1045,7 +1107,8 @@ GC_PTR *ocd;
GC_finalization_proc my_old_fn;
GC_PTR my_old_cd;
ptr_t base = GC_base(obj);
- if (0 == base || (ptr_t)obj - base != sizeof(oh)) {
+ if (0 == base) return;
+ if ((ptr_t)obj - base != sizeof(oh)) {
GC_err_printf1(
"GC_debug_register_finalizer_no_order called with non-base-pointer 0x%lx\n",
obj);
@@ -1078,7 +1141,8 @@ GC_PTR *ocd;
GC_finalization_proc my_old_fn;
GC_PTR my_old_cd;
ptr_t base = GC_base(obj);
- if (0 == base || (ptr_t)obj - base != sizeof(oh)) {
+ if (0 == base) return;
+ if ((ptr_t)obj - base != sizeof(oh)) {
GC_err_printf1(
"GC_debug_register_finalizer_ignore_self called with non-base-pointer 0x%lx\n",
obj);
diff --git a/doc/Makefile.in b/doc/Makefile.in
index 9bf1ff5..1e9dd92 100644
--- a/doc/Makefile.in
+++ b/doc/Makefile.in
@@ -106,6 +106,7 @@ PACKAGE = @PACKAGE@
RANLIB = @RANLIB@
STRIP = @STRIP@
THREADLIBS = @THREADLIBS@
+UNWINDLIBS = @UNWINDLIBS@
VERSION = @VERSION@
addincludes = @addincludes@
addlibs = @addlibs@
diff --git a/doc/README b/doc/README
index d2b427e..0776e67 100644
--- a/doc/README
+++ b/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-2003 by Hewlett-Packard Company. All rights reserved.
+Copyright (c) 1999-2004 Hewlett-Packard Development Company, L.P.
The file linux_threads.c is also
Copyright (c) 1998 by Fergus Henderson. All rights reserved.
@@ -28,7 +28,7 @@ are GPL'ed, but with an exception that should cover all uses in the
collector. (If you are concerned about such things, I recommend you look
at the notice in config.guess or ltmain.sh.)
-This is version 6.3alpha4 of a conservative garbage collector for C and C++.
+This is version 6.3alpha5 of a conservative garbage collector for C and C++.
You might find a more recent version of this at
diff --git a/doc/README.changes b/doc/README.changes
index 8910968..38bde34 100644
--- a/doc/README.changes
+++ b/doc/README.changes
@@ -1956,7 +1956,7 @@ Since 6.3alpha2:
had suffered from serious bit rot.
- Rewrote GC_apply_to_maps, eliminating an off-by-one subscript error,
and a call to alloca (for lcc compatibility).
- - Changed use_MUNMAP behavior on posixy platforms to immediately remap
+ - Changed USE_MUNMAP behavior on posixy platforms to immediately remap
the memory with PROT_NONE instead of unmapping it. The latter risks
an intervening mmap grabbing the address space out from underneath us.
Updated this code to reflect a cleaner patch from Ulrich Drepper.
@@ -1991,7 +1991,74 @@ Since 6.3alpha3:
thread creation. Fixed by explicitly checking for that case. (Added
GC_in_thread_creation.)
+Since 6.3alpha4:
+ - Fix & vs && typo in GC_generic_malloc and
+ GC_generic_malloc_ignore_off_page. (Propagated from the gcc tree.)
+ - Removed SA_NODEFER hack from NetBSD and Solaris write-protect handler.
+ (According to Christian Limpach, the NetBSD problem is fixed.
+ Presumably so is the Solaris 2.3 problem.)
+ - Removed placement delete from gc_cpp.h for the SGI compiler.
+ (Thanks to Simon Gornall for the patch.)
+ - Changed semantics of the GC_IGNORE_FB environment variable, based
+ on experimentation by Nicolas Cannasse pointing out that the old
+ interpretation was useless. We still need help in identifying win32
+ graphics memory mappings. The current "solution" is a hack.
+ - Removed "MAKEOVERRIDES =" from Makefile.am and thus Makefile.in.
+ It probably made more sense in the gcc context.
+ - Explicitly ensure that NEED_FIND_LIMIT is defined for {Open,Net}BSD/ELF.
+ - Replaced USE_HPUX_TLS macro by USE_COMPILER_TLS, since gcc often
+ supports the same extension on various platforms.
+ - Added some basic (completely untested) defines for win64, in support
+ of future work.
+ - Declared GC_jmp_buf in os_dep.s as JMP_BUF instead of jmp_buf, fixing
+ a memory overwrite bug on Solaris and perhaps other platforms.
+ - Added 0 != __libc_stack_end test to GC_linux_stack_base. (Thanks to Jakub
+ Jelinek, both for the patch, and for explaining the problem to me.)
+ Otherwise "prelink"ing could cause the collector to fail.
+ - Changed default thread local storage implementation to USE_PTHREAD_SPECIFIC
+ for HP/UX with gcc. The compiler-based implementation appears to work
+ only with the vendor compiler.
+ - Export GC_debug_header_size and GC_USR_PTR_FROM_BASE from gc_mark.h,
+ making client mark code cleaner and less dependent on GC version.
+ - Export several new procedures and GC_generic_malloc from gc_mark.h
+ to support user-defined kinds. Use the new procedures to replace existing
+ code in gcj_mlc.c and typd_mlc.c.
+ - Added support for GC_BACKTRACES.
+ - Fixed a remaining problem in CORD_str with signed characters. (Thanks
+ to Alexandr Petrosian for the patch.)
+ - Removed supposedly redundant, but very buggy, definitions of finalizer
+ macros from javaxfc.h. Fortunately this file probably has no users.
+ The correct declarations were already in gc.h.
+ - Also need to set GC_in_thread_creation while waiting for GC during
+ thread termination, since it is also possible to collect from an
+ unregistered thread in that case.
+ - Define NO_GETENV for Windows CE, since getenv doesn't appear to exist.
+ + some other minor WinCE fixes. (Thanks to Alain Novak.)
+ - Added GC_register_describe_type_fn.
+ - Arrange for debugging finalizer registration to ignore non-heap
+ registrations, since the regular version of the routine also behaves
+ that way.
+ - GC_gcj_malloc and friends need to check for finalizers waiting to be run.
+ One of the more obscure allocation routines with missing a LOCK() call.
+ - Fixed cvtres invocations in NT_MAKEFILE and NT_STATIC_THREADS_MAKEFILE
+ to work with VS.NET.
+ - Cleaned up GC_INIT calls in test. Updated gc.man to encourage GC_INIT
+ use in portable code.
+ - Taught the GC to use libunwind if --enable-full-debug is specified on
+ IA64 and libunwind is present.
+ - The USE_MUNMAP code could get confused about the age of a block and
+ prematurely unmap it. GC_unmap_old had a bug related to wrapping of
+ GC_gc_no. GC_freehblk and GC_merge_unmapped didn't maintain
+ hb_last_reclaimed reasonably when blockas were merged. The code was
+ fixed to reflect original intent, but that may not always be an
+ improvement. See todo list item.
+
To do:
+ - The USE_MUNMAP code should really use a separate data structure
+ indexed by physical page to keep track of time since last use of
+ a page. Using hblk headers means we lose track of ages when
+ blocks are merged, and we can't unmap pages that have been allocated and
+ dropped by the blacklisting code. I suspect both of these matter.
- 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
diff --git a/doc/README.environment b/doc/README.environment
index 971cc4d..97a13dc 100644
--- a/doc/README.environment
+++ b/doc/README.environment
@@ -26,6 +26,14 @@ GC_DUMP_REGULARLY - Generate a GC debugging dump GC_dump() on startup
if you have a bug to report, but please include only the
last complete dump.
+GC_BACKTRACES=<n> - Generate n random backtraces (for heap profiling) after
+ each GC. Collector must have been built with
+ KEEP_BACK_PTRS. This won't generate useful output unless
+ most objects in the heap were allocated through debug
+ allocators. This is intended to be only a statistical
+ sample; individual traces may be erroneous due to
+ concurrent heap mutation.
+
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
@@ -86,12 +94,27 @@ GC_RETRY_SIGNALS, GC_NO_RETRY_SIGNALS - Try to compensate for lost
was turned into a runtime flag to enable last-minute
work-arounds.
-GC_IGNORE_FB - (Currently win32 only.) Try to avoid treating a mapped
+GC_IGNORE_FB[=<n>] - (Win32 only.) Try to avoid treating a mapped
frame buffer as part of the root set. Certain (higher end?)
- graphics cards seems to result in the frame buffer mapped
+ graphics cards seems to result in the graphics memory mapped
into the user address space as writable memory.
Unfortunately, there seems to be no systematic way to
- identify such memory.
+ identify such memory. Setting the environment variable to n
+ causes the collector to ignore mappings longer than n MB.
+ The default value of n is currently 15. (This should cover
+ a 16 MB graphics card, since the mapping appears to be slightly
+ shorter than all of graphics memory. It will fail if a dll
+ writes pointers to collectable objects into a data segment
+ whose length is >= 15MB. Empirically that's rare, but
+ certainly possible.) WARNING: Security sensitive applications
+ should probably disable this feature by setting
+ GC_disallow_ignore_fb, or by building with -DNO_GETENV,
+ since small values could force collection of reachable
+ objects, which is conceivably a (difficult to exploit)
+ security hole. GC_IGNORE_FB values less than 3 MB
+ are never honored, eliminating this risk for most,
+ but not all, applications. This feature is likely to disappear
+ if/when we find a less disgusting "solution".
The following turn on runtime flags that are also program settable. Checked
only during initialization. We expect that they will usually be set through
diff --git a/doc/README.macros b/doc/README.macros
index b5fe679..df0ef2c 100644
--- a/doc/README.macros
+++ b/doc/README.macros
@@ -85,5 +85,10 @@ SRC_M3 Set if the collector is being built as a replacement of the
It's there primarily incase someone wants to port to a similar
system.
+USE_COMPILER_TLS Assume the existence of __thread-style thread-local
+ storage. Set automatically for thread-local allocation with
+ the HP/UX vendor compiler. Usable with gcc on sufficiently
+ up-to-date ELF platforms.
+
diff --git a/doc/README.win32 b/doc/README.win32
index 02e2149..6f57db1 100644
--- a/doc/README.win32
+++ b/doc/README.win32
@@ -114,7 +114,9 @@ Note that incremental collection is disabled with -DSMALL_CONFIG.
Threads
-------
-James Clark has contributed the necessary code to support win32 threads.
+
+James Clark has contributed the necessary code to support win32 threads
+with the collector in a DLL.
Use NT_THREADS_MAKEFILE (a.k.a gc.mak) instead of NT_MAKEFILE
to build this version. Note that this requires some files whose names
are more than 8 + 3 characters long. Thus you should unpack the tar file
@@ -130,10 +132,6 @@ This version relies on the collector residing in a dll.
This version currently supports incremental collection only if it is
enabled before any additional threads are created.
-Version 4.13 attempts to fix some of the earlier problems, but there
-may be other issues. If you need solid support for win32 threads, you
-might check with Geodesic Systems. Their collector must be licensed,
-but they have invested far more time in win32-specific issues.
Since 6.3alpha2, threads are also better supported in static library builds
with Microsoft tools (use NT_STATIC_THREADS_MAKEFILE) and with the GNU
@@ -145,6 +143,12 @@ created with GC_CreateThread. This can be accomplished by
including gc.h and then calling CreateThread, which is redefined
by gc.h.
+For the statically linked versions, it is required that GC_init()
+be called before other GC calls, since there seems to be no implicit way
+to initialize the allocation lock. The easiest way to ensure this in
+portable code is to call GC_INIT() from the main executable (not
+a dynamic library) before calling any other GC_ routines.
+
We strongly advise against using the TerminateThread() win32 API call,
especially with the garbage collector. Any use is likely to provoke a
crash in the GC, since it makes it impossible for the collector to
diff --git a/doc/gc.man b/doc/gc.man
index 48fee3a..2a550c7 100644
--- a/doc/gc.man
+++ b/doc/gc.man
@@ -63,9 +63,16 @@ It is also possible to use the collector to find storage leaks in programs desti
.LP
The collector may, on rare occasion produce warning messages. On UNIX machines these appear on stderr. Warning messages can be filtered, redirected, or ignored with
.I
-GC_set_warn_proc.
+GC_set_warn_proc
This is recommended for production code. See gc.h for details.
.LP
+Fully portable code should call
+.I
+GC_INIT
+from the main program before making any other GC calls.
+On most platforms this does nothing and the collector is initialized on first use.
+On a few platforms explicit initialization is necessary. And it can never hurt.
+.LP
Debugging versions of many of the above routines are provided as macros. Their names are identical to the above, but consist of all capital letters. If GC_DEBUG is defined before gc.h is included, these routines do additional checking, and allow the leak detecting version of the collector to produce slightly more useful output. Without GC_DEBUG defined, they behave exactly like the lower-case versions.
.LP
On some machines, collection will be performed incrementally after a call to
@@ -78,6 +85,8 @@ Other facilities not discussed here include limited facilities to support increm
.SH "SEE ALSO"
The README and gc.h files in the distribution. More detailed definitions of the functions exported by the collector are given there. (The above list is not complete.)
.LP
+The web site at http://www.hpl.hp.com/personal/Hans_Boehm/gc .
+.LP
Boehm, H., and M. Weiser, "Garbage Collection in an Uncooperative Environment",
\fISoftware Practice & Experience\fP, September 1988, pp. 807-820.
.LP
diff --git a/doc/gcdescr.html b/doc/gcdescr.html
index 8ecbac8..cab6bde 100644
--- a/doc/gcdescr.html
+++ b/doc/gcdescr.html
@@ -4,7 +4,7 @@
<AUTHOR> Hans-J. Boehm, HP Labs (Much of this was written at SGI)</author>
</HEAD>
<BODY>
-<H1> <I>This is under construction</i> </h1>
+<H1> <I>This is under construction, and may always be.</i> </h1>
<H1> Conservative GC Algorithmic Overview </h1>
<P>
This is a description of the algorithms and data structures used in our
@@ -27,20 +27,22 @@ We assume the default finalization model, but the code affected by that
is very localized.
<H2> Introduction </h2>
The garbage collector uses a modified mark-sweep algorithm. Conceptually
-it operates roughly in four phases:
+it operates roughly in four phases, which are performed occasionally
+as part of a memory allocation:
<OL>
<LI>
-<I>Preparation</i> Clear all mark bits, indicating that all objects
+<I>Preparation</i> Each object has an associated mark bit.
+Clear all mark bits, indicating that all objects
are potentially unreachable.
<LI>
<I>Mark phase</i> Marks all objects that can be reachable via chains of
-pointers from variables. Normally the collector has no real information
+pointers from variables. Often the collector has no real information
about the location of pointer variables in the heap, so it
views all static data areas, stacks and registers as potentially containing
-containing pointers. Any bit patterns that represent addresses inside
+pointers. Any bit patterns that represent addresses inside
heap objects managed by the collector are viewed as pointers.
Unless the client program has made heap object layout information
available to the collector, any heap objects found to be reachable from
@@ -87,8 +89,12 @@ others are not. Some may have per-object type descriptors that
determine pointer locations. Or a specific kind may correspond
to one specific object layout. Two built-in kinds are uncollectable.
One (<TT>STUBBORN</tt>) is immutable without special precautions.
-In spite of that, it is very likely that most applications currently
+In spite of that, it is very likely that most C clients of the
+collector currently
use at most two kinds: <TT>NORMAL</tt> and <TT>PTRFREE</tt> objects.
+The <A HREF="http://gcc.gnu.org/java">gcj</a> runtime also makes
+heavy use of a kind (allocated with GC_gcj_malloc) that stores
+type information at a known offset in method tables.
<P>
The collector uses a two level allocator. A large block is defined to
be one larger than half of <TT>HBLKSIZE</tt>, which is a power of 2,
@@ -175,6 +181,32 @@ for a single pool of physical memory.
<H2>Mark phase</h2>
+At each collection, the collector marks all objects that are
+possibly reachable from pointer variables. Since it cannot generally
+tell where pointer variables are located, it scans the following
+<I>root segments</i> for pointers:
+<UL>
+<LI>The registers. Depending on the architecture, this may be done using
+assembly code, or by calling a <TT>setjmp</tt>-like function which saves
+register contents on the stack.
+<LI>The stack(s). In the case of a single-threaded application,
+on most platforms this
+is done by scanning the memory between (an approximation of) the current
+stack pointer and <TT>GC_stackbottom</tt>. (For Itanium, the register stack
+scanned separately.) The <TT>GC_stackbottom</tt> variable is set in
+a highly platform-specific way depending on the appropriate configuration
+information in <TT>gcconfig.h</tt>. Note that the currently active
+stack needs to be scanned carefully, since callee-save registers of
+client code may appear inside collector stack frames, which may
+change during the mark process. This is addressed by scanning
+some sections of the stack "eagerly", effectively capturing a snapshot
+at one point in time.
+<LI>Static data region(s). In the simplest case, this is the region
+between <TT>DATASTART</tt> and <TT>DATAEND</tt>, as defined in
+<TT>gcconfig.h</tt>. However, in most cases, this will also involve
+static data regions associated with dynamic libraries. These are
+identified by the mostly platform-specific code in <TT>dyn_load.c</tt>.
+</ul>
The marker maintains an explicit stack of memory regions that are known
to be accessible, but that have not yet been searched for contained pointers.
Each stack entry contains the starting address of the block to be scanned,
@@ -182,8 +214,11 @@ as well as a descriptor of the block. If no layout information is
available for the block, then the descriptor is simply a length.
(For other possibilities, see <TT>gc_mark.h</tt>.)
<P>
-At the beginning of the mark phase, all root segments are pushed on the
-stack by <TT>GC_push_roots</tt>. If <TT>ALL_INTERIOR_PTRS</tt> is not
+At the beginning of the mark phase, all root segments
+(as described above) are pushed on the
+stack by <TT>GC_push_roots</tt>. (Registers and eagerly processed
+stack sections are processed by pushing the referenced objects instead
+of the stack section itself.) If <TT>ALL_INTERIOR_PTRS</tt> is not
defined, then stack roots require special treatment. In this case, the
normal marking code ignores interior pointers, but <TT>GC_push_all_stack</tt>
explicitly checks for interior pointers and pushes descriptors for target
@@ -479,8 +514,9 @@ if there is low demand for small pointerfree objects.
We support several different threading models. Unfortunately Pthreads,
the only reasonably well standardized thread model, supports too narrow
an interface for conservative garbage collection. There appears to be
-no completely portable way to allow the collector to coexist with various Pthreads
-implementations. Hence we currently support only a few of the more
+no completely portable way to allow the collector
+to coexist with various Pthreads
+implementations. Hence we currently support only the more
common Pthreads implementations.
<P>
In particular, it is very difficult for the collector to stop all other
@@ -510,6 +546,10 @@ accomplished with <TT># define</tt>'s in <TT>gc.h</tt>
(really <TT>gc_pthread_redirects.h</tt>), or optionally
by using ld's function call wrapping mechanism under Linux.
<P>
+Recent versions of the collector support several facilites to enhance
+the processor-scalability and thread performance of the collector.
+These are discussed in more detail <A HREF="scale.html">here</a>.
+<P>
Comments are appreciated. Please send mail to
<A HREF="mailto:boehm@acm.org"><TT>boehm@acm.org</tt></a> or
<A HREF="mailto:Hans.Boehm@hp.com"><TT>Hans.Boehm@hp.com</tt></a>
diff --git a/dyn_load.c b/dyn_load.c
index 30a5755..70eb764 100644
--- a/dyn_load.c
+++ b/dyn_load.c
@@ -727,6 +727,18 @@ void GC_register_dynamic_libraries()
# define HAVE_REGISTER_MAIN_STATIC_DATA
+ GC_bool GC_warn_fb = TRUE; /* Warn about traced likely */
+ /* graphics memory. */
+ GC_bool GC_disallow_ignore_fb = FALSE;
+ int GC_ignore_fb_mb; /* Ignore mappings bigger than the */
+ /* specified number of MB. */
+ GC_bool GC_ignore_fb = FALSE; /* Enable frame buffer */
+ /* checking. */
+
+ /* Issue warning if tracing apparent framebuffer. */
+ /* This limits us to one warning, and it's a back door to */
+ /* disable that. */
+
/* Should [start, start+len) be treated as a frame buffer */
/* and ignored? */
/* Unfortunately, we currently have no real way to tell */
@@ -734,35 +746,56 @@ void GC_register_dynamic_libraries()
/* FIXME: If we had more data on this phenomenon (e.g. */
/* is start aligned to a MB multiple?) we should be able to */
/* do better. */
+ /* Based on a very limited sample, it appears that: */
+ /* - Frame buffer mappings appear as mappings of length */
+ /* 2**n MB - 192K. (We guess the 192K can vary a bit.) */
+ /* - Have a stating address at best 64K aligned. */
+ /* I'd love more information about the mapping, since I */
+ /* can't reproduce the problem. */
static GC_bool is_frame_buffer(ptr_t start, size_t len)
{
static GC_bool initialized = FALSE;
- static GC_bool ignore_fb;
# define MB (1024*1024)
+# define DEFAULT_FB_MB 15
+# define MIN_FB_MB 3
- switch(len) {
- case 16*MB:
- case 32*MB:
- case 48*MB:
- case 64*MB:
- case 128*MB:
- case 256*MB:
- case 512*MB:
- case 1024*MB:
- break;
- default:
- return FALSE;
- }
+ if (GC_disallow_ignore_fb) return FALSE;
if (!initialized) {
- ignore_fb = (0 != GETENV("GC_IGNORE_FB"));
- if (!ignore_fb) {
- WARN("Possible frame buffer mapping at 0x%lx: \n"
- "\tConsider setting GC_IGNORE_FB to improve performance.\n",
- start);
+ char * ignore_fb_string = GETENV("GC_IGNORE_FB");
+
+ if (0 != ignore_fb_string) {
+ while (*ignore_fb_string == ' ' || *ignore_fb_string == '\t')
+ ++ignore_fb_string;
+ if (*ignore_fb_string == '\0') {
+ GC_ignore_fb_mb = DEFAULT_FB_MB;
+ } else {
+ GC_ignore_fb_mb = atoi(ignore_fb_string);
+ if (GC_ignore_fb_mb < MIN_FB_MB) {
+ WARN("Bad GC_IGNORE_FB value. Using %ld\n", DEFAULT_FB_MB);
+ GC_ignore_fb_mb = DEFAULT_FB_MB;
+ }
+ }
+ GC_ignore_fb = TRUE;
+ } else {
+ GC_ignore_fb_mb = DEFAULT_FB_MB; /* For warning */
}
initialized = TRUE;
}
- return ignore_fb;
+ if (len >= ((size_t)GC_ignore_fb_mb << 20)) {
+ if (GC_ignore_fb) {
+ return TRUE;
+ } else {
+ if (GC_warn_fb) {
+ WARN("Possible frame buffer mapping at 0x%lx: \n"
+ "\tConsider setting GC_IGNORE_FB to improve performance.\n",
+ start);
+ GC_warn_fb = FALSE;
+ }
+ return FALSE;
+ }
+ } else {
+ return FALSE;
+ }
}
# ifdef DEBUG_VIRTUALQUERY
diff --git a/finalize.c b/finalize.c
index 3b9d9f5..e103228 100644
--- a/finalize.c
+++ b/finalize.c
@@ -807,8 +807,37 @@ void (* GC_finalizer_notifier)() = (void (*) GC_PROTO((void)))0;
static GC_word last_finalizer_notification = 0;
+#ifdef KEEP_BACK_PTRS
+void GC_generate_random_backtrace_no_gc(void);
+#endif
+
void GC_notify_or_invoke_finalizers GC_PROTO((void))
{
+ /* This is a convenient place to generate backtraces if appropriate, */
+ /* since that code is not callable with the allocation lock. */
+# ifdef KEEP_BACK_PTRS
+ if (GC_backtraces > 0) {
+ static word last_back_trace_gc_no = 3; /* Skip early ones. */
+ long i;
+
+ LOCK();
+ if (GC_gc_no > last_back_trace_gc_no) {
+ /* Stops when GC_gc_no wraps; that's OK. */
+ last_back_trace_gc_no = (word)(-1); /* disable others. */
+ for (i = 0; i < GC_backtraces; ++i) {
+ /* FIXME: This tolerates concurrent heap mutation, */
+ /* which may cause occasional mysterious results. */
+ /* We need to release the GC lock, since GC_print_callers */
+ /* acquires it. It probably shouldn't. */
+ UNLOCK();
+ GC_generate_random_backtrace_no_gc();
+ LOCK();
+ }
+ last_back_trace_gc_no = GC_gc_no;
+ }
+ UNLOCK();
+ }
+# endif
if (GC_finalize_now == 0) return;
if (!GC_finalize_on_demand) {
(void) GC_invoke_finalizers();
diff --git a/gcj_mlc.c b/gcj_mlc.c
index a10a66f..8b1da82 100644
--- a/gcj_mlc.c
+++ b/gcj_mlc.c
@@ -72,46 +72,36 @@ void GC_init_gcj_malloc(int mp_index, void * /* really GC_mark_proc */mp)
GC_printf0("Gcj-style type information is disabled!\n");
}
# endif
+ GC_ASSERT(GC_mark_procs[mp_index] == (GC_mark_proc)0); /* unused */
GC_mark_procs[mp_index] = (GC_mark_proc)mp;
if (mp_index >= GC_n_mark_procs) ABORT("GC_init_gcj_malloc: bad index");
/* Set up object kind gcj-style indirect descriptor. */
- GC_gcjobjfreelist = (ptr_t *)
- GC_INTERNAL_MALLOC((MAXOBJSZ+1)*sizeof(ptr_t), PTRFREE);
- if (GC_gcjobjfreelist == 0) ABORT("Couldn't allocate GC_gcjobjfreelist");
- BZERO(GC_gcjobjfreelist, (MAXOBJSZ+1)*sizeof(ptr_t));
- GC_gcj_kind = GC_n_kinds++;
- GC_obj_kinds[GC_gcj_kind].ok_freelist = GC_gcjobjfreelist;
- GC_obj_kinds[GC_gcj_kind].ok_reclaim_list = 0;
+ GC_gcjobjfreelist = (ptr_t *)GC_new_free_list_inner();
if (ignore_gcj_info) {
/* Use a simple length-based descriptor, thus forcing a fully */
/* conservative scan. */
- GC_obj_kinds[GC_gcj_kind].ok_descriptor = (0 | GC_DS_LENGTH);
- GC_obj_kinds[GC_gcj_kind].ok_relocate_descr = TRUE;
+ GC_gcj_kind = GC_new_kind_inner((void **)GC_gcjobjfreelist,
+ (0 | GC_DS_LENGTH),
+ TRUE, TRUE);
} else {
- GC_obj_kinds[GC_gcj_kind].ok_descriptor =
- (((word)(-MARK_DESCR_OFFSET - GC_INDIR_PER_OBJ_BIAS))
- | GC_DS_PER_OBJECT);
- GC_obj_kinds[GC_gcj_kind].ok_relocate_descr = FALSE;
+ GC_gcj_kind = GC_new_kind_inner(
+ (void **)GC_gcjobjfreelist,
+ (((word)(-MARK_DESCR_OFFSET - GC_INDIR_PER_OBJ_BIAS))
+ | GC_DS_PER_OBJECT),
+ FALSE, TRUE);
}
- GC_obj_kinds[GC_gcj_kind].ok_init = TRUE;
/* Set up object kind for objects that require mark proc call. */
- GC_gcjdebugobjfreelist = (ptr_t *)
- GC_INTERNAL_MALLOC((MAXOBJSZ+1)*sizeof(ptr_t), PTRFREE);
- if (GC_gcjdebugobjfreelist == 0)
- ABORT("Couldn't allocate GC_gcjdebugobjfreelist");
- BZERO(GC_gcjdebugobjfreelist, (MAXOBJSZ+1)*sizeof(ptr_t));
- GC_gcj_debug_kind = GC_n_kinds++;
- GC_obj_kinds[GC_gcj_debug_kind].ok_freelist = GC_gcjdebugobjfreelist;
- GC_obj_kinds[GC_gcj_debug_kind].ok_reclaim_list = 0;
if (ignore_gcj_info) {
- GC_obj_kinds[GC_gcj_kind].ok_descriptor = (0 | GC_DS_LENGTH);
- GC_obj_kinds[GC_gcj_kind].ok_relocate_descr = TRUE;
+ GC_gcj_debug_kind = GC_gcj_kind;
+ GC_gcjdebugobjfreelist = GC_gcjobjfreelist;
} else {
- GC_obj_kinds[GC_gcj_debug_kind].ok_descriptor =
- GC_MAKE_PROC(mp_index, 1 /* allocated with debug info */);
- GC_obj_kinds[GC_gcj_debug_kind].ok_relocate_descr = FALSE;
+ GC_gcjdebugobjfreelist = (ptr_t *)GC_new_free_list_inner();
+ GC_gcj_debug_kind = GC_new_kind_inner(
+ (void **)GC_gcjdebugobjfreelist,
+ GC_MAKE_PROC(mp_index,
+ 1 /* allocated with debug info */),
+ FALSE, TRUE);
}
- GC_obj_kinds[GC_gcj_debug_kind].ok_init = TRUE;
UNLOCK();
ENABLE_SIGNALS();
}
@@ -124,6 +114,25 @@ ptr_t GC_clear_stack();
#define GENERAL_MALLOC_IOP(lb,k) \
(GC_PTR)GC_clear_stack(GC_generic_malloc_inner_ignore_off_page(lb, k))
+/* We need a mechanism to release the lock and invoke finalizers. */
+/* We don't really have an opportunity to do this on a rarely executed */
+/* path on which the lock is not held. Thus we check at a */
+/* rarely executed point at which it is safe to release the lock. */
+/* We do this even where we could just call GC_INVOKE_FINALIZERS, */
+/* since it's probably cheaper and certainly more uniform. */
+/* FIXME - Consider doing the same elsewhere? */
+static void maybe_finalize()
+{
+ static int last_finalized_no = 0;
+
+ if (GC_gc_no == last_finalized_no) return;
+ if (!GC_is_initialized) return;
+ UNLOCK();
+ GC_INVOKE_FINALIZERS();
+ last_finalized_no = GC_gc_no;
+ LOCK();
+}
+
/* Allocate an object, clear it, and store the pointer to the */
/* type structure (vtable in gcj). */
/* This adds a byte at the end of the object if GC_malloc would.*/
@@ -143,7 +152,8 @@ DCL_LOCK_STATE;
opp = &(GC_gcjobjfreelist[lw]);
LOCK();
op = *opp;
- if( EXPECT(op == 0, 0)) {
+ if(EXPECT(op == 0, 0)) {
+ maybe_finalize();
op = (ptr_t)GENERAL_MALLOC((word)lb, GC_gcj_kind);
if (0 == op) {
UNLOCK();
@@ -161,6 +171,7 @@ DCL_LOCK_STATE;
UNLOCK();
} else {
LOCK();
+ maybe_finalize();
op = (ptr_t)GENERAL_MALLOC((word)lb, GC_gcj_kind);
if (0 == op) {
UNLOCK();
@@ -179,10 +190,10 @@ GC_PTR GC_debug_gcj_malloc(size_t lb, void * ptr_to_struct_containing_descr,
{
GC_PTR result;
- /* We clone the code from GC_debug_gcj_malloc, so that we */
- /* dont end up with extra frames on the stack, which could */
+ /* We're careful to avoid extra calls, which could */
/* confuse the backtrace. */
LOCK();
+ maybe_finalize();
result = GC_generic_malloc_inner(lb + DEBUG_BYTES, GC_gcj_debug_kind);
if (result == 0) {
UNLOCK();
@@ -215,6 +226,7 @@ DCL_LOCK_STATE;
LOCK();
op = *opp;
if( EXPECT(op == 0, 0) ) {
+ maybe_finalize();
op = (ptr_t)GC_clear_stack(
GC_generic_malloc_words_small_inner(lw, GC_gcj_kind));
if (0 == op) {
@@ -242,6 +254,7 @@ void * GC_debug_gcj_fast_malloc(size_t lw,
/* dont end up with extra frames on the stack, which could */
/* confuse the backtrace. */
LOCK();
+ maybe_finalize();
result = GC_generic_malloc_inner(lb + DEBUG_BYTES, GC_gcj_debug_kind);
if (result == 0) {
UNLOCK();
@@ -278,6 +291,7 @@ DCL_LOCK_STATE;
opp = &(GC_gcjobjfreelist[lw]);
LOCK();
if( (op = *opp) == 0 ) {
+ maybe_finalize();
op = (ptr_t)GENERAL_MALLOC_IOP(lb, GC_gcj_kind);
# ifdef MERGE_SIZES
lw = GC_size_map[lb]; /* May have been uninitialized. */
@@ -289,6 +303,8 @@ DCL_LOCK_STATE;
*(void **)op = ptr_to_struct_containing_descr;
UNLOCK();
} else {
+ LOCK();
+ maybe_finalize();
op = (ptr_t)GENERAL_MALLOC_IOP(lb, GC_gcj_kind);
if (0 != op) {
*(void **)op = ptr_to_struct_containing_descr;
diff --git a/include/Makefile.in b/include/Makefile.in
index 9ade270..b1c4184 100644
--- a/include/Makefile.in
+++ b/include/Makefile.in
@@ -106,6 +106,7 @@ PACKAGE = @PACKAGE@
RANLIB = @RANLIB@
STRIP = @STRIP@
THREADLIBS = @THREADLIBS@
+UNWINDLIBS = @UNWINDLIBS@
VERSION = @VERSION@
addincludes = @addincludes@
addlibs = @addlibs@
diff --git a/include/gc.h b/include/gc.h
index 1aacdb3..58a2ff5 100644
--- a/include/gc.h
+++ b/include/gc.h
@@ -52,11 +52,18 @@
/* even semi-portably. The following is probably no better/worse */
/* than almost anything else. */
/* The ANSI standard suggests that size_t and ptr_diff_t might be */
-/* better choices. But those appear to have incorrect definitions */
-/* on may systems. Notably "typedef int size_t" seems to be both */
-/* frequent and WRONG. */
-typedef unsigned long GC_word;
-typedef long GC_signed_word;
+/* better choices. But those had incorrect definitions on some older */
+/* systems. Notably "typedef int size_t" is WRONG. */
+#ifndef _WIN64
+ typedef unsigned long GC_word;
+ typedef long GC_signed_word;
+#else
+ /* Win64 isn't really supported yet, but this is the first step. And */
+ /* it might cause error messages to show up in more plausible places. */
+ /* This needs basetsd.h, which is included by windows.h. */
+ typedef ULONG_PTR GC_word;
+ typedef LONG_PTR GC_word;
+#endif
/* Public read-only variables */
@@ -462,14 +469,19 @@ GC_API GC_PTR GC_malloc_atomic_ignore_off_page GC_PROTO((size_t lb));
# include <features.h>
# if (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 1 || __GLIBC__ > 2) \
&& !defined(__ia64__)
-# define GC_HAVE_BUILTIN_BACKTRACE
-# define GC_CAN_SAVE_CALL_STACKS
+# ifndef GC_HAVE_BUILTIN_BACKTRACE
+# define GC_HAVE_BUILTIN_BACKTRACE
+# endif
# endif
# if defined(__i386__) || defined(__x86_64__)
# define GC_CAN_SAVE_CALL_STACKS
# endif
#endif
+#if defined(GC_HAVE_BUILTIN_BACKTRACE) && !defined(GC_CAN_SAVE_CALL_STACKS)
+# define GC_CAN_SAVE_CALL_STACKS
+#endif
+
#if defined(__sparc__)
# define GC_CAN_SAVE_CALL_STACKS
#endif
@@ -596,7 +608,7 @@ GC_API GC_PTR GC_debug_realloc_replacement
/* Finalization. Some of these primitives are grossly unsafe. */
/* The idea is to make them both cheap, and sufficient to build */
-/* a safer layer, closer to PCedar finalization. */
+/* a safer layer, closer to Modula-3, Java, or PCedar finalization. */
/* The interface represents my conclusions from a long discussion */
/* with Alan Demers, Dan Greene, Carl Hauser, Barry Hayes, */
/* Christian Jacobi, and Russ Atkinson. It's not perfect, and */
@@ -911,13 +923,19 @@ extern void GC_thr_init(); /* Needed for Solaris/X86 */
#endif /* defined(GC_WIN32_THREADS) && !cygwin */
-/*
- * If you are planning on putting
- * the collector in a SunOS 5 dynamic library, you need to call GC_INIT()
- * from the statically loaded program section.
- * This circumvents a Solaris 2.X (X<=4) linker bug.
- */
+ /*
+ * Fully portable code should call GC_INIT() from the main program
+ * before making any other GC_ calls. On most platforms this is a
+ * no-op and the collector self-initializes. But a number of platforms
+ * make that too hard.
+ */
#if defined(sparc) || defined(__sparc)
+ /*
+ * If you are planning on putting
+ * the collector in a SunOS 5 dynamic library, you need to call GC_INIT()
+ * from the statically loaded program section.
+ * This circumvents a Solaris 2.X (X<=4) linker bug.
+ */
# define GC_INIT() { extern end, etext; \
GC_noop(&end, &etext); }
#else
@@ -932,9 +950,9 @@ extern void GC_thr_init(); /* Needed for Solaris/X86 */
# define GC_INIT() { GC_init(); }
# else
# define GC_INIT()
-# endif
-# endif
-#endif
+# endif /* !__MACH && !GC_WIN32_THREADS */
+# endif /* !AIX && !cygwin */
+#endif /* !sparc */
#if !defined(_WIN32_WCE) \
&& ((defined(_MSDOS) || defined(_MSC_VER)) && (_M_IX86 >= 300) \
diff --git a/include/gc_config_macros.h b/include/gc_config_macros.h
index 0c836d8..4aaca2d 100644
--- a/include/gc_config_macros.h
+++ b/include/gc_config_macros.h
@@ -106,8 +106,9 @@
#endif
# define __GC
-# include <stddef.h>
-# ifdef _WIN32_WCE
+# ifndef _WIN32_WCE
+# include <stddef.h>
+# else /* ! _WIN32_WCE */
/* Yet more kluges for WinCE */
# include <stdlib.h> /* size_t is defined here */
typedef long ptrdiff_t; /* ptrdiff_t is not defined */
diff --git a/include/gc_cpp.h b/include/gc_cpp.h
index d789a37..c4d8b50 100644
--- a/include/gc_cpp.h
+++ b/include/gc_cpp.h
@@ -152,6 +152,11 @@ by UseGC. GC is an alias for UseGC, unless GC_NAME_CONFLICT is defined.
# define GC_OPERATOR_NEW_ARRAY
#endif
+#if ! defined ( __BORLANDC__ ) /* Confuses the Borland compiler. */ \
+ && ! defined ( __sgi )
+# define GC_PLACEMENT_DELETE
+#endif
+
enum GCPlacement {UseGC,
#ifndef GC_NAME_CONFLICT
GC=UseGC,
@@ -165,7 +170,7 @@ class gc {public:
/* Must be redefined here, since the other overloadings */
/* hide the global definition. */
inline void operator delete( void* obj );
-# ifndef __BORLANDC__ /* Confuses the Borland compiler. */
+# ifdef GC_PLACEMENT_DELETE
inline void operator delete( void*, void* );
# endif
@@ -174,7 +179,7 @@ class gc {public:
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__
+# ifdef GC_PLACEMENT_DELETE
inline void gc::operator delete[]( void*, void* );
# endif
#endif /* GC_OPERATOR_NEW_ARRAY */
@@ -282,7 +287,7 @@ inline void* gc::operator new( size_t size, void *p ) {
inline void gc::operator delete( void* obj ) {
GC_FREE( obj );}
-#ifndef __BORLANDC__
+#ifdef GC_PLACEMENT_DELETE
inline void gc::operator delete( void*, void* ) {}
#endif
@@ -300,7 +305,7 @@ inline void* gc::operator new[]( size_t size, void *p ) {
inline void gc::operator delete[]( void* obj ) {
gc::operator delete( obj );}
-#ifndef __BORLANDC__
+#ifdef GC_PLACEMENT_DELETE
inline void gc::operator delete[]( void*, void* ) {}
#endif
diff --git a/include/gc_gcj.h b/include/gc_gcj.h
index 5e932af..5e79e27 100644
--- a/include/gc_gcj.h
+++ b/include/gc_gcj.h
@@ -53,7 +53,7 @@
/* respectively for the allocated objects. Mark_proc will be */
/* used to build the descriptor for objects allocated through the */
/* debugging interface. The mark_proc will be invoked on all such */
-/* objects with an "environment" value of 1. The client may chose */
+/* objects with an "environment" value of 1. The client may choose */
/* to use the same mark_proc for some of its generated mark descriptors.*/
/* In that case, it should use a different "environment" value to */
/* detect the presence or absence of the debug header. */
@@ -88,6 +88,17 @@ extern void * GC_debug_gcj_fast_malloc(size_t lw,
extern void * GC_gcj_malloc_ignore_off_page(size_t lb,
void * ptr_to_struct_containing_descr);
+/* The kind numbers of normal and debug gcj objects. */
+/* Useful only for debug support, we hope. */
+extern int GC_gcj_kind;
+
+extern int GC_gcj_debug_kind;
+
+# if defined(GC_LOCAL_ALLOC_H) && defined(GC_REDIRECT_TO_LOCAL)
+ --> gc_local_alloc.h should be included after this. Otherwise
+ --> we undo the redirection.
+# endif
+
# ifdef GC_DEBUG
# define GC_GCJ_MALLOC(s,d) GC_debug_gcj_malloc(s,d,GC_EXTRAS)
# define GC_GCJ_FAST_MALLOC(s,d) GC_debug_gcj_fast_malloc(s,d,GC_EXTRAS)
diff --git a/include/gc_local_alloc.h b/include/gc_local_alloc.h
index 88e29e9..1874c7b 100644
--- a/include/gc_local_alloc.h
+++ b/include/gc_local_alloc.h
@@ -61,6 +61,7 @@ GC_PTR GC_local_malloc_atomic(size_t bytes);
#endif
# ifdef GC_DEBUG
+ /* We don't really use local allocation in this case. */
# define GC_LOCAL_MALLOC(s) GC_debug_malloc(s,GC_EXTRAS)
# define GC_LOCAL_MALLOC_ATOMIC(s) GC_debug_malloc_atomic(s,GC_EXTRAS)
# ifdef GC_GCJ_SUPPORT
diff --git a/include/gc_mark.h b/include/gc_mark.h
index 9ddba2c..953bb74 100644
--- a/include/gc_mark.h
+++ b/include/gc_mark.h
@@ -19,10 +19,8 @@
* This interface should not be used by normal C or C++ clients.
* It will be useful to runtimes for other languages.
*
- * Note that this file is not "namespace-clean", i.e. it introduces names
- * not prefixed with GC_, which may collide with the client's names. It
- * should be included only in those few places that directly provide
- * information to the collector.
+ * This is an experts-only interface! There are many ways to break the
+ * collector in subtle ways by using this functionality.
*/
#ifndef GC_MARK_H
# define GC_MARK_H
@@ -143,5 +141,63 @@ struct GC_ms_entry *GC_mark_and_push
GC_mark_and_push(obj, msp, lim, src) : \
msp)
+extern size_t GC_debug_header_size;
+ /* The size of the header added to objects allocated through */
+ /* the GC_debug routines. */
+ /* Defined as a variable so that client mark procedures don't */
+ /* need to be recompiled for collector version changes. */
+#define GC_USR_PTR_FROM_BASE(p) ((GC_PTR)((char *)(p) + GC_debug_header_size))
+
+/* And some routines to support creation of new "kinds", e.g. with */
+/* custom mark procedures, by language runtimes. */
+/* The _inner versions assume the caller holds the allocation lock. */
+
+/* Return a new free list array. */
+void ** GC_new_free_list GC_PROTO((void));
+void ** GC_new_free_list_inner GC_PROTO((void));
+
+/* Return a new kind, as specified. */
+int GC_new_kind GC_PROTO((void **free_list, GC_word mark_descriptor_template,
+ int add_size_to_descriptor, int clear_new_objects));
+ /* The last two parameters must be zero or one. */
+int GC_new_kind_inner GC_PROTO((void **free_list,
+ GC_word mark_descriptor_template,
+ int add_size_to_descriptor,
+ int clear_new_objects));
+
+/* Return a new mark procedure identifier, suitable for use as */
+/* the first argument in GC_MAKE_PROC. */
+int GC_new_proc GC_PROTO((GC_mark_proc));
+int GC_new_proc_inner GC_PROTO((GC_mark_proc));
+
+/* Allocate an object of a given kind. Note that in multithreaded */
+/* contexts, this is usually unsafe for kinds that have the descriptor */
+/* in the object itself, since there is otherwise a window in which */
+/* the descriptor is not correct. Even in the single-threaded case, */
+/* we need to be sure that cleared objects on a free list don't */
+/* cause a GC crash if they are accidentally traced. */
+/* ptr_t */char * GC_generic_malloc GC_PROTO((GC_word lb, int k));
+
+/* FIXME - Should return void *, but that requires other changes. */
+
+typedef void (*GC_describe_type_fn) GC_PROTO((void *p, char *out_buf));
+ /* A procedure which */
+ /* produces a human-readable */
+ /* description of the "type" of object */
+ /* p into the buffer out_buf of length */
+ /* GC_TYPE_DESCR_LEN. This is used by */
+ /* the debug support when printing */
+ /* objects. */
+ /* These functions should be as robust */
+ /* as possible, though we do avoid */
+ /* invoking them on objects on the */
+ /* global free list. */
+# define GC_TYPE_DESCR_LEN 40
+
+void GC_register_describe_type_fn GC_PROTO((int kind, GC_describe_type_fn knd));
+ /* Register a describe_type function */
+ /* to be used when printing objects */
+ /* of a particular kind. */
+
#endif /* GC_MARK_H */
diff --git a/include/javaxfc.h b/include/javaxfc.h
index 880020c..23e0100 100644
--- a/include/javaxfc.h
+++ b/include/javaxfc.h
@@ -18,24 +18,4 @@
*/
void GC_finalize_all();
-/*
- * A version of GC_register_finalizer that allows the object to be
- * finalized before the objects it references. This is again error
- * prone, in that it makes it easy to accidentally reference finalized
- * objects. Again, recommended only for JVM implementors.
- */
-void GC_register_finalizer_no_order(GC_PTR obj,
- GC_finalization_proc fn, GC_PTR cd,
- GC_finalization_proc *ofn, GC_PTR * ocd);
-
-void GC_debug_register_finalizer_no_order(GC_PTR obj,
- GC_finalization_proc fn, GC_PTR cd,
- GC_finalization_proc *ofn, GC_PTR * ocd);
-#ifdef GC_DEBUG
-# define GC_REGISTER_FINALIZER(p, f, d, of, od) \
- GC_debug_register_finalizer_no_order(p, f, d, of, od)
-#else
-# define GC_REGISTER_FINALIZER(p, f, d, of, od) \
- GC_register_finalizer_no_order(p, f, d, of, od)
-#endif
diff --git a/include/private/dbg_mlc.h b/include/private/dbg_mlc.h
index e2003e6..e0a994d 100644
--- a/include/private/dbg_mlc.h
+++ b/include/private/dbg_mlc.h
@@ -123,7 +123,6 @@ typedef struct {
# 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)
diff --git a/include/private/gc_priv.h b/include/private/gc_priv.h
index 4c74b0a..b957691 100644
--- a/include/private/gc_priv.h
+++ b/include/private/gc_priv.h
@@ -615,6 +615,10 @@ extern GC_warn_proc GC_current_warn_proc;
# define LOG_PHT_ENTRIES 16 /* Collisions are likely if heap grows */
/* to more than 64K hblks >= 256MB. */
/* Each hash table occupies 8K bytes. */
+ /* Even for somewhat smaller heaps, */
+ /* say half that, collisions may be an */
+ /* issue because we blacklist */
+ /* addresses outside the heap. */
# endif
# endif
# define PHT_ENTRIES ((word)1 << LOG_PHT_ENTRIES)
@@ -1611,7 +1615,7 @@ void GC_collect_a_little_inner GC_PROTO((int n));
/* collection work, if appropriate. */
/* A unit is an amount appropriate for */
/* HBLKSIZE bytes of allocation. */
-ptr_t GC_generic_malloc GC_PROTO((word lb, int k));
+/* ptr_t GC_generic_malloc GC_PROTO((word lb, int k)); */
/* Allocate an object of the given */
/* kind. By default, there are only */
/* a few kinds: composite(pointerfree), */
@@ -1621,6 +1625,7 @@ ptr_t GC_generic_malloc GC_PROTO((word lb, int k));
/* internals to add more, e.g. to */
/* communicate object layout info */
/* to the collector. */
+ /* The actual decl is in gc_mark.h. */
ptr_t GC_generic_malloc_ignore_off_page GC_PROTO((size_t b, int k));
/* As above, but pointers past the */
/* first page of the resulting object */
@@ -1718,6 +1723,10 @@ extern GC_bool GC_print_stats; /* Produce at least some logging output */
# define COND_DUMP
#endif
+#ifdef KEEP_BACK_PTRS
+ extern long GC_backtraces;
+#endif
+
/* Macros used for collector internal allocation. */
/* These assume the collector lock is held. */
#ifdef DBG_HDRS_ALL
diff --git a/include/private/gcconfig.h b/include/private/gcconfig.h
index a3cc095..734bd85 100644
--- a/include/private/gcconfig.h
+++ b/include/private/gcconfig.h
@@ -2,7 +2,7 @@
* Copyright 1988, 1989 Hans-J. Boehm, Alan J. Demers
* Copyright (c) 1991-1994 by Xerox Corporation. All rights reserved.
* Copyright (c) 1996 by Silicon Graphics. All rights reserved.
- * Copyright (c) 2000 by Hewlett-Packard Company. All rights reserved.
+ * Copyright (c) 2000-2004 Hewlett-Packard Development Company, L.P.
*
* THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
* OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
@@ -350,6 +350,11 @@
# define MSWIN32 /* or Win32s */
# define mach_type_known
# endif
+# if defined(_MSC_VER) && defined(_M_IA64)
+# define IA64
+# define MSWIN32 /* Really win64, but we don't treat 64-bit */
+ /* variants as a differnt platform. */
+# endif
# endif
# if defined(__DJGPP__)
# define I386
@@ -926,10 +931,17 @@
# ifdef I386
# define MACH_TYPE "I386"
-# define ALIGNMENT 4 /* Appears to hold for all "32 bit" compilers */
+# if defined(__LP64__) || defined(_WIN64)
+# define CPP_WORDSZ 64
+# define ALIGNMENT 8
+# else
+# define CPP_WORDSZ 32
+# define ALIGNMENT 4
+ /* Appears to hold for all "32 bit" compilers */
/* except Borland. The -a4 option fixes */
/* Borland. */
/* Ivan Demakov: For Watcom the option is -zp4. */
+# endif
# ifndef SMALL_CONFIG
# define ALIGN_DOUBLE /* Not strictly necessary, but may give speed */
/* improvement on Pentiums. */
@@ -1628,6 +1640,19 @@
# endif // __INTEL_COMPILER
# endif
# endif
+# ifdef MSWIN32
+ /* FIXME: This is a very partial guess. There is no port, yet. */
+# define OS_TYPE "MSWIN32"
+ /* STACKBOTTOM and DATASTART are handled specially in */
+ /* os_dep.c. */
+# define DATAEND /* not needed */
+# if defined(_WIN64)
+# define CPP_WORDSZ 64
+# else
+# define CPP_WORDSZ 32 /* Is this possible? */
+# endif
+# define ALIGNMENT 8
+# endif
# endif
# ifdef M88K
@@ -2000,6 +2025,10 @@
# define USE_GENERIC_PUSH_REGS
# endif
+# if defined(MSWINCE)
+# define NO_GETENV
+# endif
+
# if defined(SPARC)
# define ASM_CLEAR_CODE /* Stack clearing is crucial, and we */
/* include assembly code to do it well. */
diff --git a/include/private/pthread_support.h b/include/private/pthread_support.h
index b65a877..d52e4da 100644
--- a/include/private/pthread_support.h
+++ b/include/private/pthread_support.h
@@ -94,9 +94,9 @@ GC_thread GC_lookup_thread(pthread_t id);
void GC_stop_init();
extern GC_bool GC_in_thread_creation;
- /* Currently in thread creation. Protected by allocation lock. */
- /* While in thread creation, it is OK to run GC from unknown */
- /* thread. */
+ /* We may currently be in thread creation or destruction. */
+ /* Only set to TRUE while allocation lock is held. */
+ /* When set, it is OK to run GC from unknown thread. */
#endif /* GC_PTHREADS && !GC_SOLARIS_THREADS.... etc */
#endif /* GC_PTHREAD_SUPPORT_H */
diff --git a/malloc.c b/malloc.c
index edcbbc5..cb3f376 100644
--- a/malloc.c
+++ b/malloc.c
@@ -36,6 +36,7 @@ register struct obj_kind * kind;
/* Allocate a large block of size lw words. */
/* The block is not cleared. */
/* Flags is 0 or IGNORE_OFF_PAGE. */
+/* We hold the allocation lock. */
ptr_t GC_alloc_large(lw, k, flags)
word lw;
int k;
@@ -76,6 +77,7 @@ unsigned flags;
/* Allocate a large block of size lb bytes. Clear if appropriate. */
+/* We hold the allocation lock. */
ptr_t GC_alloc_large_and_clear(lw, k, flags)
word lw;
int k;
@@ -217,7 +219,7 @@ register int k;
GC_words_allocd += lw;
UNLOCK();
ENABLE_SIGNALS();
- if (init & !GC_debugging_started && 0 != result) {
+ if (init && !GC_debugging_started && 0 != result) {
BZERO(result, n_blocks * HBLKSIZE);
}
}
diff --git a/mallocx.c b/mallocx.c
index 7c0bdcf..d45f21e 100644
--- a/mallocx.c
+++ b/mallocx.c
@@ -214,7 +214,7 @@ register int k;
if (0 == result) {
return((*GC_oom_fn)(lb));
} else {
- if (init & !GC_debugging_started) {
+ if (init && !GC_debugging_started) {
BZERO(result, n_blocks * HBLKSIZE);
}
return(result);
diff --git a/misc.c b/misc.c
index 8abaf22..5b10fee 100644
--- a/misc.c
+++ b/misc.c
@@ -116,6 +116,11 @@ GC_bool GC_print_back_height = 0;
GC_bool GC_dump_regularly = 0; /* Generate regular debugging dumps. */
#endif
+#ifdef KEEP_BACK_PTRS
+ long GC_backtraces = 0; /* Number of random backtraces to */
+ /* generate for each GC. */
+#endif
+
#ifdef FIND_LEAK
int GC_find_leak = 1;
#else
@@ -585,6 +590,15 @@ void GC_init_inner()
GC_dump_regularly = 1;
}
# endif
+# ifdef KEEP_BACK_PTRS
+ {
+ char * backtraces_string = GETENV("GC_BACKTRACES");
+ if (0 != backtraces_string) {
+ GC_backtraces = atol(backtraces_string);
+ if (backtraces_string[0] == '\0') GC_backtraces = 1;
+ }
+ }
+# endif
if (0 != GETENV("GC_FIND_LEAK")) {
GC_find_leak = 1;
# ifdef __STDC__
@@ -1041,7 +1055,6 @@ GC_CONST char * msg;
{
# if defined(MSWIN32)
(void) MessageBoxA(NULL, msg, "Fatal error in gc", MB_ICONERROR|MB_OK);
- DebugBreak();
# else
GC_err_printf1("%s\n", msg);
# endif
@@ -1052,7 +1065,7 @@ GC_CONST char * msg;
/* about threads. */
for(;;) {}
}
-# ifdef MSWIN32
+# if defined(MSWIN32) || defined(MSWINCE)
DebugBreak();
# else
(void) abort();
@@ -1074,6 +1087,75 @@ void GC_disable()
UNLOCK();
}
+/* Helper procedures for new kind creation. */
+void ** GC_new_free_list_inner()
+{
+ void *result = GC_INTERNAL_MALLOC((MAXOBJSZ+1)*sizeof(ptr_t), PTRFREE);
+ if (result == 0) ABORT("Failed to allocate freelist for new kind");
+ BZERO(result, (MAXOBJSZ+1)*sizeof(ptr_t));
+ return result;
+}
+
+void ** GC_new_free_list()
+{
+ void *result;
+ LOCK(); DISABLE_SIGNALS();
+ result = GC_new_free_list_inner();
+ UNLOCK(); ENABLE_SIGNALS();
+ return result;
+}
+
+int GC_new_kind_inner(fl, descr, adjust, clear)
+void **fl;
+GC_word descr;
+int adjust;
+int clear;
+{
+ int result = GC_n_kinds++;
+
+ if (GC_n_kinds > MAXOBJKINDS) ABORT("Too many kinds");
+ GC_obj_kinds[result].ok_freelist = (ptr_t *)fl;
+ GC_obj_kinds[result].ok_reclaim_list = 0;
+ GC_obj_kinds[result].ok_descriptor = descr;
+ GC_obj_kinds[result].ok_relocate_descr = adjust;
+ GC_obj_kinds[result].ok_init = clear;
+ return result;
+}
+
+int GC_new_kind(fl, descr, adjust, clear)
+void **fl;
+GC_word descr;
+int adjust;
+int clear;
+{
+ int result;
+ LOCK(); DISABLE_SIGNALS();
+ result = GC_new_kind_inner(fl, descr, adjust, clear);
+ UNLOCK(); ENABLE_SIGNALS();
+ return result;
+}
+
+int GC_new_proc_inner(proc)
+GC_mark_proc proc;
+{
+ int result = GC_n_mark_procs++;
+
+ if (GC_n_mark_procs > MAX_MARK_PROCS) ABORT("Too many mark procedures");
+ GC_mark_procs[result] = proc;
+ return result;
+}
+
+int GC_new_proc(proc)
+GC_mark_proc proc;
+{
+ int result;
+ LOCK(); DISABLE_SIGNALS();
+ result = GC_new_proc_inner(proc);
+ UNLOCK(); ENABLE_SIGNALS();
+ return result;
+}
+
+
#if !defined(NO_DEBUGGING)
void GC_dump()
diff --git a/os_dep.c b/os_dep.c
index 019220f..cb32bdd 100644
--- a/os_dep.c
+++ b/os_dep.c
@@ -87,6 +87,12 @@
# endif
#endif
+#if (defined(NETBSD) || defined(OPENBSD)) && defined(__ELF__) \
+ && !defined(NEED_FIND_LIMIT)
+ /* Used by GC_init_netbsd_elf() below. */
+# define NEED_FIND_LIMIT
+#endif
+
#ifdef NEED_FIND_LIMIT
# include <setjmp.h>
#endif
@@ -111,7 +117,10 @@
# include <sys/uio.h>
# include <malloc.h> /* for locking */
#endif
-#ifdef USE_MMAP
+#if defined(USE_MMAP) || defined(USE_MUNMAP)
+# ifndef USE_MMAP
+ --> USE_MUNMAP requires USE_MMAP
+# endif
# include <sys/types.h>
# include <sys/mman.h>
# include <sys/stat.h>
@@ -710,16 +719,12 @@ ptr_t GC_get_stack_base()
struct sigaction act;
act.sa_handler = h;
-# if defined(SUNOS5SIGS) || defined(NETBSD)
+# if 0 /* Was necessary for Solaris 2.3 and very temporary */
+ /* NetBSD bugs. */
act.sa_flags = SA_RESTART | SA_NODEFER;
# else
act.sa_flags = SA_RESTART;
# endif
- /* The presence of SA_NODEFER represents yet another gross */
- /* hack. Under Solaris 2.3, siglongjmp doesn't appear to */
- /* interact correctly with -lthread. We hide the confusion */
- /* by making sure that signal handling doesn't affect the */
- /* signal mask. */
(void) sigemptyset(&act.sa_mask);
# ifdef GC_IRIX_THREADS
@@ -749,7 +754,7 @@ ptr_t GC_get_stack_base()
# ifdef NEED_FIND_LIMIT
/* Some tools to implement HEURISTIC2 */
# define MIN_PAGE_SIZE 256 /* Smallest conceivable page size, bytes */
- /* static */ jmp_buf GC_jmp_buf;
+ /* static */ JMP_BUF GC_jmp_buf;
/*ARGSUSED*/
void GC_fault_handler(sig)
@@ -927,7 +932,11 @@ ptr_t GC_get_stack_base()
size_t i, buf_offset = 0;
/* First try the easy way. This should work for glibc 2.2 */
- if (0 != &__libc_stack_end) {
+ /* This fails in a prelinked ("prelink" command) executable */
+ /* since the correct value of __libc_stack_end never */
+ /* becomes visible to us. The second test works around */
+ /* this. */
+ if (0 != &__libc_stack_end && 0 != __libc_stack_end ) {
# ifdef IA64
/* Some versions of glibc set the address 16 bytes too */
/* low while the initialization code is running. */
@@ -1521,8 +1530,7 @@ word bytes;
#else /* Not RS6000 */
-#if defined(USE_MMAP)
-/* Tested only under Linux, IRIX5 and Solaris 2 */
+#if defined(USE_MMAP) || defined(USE_MUNMAP)
#ifdef USE_MMAP_FIXED
# define GC_MMAP_FLAGS MAP_FIXED | MAP_PRIVATE
@@ -1532,10 +1540,6 @@ word bytes;
# define GC_MMAP_FLAGS MAP_PRIVATE
#endif
-#ifndef HEAP_START
-# define HEAP_START 0
-#endif
-
#ifdef USE_MMAP_ANON
# define zero_fd -1
# if defined(MAP_ANONYMOUS)
@@ -1548,6 +1552,15 @@ word bytes;
# define OPT_MAP_ANON 0
#endif
+#endif /* defined(USE_MMAP) || defined(USE_MUNMAP) */
+
+#if defined(USE_MMAP)
+/* Tested only under Linux, IRIX5 and Solaris 2 */
+
+#ifndef HEAP_START
+# define HEAP_START 0
+#endif
+
ptr_t GC_unix_get_mem(bytes)
word bytes;
{
@@ -3932,13 +3945,15 @@ kern_return_t catch_exception_raise_state_identity(
#endif /* NEED_CALLINFO */
+#if defined(GC_HAVE_BUILTIN_BACKTRACE)
+# include <execinfo.h>
+#endif
+
#ifdef SAVE_CALL_CHAIN
#if NARGS == 0 && NFRAMES % 2 == 0 /* No padding */ \
&& defined(GC_HAVE_BUILTIN_BACKTRACE)
-#include <execinfo.h>
-
void GC_save_callers (info)
struct callinfo info[NFRAMES];
{
@@ -4014,6 +4029,8 @@ struct callinfo info[NFRAMES];
static int reentry_count = 0;
GC_bool stop = FALSE;
+ /* FIXME: This should probably use a different lock, so that we */
+ /* become callable with or without the allocation lock. */
LOCK();
++reentry_count;
UNLOCK();
@@ -4048,7 +4065,8 @@ struct callinfo info[NFRAMES];
# ifdef LINUX
FILE *pipe;
# endif
-# if defined(GC_HAVE_BUILTIN_BACKTRACE)
+# if defined(GC_HAVE_BUILTIN_BACKTRACE) \
+ && !defined(GC_BACKTRACE_SYMBOLS_BROKEN)
char **sym_name =
backtrace_symbols((void **)(&(info[i].ci_pc)), 1);
char *name = sym_name[0];
@@ -4141,7 +4159,8 @@ struct callinfo info[NFRAMES];
}
# endif /* LINUX */
GC_err_printf1("\t\t%s\n", name);
-# if defined(GC_HAVE_BUILTIN_BACKTRACE)
+# if defined(GC_HAVE_BUILTIN_BACKTRACE) \
+ && !defined(GC_BACKTRACE_SYMBOLS_BROKEN)
free(sym_name); /* May call GC_free; that's OK */
# endif
}
diff --git a/pthread_support.c b/pthread_support.c
index 85962a9..5bb157f 100644
--- a/pthread_support.c
+++ b/pthread_support.c
@@ -54,8 +54,17 @@
&& !defined(GC_AIX_THREADS)
# if defined(GC_HPUX_THREADS) && !defined(USE_PTHREAD_SPECIFIC) \
- && !defined(USE_HPUX_TLS)
-# define USE_HPUX_TLS
+ && !defined(USE_COMPILER_TLS)
+# ifdef __GNUC__
+# define USE_PTHREAD_SPECIFIC
+ /* Empirically, as of gcc 3.3, USE_COMPILER_TLS doesn't work. */
+# else
+# define USE_COMPILER_TLS
+# endif
+# endif
+
+# if defined USE_HPUX_TLS
+ --> Macro replaced by USE_COMPILER_TLS
# endif
# if (defined(GC_DGUX386_THREADS) || defined(GC_OSF1_THREADS) || \
@@ -72,7 +81,7 @@
# endif
# ifdef THREAD_LOCAL_ALLOC
-# if !defined(USE_PTHREAD_SPECIFIC) && !defined(USE_HPUX_TLS)
+# if !defined(USE_PTHREAD_SPECIFIC) && !defined(USE_COMPILER_TLS)
# include "private/specific.h"
# endif
# if defined(USE_PTHREAD_SPECIFIC)
@@ -81,7 +90,7 @@
# define GC_key_create pthread_key_create
typedef pthread_key_t GC_key_t;
# endif
-# if defined(USE_HPUX_TLS)
+# if defined(USE_COMPILER_TLS)
# define GC_getspecific(x) (x)
# define GC_setspecific(key, v) ((key) = (v), 0)
# define GC_key_create(key, d) 0
@@ -159,7 +168,7 @@ void GC_init_parallel();
/* We don't really support thread-local allocation with DBG_HDRS_ALL */
-#ifdef USE_HPUX_TLS
+#ifdef USE_COMPILER_TLS
__thread
#endif
GC_key_t GC_thread_key;
@@ -735,7 +744,9 @@ void GC_wait_for_gc_completion(GC_bool wait_for_all)
while (GC_incremental && GC_collection_in_progress()
&& (wait_for_all || old_gc_no == GC_gc_no)) {
ENTER_GC();
+ GC_in_thread_creation = TRUE;
GC_collect_a_little_inner(1);
+ GC_in_thread_creation = FALSE;
EXIT_GC();
UNLOCK();
sched_yield();
@@ -1043,9 +1054,10 @@ void GC_thread_exit_proc(void *arg)
me -> flags |= FINISHED;
}
# if defined(THREAD_LOCAL_ALLOC) && !defined(USE_PTHREAD_SPECIFIC) \
- && !defined(USE_HPUX_TLS) && !defined(DBG_HDRS_ALL)
+ && !defined(USE_COMPILER_TLS) && !defined(DBG_HDRS_ALL)
GC_remove_specific(GC_thread_key);
# endif
+ /* The following may run the GC from "nonexistent" thread. */
GC_wait_for_gc_completion(FALSE);
UNLOCK();
}
@@ -1307,7 +1319,7 @@ void GC_pause()
}
}
-#define SPIN_MAX 1024 /* Maximum number of calls to GC_pause before */
+#define SPIN_MAX 128 /* Maximum number of calls to GC_pause before */
/* give up. */
VOLATILE GC_bool GC_collecting = 0;
@@ -1332,19 +1344,34 @@ VOLATILE GC_bool GC_collecting = 0;
/* yield by calling pthread_mutex_lock(); it never makes sense to */
/* explicitly sleep. */
+#define LOCK_STATS
+#ifdef LOCK_STATS
+ unsigned long GC_spin_count = 0;
+ unsigned long GC_block_count = 0;
+ unsigned long GC_unlocked_count = 0;
+#endif
+
void GC_generic_lock(pthread_mutex_t * lock)
{
#ifndef NO_PTHREAD_TRYLOCK
unsigned pause_length = 1;
unsigned i;
- if (0 == pthread_mutex_trylock(lock)) return;
+ if (0 == pthread_mutex_trylock(lock)) {
+# ifdef LOCK_STATS
+ ++GC_unlocked_count;
+# endif
+ 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:
+# ifdef LOCK_STATS
+ ++GC_spin_count;
+# endif
return;
case EBUSY:
break;
@@ -1353,6 +1380,9 @@ void GC_generic_lock(pthread_mutex_t * lock)
}
}
#endif /* !NO_PTHREAD_TRYLOCK */
+# ifdef LOCK_STATS
+ ++GC_block_count;
+# endif
pthread_mutex_lock(lock);
}
diff --git a/tests/test.c b/tests/test.c
index cfe23c0..ccec876 100644
--- a/tests/test.c
+++ b/tests/test.c
@@ -208,7 +208,6 @@ sexpr y;
#ifdef GC_GCJ_SUPPORT
#include "gc_mark.h"
-#include "private/dbg_mlc.h" /* For USR_PTR_FROM_BASE */
#include "gc_gcj.h"
/* The following struct emulates the vtable in gcj. */
@@ -233,7 +232,7 @@ struct GC_ms_entry * fake_gcj_mark_proc(word * addr,
sexpr x;
if (1 == env) {
/* Object allocated with debug allocator. */
- addr = (word *)USR_PTR_FROM_BASE(addr);
+ addr = (word *)GC_USR_PTR_FROM_BASE(addr);
}
x = (sexpr)(addr + 1); /* Skip the vtable pointer. */
mark_stack_ptr = GC_MARK_AND_PUSH(
@@ -1486,10 +1485,6 @@ 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. */
@@ -1501,7 +1496,7 @@ void SetMinimumStack(long minSize)
/* Cheat and let stdio initialize toolbox for us. */
printf("Testing GC Macintosh port.\n");
# endif
- GC_INIT(); /* Only needed if gc is dynamic library. */
+ GC_INIT(); /* Only needed on a few platforms. */
(void) GC_set_warn_proc(warn_proc);
# if (defined(MPROTECT_VDB) || defined(PROC_VDB)) \
&& !defined(MAKE_BACK_GRAPH)
@@ -1794,9 +1789,7 @@ main()
(void)GC_printf0("pthread_default_stacksize_np failed.\n");
}
# endif /* GC_HPUX_THREADS */
-# if defined(__APPLE__) && defined(__MACH__)
- GC_INIT();
-# endif
+ GC_INIT();
pthread_attr_init(&attr);
# if defined(GC_IRIX_THREADS) || defined(GC_FREEBSD_THREADS) \
diff --git a/tests/test_cpp.cc b/tests/test_cpp.cc
index 7e50e8a..6661e41 100644
--- a/tests/test_cpp.cc
+++ b/tests/test_cpp.cc
@@ -192,7 +192,7 @@ int APIENTRY WinMain(
# endif
#endif
- GC_init();
+ GC_INIT();
# if defined(MACOS) // MacOS
char* argv_[] = {"test_cpp", "10"}; // doesn't
diff --git a/typd_mlc.c b/typd_mlc.c
index a081c97..373257c 100644
--- a/typd_mlc.c
+++ b/typd_mlc.c
@@ -348,8 +348,6 @@ mse * GC_array_mark_proc GC_PROTO((register word * addr,
mse * mark_stack_limit,
word env));
-GC_descr GC_generic_array_descr;
-
/* Caller does not hold allocation lock. */
void GC_init_explicit_typing()
{
@@ -370,47 +368,25 @@ void GC_init_explicit_typing()
}
GC_explicit_typing_initialized = TRUE;
/* Set up object kind with simple indirect descriptor. */
- GC_eobjfreelist = (ptr_t *)
- GC_INTERNAL_MALLOC((MAXOBJSZ+1)*sizeof(ptr_t), PTRFREE);
- if (GC_eobjfreelist == 0) ABORT("Couldn't allocate GC_eobjfreelist");
- BZERO(GC_eobjfreelist, (MAXOBJSZ+1)*sizeof(ptr_t));
- GC_explicit_kind = GC_n_kinds++;
- GC_obj_kinds[GC_explicit_kind].ok_freelist = GC_eobjfreelist;
- GC_obj_kinds[GC_explicit_kind].ok_reclaim_list = 0;
- GC_obj_kinds[GC_explicit_kind].ok_descriptor =
- (((word)WORDS_TO_BYTES(-1)) | GC_DS_PER_OBJECT);
- GC_obj_kinds[GC_explicit_kind].ok_relocate_descr = TRUE;
- GC_obj_kinds[GC_explicit_kind].ok_init = TRUE;
+ GC_eobjfreelist = (ptr_t *)GC_new_free_list_inner();
+ GC_explicit_kind = GC_new_kind_inner(
+ (void **)GC_eobjfreelist,
+ (((word)WORDS_TO_BYTES(-1)) | GC_DS_PER_OBJECT),
+ TRUE, TRUE);
/* Descriptors are in the last word of the object. */
- GC_typed_mark_proc_index = GC_n_mark_procs;
- GC_mark_procs[GC_typed_mark_proc_index] = GC_typed_mark_proc;
- GC_n_mark_procs++;
- /* Moving this up breaks DEC AXP compiler. */
+ GC_typed_mark_proc_index = GC_new_proc_inner(GC_typed_mark_proc);
/* Set up object kind with array descriptor. */
- GC_arobjfreelist = (ptr_t *)
- GC_INTERNAL_MALLOC((MAXOBJSZ+1)*sizeof(ptr_t), PTRFREE);
- if (GC_arobjfreelist == 0) ABORT("Couldn't allocate GC_arobjfreelist");
- BZERO(GC_arobjfreelist, (MAXOBJSZ+1)*sizeof(ptr_t));
- if (GC_n_mark_procs >= MAX_MARK_PROCS)
- ABORT("No slot for array mark proc");
- GC_array_mark_proc_index = GC_n_mark_procs++;
- if (GC_n_kinds >= MAXOBJKINDS)
- ABORT("No kind available for array objects");
- GC_array_kind = GC_n_kinds++;
- GC_obj_kinds[GC_array_kind].ok_freelist = GC_arobjfreelist;
- GC_obj_kinds[GC_array_kind].ok_reclaim_list = 0;
- GC_obj_kinds[GC_array_kind].ok_descriptor =
- GC_MAKE_PROC(GC_array_mark_proc_index, 0);;
- GC_obj_kinds[GC_array_kind].ok_relocate_descr = FALSE;
- GC_obj_kinds[GC_array_kind].ok_init = TRUE;
- /* Descriptors are in the last word of the object. */
- GC_mark_procs[GC_array_mark_proc_index] = GC_array_mark_proc;
+ GC_arobjfreelist = (ptr_t *)GC_new_free_list_inner();
+ GC_array_mark_proc_index = GC_new_proc_inner(GC_array_mark_proc);
+ GC_array_kind = GC_new_kind_inner(
+ (void **)GC_arobjfreelist,
+ GC_MAKE_PROC(GC_array_mark_proc_index, 0),
+ FALSE, TRUE);
for (i = 0; i < WORDSZ/2; i++) {
GC_descr d = (((word)(-1)) >> (WORDSZ - i)) << (WORDSZ - i);
d |= GC_DS_BITMAP;
GC_bm_table[i] = d;
}
- GC_generic_array_descr = GC_MAKE_PROC(GC_array_mark_proc_index, 0);
UNLOCK();
ENABLE_SIGNALS();
}
diff --git a/version.h b/version.h
index f7ad22a..3f46a40 100644
--- a/version.h
+++ b/version.h
@@ -3,7 +3,7 @@
/* 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 4
+#define GC_TMP_ALPHA_VERSION 5
#ifndef GC_NOT_ALPHA
# define GC_NOT_ALPHA 0xff
@@ -14,7 +14,7 @@
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.
+# error Inconsistent version info. Check README, version.h, and configure.in.
# endif
#else
# define GC_VERSION_MAJOR GC_TMP_VERSION_MAJOR
diff --git a/win32_threads.c b/win32_threads.c
index 7a1dbe2..d2e97de 100755
--- a/win32_threads.c
+++ b/win32_threads.c
@@ -130,7 +130,7 @@ static GC_thread GC_new_thread(void) {
ABORT("DuplicateHandle failed");
}
thread_table[i].stack_base = GC_get_stack_base();
- /* Up until this point, GC_psuh_all_stacks considers this thread */
+ /* Up until this point, GC_push_all_stacks considers this thread */
/* invalid. */
if (thread_table[i].stack_base == NULL)
ABORT("Failed to find stack base in GC_new_thread");