From: Hans Boehm Date: Thu, 6 May 2004 00:00:00 +0000 (+0000) Subject: gc6.3alpha6 tarball import X-Git-Tag: gc6_3alpha6^0 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=f3602b41a93efcb0891a1805f8150794cb302feb;p=gc gc6.3alpha6 tarball import --- diff --git a/Makefile b/Makefile index 74929c18..f2b32246 100644 --- a/Makefile +++ b/Makefile @@ -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 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.direct b/Makefile.direct index 74929c18..f2b32246 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 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 2c7c1b72..5477b555 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) diff --git a/checksums.c b/checksums.c index 121c36d4..57a6ebc2 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); diff --git a/configure b/configure index 3ede246c..84b7f1ca 100755 --- a/configure +++ b/configure @@ -1,7 +1,7 @@ #! /bin/sh # From configure.in Revision: 1.2 . # Guess values for system-dependent variables and create Makefiles. -# Generated by GNU Autoconf 2.53 for gc 6.3alpha5. +# Generated by GNU Autoconf 2.53 for gc 6.3alpha6. # # Report bugs to . # @@ -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.3alpha6' +PACKAGE_STRING='gc 6.3alpha6' 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.3alpha6 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.3alpha6:";; 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.3alpha6 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.3alpha6, 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.3alpha6 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.3alpha6, 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.3alpha6 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 635742cf..3e3aba34 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.3alpha6,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/dbg_mlc.c b/dbg_mlc.c index 9daa0b0d..aacbb7a1 100644 --- a/dbg_mlc.c +++ b/dbg_mlc.c @@ -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 91446305..9446bcb1 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 1e9dd929..708fd51b 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 diff --git a/doc/README b/doc/README index 0776e678..ae978c11 100644 --- a/doc/README +++ b/doc/README @@ -28,7 +28,7 @@ are GPL'ed, but with an exception that should cover all uses in the collector. (If you are concerned about such things, I recommend you look at the notice in config.guess or ltmain.sh.) -This is version 6.3alpha5 of a conservative garbage collector for C and C++. +This is version 6.3alpha6 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 38bde346..129738cf 100644 --- a/doc/README.changes +++ b/doc/README.changes @@ -2049,9 +2049,33 @@ 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. 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 00000000..0bc0953e --- /dev/null +++ b/doc/simple_example.html @@ -0,0 +1,202 @@ + + +Using the Garbage Collector: A simple example + + +

Using the Garbage Collector: A simple example

+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. The green +text contains information about other platforms or scenarios. +It can be skipped, especially on first reading. +

Building the collector

+If you haven't already so, unpack the collector and enter +the newly created directory with +
+tar xvfz gc.tar.gz
+cd gc
+
+

+You can configure, build, and install the collector in a private +directory, say /home/xyz/gc, with the following commands: +

+./configure --prefix=/home/xyz/gc --disable-threads
+make
+make check
+make install
+
+Here the "make check" command is optional, but highly recommended. +It runs a basic correctness test which usually takes well under a minute. + +

Other platforms

+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. +

+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. +

+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.) +

Threads

+If you need thread support, configure the collector with +
+--enable-threads=posix --enable-thread-local-alloc --enable-parallel-mark
+
+instead of +--disable-threads +If your target is a real old-fashioned uniprocessor (no "hyperthreading", +etc.) you will want to omit --enable-parallel-mark. +

C++

+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 --enable-cplusplus to the configure options. +
+

Writing the program

+You will need a +
+#include "gc.h"
+
+at the beginning of every file that allocates memory through the +garbage collector. Call GC_MALLOC wherever you would +have call malloc. This initializes memory to zero like +calloc; there is no need to explicitly clear the +result. +

+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 GC_MALLOC_ATOMIC instead. +

+A function GC_FREE 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. +

+A GC_REALLOC function behaves like the C library realloc. +It allocates uninitialized pointer-free memory if the original +object was allocated that way. +

+The following program loop.c is a trivial example: +

+#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;
+}
+
+ +

Interaction with the system malloc

+It is usually best not to mix garbage-collected allocation with the system +malloc-free. If you do, you need to be careful not to store +pointers to the garbage-collected heap in memory allocated with the system +malloc. +

Other Platforms

+On some other platforms it is necessary to call GC_INIT() 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. + +

Threads

+For a multithreaded program some more rules apply: +
    +
  • +Files that either allocate through the GC or make thread-related calls +should first define the macro GC_THREADS, and then +include "gc.h". On some platforms this will redefine some +threads primitives, e.g. to let the collector keep track of thread creation. +
  • +To take advantage of fast thread-local allocation, use the following instead +of including gc.h: +
    +#define GC_REDIRECT_TO_LOCAL
    +#include "gc_local_alloc.h"
    +
    +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. +
+ +

C++

+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 alternate interfaces +to make that easier. + +

Debugging

+Additional debug checks can be performed by defining GC_DEBUG before +including gc.h. Additional options are available if the collector +is also built with --enable-full_debug and all allocations are +performed with GC_DEBUG defined. + +

What if I can't rewrite/recompile my program?

+You may be able to build the collector with --enable-redirect-malloc +and set the LD_PRELOAD environment variable to point to the resulting +library, thus replacing the standard malloc with its garbage-collected +counterpart. This is rather platform dependent. See the +leak detection documentation for some more details. + +
+ +

Compiling and linking

+ +The above application loop.c test program can be compiled and linked +with + +
+cc -I/home/xyz/gc/include loop.c /home/xyz/gc/lib/libgc.a -o loop
+
+ +The -I 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 LD_LIBRARY_PATH. + + + +

Threads

+ +On pthread platforms, you will of course also have to link with +-lpthread, +and compile with any thread-safety options required by your compiler. +On some platforms, you may also need to link with -ldl +or -lrt. +Looking at threadlibs.c in the GC build directory +should give you the appropriate +list if a plain -lpthread doesn't work. + +
+ +

Running the executable

+ +The executable can of course be run normally, e.g. by typing + +
+./loop
+
+ +The operation of the collector is affected by a number of environment variables. +For example, setting GC_PRINT_STATS produces some +GC statistics on stdout. +See README.environment in the distribution for details. + + diff --git a/dyn_load.c b/dyn_load.c index 70eb7644..9bd9e060 100644 --- a/dyn_load.c +++ b/dyn_load.c @@ -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 diff --git a/include/gc.h b/include/gc.h index 58a2ff54..ae555ae6 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) diff --git a/include/gc_allocator.h b/include/gc_allocator.h index 87c85099..b0c188cd 100644 --- a/include/gc_allocator.h +++ b/include/gc_allocator.h @@ -35,6 +35,10 @@ * library, which itself was derived from the SGI STL implementation. */ +#ifndef GC_ALLOCATOR_H + +#define GC_ALLOCATOR_H + #include "gc.h" // For size_t /* First some helpers to allow us to dispatch on whether or not a type @@ -230,3 +234,4 @@ inline bool operator!=(const traceable_allocator&, const traceable_alloca return false; } +#endif /* GC_ALLOCATOR_H */ diff --git a/include/gc_config_macros.h b/include/gc_config_macros.h index 4aaca2d3..d8d31141 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/gcconfig.h b/include/private/gcconfig.h index 734bd855..94b446b6 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 # 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 962057f0..00000000 --- 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. diff --git a/mark.c b/mark.c index 4b654683..dd1fbd5f 100644 --- a/mark.c +++ b/mark.c @@ -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); } diff --git a/new_hblk.c b/new_hblk.c index 1aa2c7a1..e5580e4c 100644 --- a/new_hblk.c +++ b/new_hblk.c @@ -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 diff --git a/os_dep.c b/os_dep.c index cb32bdd0..29eee4ee 100644 --- a/os_dep.c +++ b/os_dep.c @@ -129,7 +129,7 @@ #ifdef UNIX_LIKE # include -# ifdef SUNOS5SIGS +# if defined(SUNOS5SIGS) && !defined(FREEBSD) # include # endif /* Define SETJMP and friends to be the version that restores */ @@ -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 @@ -2356,7 +2356,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 +2371,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 @@ -2413,11 +2413,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 +2428,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) @@ -2533,6 +2538,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 +2558,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 @@ -2678,7 +2693,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 +2717,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 +2749,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 +2763,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) { @@ -3146,7 +3162,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)); diff --git a/pthread_stop_world.c b/pthread_stop_world.c index 1cdda21a..832c49ca 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/tests/test.c b/tests/test.c index ccec876f..e1676aad 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/version.h b/version.h index 3f46a40d..e8f1a3ab 100644 --- a/version.h +++ b/version.h @@ -3,7 +3,7 @@ /* it to keep the old-style build process working. */ #define GC_TMP_VERSION_MAJOR 6 #define GC_TMP_VERSION_MINOR 3 -#define GC_TMP_ALPHA_VERSION 5 +#define GC_TMP_ALPHA_VERSION 6 #ifndef GC_NOT_ALPHA # define GC_NOT_ALPHA 0xff