diff options
author | Hans Boehm <boehm@acm.org> | 2003-05-14 04:00:00 +0400 |
---|---|---|
committer | Ivan Maidanski <ivmai@mail.ru> | 2014-05-17 18:44:47 +0400 |
commit | 917489831e257fd6c9b06dda740f48652a6ab2b9 (patch) | |
tree | 0e260caa703027d6742ab2f13edc7090727b6c25 | |
parent | c2556bdb7f90f61a1b17fb1ea02f47dcd2bf3285 (diff) |
gc6.2alpha5 tarball importgc6_2alpha5
-rw-r--r-- | Makefile.am | 18 | ||||
-rw-r--r-- | Makefile.in | 35 | ||||
-rw-r--r-- | alloc.c | 10 | ||||
-rwxr-xr-x | configure | 42 | ||||
-rw-r--r-- | configure.in | 8 | ||||
-rw-r--r-- | cord/cordbscs.c | 8 | ||||
-rw-r--r-- | dbg_mlc.c | 8 | ||||
-rw-r--r-- | doc/Makefile.in | 1 | ||||
-rw-r--r-- | doc/README | 2 | ||||
-rw-r--r-- | doc/README.changes | 56 | ||||
-rw-r--r-- | doc/README.macros | 13 | ||||
-rw-r--r-- | doc/README.win32 | 2 | ||||
-rw-r--r-- | dyn_load.c | 143 | ||||
-rw-r--r-- | finalize.c | 6 | ||||
-rw-r--r-- | include/Makefile.in | 1 | ||||
-rw-r--r-- | include/gc.h | 8 | ||||
-rw-r--r-- | include/gc_config_macros.h | 10 | ||||
-rw-r--r-- | include/private/gc_locks.h | 4 | ||||
-rw-r--r-- | include/private/gc_priv.h | 10 | ||||
-rw-r--r-- | include/private/gcconfig.h | 23 | ||||
-rw-r--r-- | linux_threads.c | 24 | ||||
-rw-r--r-- | mark.c | 167 | ||||
-rw-r--r-- | mark_rts.c | 5 | ||||
-rw-r--r-- | misc.c | 57 | ||||
-rw-r--r-- | os_dep.c | 260 | ||||
-rw-r--r-- | ptr_chck.c | 4 | ||||
-rw-r--r-- | reclaim.c | 2 | ||||
-rw-r--r-- | tests/test.c | 17 | ||||
-rw-r--r-- | threadlibs.c | 2 | ||||
-rw-r--r-- | version.h | 2 | ||||
-rwxr-xr-x | win32_threads.c | 37 |
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 \ @@ -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); @@ -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); + } } } @@ -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@ @@ -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. @@ -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 */ @@ -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; @@ -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() @@ -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 /* @@ -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(); @@ -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"); } @@ -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); @@ -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"); @@ -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 */ |