Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/Unity-Technologies/bdwgc.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHans Boehm <boehm@acm.org>2003-05-14 04:00:00 +0400
committerIvan Maidanski <ivmai@mail.ru>2014-05-17 18:44:47 +0400
commit917489831e257fd6c9b06dda740f48652a6ab2b9 (patch)
tree0e260caa703027d6742ab2f13edc7090727b6c25
parentc2556bdb7f90f61a1b17fb1ea02f47dcd2bf3285 (diff)
gc6.2alpha5 tarball importgc6_2alpha5
-rw-r--r--Makefile.am18
-rw-r--r--Makefile.in35
-rw-r--r--alloc.c10
-rwxr-xr-xconfigure42
-rw-r--r--configure.in8
-rw-r--r--cord/cordbscs.c8
-rw-r--r--dbg_mlc.c8
-rw-r--r--doc/Makefile.in1
-rw-r--r--doc/README2
-rw-r--r--doc/README.changes56
-rw-r--r--doc/README.macros13
-rw-r--r--doc/README.win322
-rw-r--r--dyn_load.c143
-rw-r--r--finalize.c6
-rw-r--r--include/Makefile.in1
-rw-r--r--include/gc.h8
-rw-r--r--include/gc_config_macros.h10
-rw-r--r--include/private/gc_locks.h4
-rw-r--r--include/private/gc_priv.h10
-rw-r--r--include/private/gcconfig.h23
-rw-r--r--linux_threads.c24
-rw-r--r--mark.c167
-rw-r--r--mark_rts.c5
-rw-r--r--misc.c57
-rw-r--r--os_dep.c260
-rw-r--r--ptr_chck.c4
-rw-r--r--reclaim.c2
-rw-r--r--tests/test.c17
-rw-r--r--threadlibs.c2
-rw-r--r--version.h2
-rwxr-xr-xwin32_threads.c37
31 files changed, 642 insertions, 343 deletions
diff --git a/Makefile.am b/Makefile.am
index 5c1ed96a..7b851e29 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -25,7 +25,9 @@ SUBDIRS = doc include
EXTRA_DIST =
## more items will be succesively added below
-lib_LTLIBRARIES = libgc.la
+lib_LTLIBRARIES = libgc.la @addlibs@
+
+EXTRA_LTLIBRARIES = libgccpp.la
include_HEADERS = include/gc.h include/gc_local_alloc.h \
include/gc_pthread_redirects.h include/gc_config_macros.h \
@@ -49,7 +51,11 @@ libgc_la_LDFLAGS = -version-info 1:2:0
EXTRA_libgc_la_SOURCES = alpha_mach_dep.S \
mips_sgi_mach_dep.S mips_ultrix_mach_dep.s powerpc_macosx_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 gc_cpp.cc
+ sparc_sunos4_mach_dep.s ia64_save_regs_in_stack.s
+
+libgccpp_la_SOURCES = gc_cpp.cc
+libgccpp_la_LIBADD = $(THREADLIBS)
+libgccpp_la_LDFLAGS = -version-info 1:2:0
EXTRA_DIST += alpha_mach_dep.S mips_sgi_mach_dep.S sparc_mach_dep.S
@@ -71,10 +77,14 @@ test_cpp.o: $(srcdir)/tests/test_cpp.cc
gctest_SOURCES = tests/test.c
gctest_LDADD = ./libgc.la $(THREADLIBS) $(EXTRA_TEST_LIBS)
test_cpp_SOURCES = tests/test_cpp.cc
-test_cpp_LDADD = ./libgc.la $(THREADLIBS) $(EXTRA_TEST_LIBS)
-TESTS_ENVIRONMENT = LD_LIBRARY_PATH=../../gcc
+test_cpp_LDADD = ./libgc.la ./libgccpp.la $(THREADLIBS) $(EXTRA_TEST_LIBS)
+
TESTS = gctest @addtests@
+test_cpp$(EXEEXT): test_cpp.o
+ $(LIBTOOL) --mode=link $(CXX) $(AM_CFLAGS) $(MY_CFLAGS) \
+ test_cpp.o $(test_cpp_LDADD) $(LDFLAGS) -o $@
+
## FIXME: relies on internal code generated by automake.
all_objs = @addobjs@ $(libgc_la_OBJECTS)
$(all_objs) : include/private/gcconfig.h include/private/gc_priv.h \
diff --git a/Makefile.in b/Makefile.in
index aa388c8f..4d3ee55d 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -111,6 +111,7 @@ STRIP = @STRIP@
THREADLIBS = @THREADLIBS@
VERSION = @VERSION@
addincludes = @addincludes@
+addlibs = @addlibs@
addobjs = @addobjs@
addtests = @addtests@
am__include = @am__include@
@@ -161,7 +162,9 @@ cord/cordbscs.c cord/cordtest.c cord/de.c cord/de_win.c \
cord/de_win.h cord/de_win.RC\
libtool.m4
-lib_LTLIBRARIES = libgc.la
+lib_LTLIBRARIES = libgc.la @addlibs@
+
+EXTRA_LTLIBRARIES = libgccpp.la
include_HEADERS = include/gc.h include/gc_local_alloc.h \
include/gc_pthread_redirects.h include/gc_config_macros.h \
@@ -187,8 +190,12 @@ libgc_la_LDFLAGS = -version-info 1:2:0
EXTRA_libgc_la_SOURCES = alpha_mach_dep.S \
mips_sgi_mach_dep.S mips_ultrix_mach_dep.s powerpc_macosx_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 gc_cpp.cc
+ sparc_sunos4_mach_dep.s ia64_save_regs_in_stack.s
+
+libgccpp_la_SOURCES = gc_cpp.cc
+libgccpp_la_LIBADD = $(THREADLIBS)
+libgccpp_la_LDFLAGS = -version-info 1:2:0
AM_CXXFLAGS = @GC_CFLAGS@
AM_CFLAGS = @GC_CFLAGS@
@@ -200,8 +207,8 @@ EXTRA_PROGRAMS = test_cpp
gctest_SOURCES = tests/test.c
gctest_LDADD = ./libgc.la $(THREADLIBS) $(EXTRA_TEST_LIBS)
test_cpp_SOURCES = tests/test_cpp.cc
-test_cpp_LDADD = ./libgc.la $(THREADLIBS) $(EXTRA_TEST_LIBS)
-TESTS_ENVIRONMENT = LD_LIBRARY_PATH=../../gcc
+test_cpp_LDADD = ./libgc.la ./libgccpp.la $(THREADLIBS) $(EXTRA_TEST_LIBS)
+
TESTS = gctest @addtests@
all_objs = @addobjs@ $(libgc_la_OBJECTS)
@@ -238,6 +245,9 @@ am_libgc_la_OBJECTS = allchblk.lo alloc.lo blacklst.lo checksums.lo \
reclaim.lo solaris_pthreads.lo solaris_threads.lo specific.lo \
stubborn.lo typd_mlc.lo backgraph.lo win32_threads.lo
libgc_la_OBJECTS = $(am_libgc_la_OBJECTS)
+libgccpp_la_DEPENDENCIES =
+am_libgccpp_la_OBJECTS = gc_cpp.lo
+libgccpp_la_OBJECTS = $(am_libgccpp_la_OBJECTS)
EXTRA_PROGRAMS = test_cpp$(EXEEXT)
check_PROGRAMS = gctest$(EXEEXT) @addtests@
am_gctest_OBJECTS = test.$(OBJEXT)
@@ -246,7 +256,7 @@ gctest_DEPENDENCIES = ./libgc.la
gctest_LDFLAGS =
am_test_cpp_OBJECTS = test_cpp.$(OBJEXT)
test_cpp_OBJECTS = $(am_test_cpp_OBJECTS)
-test_cpp_DEPENDENCIES = ./libgc.la
+test_cpp_DEPENDENCIES = ./libgc.la ./libgccpp.la
test_cpp_LDFLAGS =
SCRIPTS = $(dist_noinst_SCRIPTS)
@@ -294,7 +304,7 @@ CXXLD = $(CXX)
CXXLINK = $(LIBTOOL) --mode=link $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) \
$(AM_LDFLAGS) $(LDFLAGS) -o $@
DIST_SOURCES = $(libgc_la_SOURCES) $(EXTRA_libgc_la_SOURCES) \
- $(gctest_SOURCES) $(test_cpp_SOURCES)
+ $(libgccpp_la_SOURCES) $(gctest_SOURCES) $(test_cpp_SOURCES)
HEADERS = $(dist_noinst_HEADERS) $(include_HEADERS)
@@ -307,7 +317,7 @@ DIST_COMMON = $(dist_noinst_HEADERS) $(dist_noinst_SCRIPTS) \
aclocal.m4 config.guess config.sub configure configure.in \
depcomp install-sh ltconfig ltmain.sh missing mkinstalldirs
DIST_SUBDIRS = $(SUBDIRS)
-SOURCES = $(libgc_la_SOURCES) $(EXTRA_libgc_la_SOURCES) $(gctest_SOURCES) $(test_cpp_SOURCES)
+SOURCES = $(libgc_la_SOURCES) $(EXTRA_libgc_la_SOURCES) $(libgccpp_la_SOURCES) $(gctest_SOURCES) $(test_cpp_SOURCES)
all: all-recursive
@@ -358,7 +368,9 @@ clean-libLTLIBRARIES:
rm -f "$${dir}/so_locations"; \
done
libgc.la: $(libgc_la_OBJECTS) $(libgc_la_DEPENDENCIES)
- $(CXXLINK) -rpath $(libdir) $(libgc_la_LDFLAGS) $(libgc_la_OBJECTS) $(libgc_la_LIBADD) $(LIBS)
+ $(LINK) -rpath $(libdir) $(libgc_la_LDFLAGS) $(libgc_la_OBJECTS) $(libgc_la_LIBADD) $(LIBS)
+libgccpp.la: $(libgccpp_la_OBJECTS) $(libgccpp_la_DEPENDENCIES)
+ $(CXXLINK) $(libgccpp_la_LDFLAGS) $(libgccpp_la_OBJECTS) $(libgccpp_la_LIBADD) $(LIBS)
clean-checkPROGRAMS:
@list='$(check_PROGRAMS)'; for p in $$list; do \
@@ -371,9 +383,6 @@ gctest$(EXEEXT): $(gctest_OBJECTS) $(gctest_DEPENDENCIES)
@rm -f gctest$(EXEEXT)
$(LINK) $(gctest_LDFLAGS) $(gctest_OBJECTS) $(gctest_LDADD) $(LIBS)
test_cpp.$(OBJEXT): tests/test_cpp.cc
-test_cpp$(EXEEXT): $(test_cpp_OBJECTS) $(test_cpp_DEPENDENCIES)
- @rm -f test_cpp$(EXEEXT)
- $(CXXLINK) $(test_cpp_LDFLAGS) $(test_cpp_OBJECTS) $(test_cpp_LDADD) $(LIBS)
mostlyclean-compile:
-rm -f *.$(OBJEXT) core *.core
@@ -878,6 +887,10 @@ test.o: $(srcdir)/tests/test.c
# Using $< in the above seems to fail with the HP/UX on Itanium make.
test_cpp.o: $(srcdir)/tests/test_cpp.cc
$(COMPILE) -c $(srcdir)/tests/test_cpp.cc
+
+test_cpp$(EXEEXT): test_cpp.o
+ $(LIBTOOL) --mode=link $(CXX) $(AM_CFLAGS) $(MY_CFLAGS) \
+ test_cpp.o $(test_cpp_LDADD) $(LDFLAGS) -o $@
$(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_pthread_redirects.h include/gc_config_macros.h \
diff --git a/alloc.c b/alloc.c
index 4cb7a4c7..d2b874fc 100644
--- a/alloc.c
+++ b/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[] =
@@ -470,6 +477,7 @@ GC_stop_func stop_func;
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 ",
@@ -500,6 +508,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);
}
@@ -533,6 +542,7 @@ GC_stop_func stop_func;
(*GC_check_heap)();
}
+ IF_THREADS(GC_world_stopped = FALSE);
START_WORLD();
# ifdef PRINTTIMES
GET_TIME(current_time);
diff --git a/configure b/configure
index dcd45242..db84f60f 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.2alpha4.
+# Generated by GNU Autoconf 2.53 for gc 6.2alpha5.
#
# 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.2alpha4'
-PACKAGE_STRING='gc 6.2alpha4'
+PACKAGE_VERSION='6.2alpha5'
+PACKAGE_STRING='gc 6.2alpha5'
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.2alpha4 to adapt to many kinds of systems.
+\`configure' configures gc 6.2alpha5 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.2alpha4:";;
+ short | recursive ) echo "Configuration of gc 6.2alpha5:";;
esac
cat <<\_ACEOF
@@ -1010,7 +1010,7 @@ Optional Features:
(and sometimes confusing) to the casual installer
--enable-threads=TYPE choose threading package
--enable-parallel-mark parallelize marking and free list construction
- --enable-cplusplus include C++ support in GC library and include directory
+ --enable-cplusplus install C++ support
--enable-shared=PKGS build shared libraries default=yes
--enable-static=PKGS build static libraries default=yes
--enable-fast-install=PKGS optimize for fast installation default=yes
@@ -1106,7 +1106,7 @@ fi
test -n "$ac_init_help" && exit 0
if $ac_init_version; then
cat <<\_ACEOF
-gc configure 6.2alpha4
+gc configure 6.2alpha5
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.2alpha4, which was
+It was created by gc $as_me 6.2alpha5, 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.2alpha4
+ VERSION=6.2alpha5
cat >>confdefs.h <<_ACEOF
@@ -3688,6 +3688,10 @@ echo "$as_me: error: $THREADS is an unknown thread package" >&2;}
esac
+# I'm not too familiar with autoconf, is this the best way to do this? -Brian
+case "$host" in
+ *-*-darwin*) ;;
+ *)
echo "$as_me:$LINENO: checking for dlopen in -ldl" >&5
echo $ECHO_N "checking for dlopen in -ldl... $ECHO_C" >&6
@@ -3748,6 +3752,9 @@ if test $ac_cv_lib_dl_dlopen = yes; then
EXTRA_TEST_LIBS="$EXTRA_TEST_LIBS -ldl"
fi
+ ;;
+esac
+
target_all=libgc.la
@@ -3763,6 +3770,7 @@ if test "${with_ecos+set}" = set; then
fi;
addobjs=
+addlibs=
addincludes=
addtests=
CXXINCLUDES=
@@ -3780,7 +3788,7 @@ _ACEOF
esac
if test "${enable_cplusplus}" = yes; then
- addobjs="$addobjs gc_cpp.lo"
+ addlibs="$addlibs libgccpp.la"
addincludes="$addincludes include/gc_cpp.h include/gc_allocator.h"
addtests="$addtests test_cpp"
fi
@@ -3903,6 +3911,7 @@ addobjs="$addobjs $machdep"
+
# Check whether --enable-static or --disable-static was given.
if test "${enable_static+set}" = set; then
enableval="$enable_static"
@@ -5335,7 +5344,7 @@ test "x$enable_libtool_lock" != xno && enable_libtool_lock=yes
case $host in
*-*-irix6*)
# Find out which ABI we are using.
- echo '#line 5338 "configure"' > conftest.$ac_ext
+ echo '#line 5347 "configure"' > conftest.$ac_ext
if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
(eval $ac_compile) 2>&5
ac_status=$?
@@ -5871,7 +5880,7 @@ chmod -w .
save_CFLAGS="$CFLAGS"
CFLAGS="$CFLAGS -o out/conftest2.$ac_objext"
compiler_c_o=no
-if { (eval echo configure:5874: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>out/conftest.err; } && test -s out/conftest2.$ac_objext; then
+if { (eval echo configure:5883: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>out/conftest.err; } && test -s out/conftest2.$ac_objext; then
# The compiler can only warn and ignore the option if not recognized
# So say no if there are warnings
if test -s out/conftest.err; then
@@ -7664,7 +7673,7 @@ else
lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
lt_status=$lt_dlunknown
cat > conftest.$ac_ext <<EOF
-#line 7667 "configure"
+#line 7676 "configure"
#include "confdefs.h"
#if HAVE_DLFCN_H
@@ -7762,7 +7771,7 @@ else
lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
lt_status=$lt_dlunknown
cat > conftest.$ac_ext <<EOF
-#line 7765 "configure"
+#line 7774 "configure"
#include "confdefs.h"
#if HAVE_DLFCN_H
@@ -9191,7 +9200,7 @@ _ASBOX
} >&5
cat >&5 <<_CSEOF
-This file was extended by gc $as_me 6.2alpha4, which was
+This file was extended by gc $as_me 6.2alpha5, which was
generated by GNU Autoconf 2.53. Invocation command line was
CONFIG_FILES = $CONFIG_FILES
@@ -9248,7 +9257,7 @@ _ACEOF
cat >>$CONFIG_STATUS <<_ACEOF
ac_cs_version="\\
-gc config.status 6.2alpha4
+gc config.status 6.2alpha5
configured by $0, generated by GNU Autoconf 2.53,
with options \\"`echo "$ac_configure_args" | sed 's/[\\""\`\$]/\\\\&/g'`\\"
@@ -9499,6 +9508,7 @@ s,@INCLUDES@,$INCLUDES,;t t
s,@CXXINCLUDES@,$CXXINCLUDES,;t t
s,@addobjs@,$addobjs,;t t
s,@addincludes@,$addincludes,;t t
+s,@addlibs@,$addlibs,;t t
s,@addtests@,$addtests,;t t
s,@LN_S@,$LN_S,;t t
s,@ECHO@,$ECHO,;t t
diff --git a/configure.in b/configure.in
index 092447cb..2e18090e 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.2alpha4,Hans.Boehm@hp.com)
+AC_INIT(gc,6.2alpha5,Hans.Boehm@hp.com)
## version must conform to [0-9]+[.][0-9]+(alpha[0-9]+)?
AC_CONFIG_SRCDIR(gcj_mlc.c)
AC_CANONICAL_TARGET
@@ -64,7 +64,7 @@ AC_ARG_ENABLE(parallel-mark,
)
AC_ARG_ENABLE(cplusplus,
-[ --enable-cplusplus include C++ support in GC library and include directory],
+[ --enable-cplusplus install C++ support],
)
INCLUDES=-I${srcdir}/include
@@ -183,6 +183,7 @@ TARGET_ECOS="$with_ecos"
)
addobjs=
+addlibs=
addincludes=
addtests=
CXXINCLUDES=
@@ -197,7 +198,7 @@ case "$TARGET_ECOS" in
esac
if test "${enable_cplusplus}" = yes; then
- addobjs="$addobjs gc_cpp.lo"
+ addlibs="$addlibs libgccpp.la"
addincludes="$addincludes include/gc_cpp.h include/gc_allocator.h"
addtests="$addtests test_cpp"
fi
@@ -276,6 +277,7 @@ fi
addobjs="$addobjs $machdep"
AC_SUBST(addobjs)
AC_SUBST(addincludes)
+AC_SUBST(addlibs)
AC_SUBST(addtests)
AC_PROG_LIBTOOL
diff --git a/cord/cordbscs.c b/cord/cordbscs.c
index 9fc894d4..d83f4067 100644
--- a/cord/cordbscs.c
+++ b/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/dbg_mlc.c b/dbg_mlc.c
index eb489939..f640930d 100644
--- a/dbg_mlc.c
+++ b/dbg_mlc.c
@@ -924,9 +924,11 @@ void GC_print_all_smashed_proc ()
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);
}
diff --git a/doc/Makefile.in b/doc/Makefile.in
index ea2a2146..c8d1ccc4 100644
--- a/doc/Makefile.in
+++ b/doc/Makefile.in
@@ -108,6 +108,7 @@ STRIP = @STRIP@
THREADLIBS = @THREADLIBS@
VERSION = @VERSION@
addincludes = @addincludes@
+addlibs = @addlibs@
addobjs = @addobjs@
addtests = @addtests@
am__include = @am__include@
diff --git a/doc/README b/doc/README
index afe2d524..581d69df 100644
--- a/doc/README
+++ b/doc/README
@@ -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.2alpha3 of a conservative garbage collector for C and C++.
+This is version 6.2alpha5 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 627ddaef..125f83fd 100644
--- a/doc/README.changes
+++ b/doc/README.changes
@@ -1780,6 +1780,62 @@ Since 6.2alpha3:
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.
+
+
To do:
- MacOSX thread support still appears to be a bit unreliable.
- A dynamic libgc.so references dlopen unconditionally, but doesn't link
diff --git a/doc/README.macros b/doc/README.macros
index d9df8dd3..b5fe6796 100644
--- a/doc/README.macros
+++ b/doc/README.macros
@@ -51,7 +51,18 @@ _DLL Defined by Visual C++ if dynamic libraries are being built
__declspec(dllexport) needs to be added to declarations
to support the case in which the collector is in a dll.
-GC_DLL User-settable macro that forces the effect of _DLL.
+GC_DLL User-settable macro that forces the effect of _DLL. Set
+ by gc.h if _DLL is defined and GC_NOT_DLL is undefined.
+ This is the macro that is tested internally to determine
+ whether the GC is in its own dynamic library. May need
+ to be set by clients before including gc.h. Note that
+ inside the GC implementation it indicates that the
+ collector is in its own dynamic library, should export
+ its symbols, etc. But in clients it indicates that the
+ GC resides in a different DLL, its entry points should
+ be referenced accordingly, and precautions may need to
+ be taken to properly deal with statically allocated
+ variables in the main program. Used only for MS Windows.
GC_NOT_DLL User-settable macro that overrides _DLL, e.g. if dynamic
libraries are used, but the collector is in a static library.
diff --git a/doc/README.win32 b/doc/README.win32
index c95f149f..a40b375f 100644
--- a/doc/README.win32
+++ b/doc/README.win32
@@ -161,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/dyn_load.c b/dyn_load.c
index dbdf3f41..aacdaf65 100644
--- a/dyn_load.c
+++ b/dyn_load.c
@@ -283,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) {
@@ -343,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 */
@@ -359,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;
}
@@ -378,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: */
@@ -388,73 +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
-//
-// 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
-
-static char *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 /* USE_PROC_FOR_LIBRARIES */
diff --git a/finalize.c b/finalize.c
index 8350605b..3b9d9f5e 100644
--- a/finalize.c
+++ b/finalize.c
@@ -764,7 +764,6 @@ int GC_invoke_finalizers()
struct finalizable_object * curr_fo;
int count = 0;
word mem_freed_before;
- GC_bool first_time = TRUE;
DCL_LOCK_STATE;
while (GC_finalize_now != 0) {
@@ -772,9 +771,8 @@ int GC_invoke_finalizers()
DISABLE_SIGNALS();
LOCK();
# endif
- if (first_time) {
+ if (count == 0) {
mem_freed_before = GC_mem_freed;
- first_time = FALSE;
}
curr_fo = GC_finalize_now;
# ifdef THREADS
@@ -797,7 +795,7 @@ int GC_invoke_finalizers()
GC_free((GC_PTR)curr_fo);
# endif
}
- if (mem_freed_before != GC_mem_freed) {
+ if (count != 0 && mem_freed_before != GC_mem_freed) {
LOCK();
GC_finalizer_mem_freed += (GC_mem_freed - mem_freed_before);
UNLOCK();
diff --git a/include/Makefile.in b/include/Makefile.in
index a8dab022..cb650a82 100644
--- a/include/Makefile.in
+++ b/include/Makefile.in
@@ -108,6 +108,7 @@ STRIP = @STRIP@
THREADLIBS = @THREADLIBS@
VERSION = @VERSION@
addincludes = @addincludes@
+addlibs = @addlibs@
addobjs = @addobjs@
addtests = @addtests@
am__include = @am__include@
diff --git a/include/gc.h b/include/gc.h
index b1c64ced..dfecfcaf 100644
--- a/include/gc.h
+++ b/include/gc.h
@@ -344,14 +344,14 @@ GC_API void GC_add_roots GC_PROTO((char * low_address,
/* 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));
@@ -883,7 +883,7 @@ extern void GC_thr_init(); /* Needed for Solaris/X86 */
* 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 );
@@ -917,7 +917,7 @@ 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 from
* the main program, as does AIX.
diff --git a/include/gc_config_macros.h b/include/gc_config_macros.h
index 763e02fb..01de9c5c 100644
--- a/include/gc_config_macros.h
+++ b/include/gc_config_macros.h
@@ -108,7 +108,11 @@
typedef long ptrdiff_t; /* ptrdiff_t is not defined */
# endif
-#if defined(__MINGW32__) && defined(_DLL) && !defined(GC_NOT_DLL)
+#if defined(_DLL) && !defined(GC_NOT_DLL) && !defined(GC_DLL)
+# define GC_DLL
+#endif
+
+#if defined(__MINGW32__) && defined(GC_DLL)
# ifdef GC_BUILD
# define GC_API __declspec(dllexport)
# else
@@ -116,9 +120,7 @@
# endif
#endif
-#if (defined(__DMC__) || defined(_MSC_VER)) \
- && (defined(_DLL) && !defined(GC_NOT_DLL) \
- || defined(GC_DLL))
+#if (defined(__DMC__) || defined(_MSC_VER)) && defined(GC_DLL)
# ifdef GC_BUILD
# define GC_API extern __declspec(dllexport)
# else
diff --git a/include/private/gc_locks.h b/include/private/gc_locks.h
index 35c37162..61397b19 100644
--- a/include/private/gc_locks.h
+++ b/include/private/gc_locks.h
@@ -325,8 +325,8 @@
{
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 */
diff --git a/include/private/gc_priv.h b/include/private/gc_priv.h
index f2df5d4f..3822555a 100644
--- a/include/private/gc_priv.h
+++ b/include/private/gc_priv.h
@@ -905,7 +905,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]
@@ -1180,6 +1180,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))
@@ -1846,6 +1850,10 @@ 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 ... */
+# define GC_STATIC_ASSERT(expr) sizeof(char[(expr)? 1 : -1])
+
# if defined(PARALLEL_MARK) || defined(THREAD_LOCAL_ALLOC)
/* We need additional synchronization facilities from the thread */
/* support. We believe these are less performance critical */
diff --git a/include/private/gcconfig.h b/include/private/gcconfig.h
index 2290d3d1..35d47fdf 100644
--- a/include/private/gcconfig.h
+++ b/include/private/gcconfig.h
@@ -26,6 +26,12 @@
# 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. */
@@ -703,9 +709,6 @@
/* executable on a 64 bit kernel. */
# define LINUX_STACKBOTTOM
# define DYNAMIC_LOADING
-# undef STACK_GRAN
-# define STACK_GRAN 0x10000000
- /* Stack usually starts at 0x80000000 */
# define SEARCH_FOR_DATA_START
extern int _end[];
# define DATAEND (_end)
@@ -1884,7 +1887,7 @@
/* 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
@@ -2039,9 +2042,7 @@
+ GC_page_size-1)
# else
# ifdef MSWIN32
-# ifdef GC_PRIVATE_H
- extern ptr_t GC_win32_get_mem();
-# endif
+ extern ptr_t GC_win32_get_mem();
# define GET_MEM(bytes) (struct hblk *)GC_win32_get_mem(bytes)
# else
# ifdef MACOS
@@ -2057,9 +2058,7 @@
# endif
# else
# ifdef MSWINCE
-# ifdef GC_PRIVATE_H
- extern ptr_t GC_wince_get_mem();
-# endif
+ 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)
@@ -2068,9 +2067,7 @@
GC_amiga_get_mem((size_t)bytes + GC_page_size) \
+ GC_page_size-1)
# else
-# ifdef GC_PRIVATE_H
- extern ptr_t GC_unix_get_mem();
-# endif
+ extern ptr_t GC_unix_get_mem();
# define GET_MEM(bytes) (struct hblk *)GC_unix_get_mem(bytes)
# endif
# endif
diff --git a/linux_threads.c b/linux_threads.c
index 96943d38..ab5820aa 100644
--- a/linux_threads.c
+++ b/linux_threads.c
@@ -724,6 +724,7 @@ void GC_suspend_handler(int sig)
void GC_restart_handler(int sig)
{
+ pthread_t my_thread = pthread_self();
GC_thread me;
if (sig != SIG_THR_RESTART) ABORT("Bad signal in suspend_handler");
@@ -733,7 +734,7 @@ void GC_restart_handler(int sig)
/* 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 = GC_lookup_thread(my_thread);
me->signal = SIG_THR_RESTART;
/*
@@ -967,8 +968,9 @@ int GC_suspend_all()
/* Caller holds allocation lock. */
void GC_stop_world()
{
- register int i;
- register int n_live_threads;
+ int i;
+ int n_live_threads;
+ int code;
/* Make sure all free list construction has stopped before we start. */
/* No new construction can start, since free list construction is */
@@ -1017,10 +1019,12 @@ void GC_stop_world()
for (i = 0; i < n_live_threads; i++) {
# ifdef GC_MACOSX_THREADS
if (KERN_SUCCESS != semaphore_wait(GC_suspend_ack_sem))
- ABORT("semaphore_wait in handler failed");
+ ABORT("semaphore_wait for handler failed");
# else
- if (0 != sem_wait(&GC_suspend_ack_sem))
- ABORT("sem_wait in handler failed");
+ if (0 != (code = sem_wait(&GC_suspend_ack_sem))) {
+ GC_err_printf1("Sem_wait returned %ld\n", (unsigned long)code);
+ ABORT("sem_wait for handler failed");
+ }
# endif
}
# ifdef PARALLEL_MARK
@@ -1174,11 +1178,9 @@ int GC_get_nprocs()
/* 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
+# define STAT_READ read
+ /* If read is wrapped, this may need to be redefined to call */
+ /* the real one. */
char stat_buf[STAT_BUF_SIZE];
int f;
char c;
diff --git a/mark.c b/mark.c
index 33f4ff88..ca947290 100644
--- a/mark.c
+++ b/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()
diff --git a/mark_rts.c b/mark_rts.c
index f663dcd5..2aae5165 100644
--- a/mark_rts.c
+++ b/mark_rts.c
@@ -573,8 +573,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/misc.c b/misc.c
index ef90c00c..60857f5a 100644
--- a/misc.c
+++ b/misc.c
@@ -49,7 +49,7 @@
# if defined(GC_WIN32_THREADS)
# if defined(GC_PTHREADS)
pthread_mutex_t GC_allocate_ml = PTHREAD_MUTEX_INITIALIZER;
-# elif !defined(GC_NOT_DLL) && (defined(_DLL) || defined(GC_DLL))
+# elif defined(GC_DLL)
__declspec(dllexport) CRITICAL_SECTION GC_allocate_ml;
# else
CRITICAL_SECTION GC_allocate_ml;
@@ -499,6 +499,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)));
@@ -509,21 +525,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
-#endif
+static GC_bool installed_looping_handler = FALSE;
-void GC_exit_check GC_PROTO((void))
+void maybe_install_looping_handler()
{
- GC_gcollect();
+ /* 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;
+ }
}
-#ifdef SEARCH_FOR_DATA_START
- extern void GC_init_linux_data_start GC_PROTO((void));
+#else /* !UNIX_LIKE */
+
+# define maybe_install_looping_handler()
+
#endif
void GC_init_inner()
@@ -590,11 +608,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);
@@ -641,9 +655,9 @@ void GC_init_inner()
# 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(
@@ -765,8 +779,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();
diff --git a/os_dep.c b/os_dep.c
index a2a31c24..668cd26c 100644
--- a/os_dep.c
+++ b/os_dep.c
@@ -150,6 +150,155 @@
# 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 */
@@ -679,6 +828,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;
@@ -692,9 +868,15 @@ ptr_t GC_get_stack_base()
/* 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;
}
}
@@ -706,11 +888,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;
@@ -945,12 +1124,10 @@ void GC_register_data_segments()
/* all real work is done by GC_register_dynamic_libraries. Under */
/* win32s, we cannot find the data segments associated with dll's. */
/* We register 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
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()
{
@@ -2583,7 +2760,10 @@ 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) || !defined(SA_SIGINFO)
/* This is Irix 5.x, not 6.x. Irix 5.x does not have */
@@ -2879,13 +3059,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
@@ -3465,7 +3638,7 @@ struct callinfo info[NFRAMES];
}
name = result_buf;
pclose(pipe);
- out:
+ out:;
}
# endif /* LINUX */
GC_err_printf1("\t\t%s\n", name);
@@ -3481,31 +3654,6 @@ struct callinfo info[NFRAMES];
#endif /* NEED_CALLINFO */
-#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
-
-
-/* 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;
-}
-#endif /* LINUX && ... */
#if defined(LINUX) && defined(__ELF__) && !defined(SMALL_CONFIG)
@@ -3513,20 +3661,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));
- close(f);
+ GC_apply_to_maps(dump_maps);
GC_err_printf0("---------- End address map ----------\n");
}
diff --git a/ptr_chck.c b/ptr_chck.c
index af49d5f5..d83d730d 100644
--- a/ptr_chck.c
+++ b/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/reclaim.c b/reclaim.c
index 93c7b992..323d420f 100644
--- a/reclaim.c
+++ b/reclaim.c
@@ -904,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/tests/test.c b/tests/test.c
index 84b57a6d..43ebe8c9 100644
--- a/tests/test.c
+++ b/tests/test.c
@@ -69,11 +69,6 @@
# endif
# ifdef GC_WIN32_THREADS
-# ifndef MSWINCE
- /* FIXME - Why is this here? */
-# include <process.h>
-# define GC_CreateThread(a,b,c,d,e,f) ((HANDLE) _beginthreadex(a,b,c,d,e,f))
-# endif
static CRITICAL_SECTION incr_cs;
# endif
@@ -534,7 +529,7 @@ struct {
#ifdef THREADS
# if defined(GC_WIN32_THREADS) && !defined(CYGWIN32)
- unsigned __stdcall tiny_reverse_test(void * arg)
+ DWORD __stdcall tiny_reverse_test(void * arg)
# else
void * tiny_reverse_test(void * arg)
# endif
@@ -569,7 +564,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) {
@@ -762,6 +757,7 @@ VOLATILE int dropped_something = 0;
FAIL;
}
finalized_count++;
+ t -> level = -1; /* detect duplicate finalization immediately */
# ifdef PCR
PCR_ThCrSec_ExitSys();
# endif
@@ -1503,7 +1499,7 @@ void SetMinimumStack(long minSize)
#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;
@@ -1535,7 +1531,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,
@@ -1597,10 +1593,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
diff --git a/threadlibs.c b/threadlibs.c
index 4c6ad581..7db05f58 100644
--- a/threadlibs.c
+++ b/threadlibs.c
@@ -4,7 +4,7 @@
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");
diff --git a/version.h b/version.h
index ebcb35c0..384dcbe6 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 2
-#define GC_TMP_ALPHA_VERSION 4
+#define GC_TMP_ALPHA_VERSION 5
#if defined(GC_VERSION_MAJOR)
# if GC_TMP_VERSION_MAJOR != GC_VERSION_MAJOR || \
diff --git a/win32_threads.c b/win32_threads.c
index 9b584160..6e06101e 100755
--- a/win32_threads.c
+++ b/win32_threads.c
@@ -19,14 +19,10 @@
#endif
-
-#if 0
-#define STRICT
-#include <windows.h>
+#ifndef MAX_THREADS
+# define MAX_THREADS 64
#endif
-#define MAX_THREADS 64
-
struct thread_entry {
LONG in_use;
DWORD id;
@@ -373,9 +369,11 @@ 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(MSWINCE) && defined(GC_DLL)
-HANDLE WINAPI GC_CreateThread(
+/* 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 )
@@ -384,7 +382,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;
@@ -565,10 +566,11 @@ DWORD WINAPI main_thread_start(LPVOID arg)
LONG WINAPI GC_write_fault_handler(struct _EXCEPTION_POINTERS *exc_info);
-/* threadAttach/threadDetach routines used by both CYGWIN and DLL implementation,
- since both recieve explicit notification on thread creation/destruction
+/* threadAttach/threadDetach routines used by both CYGWIN and DLL
+ * implementation, since both recieve explicit notification on thread
+ * creation/destruction.
*/
-void threadAttach() {
+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. */
@@ -617,7 +619,7 @@ void threadAttach() {
while (GC_please_stop) Sleep(20);
}
-void threadDetach(DWORD thread_id) {
+static void threadDetach(DWORD thread_id) {
int i;
LOCK();
@@ -783,7 +785,8 @@ void GC_thread_exit_proc(void *arg)
int i;
# if DEBUG_CYGWIN_THREADS
- GC_printf2("thread 0x%x(0x%x) called pthread_exit().\n",(int)pthread_self(),GetCurrentThreadId());
+ GC_printf2("thread 0x%x(0x%x) called pthread_exit().\n",
+ (int)pthread_self(),GetCurrentThreadId());
# endif
LOCK();
@@ -806,12 +809,13 @@ int GC_pthread_sigmask(int how, const sigset_t *set, sigset_t *oset) {
int GC_pthread_detach(pthread_t thread) {
return pthread_detach(thread);
}
-#else
+#else /* !CYGWIN32 */
/*
* We avoid acquiring locks here, since this doesn't seem to be preemptable.
* Pontus Rydin suggests wrapping the thread start routine instead.
*/
+#ifdef GC_DLL
BOOL WINAPI DllMain(HINSTANCE inst, ULONG reason, LPVOID reserved)
{
switch (reason) {
@@ -852,7 +856,8 @@ BOOL WINAPI DllMain(HINSTANCE inst, ULONG reason, LPVOID reserved)
}
return TRUE;
}
-#endif /* CYGWIN32 */
+#endif /* GC_DLL */
+#endif /* !CYGWIN32 */
# endif /* !MSWINCE */