diff options
author | Ivan Maidanski <ivmai@mail.ru> | 2011-07-26 15:51:40 +0200 |
---|---|---|
committer | Ivan Maidanski <ivmai@mail.ru> | 2011-07-26 15:51:40 +0200 |
commit | f4549e6f616d1b976126e1afddde3fb15c88bb08 (patch) | |
tree | 468562a9464cbbf6d0218650b15bd54926f6660b | |
parent | cab07051b9609b90d82db8c4586988a804a25264 (diff) |
gc6.3 tarball importgc6_3
-rw-r--r-- | Makefile | 16 | ||||
-rw-r--r-- | Makefile.am | 2 | ||||
-rw-r--r-- | Makefile.direct | 16 | ||||
-rw-r--r-- | Makefile.in | 4 | ||||
-rw-r--r-- | NT_STATIC_THREADS_MAKEFILE | 2 | ||||
-rw-r--r-- | allchblk.c | 16 | ||||
-rw-r--r-- | alloc.c | 14 | ||||
-rw-r--r-- | checksums.c | 34 | ||||
-rwxr-xr-x | configure | 24 | ||||
-rw-r--r-- | configure.in | 4 | ||||
-rw-r--r-- | darwin_stop_world.c | 27 | ||||
-rw-r--r-- | dbg_mlc.c | 10 | ||||
-rw-r--r-- | doc/Makefile.am | 2 | ||||
-rw-r--r-- | doc/Makefile.in | 2 | ||||
-rw-r--r-- | doc/README | 2 | ||||
-rw-r--r-- | doc/README.changes | 50 | ||||
-rw-r--r-- | doc/simple_example.html | 202 | ||||
-rw-r--r-- | dyn_load.c | 14 | ||||
-rw-r--r-- | headers.c | 2 | ||||
-rw-r--r-- | include/gc.h | 5 | ||||
-rw-r--r-- | include/gc_allocator.h | 17 | ||||
-rw-r--r-- | include/gc_config_macros.h | 5 | ||||
-rw-r--r-- | include/private/gc_priv.h | 8 | ||||
-rw-r--r-- | include/private/gcconfig.h | 46 | ||||
-rw-r--r-- | ltconfig | 3 | ||||
-rw-r--r-- | mark.c | 10 | ||||
-rw-r--r-- | new_hblk.c | 12 | ||||
-rw-r--r-- | os_dep.c | 84 | ||||
-rw-r--r-- | pthread_stop_world.c | 58 | ||||
-rw-r--r-- | solaris_pthreads.c | 4 | ||||
-rw-r--r-- | solaris_threads.c | 16 | ||||
-rw-r--r-- | tests/middle.c | 25 | ||||
-rw-r--r-- | tests/test.c | 4 | ||||
-rw-r--r-- | threadlibs.c | 1 | ||||
-rw-r--r-- | version.h | 2 |
35 files changed, 576 insertions, 167 deletions
@@ -320,14 +320,15 @@ DOC_FILES= README.QUICK doc/README.Mac doc/README.MacOSX doc/README.OS2 \ doc/README.environment doc/tree.html doc/gcdescr.html \ doc/README.autoconf doc/README.macros doc/README.ews4800 \ doc/README.DGUX386 doc/README.arm.cross doc/leak.html \ - doc/scale.html doc/gcinterface.html doc/README.darwin + doc/scale.html doc/gcinterface.html doc/README.darwin \ + doc/simple_example.html TESTS= tests/test.c tests/test_cpp.cc tests/trace_test.c \ - tests/leak_test.c tests/thread_leak_test.c + tests/leak_test.c tests/thread_leak_test.c tests/middle.c GNU_BUILD_FILES= configure.in Makefile.am configure acinclude.m4 \ libtool.m4 install-sh configure.host Makefile.in \ - ltconfig aclocal.m4 config.sub config.guess \ + aclocal.m4 config.sub config.guess \ include/Makefile.am include/Makefile.in \ doc/Makefile.am doc/Makefile.in \ ltmain.sh mkinstalldirs depcomp missing @@ -367,16 +368,23 @@ SPECIALCFLAGS = -I$(srcdir)/include all: gc.a gctest -BSD-pkg-all: bsd-libgc.a +LEAKFLAGS=$(CFLAGS) -DFIND_LEAK + +BSD-pkg-all: bsd-libgc.a bsd-libleak.a bsd-libgc.a: $(MAKE) CFLAGS="$(CFLAGS)" clean c++-t mv gc.a bsd-libgc.a +bsd-libleak.a: + $(MAKE) -f Makefile.direct CFLAGS="$(LEAKFLAGS)" clean c++-nt + mv gc.a bsd-libleak.a + BSD-pkg-install: BSD-pkg-all ${CP} bsd-libgc.a libgc.a ${INSTALL_DATA} libgc.a ${PREFIX}/lib ${INSTALL_DATA} gc.h gc_cpp.h ${PREFIX}/include + ${INSTALL_MAN} doc/gc.man ${PREFIX}/man/man3/gc.3 pcr: PCR-Makefile include/private/gc_private.h include/private/gc_hdrs.h \ include/private/gc_locks.h include/gc.h include/private/gcconfig.h \ diff --git a/Makefile.am b/Makefile.am index ed24152..2aba243 100644 --- a/Makefile.am +++ b/Makefile.am @@ -85,7 +85,7 @@ test.o: $(srcdir)/tests/test.c $(COMPILE) -c $(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 + $(CXXCOMPILE) -c $(srcdir)/tests/test_cpp.cc ## FIXME: this is probably the reason why some files from BUILT_SOURCES ## are included in the distribution diff --git a/Makefile.direct b/Makefile.direct index 74929c1..20fa40a 100644 --- a/Makefile.direct +++ b/Makefile.direct @@ -320,14 +320,15 @@ DOC_FILES= README.QUICK doc/README.Mac doc/README.MacOSX doc/README.OS2 \ doc/README.environment doc/tree.html doc/gcdescr.html \ doc/README.autoconf doc/README.macros doc/README.ews4800 \ doc/README.DGUX386 doc/README.arm.cross doc/leak.html \ - doc/scale.html doc/gcinterface.html doc/README.darwin + doc/scale.html doc/gcinterface.html doc/README.darwin \ + doc/simple_example.html TESTS= tests/test.c tests/test_cpp.cc tests/trace_test.c \ - tests/leak_test.c tests/thread_leak_test.c + tests/leak_test.c tests/thread_leak_test.c tests/middle.c GNU_BUILD_FILES= configure.in Makefile.am configure acinclude.m4 \ libtool.m4 install-sh configure.host Makefile.in \ - ltconfig aclocal.m4 config.sub config.guess \ + aclocal.m4 config.sub config.guess \ include/Makefile.am include/Makefile.in \ doc/Makefile.am doc/Makefile.in \ ltmain.sh mkinstalldirs depcomp missing @@ -367,16 +368,23 @@ SPECIALCFLAGS = -I$(srcdir)/include all: gc.a gctest -BSD-pkg-all: bsd-libgc.a +LEAKFLAGS=$(CFLAGS) -DFIND_LEAK + +BSD-pkg-all: bsd-libgc.a bsd-libleak.a bsd-libgc.a: $(MAKE) CFLAGS="$(CFLAGS)" clean c++-t mv gc.a bsd-libgc.a +bsd-libleak.a: + $(MAKE) -f Makefile.direct CFLAGS="$(LEAKFLAGS)" clean c++-nt + mv gc.a bsd-libleak.a + BSD-pkg-install: BSD-pkg-all ${CP} bsd-libgc.a libgc.a ${INSTALL_DATA} libgc.a ${PREFIX}/lib ${INSTALL_DATA} gc.h gc_cpp.h ${PREFIX}/include + ${INSTALL_MAN} doc/gc.man ${PREFIX}/man/man3/gc.3 pcr: PCR-Makefile include/private/gc_private.h include/private/gc_hdrs.h \ include/private/gc_locks.h include/gc.h include/private/gcconfig.h \ diff --git a/Makefile.in b/Makefile.in index 2c7c1b7..fb52a37 100644 --- a/Makefile.in +++ b/Makefile.in @@ -326,7 +326,7 @@ RECURSIVE_TARGETS = info-recursive dvi-recursive install-info-recursive \ DIST_COMMON = $(dist_noinst_HEADERS) $(dist_noinst_SCRIPTS) \ $(include_HEADERS) Makefile.am Makefile.in acinclude.m4 \ aclocal.m4 config.guess config.sub configure configure.in \ - depcomp install-sh ltconfig ltmain.sh missing mkinstalldirs + depcomp install-sh ltmain.sh missing mkinstalldirs DIST_SUBDIRS = $(SUBDIRS) SOURCES = $(libgc_la_SOURCES) $(EXTRA_libgc_la_SOURCES) $(libgccpp_la_SOURCES) $(gctest_SOURCES) $(test_cpp_SOURCES) @@ -902,7 +902,7 @@ test.o: $(srcdir)/tests/test.c $(COMPILE) -c $(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 + $(CXXCOMPILE) -c $(srcdir)/tests/test_cpp.cc $(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/NT_STATIC_THREADS_MAKEFILE b/NT_STATIC_THREADS_MAKEFILE index 7238c94..a7582af 100644 --- a/NT_STATIC_THREADS_MAKEFILE +++ b/NT_STATIC_THREADS_MAKEFILE @@ -1,4 +1,4 @@ -# Makefile for Windows NT. Assumes Microsoft compiler, and a single thread. +# Makefile for Windows NT. Assumes Microsoft compiler. # DLLs are included in the root set under NT, but not under win32S. # Use "nmake nodebug=1 all" for optimized versions of library, gctest and editor. @@ -111,7 +111,7 @@ void GC_print_hblkfreelist() for (i = 0; i <= N_HBLK_FLS; ++i) { h = GC_hblkfreelist[i]; # ifdef USE_MUNMAP - if (0 != h) GC_printf1("Free list %ld (Total size %ld):\n", + if (0 != h) GC_printf1("Free list %ld:\n", (unsigned long)i); # else if (0 != h) GC_printf2("Free list %ld (Total size %ld):\n", @@ -133,10 +133,12 @@ void GC_print_hblkfreelist() h = hhdr -> hb_next; } } - if (total_free != GC_large_free_bytes) { +# ifndef USE_MUNMAP + if (total_free != GC_large_free_bytes) { GC_printf1("GC_large_free_bytes = %lu (INCONSISTENT!!)\n", (unsigned long) GC_large_free_bytes); - } + } +# endif GC_printf1("Total of %lu bytes on free list\n", (unsigned long)total_free); } @@ -181,7 +183,7 @@ void GC_dump_regions() hhdr = HDR(p); GC_printf1("\t0x%lx ", (unsigned long)p); if (IS_FORWARDING_ADDR_OR_NIL(hhdr)) { - GC_printf1("Missing header!!\n", hhdr); + GC_printf1("Missing header!!(%ld)\n", hhdr); p += HBLKSIZE; continue; } @@ -468,7 +470,11 @@ int index; if (total_size == bytes) return h; rest = (struct hblk *)((word)h + bytes); rest_hdr = GC_install_header(rest); - if (0 == rest_hdr) return(0); + if (0 == rest_hdr) { + /* This may be very bad news ... */ + WARN("Header allocation failed: Dropping block.\n", 0); + return(0); + } rest_hdr -> hb_sz = total_size - bytes; rest_hdr -> hb_flags = 0; # ifdef GC_ASSERTIONS @@ -133,7 +133,7 @@ int GC_n_attempts = 0; /* Number of attempts at finishing */ if (GC_print_stats) { GC_printf0("Abandoning stopped marking after "); GC_printf1("%lu msecs", (unsigned long)time_diff); - GC_printf1("(attempt %d)\n", (unsigned long) GC_n_attempts); + GC_printf1("(attempt %ld)\n", (unsigned long) GC_n_attempts); } # endif return(1); @@ -942,12 +942,7 @@ word n; (GC_PTR)GC_min((ptr_t)GC_least_plausible_heap_addr, (ptr_t)space - expansion_slop); } - /* Force GC before we are likely to allocate past expansion_slop */ - GC_collect_at_heapsize = - GC_heapsize + expansion_slop - 2*MAXHINCR*HBLKSIZE; # if defined(LARGE_CONFIG) - if (GC_collect_at_heapsize < GC_heapsize /* wrapped */) - GC_collect_at_heapsize = (word)(-1); if (((ptr_t)GC_greatest_plausible_heap_addr <= (ptr_t)space + bytes || (ptr_t)GC_least_plausible_heap_addr >= (ptr_t)space) && GC_heapsize > 0) { @@ -958,6 +953,13 @@ word n; GC_prev_heap_addr = GC_last_heap_addr; GC_last_heap_addr = (ptr_t)space; GC_add_to_heap(space, bytes); + /* Force GC before we are likely to allocate past expansion_slop */ + GC_collect_at_heapsize = + GC_heapsize + expansion_slop - 2*MAXHINCR*HBLKSIZE; +# if defined(LARGE_CONFIG) + if (GC_collect_at_heapsize < GC_heapsize /* wrapped */) + GC_collect_at_heapsize = (word)(-1); +# endif return(TRUE); } diff --git a/checksums.c b/checksums.c index 121c36d..57a6ebc 100644 --- a/checksums.c +++ b/checksums.c @@ -13,14 +13,14 @@ /* Boehm, March 29, 1995 12:51 pm PST */ # ifdef CHECKSUMS -# include "gc_priv.h" +# include "private/gc_priv.h" /* This is debugging code intended to verify the results of dirty bit */ /* computations. Works only in a single threaded environment. */ /* We assume that stubborn objects are changed only when they are */ /* enabled for writing. (Certain kinds of writing are actually */ /* safe under other conditions.) */ -# define NSUMS 2000 +# define NSUMS 10000 # define OFFSET 0x10000 @@ -29,7 +29,7 @@ typedef struct { word old_sum; word new_sum; struct hblk * block; /* Block to which this refers + OFFSET */ - /* to hide it from colector. */ + /* to hide it from collector. */ } page_entry; page_entry GC_sums [NSUMS]; @@ -76,12 +76,13 @@ int index; { page_entry *pe = GC_sums + index; register hdr * hhdr = HDR(h); + struct hblk *b; if (pe -> block != 0 && pe -> block != h + OFFSET) ABORT("goofed"); pe -> old_sum = pe -> new_sum; pe -> new_sum = GC_checksum(h); # if !defined(MSWIN32) && !defined(MSWINCE) - if (pe -> new_sum != 0 && !GC_page_was_ever_dirty(h)) { + if (pe -> new_sum != 0x80000000 && !GC_page_was_ever_dirty(h)) { GC_printf1("GC_page_was_ever_dirty(0x%lx) is wrong\n", (unsigned long)h); } @@ -91,13 +92,19 @@ int index; } else { GC_n_clean++; } - if (pe -> new_valid && pe -> old_sum != pe -> new_sum) { + b = h; + while (IS_FORWARDING_ADDR_OR_NIL(hhdr) && hhdr != 0) { + b -= (word)hhdr; + hhdr = HDR(b); + } + if (pe -> new_valid + && hhdr != 0 && hhdr -> hb_descr != 0 /* may contain pointers */ + && pe -> old_sum != pe -> new_sum) { if (!GC_page_was_dirty(h) || !GC_page_was_ever_dirty(h)) { /* Set breakpoint here */GC_n_dirty_errors++; } # ifdef STUBBORN_ALLOC - if (!IS_FORWARDING_ADDR_OR_NIL(hhdr) - && hhdr -> hb_map != GC_invalid_map + if ( hhdr -> hb_map != GC_invalid_map && hhdr -> hb_obj_kind == STUBBORN && !GC_page_was_changed(h) && !GC_on_free_list(h)) { @@ -120,26 +127,17 @@ word dummy; register hdr * hhdr = HDR(h); register bytes = WORDS_TO_BYTES(hhdr -> hb_sz); - bytes += HDR_BYTES + HBLKSIZE-1; + bytes += HBLKSIZE-1; bytes &= ~(HBLKSIZE-1); GC_bytes_in_used_blocks += bytes; } void GC_check_blocks() { - word bytes_in_free_blocks = 0; - struct hblk * h = GC_hblkfreelist; - hdr * hhdr = HDR(h); - word sz; + word bytes_in_free_blocks = GC_large_free_bytes; GC_bytes_in_used_blocks = 0; GC_apply_to_all_blocks(GC_add_block, (word)0); - while (h != 0) { - sz = hhdr -> hb_sz; - bytes_in_free_blocks += sz; - h = hhdr -> hb_next; - hhdr = HDR(h); - } GC_printf2("GC_bytes_in_used_blocks = %ld, bytes_in_free_blocks = %ld ", GC_bytes_in_used_blocks, bytes_in_free_blocks); GC_printf1("GC_heapsize = %ld\n", GC_heapsize); @@ -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.3alpha5. +# Generated by GNU Autoconf 2.53 for gc 6.3. # # 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.3alpha5' -PACKAGE_STRING='gc 6.3alpha5' +PACKAGE_VERSION='6.3' +PACKAGE_STRING='gc 6.3' 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.3alpha5 to adapt to many kinds of systems. +\`configure' configures gc 6.3 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.3alpha5:";; + short | recursive ) echo "Configuration of gc 6.3:";; esac cat <<\_ACEOF @@ -1106,7 +1106,7 @@ fi test -n "$ac_init_help" && exit 0 if $ac_init_version; then cat <<\_ACEOF -gc configure 6.3alpha5 +gc configure 6.3 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.3alpha5, which was +It was created by gc $as_me 6.3, 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.3alpha5 + VERSION=6.3 cat >>confdefs.h <<_ACEOF @@ -8558,8 +8558,6 @@ LIBTOOL='$(SHELL) $(top_builddir)/libtool' # # Check for AViiON Machines running DGUX # -echo "$as_me:$LINENO: checking if host is AViiON running DGUX" >&5 -echo $ECHO_N "checking if host is AViiON running DGUX... $ECHO_C" >&6 ac_is_dgux=no if test "${ac_cv_header_sys_dg_sys_info_h+set}" = set; then echo "$as_me:$LINENO: checking for sys/dg_sys_info.h" >&5 @@ -8668,8 +8666,6 @@ fi -echo "$as_me:$LINENO: result: $ac_is_dgux" >&5 -echo "${ECHO_T}$ac_is_dgux" >&6 ## :GOTCHA: we do not check anything but sys/dg_sys_info.h if test $ac_is_dgux = yes; then if test "$enable_full_debug" = "yes"; then @@ -9347,7 +9343,7 @@ _ASBOX } >&5 cat >&5 <<_CSEOF -This file was extended by gc $as_me 6.3alpha5, which was +This file was extended by gc $as_me 6.3, which was generated by GNU Autoconf 2.53. Invocation command line was CONFIG_FILES = $CONFIG_FILES @@ -9404,7 +9400,7 @@ _ACEOF cat >>$CONFIG_STATUS <<_ACEOF ac_cs_version="\\ -gc config.status 6.3alpha5 +gc config.status 6.3 configured by $0, generated by GNU Autoconf 2.53, with options \\"`echo "$ac_configure_args" | sed 's/[\\""\`\$]/\\\\&/g'`\\" diff --git a/configure.in b/configure.in index 635742c..7914692 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.3alpha5,Hans.Boehm@hp.com) +AC_INIT(gc,6.3,Hans.Boehm@hp.com) ## version must conform to [0-9]+[.][0-9]+(alpha[0-9]+)? AC_CONFIG_SRCDIR(gcj_mlc.c) AC_CANONICAL_TARGET @@ -308,12 +308,10 @@ AC_PROG_LIBTOOL # # Check for AViiON Machines running DGUX # -AC_MSG_CHECKING(if host is AViiON running DGUX) ac_is_dgux=no AC_CHECK_HEADER(sys/dg_sys_info.h, [ac_is_dgux=yes;]) -AC_MSG_RESULT($ac_is_dgux) ## :GOTCHA: we do not check anything but sys/dg_sys_info.h if test $ac_is_dgux = yes; then if test "$enable_full_debug" = "yes"; then diff --git a/darwin_stop_world.c b/darwin_stop_world.c index 02d751e..36378cb 100644 --- a/darwin_stop_world.c +++ b/darwin_stop_world.c @@ -210,22 +210,39 @@ int GC_suspend_thread_list(thread_act_array_t act_list, int count, mach_msg_type_number_t outCount = THREAD_INFO_MAX; kern_return_t kern_result = thread_info(thread, THREAD_BASIC_INFO, (thread_info_t)&info, &outCount); - if(kern_result != KERN_SUCCESS) ABORT("thread_info failed"); + if(kern_result != KERN_SUCCESS) { + /* the thread may have quit since the thread_threads () call + * we mark already_suspended so it's not dealt with anymore later + */ + if (!found) { + GC_mach_threads[GC_mach_threads_count].already_suspended = TRUE; + GC_mach_threads_count++; + } + continue; + } # if DEBUG_THREADS GC_printf2("Thread state for 0x%lx = %d\n", thread, info.run_state); # endif if (!found) { - GC_mach_threads[GC_mach_threads_count].already_suspended = - (info.run_state != TH_STATE_RUNNING); + GC_mach_threads[GC_mach_threads_count].already_suspended = info.suspend_count; } - if (info.run_state != TH_STATE_RUNNING) continue; + if (info.suspend_count) continue; # if DEBUG_THREADS GC_printf1("Suspending 0x%lx\n", thread); # endif /* Suspend the thread */ kern_result = thread_suspend(thread); - if(kern_result != KERN_SUCCESS) ABORT("thread_suspend failed"); + if(kern_result != KERN_SUCCESS) { + /* the thread may have quit since the thread_threads () call + * we mark already_suspended so it's not dealt with anymore later + */ + if (!found) { + GC_mach_threads[GC_mach_threads_count].already_suspended = TRUE; + GC_mach_threads_count++; + } + continue; + } } if (!found) GC_mach_threads_count++; } @@ -818,7 +818,15 @@ GC_PTR p; uncollectable = TRUE; } # endif - if (uncollectable) GC_free(base); + if (uncollectable) { + GC_free(base); + } else { + size_t i; + size_t obj_sz = hhdr -> hb_sz - BYTES_TO_WORDS(sizeof(oh)); + + for (i = 0; i < obj_sz; ++i) ((word *)p)[i] = 0xdeadbeef; + GC_ASSERT((word *)p + i == (word *)base + hhdr -> hb_sz); + } } /* !GC_find_leak */ } diff --git a/doc/Makefile.am b/doc/Makefile.am index 9144630..9446bcb 100644 --- a/doc/Makefile.am +++ b/doc/Makefile.am @@ -23,5 +23,5 @@ dist_pkgdata_DATA = barrett_diagram debugging.html gc.man \ README.MacOSX README.macros README.OS2 README.rs6000 \ README.sgi README.solaris2 README.uts README.win32 \ tree.html leak.html gcinterface.html scale.html \ - README.darwin + README.darwin simple_example.html diff --git a/doc/Makefile.in b/doc/Makefile.in index 1e9dd92..708fd51 100644 --- a/doc/Makefile.in +++ b/doc/Makefile.in @@ -127,7 +127,7 @@ dist_pkgdata_DATA = barrett_diagram debugging.html gc.man \ README.MacOSX README.macros README.OS2 README.rs6000 \ README.sgi README.solaris2 README.uts README.win32 \ tree.html leak.html gcinterface.html scale.html \ - README.darwin + README.darwin simple_example.html subdir = doc mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs @@ -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.3alpha5 of a conservative garbage collector for C and C++. +This is version 6.3 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 38bde34..e27e7d6 100644 --- a/doc/README.changes +++ b/doc/README.changes @@ -2049,9 +2049,57 @@ Since 6.3alpha4: - The USE_MUNMAP code could get confused about the age of a block and prematurely unmap it. GC_unmap_old had a bug related to wrapping of GC_gc_no. GC_freehblk and GC_merge_unmapped didn't maintain - hb_last_reclaimed reasonably when blockas were merged. The code was + hb_last_reclaimed reasonably when blocks were merged. The code was fixed to reflect original intent, but that may not always be an improvement. See todo list item. + +Since 6.3alpha5: + - Define USE_GENERIC_PUSH_REGS for NetBSD/M68K. + - Fixed the X86_64 PREFETCH macros to correctly handle ia32e (which uses + different prefetch instructions from AMD64). (Thanks to H.J. Lu.) + - GC_config_macros.h did not correctly define GC_WIN32_THREADS from + GC_THREADS. + - Added simple_example.html. + - Merged Andrew Gray's patch to correctly restore signal handlers on + FreeBSD. + - Merged a patch from Andreas Jaeger to deal with prefetch-related warnings + on x86-64. Added some other casts so that the PREFETCH macros + always get a ptr_t argument. Removed some casts inthe PREFETCH + implementations. + - At Jesse Jones suggestion: Added a header guard for gc_allocator.h + and changed GC_debug_free to clobber contents of deallocated object. + - The signal masking code in pthread_stop_world.c contained some errors. + In particular SIGSEGV was masked in the handler, in spite of the fact that + it wrote to the heap. This could lead to an uncaught SIGSEGV, which + apparently became much more likely in Linux 2.6. Also fixed some + typos, and reduced code duplication in the same area. + - Remove ltconfig, clean up configure messages for DGUX (thanks to + Adrian Bunk for the patches). + - Integrated NetBSD/OpenBSD patches from Marc Recht and Matthias Drochner. + +Since gc6.3alpha6: + - Compile test_cpp.cc with CXXCOMPILE instead of COMPILE. + - Very large allocations could cause a collector hang. Correct + calculation of GC_collect_at_heapsize. + - GC_print_hblkfreelist printed some bogus results if USE_MUNMAP + was defined. + - The generic GC_THREADS macro didn't work correctly on Solaris, + since the implementation failed to include gc_config_macros.h + before deciding whether or not to compile the rest of the file. + - Threadlibs.c failed to expand the generic GC_THREADS macro. + - Correct MacOSX thread stop code. (Thanks to Dick Porter.) + - SMALL_OBJ definition was off by one. This could cause crashes + at startup. (Thanks to Zoltan Varga for narrowing this down to + a trivial test case.) + - Integrate Paolo Molara's patch to deal with a race in the Darwin + thread stopping code. + - Changed X86_64 implementation to use SA_SIGINFO in the MPROTECT_VDB + implementation. The old approach appears to have been broken by + recent kernels. + - Add GC_ATTR_UNUSED to eliminate a warning in gc_allocator.h. (Thanks + to Andrew Begel.) + - Fix GC_task_self declaration in os_dep.c. (Thanks to Andrew Pinski.) + - Increase INITIAL_BUF_SZ in os_dep.c for Solaris /proc reads. To do: - The USE_MUNMAP code should really use a separate data structure diff --git a/doc/simple_example.html b/doc/simple_example.html new file mode 100644 index 0000000..0bc0953 --- /dev/null +++ b/doc/simple_example.html @@ -0,0 +1,202 @@ +<HTML> +<HEAD> +<TITLE>Using the Garbage Collector: A simple example</title> +</head> +<BODY> +<H1>Using the Garbage Collector: A simple example</h1> +The following consists of step-by-step instructions for building and +using the collector. We'll assume a Linux/gcc platform and +a single-threaded application. <FONT COLOR=green>The green +text contains information about other platforms or scenarios. +It can be skipped, especially on first reading</font>. +<H2>Building the collector</h2> +If you haven't already so, unpack the collector and enter +the newly created directory with +<PRE> +tar xvfz gc<version>.tar.gz +cd gc<version> +</pre> +<P> +You can configure, build, and install the collector in a private +directory, say /home/xyz/gc, with the following commands: +<PRE> +./configure --prefix=/home/xyz/gc --disable-threads +make +make check +make install +</pre> +Here the "<TT>make check</tt>" command is optional, but highly recommended. +It runs a basic correctness test which usually takes well under a minute. +<FONT COLOR=green> +<H3>Other platforms</h3> +On non-Unix, non-Linux platforms, the collector is usually built by copying +the appropriate makefile (see the platform-specific README in doc/README.xxx +in the distribution) to the file "Makefile" (overwriting the copy of +Makefile.direct that was originally there), and then typing "make" +(or "nmake" or ...). This builds the library in the source tree. You may +want to move it and the files in the include directory to a more convenient +place. +<P> +If you use a makefile that does not require running a configure script, +you should first look at the makefile, and adjust any options that are +documented there. +<P> +If your platform provides a "make" utility, that is generally preferred +to platform- and compiler- dependent "project" files. (At least that is the +strong preference of the would-be maintainer of those project files.) +<H3>Threads</h3> +If you need thread support, configure the collector with +<PRE> +--enable-threads=posix --enable-thread-local-alloc --enable-parallel-mark +</pre> +instead of +<TT>--disable-threads</tt> +If your target is a real old-fashioned uniprocessor (no "hyperthreading", +etc.) you will want to omit <TT>--enable-parallel-mark</tt>. +<H3>C++</h3> +You will need to include the C++ support, which unfortunately tends to +be among the least portable parts of the collector, since it seems +to rely on some corner cases of the language. On Linux, it +suffices to add <TT>--enable-cplusplus</tt> to the configure options. +</font> +<H2>Writing the program</h2> +You will need a +<PRE> +#include "gc.h" +</pre> +at the beginning of every file that allocates memory through the +garbage collector. Call <TT>GC_MALLOC</tt> wherever you would +have call <TT>malloc</tt>. This initializes memory to zero like +<TT>calloc</tt>; there is no need to explicitly clear the +result. +<P> +If you know that an object will not contain pointers to the +garbage-collected heap, and you don't need it to be initialized, +call <TT>GC_MALLOC_ATOMIC</tt> instead. +<P> +A function <TT>GC_FREE</tt> is provided but need not be called. +For very small objects, your program will probably perform better if +you do not call it, and let the collector do its job. +<P> +A <TT>GC_REALLOC</tt> function behaves like the C library <TT>realloc</tt>. +It allocates uninitialized pointer-free memory if the original +object was allocated that way. +<P> +The following program <TT>loop.c</tt> is a trivial example: +<PRE> +#include "gc.h" +#include <assert.h> +#include <stdio.h> + +int main() +{ + int i; + + GC_INIT(); /* Optional on Linux/X86; see below. */ + for (i = 0; i < 10000000; ++i) + { + int **p = (int **) GC_MALLOC(sizeof(int *)); + int *q = (int *) GC_MALLOC_ATOMIC(sizeof(int)); + assert(*p == 0); + *p = (int *) GC_REALLOC(q, 2 * sizeof(int)); + if (i % 100000 == 0) + printf("Heap size = %d\n", GC_get_heap_size()); + } + return 0; +} +</pre> +<FONT COLOR=green> +<H3>Interaction with the system malloc</h3> +It is usually best not to mix garbage-collected allocation with the system +<TT>malloc-free</tt>. If you do, you need to be careful not to store +pointers to the garbage-collected heap in memory allocated with the system +<TT>malloc</tt>. +<H3>Other Platforms</h3> +On some other platforms it is necessary to call <TT>GC_INIT()</tt> from the main program, +which is presumed to be part of the main executable, not a dynamic library. +This can never hurt, and is thus generally good practice. + +<H3>Threads</h3> +For a multithreaded program some more rules apply: +<UL> +<LI> +Files that either allocate through the GC <I>or make thread-related calls</i> +should first define the macro <TT>GC_THREADS</tt>, and then +include <TT>"gc.h"</tt>. On some platforms this will redefine some +threads primitives, e.g. to let the collector keep track of thread creation. +<LI> +To take advantage of fast thread-local allocation, use the following instead +of including <TT>gc.h</tt>: +<PRE> +#define GC_REDIRECT_TO_LOCAL +#include "gc_local_alloc.h" +</pre> +This will cause GC_MALLOC and GC_MALLOC_ATOMIC to keep per-thread allocation +caches, and greatly reduce the number of lock acquisitions during allocation. +</ul> + +<H3>C++</h3> +In the case of C++, you need to be especially careful not to store pointers +to the garbage-collected heap in areas that are not traced by the collector. +The collector includes some <A HREF="gcinterface.html">alternate interfaces</a> +to make that easier. + +<H3>Debugging</h3> +Additional debug checks can be performed by defining <TT>GC_DEBUG</tt> before +including <TT>gc.h</tt>. Additional options are available if the collector +is also built with <TT>--enable-full_debug</tt> and all allocations are +performed with <TT>GC_DEBUG</tt> defined. + +<H3>What if I can't rewrite/recompile my program?</h3> +You may be able to build the collector with <TT>--enable-redirect-malloc</tt> +and set the <TT>LD_PRELOAD</tt> environment variable to point to the resulting +library, thus replacing the standard <TT>malloc</tt> with its garbage-collected +counterpart. This is rather platform dependent. See the +<A HREF="leak.html">leak detection documentation</a> for some more details. + +</font> + +<H2>Compiling and linking</h2> + +The above application <TT>loop.c</tt> test program can be compiled and linked +with + +<PRE> +cc -I/home/xyz/gc/include loop.c /home/xyz/gc/lib/libgc.a -o loop +</pre> + +The <TT>-I</tt> option directs the compiler to the right include +directory. In this case, we list the static library +directly on the compile line; the dynamic library could have been +used instead, provided we arranged for the dynamic loader to find +it, e.g. by setting <TT>LD_LIBRARY_PATH</tt>. + +<FONT COLOR=green> + +<H3>Threads</h3> + +On pthread platforms, you will of course also have to link with +<TT>-lpthread</tt>, +and compile with any thread-safety options required by your compiler. +On some platforms, you may also need to link with <TT>-ldl</tt> +or <TT>-lrt</tt>. +Looking at threadlibs.c in the GC build directory +should give you the appropriate +list if a plain <TT>-lpthread</tt> doesn't work. + +</font> + +<H2>Running the executable</h2> + +The executable can of course be run normally, e.g. by typing + +<PRE> +./loop +</pre> + +The operation of the collector is affected by a number of environment variables. +For example, setting <TT>GC_PRINT_STATS</tt> produces some +GC statistics on stdout. +See <TT>README.environment</tt> in the distribution for details. +</body> +</html> @@ -91,10 +91,18 @@ /* Newer versions of GNU/Linux define this macro. We * define it similarly for any ELF systems that don't. */ # ifndef ElfW -# if !defined(ELF_CLASS) || ELF_CLASS == ELFCLASS32 -# define ElfW(type) Elf32_##type +# ifdef __NetBSD__ +# if ELFSIZE == 32 +# define ElfW(type) Elf32_##type +# else +# define ElfW(type) Elf64_##type +# endif # else -# define ElfW(type) Elf64_##type +# if !defined(ELF_CLASS) || ELF_CLASS == ELFCLASS32 +# define ElfW(type) Elf32_##type +# else +# define ElfW(type) Elf64_##type +# endif # endif # endif @@ -206,7 +206,7 @@ register struct hblk * h; { hdr * result; - if (!get_index((word) h)) return(FALSE); + if (!get_index((word) h)) return(0); result = alloc_hdr(); SET_HDR(h, result); # ifdef USE_MUNMAP diff --git a/include/gc.h b/include/gc.h index 58a2ff5..2a89009 100644 --- a/include/gc.h +++ b/include/gc.h @@ -778,6 +778,7 @@ GC_API GC_PTR GC_call_with_alloc_lock /* The following routines are primarily intended for use with a */ /* preprocessor which inserts calls to check C pointer arithmetic. */ +/* They indicate failure by invoking the corresponding _print_proc. */ /* Check that p and q point to the same object. */ /* Fail conspicuously if they don't. */ @@ -855,7 +856,7 @@ GC_API GC_PTR GC_is_valid_displacement GC_PROTO((GC_PTR p)); # define GC_PTR_STORE(p, q) *((p) = (q)) #endif -/* Fynctions called to report pointer checking errors */ +/* Functions called to report pointer checking errors */ GC_API void (*GC_same_obj_print_proc) GC_PROTO((GC_PTR p, GC_PTR q)); GC_API void (*GC_is_valid_displacement_print_proc) @@ -929,7 +930,7 @@ extern void GC_thr_init(); /* Needed for Solaris/X86 */ * no-op and the collector self-initializes. But a number of platforms * make that too hard. */ -#if defined(sparc) || defined(__sparc) +#if (defined(sparc) || defined(__sparc)) && defined(sun) /* * If you are planning on putting * the collector in a SunOS 5 dynamic library, you need to call GC_INIT() diff --git a/include/gc_allocator.h b/include/gc_allocator.h index 87c8509..200f181 100644 --- a/include/gc_allocator.h +++ b/include/gc_allocator.h @@ -35,7 +35,17 @@ * library, which itself was derived from the SGI STL implementation. */ -#include "gc.h" // For size_t +#ifndef GC_ALLOCATOR_H + +#define GC_ALLOCATOR_H + +#include "gc.h" + +#if defined(__GNUC__) +# define GC_ATTR_UNUSED __attribute__((unused)) +#else +# define GC_ATTR_UNUSED +#endif /* First some helpers to allow us to dispatch on whether or not a type * is known to be pointerfree. @@ -118,7 +128,7 @@ public: } // __p is not permitted to be a null pointer. - void deallocate(pointer __p, size_type GC_n) + void deallocate(pointer __p, size_type GC_ATTR_UNUSED GC_n) { GC_FREE(__p); } size_type max_size() const throw() @@ -194,7 +204,7 @@ public: } // __p is not permitted to be a null pointer. - void deallocate(pointer __p, size_type GC_n) + void deallocate(pointer __p, size_type GC_ATTR_UNUSED GC_n) { GC_FREE(__p); } size_type max_size() const throw() @@ -230,3 +240,4 @@ inline bool operator!=(const traceable_allocator<GC_T1>&, const traceable_alloca return false; } +#endif /* GC_ALLOCATOR_H */ diff --git a/include/gc_config_macros.h b/include/gc_config_macros.h index 4aaca2d..d8d3114 100644 --- a/include/gc_config_macros.h +++ b/include/gc_config_macros.h @@ -97,7 +97,10 @@ # endif #endif /* GC_THREADS */ -#if defined(GC_THREADS) && !defined(GC_PTHREADS) && defined(MSWIN32) +#if defined(GC_THREADS) && !defined(GC_PTHREADS) && \ + (defined(_WIN32) || defined(_MSC_VER) || defined(__CYGWIN__) \ + || defined(__MINGW32__) || defined(__BORLANDC__) \ + || defined(_WIN32_WCE)) # define GC_WIN32_THREADS #endif diff --git a/include/private/gc_priv.h b/include/private/gc_priv.h index b957691..08dd8ea 100644 --- a/include/private/gc_priv.h +++ b/include/private/gc_priv.h @@ -550,7 +550,7 @@ extern GC_warn_proc GC_current_warn_proc; #define CPP_MAXOBJBYTES (CPP_HBLKSIZE/2) #define MAXOBJBYTES ((word)CPP_MAXOBJBYTES) -#define CPP_MAXOBJSZ BYTES_TO_WORDS(CPP_HBLKSIZE/2) +#define CPP_MAXOBJSZ BYTES_TO_WORDS(CPP_MAXOBJBYTES) #define MAXOBJSZ ((word)CPP_MAXOBJSZ) # define divHBLKSZ(n) ((n) >> LOG_HBLKSIZE) @@ -578,7 +578,7 @@ extern GC_warn_proc GC_current_warn_proc; # else # define ALIGNED_WORDS(n) ROUNDED_UP_WORDS(n) # endif -# define SMALL_OBJ(bytes) ((bytes) < (MAXOBJBYTES - EXTRA_BYTES)) +# define SMALL_OBJ(bytes) ((bytes) <= (MAXOBJBYTES - EXTRA_BYTES)) # define ADD_SLOP(bytes) ((bytes) + EXTRA_BYTES) # ifndef MIN_WORDS /* MIN_WORDS is the size of the smallest allocated object. */ @@ -938,11 +938,11 @@ struct _GC_arrays { char _valid_offsets[VALID_OFFSET_SZ]; /* GC_valid_offsets[i] == TRUE ==> i */ /* is registered as a displacement. */ -# define OFFSET_VALID(displ) \ - (GC_all_interior_pointers || GC_valid_offsets[displ]) char _modws_valid_offsets[sizeof(word)]; /* GC_valid_offsets[i] ==> */ /* GC_modws_valid_offsets[i%sizeof(word)] */ +# define OFFSET_VALID(displ) \ + (GC_all_interior_pointers || GC_valid_offsets[displ]) # ifdef STUBBORN_ALLOC page_hash_table _changed_pages; /* Stubborn object pages that were changes since last call to */ diff --git a/include/private/gcconfig.h b/include/private/gcconfig.h index 734bd85..94b446b 100644 --- a/include/private/gcconfig.h +++ b/include/private/gcconfig.h @@ -310,6 +310,10 @@ # define I386 # define mach_type_known # endif +# if defined(__NetBSD__) && defined(__x86_64__) +# define X86_64 +# define mach_type_known +# endif # if defined(bsdi) && (defined(i386) || defined(__i386__)) # define I386 # define BSDI @@ -605,8 +609,14 @@ # ifdef OPENBSD # define OS_TYPE "OPENBSD" # define HEURISTIC2 - extern char etext[]; -# define DATASTART ((ptr_t)(etext)) +# ifdef __ELF__ +# define DATASTART GC_data_start +# define DYNAMIC_LOADING +# else + extern char etext[]; +# define DATASTART ((ptr_t)(etext)) +# endif +# define USE_GENERIC_PUSH_REGS # endif # ifdef NETBSD # define OS_TYPE "NETBSD" @@ -618,6 +628,7 @@ extern char etext[]; # define DATASTART ((ptr_t)(etext)) # endif +# define USE_GENERIC_PUSH_REGS # endif # ifdef LINUX # define OS_TYPE "LINUX" @@ -1086,6 +1097,8 @@ # define DATASTART ((ptr_t)((((word) (etext)) + 0xfff) & ~0xfff)) # endif # ifdef USE_I686_PREFETCH + /* FIXME: Thus should use __builtin_prefetch, but we'll leave that */ + /* for the next rtelease. */ # define PREFETCH(x) \ __asm__ __volatile__ (" prefetchnta %0": : "m"(*(char *)(x))) /* Empirically prefetcht0 is much more effective at reducing */ @@ -1624,17 +1637,17 @@ # ifdef __GNUC__ # ifndef __INTEL_COMPILER # define PREFETCH(x) \ - __asm__ (" lfetch [%0]": : "r"((void *)(x))) + __asm__ (" lfetch [%0]": : "r"(x)) # define PREFETCH_FOR_WRITE(x) \ - __asm__ (" lfetch.excl [%0]": : "r"((void *)(x))) + __asm__ (" lfetch.excl [%0]": : "r"(x)) # define CLEAR_DOUBLE(x) \ __asm__ (" stf.spill [%0]=f0": : "r"((void *)(x))) # else # include <ia64intrin.h> # define PREFETCH(x) \ - __lfetch(__lfhint_none, (void*)(x)) + __lfetch(__lfhint_none, (x)) # define PREFETCH_FOR_WRITE(x) \ - __lfetch(__lfhint_nta, (void*)(x)) + __lfetch(__lfhint_nta, (x)) # define CLEAR_DOUBLE(x) \ __stf_spill((void *)(x), 0) # endif // __INTEL_COMPILER @@ -1840,10 +1853,19 @@ extern int etext[]; # define DATASTART ((ptr_t)((((word) (etext)) + 0xfff) & ~0xfff)) # endif -# define PREFETCH(x) \ - __asm__ __volatile__ (" prefetch %0": : "m"(*(char *)(x))) -# define PREFETCH_FOR_WRITE(x) \ - __asm__ __volatile__ (" prefetchw %0": : "m"(*(char *)(x))) +# if defined(__GNUC__) && __GNUC >= 3 +# define PREFETCH(x) __builtin_prefetch((x), 0, 0) +# define PREFETCH_FOR_WRITE(x) __builtin_prefetch((x), 1) +# endif +# endif +# ifdef NETBSD +# define OS_TYPE "NETBSD" +# ifdef __ELF__ +# define DYNAMIC_LOADING +# endif +# define HEURISTIC2 + extern char etext[]; +# define SEARCH_FOR_DATA_START # endif # endif @@ -1907,6 +1929,10 @@ # define SUNOS5SIGS # endif +# if defined(FREEBSD) && (__FreeBSD__ >= 4) +# define SUNOS5SIGS +# endif + # if defined(SVR4) || defined(LINUX) || defined(IRIX5) || defined(HPUX) \ || defined(OPENBSD) || defined(NETBSD) || defined(FREEBSD) \ || defined(DGUX) || defined(BSD) || defined(SUNOS4) \ diff --git a/ltconfig b/ltconfig deleted file mode 100644 index 962057f..0000000 --- a/ltconfig +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/sh -# I could find no versions of autoconf that don't invoke ltconfig, but -# libtool no longer includes an ltconfig. Yuch. @@ -684,7 +684,7 @@ mse * mark_stack_limit; current = *current_p; FIXUP_POINTER(current); if ((ptr_t)current >= least_ha && (ptr_t)current < greatest_ha) { - PREFETCH(current); + PREFETCH((ptr_t)current); HC_PUSH_CONTENTS((ptr_t)current, mark_stack_top, mark_stack_limit, current_p, exit1); } @@ -760,7 +760,7 @@ mse * mark_stack_limit; FIXUP_POINTER(deferred); limit = (word *)((char *)limit - ALIGNMENT); if ((ptr_t)deferred >= least_ha && (ptr_t)deferred < greatest_ha) { - PREFETCH(deferred); + PREFETCH((ptr_t)deferred); break; } if (current_p > limit) goto next_object; @@ -770,7 +770,7 @@ mse * mark_stack_limit; FIXUP_POINTER(deferred); limit = (word *)((char *)limit - ALIGNMENT); if ((ptr_t)deferred >= least_ha && (ptr_t)deferred < greatest_ha) { - PREFETCH(deferred); + PREFETCH((ptr_t)deferred); break; } if (current_p > limit) goto next_object; @@ -787,7 +787,7 @@ mse * mark_stack_limit; if ((ptr_t)current >= least_ha && (ptr_t)current < greatest_ha) { /* Prefetch the contents of the object we just pushed. It's */ /* likely we will need them soon. */ - PREFETCH(current); + PREFETCH((ptr_t)current); HC_PUSH_CONTENTS((ptr_t)current, mark_stack_top, mark_stack_limit, current_p, exit2); } @@ -1739,7 +1739,7 @@ register hdr * hhdr; { register int sz = hhdr -> hb_sz; - if (sz < MAXOBJSZ) { + if (sz <= MAXOBJSZ) { return(GC_page_was_dirty(h)); } else { register ptr_t p = (ptr_t)h; @@ -104,7 +104,7 @@ ptr_t ofl; p[3] = 0; p += 4; for (; p < lim; p += 4) { - PREFETCH_FOR_WRITE(p+64); + PREFETCH_FOR_WRITE((ptr_t)(p+64)); p[0] = (word)(p-4); p[1] = 0; CLEAR_DOUBLE(p+2); @@ -142,7 +142,7 @@ ptr_t ofl; p[4] = (word)p; p += 8; for (; p < lim; p += 8) { - PREFETCH_FOR_WRITE(p+64); + PREFETCH_FOR_WRITE((ptr_t)(p+64)); p[0] = (word)(p-4); p[4] = (word)p; }; @@ -171,10 +171,10 @@ ptr_t list; /* If we were more serious about it, these should go inside */ /* the loops. But write prefetches usually don't seem to */ /* matter much. */ - PREFETCH_FOR_WRITE((char *)h); - PREFETCH_FOR_WRITE((char *)h + 128); - PREFETCH_FOR_WRITE((char *)h + 256); - PREFETCH_FOR_WRITE((char *)h + 378); + PREFETCH_FOR_WRITE((ptr_t)h); + PREFETCH_FOR_WRITE((ptr_t)h + 128); + PREFETCH_FOR_WRITE((ptr_t)h + 256); + PREFETCH_FOR_WRITE((ptr_t)h + 378); /* Handle small objects sizes more efficiently. For larger objects */ /* the difference is less significant. */ # ifndef SMALL_CONFIG @@ -129,7 +129,7 @@ #ifdef UNIX_LIKE # include <fcntl.h> -# ifdef SUNOS5SIGS +# if defined(SUNOS5SIGS) && !defined(FREEBSD) # include <sys/siginfo.h> # endif /* Define SETJMP and friends to be the version that restores */ @@ -2192,7 +2192,7 @@ GC_bool is_ptrfree; /* Using vm_protect (mach syscall) over mprotect (BSD syscall) seems to decrease the likelihood of some of the problems described below. */ #include <mach/vm_map.h> - extern mach_port_t GC_task_self; + static mach_port_t GC_task_self; #define PROTECT(addr,len) \ if(vm_protect(GC_task_self,(vm_address_t)(addr),(vm_size_t)(len), \ FALSE,VM_PROT_READ) != KERN_SUCCESS) { \ @@ -2225,9 +2225,9 @@ GC_bool is_ptrfree; # endif /* !DARWIN */ # endif /* MSWIN32 || MSWINCE || DARWIN */ -#if defined(SUNOS4) || defined(FREEBSD) +#if defined(SUNOS4) || (defined(FREEBSD) && !defined(SUNOS5SIGS)) typedef void (* SIG_PF)(); -#endif /* SUNOS4 || FREEBSD */ +#endif /* SUNOS4 || (FREEBSD && !SUNOS5SIGS) */ #if defined(SUNOS5SIGS) || defined(OSF1) || defined(LINUX) \ || defined(HURD) @@ -2254,13 +2254,13 @@ GC_bool is_ptrfree; #endif /* IRIX5 || OSF1 || HURD */ #if defined(SUNOS5SIGS) -# ifdef HPUX -# define SIGINFO __siginfo +# if defined(HPUX) || defined(FREEBSD) +# define SIGINFO_T siginfo_t # else -# define SIGINFO siginfo +# define SIGINFO_T struct siginfo # endif # ifdef __STDC__ - typedef void (* REAL_SIG_PF)(int, struct SIGINFO *, void *); + typedef void (* REAL_SIG_PF)(int, SIGINFO_T *, void *); # else typedef void (* REAL_SIG_PF)(); # endif @@ -2280,8 +2280,11 @@ GC_bool is_ptrfree; # if defined(ALPHA) || defined(M68K) typedef void (* REAL_SIG_PF)(int, int, s_c *); # else -# if defined(IA64) || defined(HP_PA) +# if defined(IA64) || defined(HP_PA) || defined(X86_64) typedef void (* REAL_SIG_PF)(int, siginfo_t *, s_c *); + /* FIXME: */ + /* According to SUSV3, the last argument should have type */ + /* void * or ucontext_t * */ # else typedef void (* REAL_SIG_PF)(int, s_c); # endif @@ -2356,7 +2359,7 @@ SIG_PF GC_old_segv_handler; /* Also old MSWIN32 ACCESS_VIOLATION filter */ /*ARGSUSED*/ #if !defined(DARWIN) -# if defined (SUNOS4) || defined(FREEBSD) +# if defined (SUNOS4) || (defined(FREEBSD) && !defined(SUNOS5SIGS)) void GC_write_fault_handler(sig, code, scp, addr) int sig, code; struct sigcontext *scp; @@ -2371,7 +2374,7 @@ SIG_PF GC_old_segv_handler; /* Also old MSWIN32 ACCESS_VIOLATION filter */ # define SIG_OK (sig == SIGBUS) # define CODE_OK (code == BUS_PAGE_FAULT) # endif -# endif /* SUNOS4 || FREEBSD */ +# endif /* SUNOS4 || (FREEBSD && !SUNOS5SIGS) */ # if defined(IRIX5) || defined(OSF1) || defined(HURD) # include <errno.h> @@ -2394,7 +2397,7 @@ SIG_PF GC_old_segv_handler; /* Also old MSWIN32 ACCESS_VIOLATION filter */ # if defined(ALPHA) || defined(M68K) void GC_write_fault_handler(int sig, int code, s_c * sc) # else -# if defined(IA64) || defined(HP_PA) +# if defined(IA64) || defined(HP_PA) || defined(X86_64) void GC_write_fault_handler(int sig, siginfo_t * si, s_c * scp) # else # if defined(ARM32) @@ -2413,11 +2416,11 @@ SIG_PF GC_old_segv_handler; /* Also old MSWIN32 ACCESS_VIOLATION filter */ # if defined(SUNOS5SIGS) # ifdef __STDC__ - void GC_write_fault_handler(int sig, struct SIGINFO *scp, void * context) + void GC_write_fault_handler(int sig, SIGINFO_T *scp, void * context) # else void GC_write_fault_handler(sig, scp, context) int sig; - struct SIGINFO *scp; + SIGINFO_T *scp; void * context; # endif # ifdef HPUX @@ -2428,9 +2431,14 @@ SIG_PF GC_old_segv_handler; /* Also old MSWIN32 ACCESS_VIOLATION filter */ || (scp -> si_code == SEGV_UNKNOWN) \ || (scp -> si_code == BUS_OBJERR) # else -# define SIG_OK (sig == SIGSEGV) -# define CODE_OK (scp -> si_code == SEGV_ACCERR) -# endif +# ifdef FREEBSD +# define SIG_OK (sig == SIGBUS) +# define CODE_OK (scp -> si_code == BUS_PAGE_FAULT) +# else +# define SIG_OK (sig == SIGSEGV) +# define CODE_OK (scp -> si_code == SEGV_ACCERR) +# endif +# endif # endif /* SUNOS5SIGS */ # if defined(MSWIN32) || defined(MSWINCE) @@ -2455,7 +2463,7 @@ SIG_PF GC_old_segv_handler; /* Also old MSWIN32 ACCESS_VIOLATION filter */ char * addr = (char *) (scp -> si_addr); # endif # ifdef LINUX -# if defined(I386) || defined (X86_64) +# if defined(I386) char * addr = (char *) (sc.cr2); # else # if defined(M68K) @@ -2490,7 +2498,7 @@ SIG_PF GC_old_segv_handler; /* Also old MSWIN32 ACCESS_VIOLATION filter */ # ifdef ALPHA char * addr = get_fault_addr(sc); # else -# if defined(IA64) || defined(HP_PA) +# if defined(IA64) || defined(HP_PA) || defined(X86_64) char * addr = si -> si_addr; /* I believe this is claimed to work on all platforms for */ /* Linux 2.3.47 and later. Hopefully we don't have to */ @@ -2533,6 +2541,10 @@ SIG_PF GC_old_segv_handler; /* Also old MSWIN32 ACCESS_VIOLATION filter */ in_allocd_block = (HDR(addr) != 0); # endif if (!in_allocd_block) { + /* FIXME - We should make sure that we invoke the */ + /* old handler with the appropriate calling */ + /* sequence, which often depends on SA_SIGINFO. */ + /* Heap blocks now begin and end on page boundaries */ SIG_PF old_handler; @@ -2549,11 +2561,17 @@ SIG_PF GC_old_segv_handler; /* Also old MSWIN32 ACCESS_VIOLATION filter */ return(EXCEPTION_CONTINUE_SEARCH); # endif } else { -# if defined (SUNOS4) || defined(FREEBSD) +# if defined (SUNOS4) \ + || (defined(FREEBSD) && !defined(SUNOS5SIGS)) (*old_handler) (sig, code, scp, addr); return; # endif # if defined (SUNOS5SIGS) + /* + * FIXME: For FreeBSD, this code should check if the + * old signal handler used the traditional BSD style and + * if so call it using that style. + */ (*(REAL_SIG_PF)old_handler) (sig, scp, context); return; # endif @@ -2561,7 +2579,7 @@ SIG_PF GC_old_segv_handler; /* Also old MSWIN32 ACCESS_VIOLATION filter */ # if defined(ALPHA) || defined(M68K) (*(REAL_SIG_PF)old_handler) (sig, code, sc); # else -# if defined(IA64) || defined(HP_PA) +# if defined(IA64) || defined(HP_PA) || defined(X86_64) (*(REAL_SIG_PF)old_handler) (sig, si, scp); # else (*(REAL_SIG_PF)old_handler) (sig, sc); @@ -2655,7 +2673,8 @@ void GC_dirty_init() struct sigaction act, oldact; /* We should probably specify SA_SIGINFO for Linux, and handle */ /* the different architectures more uniformly. */ -# if defined(IRIX5) || defined(LINUX) || defined(OSF1) || defined(HURD) +# if defined(IRIX5) || defined(LINUX) && !defined(X86_64) \ + || defined(OSF1) || defined(HURD) act.sa_flags = SA_RESTART; act.sa_handler = (SIG_PF)GC_write_fault_handler; # else @@ -2678,7 +2697,7 @@ void GC_dirty_init() GC_err_printf0("Page size not multiple of HBLKSIZE\n"); ABORT("Page size not multiple of HBLKSIZE"); } -# if defined(SUNOS4) || defined(FREEBSD) +# if defined(SUNOS4) || (defined(FREEBSD) && !defined(SUNOS5SIGS)) GC_old_bus_handler = signal(SIGBUS, GC_write_fault_handler); if (GC_old_bus_handler == SIG_IGN) { GC_err_printf0("Previously ignored bus error!?"); @@ -2702,13 +2721,13 @@ void GC_dirty_init() # endif } # endif -# if defined(SUNOS5SIGS) || defined(IRIX5) || defined(LINUX) \ - || defined(OSF1) || defined(HURD) +# if (defined(SUNOS5SIGS) && !defined(FREEBSD)) || defined(IRIX5) \ + || defined(LINUX) || defined(OSF1) || defined(HURD) /* SUNOS5SIGS includes HPUX */ # if defined(GC_IRIX_THREADS) sigaction(SIGSEGV, 0, &oldact); sigaction(SIGSEGV, &act, 0); -# else +# else { int res = sigaction(SIGSEGV, &act, &oldact); if (res != 0) ABORT("Sigaction failed"); @@ -2734,8 +2753,9 @@ void GC_dirty_init() GC_err_printf0("Replaced other SIGSEGV handler\n"); # endif } -# endif -# if defined(HPUX) || defined(LINUX) || defined(HURD) +# endif /* (SUNOS5SIGS && !FREEBSD) || IRIX5 || LINUX || OSF1 || HURD */ +# if defined(HPUX) || defined(LINUX) || defined(HURD) \ + || (defined(FREEBSD) && defined(SUNOS5SIGS)) sigaction(SIGBUS, &act, &oldact); GC_old_bus_handler = oldact.sa_handler; if (GC_old_bus_handler == SIG_IGN) { @@ -2747,7 +2767,7 @@ void GC_dirty_init() GC_err_printf0("Replaced other SIGBUS handler\n"); # endif } -# endif /* HPUX || LINUX || HURD */ +# endif /* HPUX || LINUX || HURD || (FREEBSD && SUNOS5SIGS) */ # if defined(MSWIN32) GC_old_segv_handler = SetUnhandledExceptionFilter(GC_write_fault_handler); if (GC_old_segv_handler != NULL) { @@ -3032,7 +3052,7 @@ word n; #include <sys/procfs.h> #include <sys/stat.h> -#define INITIAL_BUF_SZ 4096 +#define INITIAL_BUF_SZ 16384 word GC_proc_buf_size = INITIAL_BUF_SZ; char *GC_proc_buf; @@ -3146,7 +3166,7 @@ int dummy; GC_proc_buf = bufp = new_buf; GC_proc_buf_size = new_size; } - if (syscall(SYS_read, GC_proc_fd, bufp, GC_proc_buf_size) <= 0) { + if (READ(GC_proc_fd, bufp, GC_proc_buf_size) <= 0) { WARN("Insufficient space for /proc read\n", 0); /* Punt: */ memset(GC_grungy_pages, 0xff, sizeof (page_hash_table)); @@ -3367,8 +3387,6 @@ extern kern_return_t exception_raise_state_identity( #define MAX_EXCEPTION_PORTS 16 -static mach_port_t GC_task_self; - static struct { mach_msg_type_number_t count; exception_mask_t masks[MAX_EXCEPTION_PORTS]; diff --git a/pthread_stop_world.c b/pthread_stop_world.c index 1cdda21..832c49c 100644 --- a/pthread_stop_world.c +++ b/pthread_stop_world.c @@ -39,6 +39,34 @@ void GC_print_sig_mask() #endif +/* Remove the signals that we want to allow in thread stopping */ +/* handler from a set. */ +void GC_remove_allowed_signals(sigset_t *set) +{ +# ifdef NO_SIGNALS + if (sigdelset(set, SIGINT) != 0 + || sigdelset(set, SIGQUIT) != 0 + || sigdelset(set, SIGABRT) != 0 + || sigdelset(set, SIGTERM) != 0) { + ABORT("sigdelset() failed"); + } +# endif + +# ifdef MPROTECT_VDB + /* Handlers write to the thread structure, which is in the heap, */ + /* and hence can trigger a protection fault. */ + if (sigdelset(set, SIGSEGV) != 0 +# ifdef SIGBUS + || sigdelset(set, SIGBUS) != 0 +# endif + ) { + ABORT("sigdelset() failed"); + } +# endif +} + +static sigset_t suspend_handler_mask; + word GC_stop_count; /* Incremented at the beginning of GC_stop_world. */ #ifdef GC_OSF1_THREADS @@ -78,7 +106,6 @@ void GC_suspend_handler(int sig) int dummy; pthread_t my_thread = pthread_self(); GC_thread me; - sigset_t mask; # ifdef PARALLEL_MARK word my_mark_no = GC_mark_no; /* Marker can't proceed until we acknowledge. Thus this is */ @@ -125,17 +152,9 @@ void GC_suspend_handler(int sig) /* this thread a SIG_THR_RESTART signal. */ /* SIG_THR_RESTART should be masked at this point. Thus there */ /* is no race. */ - if (sigfillset(&mask) != 0) ABORT("sigfillset() failed"); - if (sigdelset(&mask, SIG_THR_RESTART) != 0) ABORT("sigdelset() failed"); -# ifdef NO_SIGNALS - if (sigdelset(&mask, SIGINT) != 0) ABORT("sigdelset() failed"); - if (sigdelset(&mask, SIGQUIT) != 0) ABORT("sigdelset() failed"); - if (sigdelset(&mask, SIGTERM) != 0) ABORT("sigdelset() failed"); - if (sigdelset(&mask, SIGABRT) != 0) ABORT("sigdelset() failed"); -# endif do { me->stop_info.signal = 0; - sigsuspend(&mask); /* Wait for signal */ + sigsuspend(&suspend_handler_mask); /* Wait for signal */ } while (me->stop_info.signal != SIG_THR_RESTART); /* If the RESTART signal gets lost, we can still lose. That should be */ /* less likely than losing the SUSPEND signal, since we don't do much */ @@ -417,16 +436,9 @@ void GC_stop_init() { if (sigfillset(&act.sa_mask) != 0) { ABORT("sigfillset() failed"); } -# ifdef NO_SIGNALS - if (sigdelset(&act.sa_mask, SIGINT) != 0 - || sigdelset(&act.sa_mask, SIGQUIT != 0) - || sigdelset(&act.sa_mask, SIGABRT != 0) - || sigdelset(&act.sa_mask, SIGTERM != 0)) { - ABORT("sigdelset() failed"); - } -# endif - - /* SIG_THR_RESTART is unmasked by the handler when necessary. */ + GC_remove_allowed_signals(&act.sa_mask); + /* SIG_THR_RESTART is set in the resulting mask. */ + /* It is unmasked by the handler when necessary. */ act.sa_handler = GC_suspend_handler; if (sigaction(SIG_SUSPEND, &act, NULL) != 0) { ABORT("Cannot set SIG_SUSPEND handler"); @@ -437,6 +449,12 @@ void GC_stop_init() { ABORT("Cannot set SIG_THR_RESTART handler"); } + /* Inititialize suspend_handler_mask. It excludes SIG_THR_RESTART. */ + if (sigfillset(&suspend_handler_mask) != 0) ABORT("sigfillset() failed"); + GC_remove_allowed_signals(&suspend_handler_mask); + if (sigdelset(&suspend_handler_mask, SIG_THR_RESTART) != 0) + ABORT("sigdelset() failed"); + /* Check for GC_RETRY_SIGNALS. */ if (0 != GETENV("GC_RETRY_SIGNALS")) { GC_retry_signals = TRUE; diff --git a/solaris_pthreads.c b/solaris_pthreads.c index bae7719..1e43d09 100644 --- a/solaris_pthreads.c +++ b/solaris_pthreads.c @@ -16,8 +16,10 @@ * Modified by Peter C. for Solaris Posix Threads. */ -# if defined(GC_SOLARIS_PTHREADS) +# if defined(GC_SOLARIS_PTHREADS) || defined(GC_THREADS) # include "private/gc_priv.h" +# endif +# if defined(GC_SOLARIS_PTHREADS) # include <pthread.h> # include <thread.h> # include <signal.h> diff --git a/solaris_threads.c b/solaris_threads.c index 5f05b19..0a07690 100644 --- a/solaris_threads.c +++ b/solaris_threads.c @@ -16,9 +16,12 @@ */ /* Boehm, September 14, 1994 4:44 pm PDT */ -# if defined(GC_SOLARIS_THREADS) || defined(GC_SOLARIS_PTHREADS) +# if defined(GC_SOLARIS_THREADS) || defined(GC_SOLARIS_PTHREADS) \ + || defined(GC_THREADS) +# include "private/gc_priv.h" +# endif -# include "private/gc_priv.h" +# if defined(GC_SOLARIS_THREADS) || defined(GC_SOLARIS_PTHREADS) # include "private/solaris_threads.h" # include <thread.h> # include <synch.h> @@ -786,6 +789,7 @@ void GC_thr_init(void) { GC_thread t; thread_t tid; + int ret; if (GC_thr_initialized) return; @@ -803,9 +807,11 @@ void GC_thr_init(void) t = GC_new_thread(thr_self()); t -> stack_size = 0; t -> flags = DETACHED | CLIENT_OWNS_STACK; - if (thr_create(0 /* stack */, 0 /* stack_size */, GC_thr_daemon, - 0 /* arg */, THR_DETACHED | THR_DAEMON, - &tid /* thread_id */) != 0) { + ret = thr_create(0 /* stack */, 0 /* stack_size */, GC_thr_daemon, + 0 /* arg */, THR_DETACHED | THR_DAEMON, + &tid /* thread_id */); + if (ret != 0) { + GC_err_printf1("Thr_create returned %ld\n", ret); ABORT("Cant fork daemon"); } thr_setprio(tid, 126); diff --git a/tests/middle.c b/tests/middle.c new file mode 100644 index 0000000..5d9360a --- /dev/null +++ b/tests/middle.c @@ -0,0 +1,25 @@ +/* + * Test at the boundary between small and large objects. + * Inspired by a test case from Zoltan Varga. + */ +#include <gc.h> +#include <stdio.h> + +int main () +{ + int i; + + GC_all_interior_pointers = 0; + + for (i = 0; i < 20000; ++i) { + GC_malloc_atomic (4096); + GC_malloc (4096); + } + for (i = 0; i < 20000; ++i) { + GC_malloc_atomic (2048); + GC_malloc (2048); + } + printf("Final heap size is %ld\n", GC_get_heap_size()); + return 0; +} + diff --git a/tests/test.c b/tests/test.c index ccec876..e1676aa 100644 --- a/tests/test.c +++ b/tests/test.c @@ -1255,9 +1255,11 @@ void run_one_test() FAIL; } if (!TEST_FAIL_COUNT(1)) { -# if!(defined(RS6000) || defined(POWERPC) || defined(IA64)) +# if!(defined(RS6000) || defined(POWERPC) || defined(IA64)) || defined(M68K) /* ON RS6000s function pointers point to a descriptor in the */ /* data segment, so there should have been no failures. */ + /* The same applies to IA64. Something similar seems to */ + /* be going on with NetBSD/M68K. */ (void)GC_printf0("GC_is_visible produced wrong failure indication\n"); FAIL; # endif diff --git a/threadlibs.c b/threadlibs.c index 247d3c6..264b724 100644 --- a/threadlibs.c +++ b/threadlibs.c @@ -1,3 +1,4 @@ +# include "gc_config_macros.h" # include "private/gcconfig.h" # include <stdio.h> @@ -3,7 +3,7 @@ /* it to keep the old-style build process working. */ #define GC_TMP_VERSION_MAJOR 6 #define GC_TMP_VERSION_MINOR 3 -#define GC_TMP_ALPHA_VERSION 5 +#define GC_TMP_ALPHA_VERSION GC_NOT_ALPHA #ifndef GC_NOT_ALPHA # define GC_NOT_ALPHA 0xff |