summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile41
-rw-r--r--Makefile.DLLs107
-rw-r--r--Makefile.dj179
-rw-r--r--README136
-rw-r--r--README.Mac328
-rw-r--r--README.alpha15
-rw-r--r--README.dj23
-rw-r--r--README.hp4
-rw-r--r--README.linux7
-rw-r--r--README.sgi9
-rw-r--r--README.solaris254
-rw-r--r--README.win3258
-rw-r--r--WCC_MAKEFILE123
-rw-r--r--allchblk.c14
-rw-r--r--alloc.c37
-rw-r--r--blacklst.c17
-rw-r--r--config.h148
-rw-r--r--cord/gc.h42
-rw-r--r--dbg_mlc.c12
-rw-r--r--dyn_load.c86
-rw-r--r--gc.h42
-rw-r--r--gc_alloc.h12
-rw-r--r--gc_cpp.h4
-rw-r--r--gc_priv.h100
-rw-r--r--gc_typed.h7
-rw-r--r--gc_watcom.asm51
-rw-r--r--if_mach.c1
-rw-r--r--if_not_there.c1
-rw-r--r--include/gc.h42
-rw-r--r--include/gc_alloc.h12
-rw-r--r--include/gc_cpp.h4
-rw-r--r--include/gc_typed.h7
-rw-r--r--include/private/gc_priv.h100
-rw-r--r--irix_threads.c33
-rw-r--r--mach_dep.c6
-rw-r--r--malloc.c7
-rw-r--r--mallocx.c1
-rw-r--r--mark.c23
-rw-r--r--mark_rts.c113
-rw-r--r--misc.c47
-rw-r--r--os_dep.c239
-rw-r--r--reclaim.c2
-rw-r--r--setjmp_t.c49
-rw-r--r--solaris_pthreads.c170
-rw-r--r--solaris_threads.c322
-rw-r--r--solaris_threads.h34
-rw-r--r--sparc_sunos4_mach_dep.s38
-rw-r--r--test.c8
-rw-r--r--test_cpp.cc1
-rw-r--r--typd_mlc.c53
-rw-r--r--version.h11
51 files changed, 2449 insertions, 531 deletions
diff --git a/Makefile b/Makefile
index 6ab9dbf7..87fcc3f7 100644
--- a/Makefile
+++ b/Makefile
@@ -15,7 +15,7 @@ AS=as
# Under Irix 6, you will have to specify the ABI for as if you specify
# it for the C compiler.
-CFLAGS= -O -DNO_SIGNALS -DALL_INTERIOR_POINTERS -DSILENT -DATOMIC_UNCOLLECTABLE
+CFLAGS= -O -DNO_SIGNALS -DALL_INTERIOR_POINTERS -DATOMIC_UNCOLLECTABLE -DNO_EXECUTE_PERMISSION -DSILENT
# Setjmp_test may yield overly optimistic results when compiled
# without optimization.
@@ -29,7 +29,9 @@ CFLAGS= -O -DNO_SIGNALS -DALL_INTERIOR_POINTERS -DSILENT -DATOMIC_UNCOLLECTABLE
# -DSOLARIS_THREADS enables support for Solaris (thr_) threads.
# (Clients should also define SOLARIS_THREADS and then include
# gc.h before performing thr_ or dl* or GC_ operations.)
-# This is broken on nonSPARC machines.
+# Must also define -D_REENTRANT
+# -D_SOLARIS_PTHREADS enables support for Solaris pthreads.
+# Define SOLARIS_THREADS as well.
# -DIRIX_THREADS enables support for Irix pthreads. See README.irix.
# -DALL_INTERIOR_POINTERS allows all pointers to the interior
# of objects to be recognized. (See gc_priv.h for consequences.)
@@ -81,6 +83,17 @@ CFLAGS= -O -DNO_SIGNALS -DALL_INTERIOR_POINTERS -DSILENT -DATOMIC_UNCOLLECTABLE
# -DATOMIC_UNCOLLECTABLE includes code for GC_malloc_atomic_uncollectable.
# This is useful if either the vendor malloc implementation is poor,
# or if REDIRECT_MALLOC is used.
+# -DHBLKSIZE=ddd, where ddd is a power of 2 between 512 and 16384, explicitly
+# sets the heap block size. Each heap block is devoted to a single size and
+# kind of object. For the incremental collector it makes sense to match
+# the most likely page size. Otherwise large values result in more
+# fragmentation, but generally better performance for large heaps.
+# -DUSE_MMAP use MMAP instead of sbrk to get new memory.
+# Works for Solaris and Irix.
+# -DMMAP_STACKS (for Solaris threads) Use mmap from /dev/zero rather than
+# GC_scratch_alloc() to get stack memory.
+
+
LIBGC_CFLAGS= -O -DNO_SIGNALS -DSILENT \
-DREDIRECT_MALLOC=GC_malloc_uncollectable \
@@ -98,9 +111,9 @@ RANLIB= ranlib
srcdir = .
VPATH = $(srcdir)
-OBJS= alloc.o reclaim.o allchblk.o misc.o mach_dep.o os_dep.o mark_rts.o headers.o mark.o obj_map.o blacklst.o finalize.o new_hblk.o dbg_mlc.o malloc.o stubborn.o checksums.o solaris_threads.o irix_threads.o typd_mlc.o ptr_chck.o mallocx.o
+OBJS= alloc.o reclaim.o allchblk.o misc.o mach_dep.o os_dep.o mark_rts.o headers.o mark.o obj_map.o blacklst.o finalize.o new_hblk.o dbg_mlc.o malloc.o stubborn.o checksums.o solaris_threads.o irix_threads.o typd_mlc.o ptr_chck.o mallocx.o solaris_pthreads.o
-CSRCS= reclaim.c allchblk.c misc.c alloc.c mach_dep.c os_dep.c mark_rts.c headers.c mark.c obj_map.c pcr_interface.c blacklst.c finalize.c new_hblk.c real_malloc.c dyn_load.c dbg_mlc.c malloc.c stubborn.c checksums.c solaris_threads.c irix_threads.c typd_mlc.c ptr_chck.c mallocx.c
+CSRCS= reclaim.c allchblk.c misc.c alloc.c mach_dep.c os_dep.c mark_rts.c headers.c mark.c obj_map.c pcr_interface.c blacklst.c finalize.c new_hblk.c real_malloc.c dyn_load.c dbg_mlc.c malloc.c stubborn.c checksums.c solaris_threads.c irix_threads.c typd_mlc.c ptr_chck.c mallocx.c solaris_pthreads.c
CORD_SRCS= cord/cordbscs.c cord/cordxtra.c cord/cordprnt.c cord/de.c cord/cordtest.c cord/cord.h cord/ec.h cord/private/cord_pos.h cord/de_win.c cord/de_win.h cord/de_cmds.h cord/de_win.ICO cord/de_win.RC cord/SCOPTIONS.amiga cord/SMakefile.amiga
@@ -111,7 +124,7 @@ SRCS= $(CSRCS) mips_sgi_mach_dep.s rs6000_mach_dep.s alpha_mach_dep.s \
config.h gc_mark.h include/gc_inl.h include/gc_inline.h gc.man \
threadlibs.c if_mach.c if_not_there.c gc_cpp.cc gc_cpp.h weakpointer.h \
gcc_support.c mips_ultrix_mach_dep.s include/gc_alloc.h gc_alloc.h \
- $(CORD_SRCS)
+ sparc_sunos4_mach_dep.s solaris_threads.h $(CORD_SRCS)
OTHER_FILES= Makefile PCR-Makefile OS2_MAKEFILE NT_MAKEFILE BCC_MAKEFILE \
README test.c test_cpp.cc setjmp_t.c SMakefile.amiga \
@@ -126,7 +139,9 @@ OTHER_FILES= Makefile PCR-Makefile OS2_MAKEFILE NT_MAKEFILE BCC_MAKEFILE \
include/gc_cpp.h Mac_files/datastart.c Mac_files/dataend.c \
Mac_files/MacOS_config.h Mac_files/MacOS_Test_config.h \
add_gc_prefix.c README.solaris2 README.sgi README.hp README.uts \
- win32_threads.c NT_THREADS_MAKEFILE gc.mak README.dj Makefile.dj
+ win32_threads.c NT_THREADS_MAKEFILE gc.mak README.dj Makefile.dj \
+ README.alpha README.linux version.h Makefile.DLLs gc_watcom.asm \
+ WCC_MAKEFILE
CORD_INCLUDE_FILES= $(srcdir)/gc.h $(srcdir)/cord/cord.h $(srcdir)/cord/ec.h \
$(srcdir)/cord/private/cord_pos.h
@@ -227,6 +242,7 @@ mach_dep.o: $(srcdir)/mach_dep.c $(srcdir)/mips_sgi_mach_dep.s $(srcdir)/mips_ul
./if_mach RS6000 "" $(AS) -o mach_dep.o $(srcdir)/rs6000_mach_dep.s
./if_mach ALPHA "" $(AS) -o mach_dep.o $(srcdir)/alpha_mach_dep.s
./if_mach SPARC SUNOS5 $(AS) -o mach_dep.o $(srcdir)/sparc_mach_dep.s
+ ./if_mach SPARC SUNOS4 $(AS) -o mach_dep.o $(srcdir)/sparc_sunos4_mach_dep.s
./if_not_there mach_dep.o $(CC) -c $(SPECIALCFLAGS) $(srcdir)/mach_dep.c
mark_rts.o: $(srcdir)/mark_rts.c if_mach if_not_there $(UTILS)
@@ -236,6 +252,8 @@ mark_rts.o: $(srcdir)/mark_rts.c if_mach if_not_there $(UTILS)
# Work-around for DEC optimizer tail recursion elimination bug.
# The ALPHA-specific line should be removed if gcc is used.
+alloc.o: version.h
+
cord/cordbscs.o: $(srcdir)/cord/cordbscs.c $(CORD_INCLUDE_FILES)
$(CC) $(CFLAGS) -c $(srcdir)/cord/cordbscs.c
mv cordbscs.o cord/cordbscs.o
@@ -343,6 +361,17 @@ gctest_dyn_link: test.o libgc.so
gctest_irix_dyn_link: test.o libirixgc.so
$(CC) -L$(ABSDIR) -o gctest_irix_dyn_link test.o -lirixgc
+test_dll.o: test.c libgc_globals.h
+ $(CC) $(CFLAGS) -DGC_USE_DLL -c test.c -o test_dll.o
+
+test_dll: test_dll.o libgc_dll.a libgc.dll
+ $(CC) test_dll.o -L$(ABSDIR) -lgc_dll -o test_dll
+
+SYM_PREFIX-libgc=GC
+
+# Uncomment the following line to build a GNU win32 DLL
+# include Makefile.DLLs
+
reserved_namespace: $(SRCS)
for file in $(SRCS) test.c test_cpp.cc; do \
sed s/GC_/_GC_/g < $$file > tmp; \
diff --git a/Makefile.DLLs b/Makefile.DLLs
new file mode 100644
index 00000000..011f49d3
--- /dev/null
+++ b/Makefile.DLLs
@@ -0,0 +1,107 @@
+#-----------------------------------------------------------------------------#
+
+# Makefile.DLLs, version 0.4.
+
+# Contributed by Fergus Henderson.
+
+# This Makefile contains rules for creating DLLs on Windows using gnu-win32.
+
+#-----------------------------------------------------------------------------#
+
+# This rule creates a `.def' file, which lists the symbols that are exported
+# from the DLL. We use `nm' to get a list of all the exported text (`T')
+# symbols and data symbols -- including uninitialized data (`B'),
+# initialized data (`D'), read-only data (`R'), and common blocks (`C').
+%.def: %.a
+ echo EXPORTS > $@
+ nm $< | grep '^........ [BCDRT] _' | sed 's/[^_]*_//' >> $@
+
+# We need to use macros to access global data:
+# the user of the DLL must refer to `foo' as `(*__imp_foo)'.
+# This rule creates a `_globals.h' file, which contains macros
+# for doing this.
+
+SYM_PREFIX = $(firstword $(SYM_PREFIX-$*) $*)
+DLL_MACRO = $(SYM_PREFIX)_USE_DLL
+IMP_MACRO = $(SYM_PREFIX)_IMP
+GLOBAL_MACRO = $(SYM_PREFIX)_GLOBAL
+
+%_globals.h: %.a
+ echo "/* automatically generated by Makefile.DLLs */" > $@
+ echo "#if defined(__GNUC__) && defined(_WIN32) \\" >> $@
+ echo " && defined($(DLL_MACRO))" >> $@
+ echo "# define $(IMP_MACRO)(name) __imp_##name" >> $@
+ echo "# define $(GLOBAL_MACRO)(name) (*$(IMP_MACRO)(name))" >> $@
+ echo "#else" >> $@
+ echo "# define $(GLOBAL_MACRO)(name) name" >> $@
+ echo "#endif" >> $@
+ echo "" >> $@
+ for sym in `nm $< | grep '^........ [BCDR] _' | sed 's/[^_]*_//'`; do \
+ echo "#define $$sym $(GLOBAL_MACRO)($$sym)" >> $@; \
+ done
+
+# This rule creates the export object file (`foo.exp') which contains the
+# jump table array; this export object file becomes part of the DLL.
+# This rule also creates the import library (`foo_dll.a') which contains small
+# stubs for all the functions exported by the DLL which jump to them via the
+# jump table. Executables that will use the DLL must be linked against this
+# stub library.
+%.exp %_dll.a : %.def
+ dlltool $(DLLTOOLFLAGS) $(DLLTOOLFLAGS-$*) \
+ --def $< \
+ --dllname $*.dll \
+ --output-exp $*.exp \
+ --output-lib $*_dll.a
+
+# The `sed' commands below are to convert DOS-style `C:\foo\bar'
+# pathnames into Unix-style `//c/foo/bar' pathnames.
+CYGWIN32_LIBS = $(shell echo \
+ -L`dirname \`gcc -print-file-name=libgcc.a | \
+ sed -e 's@^\\\\([A-Za-z]\\\\):@//\\\\1@g' -e 's@\\\\\\\\@/@g' \` ` \
+ -L`dirname \`gcc -print-file-name=libcygwin.a | \
+ sed -e 's@^\\\\([A-Za-z]\\\\):@//\\\\1@g' -e 's@\\\\\\\\@/@g' \` ` \
+ -L`dirname \`gcc -print-file-name=libkernel32.a | \
+ sed -e 's@^\\\\([A-Za-z]\\\\):@//\\\\1@g' -e 's@\\\\\\\\@/@g' \` ` \
+ -lgcc -lcygwin -lkernel32 -lgcc)
+
+RELOCATABLE=yes
+
+ifeq "$(strip $(RELOCATABLE))" "yes"
+
+# to create relocatable DLLs, we need to do two passes
+%.dll: %.exp %.a dll_fixup.o dll_init.o
+ $(LD) $(LDFLAGS) $(LDFLAGS-$*) --dll -o $*.base \
+ -e _dll_entry@12 dll_init.o \
+ dll_fixup.o $*.exp $*.a \
+ $(LDLIBS) $(LDLIBS-$*) \
+ $(CYGWIN32_LIBS)
+ $(LD) $(LDFLAGS) $(LDFLAGS-$*) --dll --base-file $*.base -o $@ \
+ -e _dll_entry@12 dll_init.o \
+ dll_fixup.o $*.exp $*.a \
+ $(LDLIBS) $(LDLIBS-$*) \
+ $(CYGWIN32_LIBS)
+ rm -f $*.base
+else
+
+%.dll: %.exp %.a dll_fixup.o dll_init.o
+ $(LD) $(LDFLAGS) $(LDFLAGS-$*) --dll -o $@ \
+ -e _dll_entry@12 dll_init.o \
+ dll_fixup.o $*.exp $*.a \
+ $(LDLIBS) $(LDLIBS-$*) \
+ $(CYGWIN32_LIBS)
+
+endif
+
+# This black magic piece of assembler needs to be linked in in order to
+# properly terminate the list of imported DLLs.
+dll_fixup.s:
+ echo '.section .idata$$3' > dll_fixup.s
+ echo '.long 0,0,0,0, 0,0,0,0' >> dll_fixup.s
+
+# This bit is necessary to provide an initialization function for the DLL.
+dll_init.c:
+ echo '__attribute__((stdcall))' > dll_init.c
+ echo 'int dll_entry(int handle, int reason, void *ptr)' >> dll_init.c
+ echo '{return 1; }' >> dll_init.c
+
+dont_throw_away: dll_fixup.o dll_init.o
diff --git a/Makefile.dj b/Makefile.dj
index 965d314c..9187f73a 100644
--- a/Makefile.dj
+++ b/Makefile.dj
@@ -6,18 +6,31 @@
# test - prints porting information, then builds basic version of gc.a,
# and runs some tests of collector and cords. Does not add cords or
# c++ interface to gc.a
-# cord/de - builds dumb editor based on cords.
+# cord/de$(EXE_SUFFIX) - builds dumb editor based on cords.
CC=gcc
-CXX=gxx
+CXX=gcc -x c++
+CXXLD=gxx
+RM=rm -f
+MV=mv
+EXE_SUFFIX=.exe
+RANLIB=ranlib
-CFLAGS= -O -DNO_SIGNALS -DALL_INTERIOR_POINTERS -DSILENT
+CFLAGS= -O -DNO_SIGNALS -DALL_INTERIOR_POINTERS -DSILENT -DATOMIC_UNCOLLECTABLE
# Setjmp_test may yield overly optimistic results when compiled
# without optimization.
# -DSILENT disables statistics printing, and improves performance.
+# -DCHECKSUMS reports on erroneously clear dirty bits, and unexpectedly
+# altered stubborn objects, at substantial performance cost.
+# Use only for incremental collector debugging.
# -DFIND_LEAK causes the collector to assume that all inaccessible
# objects should have been explicitly deallocated, and reports exceptions.
# Finalization and the test program are not usable in this mode.
+# -DSOLARIS_THREADS enables support for Solaris (thr_) threads.
+# (Clients should also define SOLARIS_THREADS and then include
+# gc.h before performing thr_ or dl* or GC_ operations.)
+# This is broken on nonSPARC machines.
+# -DIRIX_THREADS enables support for Irix pthreads. See README.irix.
# -DALL_INTERIOR_POINTERS allows all pointers to the interior
# of objects to be recognized. (See gc_priv.h for consequences.)
# -DSMALL_CONFIG tries to tune the collector for small heap sizes,
@@ -33,7 +46,7 @@ CFLAGS= -O -DNO_SIGNALS -DALL_INTERIOR_POINTERS -DSILENT
# is normally more than one byte due to alignment constraints.)
# -DDONT_ADD_BYTE_AT_END disables the padding.
# -DNO_SIGNALS does not disable signals during critical parts of
-# the GC process. This is no less correct than many malloc
+# the GC process. This is no less correct than many malloc
# implementations, and it sometimes has a significant performance
# impact. However, it is dangerous for many not-quite-ANSI C
# programs that call things like printf in asynchronous signal handlers.
@@ -59,6 +72,15 @@ CFLAGS= -O -DNO_SIGNALS -DALL_INTERIOR_POINTERS -DSILENT
# -DREDIRECT_MALLOC.
# -DNO_DEBUGGING removes GC_dump and the debugging routines it calls.
# Reduces code size slightly at the expense of debuggability.
+# -DJAVA_FINALIZATION makes it somewhat safer to finalize objects out of
+# order by specifying a nonstandard finalization mark procedure (see
+# finalize.c). Objects reachable from finalizable objects will be marked
+# in a sepearte postpass, and hence their memory won't be reclaimed.
+# Not recommended unless you are implementing a language that specifies
+# these semantics.
+# -DATOMIC_UNCOLLECTABLE includes code for GC_malloc_atomic_uncollectable.
+# This is useful if either the vendor malloc implementation is poor,
+# or if REDIRECT_MALLOC is used.
LIBGC_CFLAGS= -O -DNO_SIGNALS -DSILENT \
-DREDIRECT_MALLOC=GC_malloc_uncollectable \
@@ -71,21 +93,46 @@ RANLIB= ranlib
# Redefining srcdir allows object code for the nonPCR version of the collector
-# to be generated in different directories. In this case, the destination
-directory
+# to be generated in different directories. In this case, the destination directory
# should contain a copy of the original include directory.
srcdir = .
VPATH = $(srcdir)
-OBJS= alloc.o reclaim.o allchblk.o misc.o mach_dep.o os_dep.o mark_rts.o \
-headers.o mark.o obj_map.o blacklst.o finalize.o new_hblk.o dbg_mlc.o malloc.o\
-stubborn.o typd_mlc.o ptr_chck.o mallocx.o
+OBJS= alloc.o reclaim.o allchblk.o misc.o mach_dep.o os_dep.o mark_rts.o headers.o mark.o obj_map.o blacklst.o finalize.o new_hblk.o dbg_mlc.o malloc.o stubborn.o checksums.o solaris_threads.o irix_threads.o typd_mlc.o ptr_chck.o mallocx.o
+
+CSRCS= reclaim.c allchblk.c misc.c alloc.c mach_dep.c os_dep.c mark_rts.c headers.c mark.c obj_map.c pcr_interface.c blacklst.c finalize.c new_hblk.c real_malloc.c dyn_load.c dbg_mlc.c malloc.c stubborn.c checksums.c solaris_threads.c irix_threads.c typd_mlc.c ptr_chck.c mallocx.c
+
+CORD_SRCS= cord/cordbscs.c cord/cordxtra.c cord/cordprnt.c cord/de.c cord/cordtest.c cord/cord.h cord/ec.h cord/private/cord_pos.h cord/de_win.c cord/de_win.h cord/de_cmds.h cord/de_win.ICO cord/de_win.RC cord/SCOPTIONS.amiga cord/SMakefile.amiga
CORD_OBJS= cord/cordbscs.o cord/cordxtra.o cord/cordprnt.o
+SRCS= $(CSRCS) mips_sgi_mach_dep.s rs6000_mach_dep.s alpha_mach_dep.s \
+ sparc_mach_dep.s gc.h gc_typed.h gc_hdrs.h gc_priv.h gc_private.h \
+ config.h gc_mark.h include/gc_inl.h include/gc_inline.h gc.man \
+ threadlibs.c if_mach.c if_not_there.c gc_cpp.cc gc_cpp.h weakpointer.h \
+ gcc_support.c mips_ultrix_mach_dep.s include/gc_alloc.h gc_alloc.h \
+ $(CORD_SRCS)
+
+OTHER_FILES= Makefile PCR-Makefile OS2_MAKEFILE NT_MAKEFILE BCC_MAKEFILE \
+ README test.c test_cpp.cc setjmp_t.c SMakefile.amiga \
+ SCoptions.amiga README.amiga README.win32 cord/README \
+ cord/gc.h include/gc.h include/gc_typed.h include/cord.h \
+ include/ec.h include/private/cord_pos.h include/private/config.h \
+ include/private/gc_hdrs.h include/private/gc_priv.h \
+ include/gc_cpp.h README.rs6000 \
+ include/weakpointer.h README.QUICK callprocs pc_excludes \
+ barrett_diagram README.OS2 README.Mac MacProjects.sit.hqx \
+ MacOS.c EMX_MAKEFILE makefile.depend README.debugging \
+ include/gc_cpp.h Mac_files/datastart.c Mac_files/dataend.c \
+ Mac_files/MacOS_config.h Mac_files/MacOS_Test_config.h \
+ add_gc_prefix.c README.solaris2 README.sgi README.hp README.uts \
+ win32_threads.c NT_THREADS_MAKEFILE gc.mak README.dj Makefile.dj
+
CORD_INCLUDE_FILES= $(srcdir)/gc.h $(srcdir)/cord/cord.h $(srcdir)/cord/ec.h \
$(srcdir)/cord/private/cord_pos.h
+UTILS= if_mach$(EXE_SUFFIX) if_not_there$(EXE_SUFFIX) threadlibs$(EXE_SUFFIX)
+
# Libraries needed for curses applications. Only needed for de.
CURSES= -lcurses -ltermlib
@@ -94,7 +141,7 @@ CURSES= -lcurses -ltermlib
# the SHELL environment variable.
SHELL= /bin/sh
-SPECIALCFLAGS =
+SPECIALCFLAGS =
# Alternative flags to the C compiler for mach_dep.c.
# Mach_dep.c often doesn't like optimization, and it's
# not time-critical anyway.
@@ -102,8 +149,11 @@ SPECIALCFLAGS =
all: gc.a gctest
-$(OBJS) test.o dyn_load.o dyn_load_sunos53.o: $(srcdir)/gc_priv.h \
- $(srcdir)/gc_hdrs.h $(srcdir)/gc.h \
+pcr: PCR-Makefile gc_private.h gc_hdrs.h gc.h config.h mach_dep.o $(SRCS)
+ make -f PCR-Makefile depend
+ make -f PCR-Makefile
+
+$(OBJS) test.o dyn_load.o dyn_load_sunos53.o: $(srcdir)/gc_priv.h $(srcdir)/gc_hdrs.h $(srcdir)/gc.h \
$(srcdir)/config.h $(srcdir)/gc_typed.h Makefile
# The dependency on Makefile is needed. Changing
# options such as -DSILENT affects the size of GC_arrays,
@@ -111,71 +161,81 @@ $(OBJS) test.o dyn_load.o dyn_load_sunos53.o: $(srcdir)/gc_priv.h \
mark.o typd_mlc.o finalize.o: $(srcdir)/gc_mark.h
-gc.a: $(OBJS) dyn_load.o
- $(AR) ru gc.a $(OBJS) dyn_load.o
- $(RANLIB) gc.a
+base_lib gc.a: $(OBJS) dyn_load.o $(UTILS)
+ echo > base_lib
+ $(RM) on_sparc_sunos5
+ ./if_mach SPARC SUNOS5 touch on_sparc_sunos5
+ ./if_mach SPARC SUNOS5 $(AR) rus gc.a $(OBJS) dyn_load.o
+ ./if_not_there on_sparc_sunos5 $(AR) ru gc.a $(OBJS) dyn_load.o
+ -./if_not_there on_sparc_sunos5 $(RANLIB) gc.a
+# ignore ranlib failure; that usually means it doesn't exist, and isn't needed
-libgc.a:
+libgc.a:
make CFLAGS="$(LIBGC_CFLAGS)" clean gc.a gcc_support.o
- move gc.a libgc.a
- -del on_sparc_sunos5
+ $(MV) gc.a libgc.a
+ -$(RM) on_sparc_sunos5
./if_mach SPARC SUNOS5 touch on_sparc_sunos5
./if_mach SPARC SUNOS5 $(AR) rus libgc.a gcc_support.o
./if_not_there on_sparc_sunos5 $(AR) ru libgc.a gcc_support.o
- ./if_not_there on_sparc_sunos5 $(RANLIB) libgc.a || cat /dev/null
+ -./if_not_there on_sparc_sunos5 $(RANLIB) libgc.a
-cords: $(CORD_OBJS) cord/cordtest
- -del on_sparc_sunos5
+cords: $(CORD_OBJS) cord/cordtest$(EXE_SUFFIX) $(UTILS)
+ -$(RM) on_sparc_sunos5
./if_mach SPARC SUNOS5 touch on_sparc_sunos5
./if_mach SPARC SUNOS5 $(AR) rus gc.a $(CORD_OBJS)
./if_not_there on_sparc_sunos5 $(AR) ru gc.a $(CORD_OBJS)
- ./if_not_there on_sparc_sunos5 $(RANLIB) gc.a || cat /dev/null
+ -./if_not_there on_sparc_sunos5 $(RANLIB) gc.a
gc_cpp.o: $(srcdir)/gc_cpp.cc $(srcdir)/gc_cpp.h $(srcdir)/gc.h Makefile
$(CXX) -c $(CXXFLAGS) $(srcdir)/gc_cpp.cc
-test_cpp: $(srcdir)/test_cpp.cc $(srcdir)/gc_cpp.h gc_cpp.o $(srcdir)/gc.h gc.a
- -del test_cpp
- $(CXX) $(CXXFLAGS) -o test_cpp $(srcdir)/test_cpp.cc gc_cpp.o gc.a
-
+test_cpp: $(srcdir)/test_cpp.cc $(srcdir)/gc_cpp.h gc_cpp.o $(srcdir)/gc.h \
+base_lib $(UTILS)
+ -$(RM) test_cpp test_cpp$(EXE_SUFFIX)
+ ./if_mach HP_PA "" $(CXX) $(CXXFLAGS) -o test_cpp $(srcdir)/test_cpp.cc gc_cpp.o gc.a -ldld
+ ./if_not_there test_cpp$(EXE_SUFFIX) $(CXXLD) $(CXXFLAGS) -o test_cpp $(srcdir)/test_cpp.cc gc_cpp.o gc.a
c++: gc_cpp.o $(srcdir)/gc_cpp.h test_cpp
- -del on_sparc_sunos5
+ -$(RM) on_sparc_sunos5
$(AR) ru gc.a gc_cpp.o
$(RANLIB) gc.a
./test_cpp 1
+ echo > c++
+
+dyn_load_sunos53.o: dyn_load.c
+ $(CC) $(CFLAGS) -DSUNOS53_SHARED_LIB -c $(srcdir)/dyn_load.c -o $@
mach_dep.o: $(srcdir)/mach_dep.c
# $(srcdir)/mips_mach_dep.s $(srcdir)/rs6000_mach_dep.s if_mach if_not_there
- -del mach_dep.o
+ -$(RM) mach_dep.o
$(CC) -c $(SPECIALCFLAGS) $(srcdir)/mach_dep.c
mark_rts.o: $(srcdir)/mark_rts.c
- -del mark_rts.o
+ -$(RM) mark_rts.o
$(CC) -c $(CFLAGS) $(srcdir)/mark_rts.c
cord/cordbscs.o: $(srcdir)/cord/cordbscs.c $(CORD_INCLUDE_FILES)
$(CC) $(CFLAGS) -c $(srcdir)/cord/cordbscs.c
- move cordbscs.o cord/cordbscs.o
+ $(MV) cordbscs.o cord/cordbscs.o
# not all compilers understand -o filename
cord/cordxtra.o: $(srcdir)/cord/cordxtra.c $(CORD_INCLUDE_FILES)
$(CC) $(CFLAGS) -c $(srcdir)/cord/cordxtra.c
- move cordxtra.o cord/cordxtra.o
+ $(MV) cordxtra.o cord/cordxtra.o
cord/cordprnt.o: $(srcdir)/cord/cordprnt.c $(CORD_INCLUDE_FILES)
$(CC) $(CFLAGS) -c $(srcdir)/cord/cordprnt.c
- move cordprnt.o cord/cordprnt.o
+ $(MV) cordprnt.o cord/cordprnt.o
-cord/cordtest: $(srcdir)/cord/cordtest.c $(CORD_OBJS) gc.a
- -del cord/cordtest
- $(CC) $(CFLAGS) -o cord/cordtest $(srcdir)/cord/cordtest.c\
+cord/cordtest$(EXE_SUFFIX): $(srcdir)/cord/cordtest.c $(CORD_OBJS) gc.a $(UTILS)
+ -$(RM) cord/cordtest$(EXE_SUFFIX)
+ $(CC) $(CFLAGS) -o cordtest $(srcdir)/cord/cordtest.c\
$(CORD_OBJS) gc.a
+ ./if_not_there cord/cordtest$(EXE_SUFFIX) \
+ $(MV) cordtest$(EXE_SUFFIX) cord/cordtest$(EXE_SUFFIX)
-cord/de: $(srcdir)/cord/de.c cord/cordbscs.o cord/cordxtra.o gc.a
- -del cord/de
- ./if_mach SPARC SUNOS5 $(CC) $(CFLAGS) -o cord/de $(srcdir)/cord/de.c\
-cord/cordbscs.o cord/cordxtra.o gc.a $(CURSES) -lthread -ldl
+cord/de$(EXE_SUFFIX): $(srcdir)/cord/de.c cord/cordbscs.o cord/cordxtra.o gc.a
+ -$(RM) cord/de$(EXE_SUFFIX)
./if_mach SPARC DRSNX $(CC) $(CFLAGS) -o cord/de $(srcdir)/cord/de.c\
cord/cordbscs.o cord/cordxtra.o gc.a $(CURSES) -lucb
./if_mach HP_PA "" $(CC) $(CFLAGS) -o cord/de $(srcdir)/cord/de.c\
@@ -186,30 +246,45 @@ cord/cordbscs.o cord/cordxtra.o gc.a -lcurses
cord/cordbscs.o cord/cordxtra.o gc.a -lcurses
./if_not_there cord/de $(CC) $(CFLAGS) -o cord/de $(srcdir)/cord/de.c\
cord/cordbscs.o cord/cordxtra.o gc.a $(CURSES)
+ ./if_not_there cord/de$(EXE_SUFFIX) \
+ $(MV) de$(EXE_SUFFIX) cord/de$(EXE_SUFFIX)
+
+if_mach$(EXE_SUFFIX): $(srcdir)/if_mach.c $(srcdir)/config.h
+ $(CC) $(CFLAGS) -o if_mach $(srcdir)/if_mach.c
+
+threadlibs$(EXE_SUFFIX): $(srcdir)/threadlibs.c $(srcdir)/config.h Makefile
+ $(CC) $(CFLAGS) -o threadlibs $(srcdir)/threadlibs.c
+
+if_not_there$(EXE_SUFFIX): $(srcdir)/if_not_there.c
+ $(CC) $(CFLAGS) -o if_not_there $(srcdir)/if_not_there.c
clean:
- -del gc.a *.o gctest gctest_dyn_link test_cpp \
+ -$(RM) gc.a *.o gctest gctest_dyn_link test_cpp \
setjmp_test mon.out gmon.out a.out core if_not_there if_mach \
- $(CORD_OBJS) cord/cordtest cord/de
- -del *~
-
-gctest: test.o gc.a
- -del gctest
+ $(CORD_OBJS) cordtest cord/cordtest de cord/de
+ -$(RM) gctest$(EXE_SUFFIX) gctest_dyn_link$(EXE_SUFFIX) test_cpp$(EXE_SUFFIX) \
+ setjmp_test$(EXE_SUFFIX) if_not_there$(EXE_SUFFIX) if_mach$(EXE_SUFFIX) \
+ cord/cordtest$(EXE_SUFFIX)
+ -$(RM) *~
+
+gctest$(EXE_SUFFIX): test.o gc.a
+ -$(RM) gctest$(EXE_SUFFIX)
$(CC) $(CFLAGS) -o gctest test.o gc.a
# If an optimized setjmp_test generates a segmentation fault,
# odds are your compiler is broken. Gctest may still work.
# Try compiling setjmp_t.c unoptimized.
-setjmp_test: $(srcdir)/setjmp_t.c $(srcdir)/gc.h
+setjmp_test$(EXE_SUFFIX): $(srcdir)/setjmp_t.c $(srcdir)/gc.h \
+ if_mach$(EXE_SUFFIX) if_not_there$(EXE_SUFFIX)
+ -$(RM) setjmp_test$(EXE_SUFFIX)
$(CC) $(CFLAGS) -o setjmp_test $(srcdir)/setjmp_t.c
-test: KandRtest cord/cordtest
- cord/cordtest
+test: KandRtest cord/cordtest$(EXE_SUFFIX)
+ ./cord/cordtest$(EXE_SUFFIX)
# Those tests that work even with a K&R C compiler:
-KandRtest: setjmp_test gctest
- ./setjmp_test
- ./gctest
-
+KandRtest: setjmp_test$(EXE_SUFFIX) gctest$(EXE_SUFFIX)
+ ./setjmp_test$(EXE_SUFFIX)
+ ./gctest$(EXE_SUFFIX)
diff --git a/README b/README
index 9d6fc0dd..a1d39985 100644
--- a/README
+++ b/README
@@ -11,7 +11,7 @@ Permission to modify the code and to distribute modified code is granted,
provided the above notices are retained, and a notice that the code was
modified is included with the above copyright notice.
-This is version 4.11 of a conservative garbage collector for C and C++.
+This is version 4.12 of a conservative garbage collector for C and C++.
HISTORY -
@@ -213,28 +213,14 @@ include subdirectory. (Normally this is just gc.h. "Make cords" adds
"cord.h" and "ec.h".)
The collector currently is designed to run essentially unmodified on
-at least the following machines (most or all of the system names mentioned are
-trademarks of their respective holders):
-
- SGI workstations under IRIX 4, 5, & 6
- Intel 386 or 486 under most operating systems, but not MSDOS.
- (Win32S is somewhat supported, so it is marginally possible to
- build applications for Windows 3.1. DOS + djgpp should also
- work.)
- Sun 3
- Sun 4 under SunOS 4.X or Solaris2.X (with or without threads)
- Vax under 4.3BSD, Ultrix
- IBM PC/RT (Berkeley UNIX)
- IBM RS/6000
- HP9000/300
- HP9000/700
- DECstations under Ultrix
- DEC Alpha running OSF/1
- Sony News
- Apple Macintosh under A/UX or MacOS
- Commodore Amiga
- NeXT machines
- Some more obscure and/or obsolete systems ...
+machines that use a flat 32-bit or 64-bit address space.
+That includes the vast majority of Workstations and X86 (X >= 3) PCs.
+(The list here was deleted because it was getting too long and constantly
+out of date.)
+ It does NOT run under plain 16-bit DOS or Windows 3.X. There are however
+various packages (e.g. win32s, djgpp) that allow flat 32-bit address
+applications to run under those systemsif the have at least an 80386 processor,
+and several of those are compatible with the collector.
In a few cases (Amiga, OS/2, Win32, MacOS) a separate makefile
or equivalent is supplied. Many of these have separate README.system
@@ -1249,5 +1235,107 @@ Since 4.10:
Patrick Bridges.)
- Changed the Borland cc configuration so that the assembler is not
required.
- - Fixed a bug in the C++ test that casued it to fail in 64-bit
+ - Fixed a bug in the C++ test that caused it to fail in 64-bit
environments.
+
+Since 4.11:
+ - Fixed ElfW definition in dyn_load.c. (Thanks to Fergus Henderson.)
+ This prevented the dynamic library support from compiling on some
+ older ELF Linux systems.
+ - Fixed UTS4 port (which I apparently mangled during the integration)
+ (Thanks to again to Alistair Crooks.)
+ - "Make C++" failed on Suns with SC4.0, due to a problem with "bool".
+ Fixed in gc_priv.h.
+ - Added more pieces for GNU win32. (Thanks to Timothy N. Newsham.)
+ The current state of things should suffice for at least some
+ applications.
+ - Changed the out of memory retry count handling as suggested by
+ Kenjiro Taura. (This matters only if GC_max_retries > 0, which
+ is no longer the default.)
+ - If a /proc read failed repeatedly, GC_written_pages was not updated
+ correctly. (Thanks to Peter Chubb for diagnosing this.)
+ - Under unlikely circumstances, the allocator could infinite loop in
+ an out of memory situation. (Thanks again to Kenjiro Taura for
+ identifying the problem and supplying a fix.)
+ - Fixed a syntactic error in the DJGPP code. (Thanks to Fergus
+ Henderson for finding this by inspection.) Also fixed a test program
+ problem with DJGPP (Thanks to Peter Monks.)
+ - Atomic uncollectable objects were not treated correctly by the
+ incremental collector. This resulted in weird log statistics and
+ occasional performance problems. (Thanks to Peter Chubb for pointing
+ this out.)
+ - Fixed some problems resulting from compilers that dont define
+ __STDC__. In this case void * and char * were used inconsistently
+ in some cases. (Void * should not have been used at all. If
+ you have an ANSI superset compiler that does not define __STDC__,
+ please compile with -D__STDC__=0. Thanks to Manuel Serrano and others
+ for pointing out the problem.)
+ - Fixed a compilation problem on Irix with -n32 and -DIRIX_THREADS.
+ Also fixed some other IRIX_THREADS problems which may or may not have
+ had observable symptoms.
+ - Fixed an HP PA compilation problem in dyn_load.c. (Thanks to
+ Philippe Queinnec.)
+ - SEGV fault handlers sometimes did not get reset correctly. (Thanks
+ to David Pickens.)
+ - Added a fix for SOLARIS_THREADS on Intel. (Thanks again to David
+ Pickens.) This probably needs more work to become functional.
+ - Fixed struct sigcontext_struct in os_dep.c for compilation under
+ Linux 2.1.X. (Thanks to Fergus Henderson.)
+ - Changed the DJGPP STACKBOTTOM and DATASTART values to those suggested
+ by Kristian Kristensen. These may still not be right, but it is
+ it is likely to work more often than what was there before. They may
+ even be exactly right.
+ - Added a #include <string.h> to test_cpp.cc. This appears to help
+ with HP/UX and gcc. (Thanks to assar@sics.se.)
+ - Version 4.11 failed to run in incremental mode on recent 64-bit Irix
+ kernels. This was a problem related to page unaligned heap segments.
+ Changed the code to page align heap sections on all platforms.
+ (I had mistakenly identified this as a kernel problem earlier.
+ It was not.)
+ - Version 4.11 did not make allocated storage executable, except on
+ one or two platforms, due to a bug in a #if test. (Thanks to Dave
+ Grove for pointing this out.)
+ - Added sparc_sunos4_mach_dep.s to support Sun's compilers under SunOS4.
+ - Added GC_exclude_static_roots.
+ - Fixed the object size mapping algorithm. This shouldn't matter,
+ but the old code was ugly.
+ - Heap checking code could die if one of the allocated objects was
+ larger than its base address. (Unsigned underflow problem. Thanks
+ to Clay Spence for isolating the problem.)
+ - Added RS6000 (AIX) dynamic library support and fixed STACK_BOTTOM.
+ (Thanks to Fred Stearns.)
+ - Added Fergus Henderson's patches for improved robustness with large
+ heaps and lots of blacklisting.
+ - Added Peter Chubb's changes to support Solaris Pthreads, to support
+ MMAP allocation in Solaris, to allow Solaris to find dynamic libraries
+ through /proc, to add malloc_typed_ignore_off_page, and a few other
+ minor features and bug fixes.
+ - The Solaris 2 port should not use sbrk. I received confirmation from
+ Sun that the use of sbrk and malloc in the same program is not
+ supported. The collector now defines USE_MMAP by default on Solaris.
+ - Replaced the djgpp makefile with Gary Leavens' version.
+ - Fixed MSWIN32 detection test.
+ - Added Fergus Henderson's patches to allow putting the collector into
+ a DLL under GNU win32.
+ - Added Ivan V. Demakov's port to Watcom C on X86.
+ - Added Ian Piumarta's Linux/PowerPC port.
+ - On Brian Burton's suggestion added PointerFreeGC to the placement
+ options in gc_cpp.h. This is of course unsafe, and may be controversial.
+ On the other hand, it seems to be needed often enough that it's worth
+ adding as a standard facility.
+
+To do:
+ - Very large root set sizes (> 16 MB or so) could cause the collector
+ to abort with an unexpected mark stack overflow. (Thanks again to
+ Peter Chubb.) NOT YET FIXED. Workaround is to increase the initial
+ size.
+ - The SGI version of the collector marks from mmapped pages, even
+ if they are not part of dynamic library static data areas. This
+ causes performance problems with some SGI libraries that use mmap
+ as a bitmap allocator. NOT YET FIXED. It may be possible to turn
+ off DYNAMIC_LOADING in the collector as a workaround. It may also
+ be possible to conditionally intercept mmap and use GC_exclude_static_roots.
+ The real fix is to walk rld data structures, which looks possible.
+ - SGI pthreads and incremental collection don't mix yet.
+ - Integrate MIT and DEC pthreads ports.
+
diff --git a/README.Mac b/README.Mac
index 180de7e5..538ad73c 100644
--- a/README.Mac
+++ b/README.Mac
@@ -1,5 +1,329 @@
-README.Mac
-----------
+Lars Farm's suggestions on building the collector:
+----------------------------------------------------------------------------
+Garbage Collection on MacOS - a manual 'MakeFile'
+-------------------------------------------------
+
+Project files and IDE's are great on the Macintosh, but they do have
+problems when used as distribution media. This note tries to provide
+porting instructions in pure TEXT form to avoid those problems. A manual
+'makefile' if you like.
+
+ GC version: 4.12a2
+ Codewarrior: CWPro1
+ date: 18 July 1997
+
+The notes may or may not apply to earlier or later versions of the
+GC/CWPro. Actually, they do apply to earlier versions of both except that
+until recently a project could only build one target so each target was a
+separate project. The notes will most likely apply to future versions too.
+Possibly with minor tweaks.
+
+This is just to record my experiences. These notes do not mean I now
+provide a supported port of the GC to MacOS. It works for me. If it works
+for you, great. If it doesn't, sorry, try again...;-) Still, if you find
+errors, please let me know.
+
+ mailto: lars.farm@ite.mh.se
+
+ address: Lars Farm
+ Krönvägen 33b
+ 856 44 Sundsvall
+ Sweden
+
+Porting to MacOS is a bit more complex than it first seems. Which MacOS?
+68K/PowerPC? Which compiler? Each supports both 68K and PowerPC and offer a
+large number of (unique to each environment) compiler settings. Each
+combination of compiler/68K/PPC/settings require a unique combination of
+standard libraries. And the IDE's does not select them for you. They don't
+even check that the library is built with compatible setting and this is
+the major source of problems when porting the GC (and otherwise too).
+
+You will have to make choices when you configure the GC. I've made some
+choices here, but there are other combinations of settings and #defines
+that work too.
+
+As for target settings the major obstacles may be:
+- 68K Processor: check "4-byte Ints".
+- PPC Processor: uncheck "Store Static Data in TOC".
+
+What you need to do:
+===================
+
+1) Build the GC as a library
+2) Test that the library works with 'test.c'.
+3) Test that the C++ interface 'gc_cpp.cc/h' works with 'test_cpp.cc'.
+
+1) The Libraries:
+=================
+I made one project with four targets (68K/PPC tempmem or appheap). One target
+will suffice if you're able to decide which one you want. I wasn't...
+
+Codewarrior allows a large number of compiler/linker settings. I used these:
+
+Settings shared by all targets:
+------------------------------
+o Access Paths:
+ - User Paths: the GC folder
+ - System Paths: {Compiler}:Metrowerks Standard Library:
+ {Compiler}:MacOS Support:Headers:
+ {Compiler}:MacOS Support:MacHeaders:
+o C/C++ language:
+ - inlining: normal
+ - direct to SOM: off
+ - enable/check: exceptions, RTTI, bool (and if you like pool strings)
+
+PowerPC target settings
+-----------------------
+o Target Settings:
+ - name of target
+ - MacOS PPC Linker
+o PPC Target
+ - name of library
+o C/C++ language
+ - prefix file as described below
+o PPC Processor
+ - Struct Alignment: PowerPC
+ - uncheck "Store Static Data in TOC" -- important!
+ I don't think the others matter, I use full optimization and its ok
+o PPC Linker
+ - Factory Settings (SYM file with full paths, faster linking, dead-strip
+ static init, Main: __start)
+
+
+68K target settings
+-------------------
+o Target Settings:
+ - name of target
+ - MacOS 68K Linker
+o 68K Target
+ - name of library
+ - A5 relative data
+o C/C++ language
+ - prefix file as described below
+o 68K Processor
+ - Code model: smart
+ - Struct alignment: 68K
+ - FP: SANE
+ - enable 4-Byte Ints -- important!
+ I don't think the others matter. I selected...
+ - enable: 68020
+ - enable: global register allocation
+o IR Optimizer
+ - enable: Optimize Space, Optimize Speed
+ I suppose the others would work too, but haven't tried...
+o 68K Linker
+ - Factory Settings (New Style MacsBug,SYM file with full paths,
+ A6 Frames, fast link, Merge compiler glue into segment 1,
+ dead-strip static init)
+
+Prefix Files to configure the GC sources
+----------------------------------------
+The Codewarrior equivalent of commandline compilers -DNAME=X is to use
+prefix-files. A TEXT file that is automatically #included before the first byte
+of every source file. I used these:
+
+---- ( cut here ) ---- gc_prefix_tempmem.h -- 68K and PPC -----
+ #include "gc_prefix_common.h"
+ #undef USE_TEMPORARY_MEMORY
+ #define USE_TEMPORARY_MEMORY
+---- ( cut here ) ---- gc_prefix_appmem.h -- 68K and PPC -----
+ #include "gc_prefix_common.h"
+ #undef USE_TEMPORARY_MEMORY
+// #define USE_TEMPORARY_MEMORY
+
+---- ( cut here ) ---- gc_prefix_common.h --------------------
+// gc_prefix_common.h
+// ------------------
+// Codewarrior prefix file to configure the GC libraries
+//
+// prefix files are the Codewarrior equivalent of the
+// command line option -Dname=x frequently seen in makefiles
+
+#if !__MWERKS__
+ #error only tried this with Codewarrior
+#endif
+
+#if macintosh
+ #define MSL_USE_PRECOMPILED_HEADERS 0
+ #include <ansi_prefix.mac.h>
+ #ifndef __STDC__
+ #define __STDC__ 0
+ #endif
+
+ // See list of #defines to configure the library in: 'MakeFile'
+ // see also README
+
+ #define SILENT // no collection messages. In case
+ // of trouble you might want this off
+ #define ALL_INTERIOR_POINTERS // follows interior pointers.
+//#define DONT_ADD_BYTE_AT_END // disables the padding if defined.
+//#define SMALL_CONFIG // whether to use a smaller heap.
+ #define NO_SIGNALS // signals aren't real on the Macintosh.
+ #define ATOMIC_UNCOLLECTABLE // GC_malloc_atomic_uncollectable()
+
+ // define either or none as per personal preference
+ // used in malloc.c
+ #define REDIRECT_MALLOC GC_malloc
+//#define REDIRECT_MALLOC GC_malloc_uncollectable
+ // if REDIRECT_MALLOC is #defined make sure that the GC library
+ // is listed before the ANSI/ISO libs in the Codewarrior
+ // 'Link order' panel
+//#define IGNORE_FREE
+
+ // mac specific configs
+//#define USE_TEMPORARY_MEMORY // use Macintosh temporary memory.
+//#define SHARED_LIBRARY_BUILD // build for use in a shared library.
+
+#else
+ // could build Win32 here too, or in the future
+ // Rhapsody PPC-mach, Rhapsody PPC-MacOS,
+ // Rhapsody Intel-mach, Rhapsody Intel-Win32,...
+ // ... ugh this will get messy ...
+#endif
+
+// make sure ints are at least 32-bit
+// ( could be set to 16-bit by compiler settings (68K) )
+
+struct gc_private_assert_intsize_{ char x[ sizeof(int)>=4 ? 1 : 0 ]; };
+
+#if __powerc
+ #if __option(toc_data)
+ #error turn off "store static data in TOC" when using GC
+ // ... or find a way to add TOC to the root set...(?)
+ #endif
+#endif
+---- ( cut here ) ---- end of gc_prefix_common.h -----------------
+
+Files to build the GC libraries:
+--------------------------------
+ allchblk.c
+ alloc.c
+ blacklst.c
+ checksums.c
+ dbg_mlc.c
+ finalize.c
+ headers.c
+ mach_dep.c
+ MacOS.c -- contains MacOS code
+ malloc.c
+ mallocx.c
+ mark.c
+ mark_rts.c
+ misc.c
+ new_hblk.c
+ obj_map.c
+ os_dep.c -- contains MacOS code
+ ptr_chck.c
+ reclaim.c
+ stubborn.c
+ typd_mlc.c
+ gc++.cc -- this is 'gc_cpp.cc' with less 'inline' and
+ -- throw std::bad_alloc when out of memory
+ -- gc_cpp.cc works just fine too
+
+2) Test that the library works with 'test.c'.
+=============================================
+
+The test app is just an ordinary ANSI-C console app. Make sure settings
+match the library you're testing.
+
+Files
+-----
+ test.c
+ the GC library to test -- link order before ANSI libs
+ suitable Mac+ANSI libraries
+
+prefix:
+------
+---- ( cut here ) ---- gc_prefix_testlib.h -- all libs -----
+#define MSL_USE_PRECOMPILED_HEADERS 0
+#include <ansi_prefix.mac.h>
+#undef NDEBUG
+
+#define ALL_INTERIOR_POINTERS /* for GC_priv.h
+---- ( cut here ) ----
+
+3) Test that the C++ interface 'gc_cpp.cc/h' works with 'test_cpp.cc'.
+
+The test app is just an ordinary ANSI-C console app. Make sure settings match
+the library you're testing.
+
+Files
+-----
+ test_cpp.cc
+ the GC library to test -- link order before ANSI libs
+ suitable Mac+ANSI libraries
+
+prefix:
+------
+same as for test.c
+
+For convenience I used one test-project with several targets so that all
+test apps are build at once. Two for each library to test: test.c and
+gc_app.cc. When I was satisfied that the libraries were ok. I put the
+libraries + gc.h + the c++ interface-file in a folder that I then put into
+the MSL hierarchy so that I don't have to alter access-paths in projects
+that use the GC.
+
+After that, just add the proper GC library to your project and the GC is in
+action! malloc will call GC_malloc and free GC_free, new/delete too. You
+don't have to call free or delete. You may have to be a bit cautious about
+delete if you're freeing other resources than RAM. See gc_cpp.h. You can
+also keep coding as always with delete/free. That works too. If you want,
+"include <gc.h> and tweak it's use a bit.
+
+Symantec SPM
+============
+It has been a while since I tried the GC in SPM, but I think that the above
+instructions should be sufficient to guide you through in SPM too. SPM
+needs to know where the global data is. Use the files 'datastart.c' and
+'dataend.c'. Put 'datastart.c' at the top of your project and 'dataend.c'
+at the bottom of your project so that all data is surrounded. This is not
+needed in Codewarrior because it provides intrinsic variables
+__datastart__, __data_end__ that wraps all globals.
+
+Source Changes (GC 4.12a2)
+==========================
+Very few. Just one tiny in the GC, not strictly needed.
+- MacOS.c line 131 in routine GC_MacFreeTemporaryMemory()
+ change # if !defined(SHARED_LIBRARY_BUILD)
+ to # if !defined(SILENT) && !defined(SHARED_LIBRARY_BUILD)
+ To turn off a message when the application quits (actually, I faked
+ this change by #defining SHARED_LIBRARY_BUILD in a statically linked
+ library for more than a year without ill effects but perhaps this is
+ better).
+
+- test_cpp.cc
+ made the first lines of main() look like this:
+ ------------
+ int main( int argc, char* argv[] ) {
+ #endif
+ #if macintosh // MacOS
+ char* argv_[] = {"test_cpp","10"}; // doesn't
+ argv=argv_; // have a
+ argc = sizeof(argv_)/sizeof(argv_[0]); // commandline
+ #endif //
+
+ int i, iters, n;
+ # ifndef __GNUC__
+ alloc dummy_to_fool_the_compiler_into_doing_things_it_currently_cant_handle;
+ ------------
+
+- config.h
+ __MWERKS__ does not have to mean MACOS. You can use Codewarrior to
+ build a Win32 or BeOS library and soon a Rhapsody library. You may
+ have to change that #if...
+
+
+
+ It worked for me, hope it works for you.
+
+ Lars Farm
+ 18 July 1997
+----------------------------------------------------------------------------
+
+
+Patrick Beard's instructions (may be dated):
v4.3 of the collector now runs under Symantec C++/THINK C v7.0.4, and
Metrowerks C/C++ v4.5 both 68K and PowerPC. Project files are provided
diff --git a/README.alpha b/README.alpha
new file mode 100644
index 00000000..b187fd5b
--- /dev/null
+++ b/README.alpha
@@ -0,0 +1,15 @@
+Should work under OSF/1 and Linux. Currently no VMS or NT support, though
+the latter shouldn't be hard.
+
+Incremental gc not yet supported under Linux because signal handler
+for SIGSEGV can't get a hold of fault address. Dynamic library support
+is also missing from Linux/alpha, probably for no good reason.
+
+From Philippe Queinnec:
+
+System: DEC/Alpha OSF1 v3.2, vendor cc
+Problem: can't link if libgc has been compiled with "cc -std1".
+ It works if the library has been compiled with either gcc or "cc"
+ alone. The problem is because the variable "end" is not defined if
+ compiling in std1 mode (see man ld).
+Proposed fix: none. Don't use cc -std1 !
diff --git a/README.dj b/README.dj
index 0462c38e..613bc423 100644
--- a/README.dj
+++ b/README.dj
@@ -1,19 +1,12 @@
-[Partially supplied by Xiaokun Zhu <xiaokun@aero.gla.ac.uk>]
+[Original version supplied by Xiaokun Zhu <xiaokun@aero.gla.ac.uk>]
+[This version came mostly from Gary Leavens. ]
-There is no caddr_t in djgpp 2.01 so the following declaration was added to
-os_dep.c. It may need to be removed for other versions.
+Look first at Makefile.dj, and possibly change the definitions of
+RM and MV if you don't have rm and mv installed.
+Then use Makefile.dj to compile the garbage collector.
+For example, you can do:
- typedef caddr_t long unsigned int;
+ make -f Makefile.dj test
+All the tests should work fine.
-Use Makefile.dj to compile it :
-
- C> make -f Makefile.dj test
-
-
-!!! setjmp_t.exe works fine.
-!!! gctest.exe works fine.
-!!! cordtest.exe fail.
-!!! test_cpp.exe works fine.
-
-In some cases it may be necessary to explicitly set GC_stackbottom.
diff --git a/README.hp b/README.hp
index 70490b92..869aaea6 100644
--- a/README.hp
+++ b/README.hp
@@ -3,3 +3,7 @@ The alternative is to build the collector without defining DYNAMIC_LOADING
in config.h and ensuring that all garbage collectable objects are
accessible without considering statically allocated variables in dynamic
libraries.
+
+The collector should compile with either plain cc or cc -Ae. CC -Aa
+fails to define _HPUX_SOURCE and thus will not configure the collector
+correctly.
diff --git a/README.linux b/README.linux
new file mode 100644
index 00000000..9ec4161f
--- /dev/null
+++ b/README.linux
@@ -0,0 +1,7 @@
+See README.alpha for Linux on DEC AXP info. This file applies to
+Linux/Intel.
+
+Incremental GC is supported.
+
+Dynamic libraries are supported on an ELF system. A static executable
+should be linked with the gcc option "-Wl,-defsym,_DYNAMIC=0".
diff --git a/README.sgi b/README.sgi
index c15151f0..3174e9c9 100644
--- a/README.sgi
+++ b/README.sgi
@@ -9,14 +9,15 @@ at least one explicit call to malloc instead of new to ensure that the proper
version of malloc is linked in.
Sproc threads are not supported in this version, though there may exist other
-ports. Pthreads are somewhat supported without incremental collection. This
+ports.
+
+Pthreads are somewhat supported without incremental collection. This
requires that:
1) You compile the collector with -DIRIX_THREADS specified in the Makefile.
-2) You have the latest pthreads patches installed. As of 11/7/96, some of
-the required patches were not yet generally available, so you may have
-to wait. If gctest fails, this is the likely cause.
+2) You have the latest pthreads patches installed.
+
(Though the collector makes only documented pthread calls,
it relies on signal/threads interactions working just right in ways
that are not required by the standard. It is unlikely that this code
diff --git a/README.solaris2 b/README.solaris2
index 4a6cf129..1edd6e66 100644
--- a/README.solaris2
+++ b/README.solaris2
@@ -5,53 +5,30 @@ through the appropriate /proc calls. But it can also be configured
and signals. This may result in shorter pause times, but it is no longer
safe to issue arbitrary system calls that write to the heap.
-The collector normally obtains memory through sbrk. There is some reason
+Under other UNIX versions,
+the collector normally obtains memory through sbrk. There is some reason
to expect that this is not safe if the client program also calls the system
malloc, or especially realloc. The sbrk man page strongly suggests this is
not safe: "Many library routines use malloc() internally, so use brk()
and sbrk() only when you know that malloc() definitely will not be used by
any library routine." This doesn't make a lot of sense to me, since there
seems to be no documentation as to which routines can transitively call malloc.
-Furthermore there typically isn't much of a performance advantage to be
-gained from such a restriction.
+Nonetheless, under Solaris2, the collector now (since 4.12) allocates
+memory using mmap by default. (It defines USE_MMAP in config.h.)
+You may want to reverse this decisions if you use -DREDIRECT_MALLOC=...
-To complicate matters, empirically this approach seems to work, at least
-most of the time. There have been reports of crashes in Sun's realloc
-function. But I haven't been able to reproduce this on an example small
-enough to preclude other bugs.
-
-As it stands, you have 4 choices:
-
-1. Use the collector as is, possibly avoiding the system realloc function.
-If you get a simple program that does this to crash, send me a copy, and
-I'll change the default to do something else. Please also complain to Sun,
-if you find such a case.
-
-2. Build the collector with -DREDIRECT_MALLOC=GC_malloc_uncollectable, thus
-redirecting system allocation calls through the collector. I believe
-this is OK under Solaris, but there is some risk of infinite recursion if
-you turn on collector log messages.
-
-3. Change the GET_MEM definition for SPARC and SUNOS5 in gc_priv.h to
-be the same as for the AMIGA or NEXT. The collector will then obtain
-memory through the system calloc function. This is probably the safest,
-but it incurs a fragmentation penalty. Since the system malloc is likely
-to reserve header space in each object, the different heap sections
-are virtually guaranteed to not be adjacent. Thus large objects have to fit
-entirely in one section.
-
-4. Change GET_MEM to allocate memory from a different part of the address
-space, e.g. with mmap. Based on previous experiences with older versions
-of SunOS and other operating systems, this risks other performance problems.
-I have not tried it with Solaris 2.
SOLARIS THREADS:
The collector must be compiled with -DSOLARIS_THREADS to be thread safe.
It is also essential that gc.h be included in files that call thr_create,
thr_join, thr_suspend, thr_continue, or dlopen. Gc.h macro defines
-these to also do GC bookkeeping, etc. Gc.h must be included with SOLARIS_THREADS
-defined, otherwise these replacements are not visible.
+these to also do GC bookkeeping, etc. Gc.h must be included with
+SOLARIS_THREADS defined, otherwise these replacements are not visible.
+A collector built in this way way only be used by programs that are
+linked with the threads library.
+
+If you are using the Pthreads interface, also define _SOLARIS_PTHREADS.
In this mode, the collector contains various workarounds for older Solaris
bugs. Mostly, these should not be noticeable unless you look at system
@@ -64,7 +41,14 @@ Jeremy Fitzhardinge points out that there is a problem with the dlopen
replacement, in that startup code in the library is run while the allocation
lock is held. This appears to be difficult to fix, since the collector does
look at data structures maintained by dlopen, and hence some locking is needed
-around the dlopen call.
+around the dlopen call. Defining USE_PROC_FOR_LIBRARIES will get address
+space layout information from /proc avoiding the dlopen lock. But this has
+other disadvanatages, e.g. mmapped files may be scanned.
+
+If solaris_threads are used on an X86 processor with malloc redirected to
+GC_malloc, it is necessary to call GC_thr_init explicitly before forking the
+first thread. (This avoids a deadlock arising from calling GC_thr_init
+with the allocation lock held.)
Hans-J. Boehm
(The above contains my personal opinions, which are probably not shared
diff --git a/README.win32 b/README.win32
index 16115629..95bf50fe 100644
--- a/README.win32
+++ b/README.win32
@@ -1,5 +1,7 @@
The collector has only been compiled under Windows NT, with the
-original Microsoft SDK, with Visual C++ 2.0, and with Borland 4.5.
+original Microsoft SDK, with Visual C++ 2.0 and later, with
+the GNU win32 environment, with Borland 4.5, and recently with
+Watcom C.
It runs under both win32s and win32, but with different semantics.
Under win32, all writable pages outside of the heaps and stack are
@@ -39,6 +41,10 @@ For Microsoft development tools, rename NT_MAKEFILE as
MAKEFILE. (Make sure that the CPU environment variable is defined
to be i386.)
+For GNU-win32, use the regular makefile, possibly after uncommenting
+the line "include Makefile.DLLs". The latter should be necessary only
+if you want to package the collector as a DLL.
+
For Borland tools, use BCC_MAKEFILE. Note that
Borland's compiler defaults to 1 byte alignment in structures (-a1),
whereas Visual C++ appears to default to 8 byte alignment (/Zp8).
@@ -101,4 +107,54 @@ to support it.
Hans
+Ivan V. Demakov's README for the Watcom port:
+
+[ He points out in a later message that there may be a problem compiling
+ under Windows-3.11 for Windows NT. ]
+
+Watcom C/C++ 10.5, 10.6, 11.0 tested.
+
+The collector runs on WIN32 and DOS4GW dos-extender with both
+stack and register based calling conventions (options -5r and -5s).
+Incremental collection not supported.
+
+OS/2 not tested, but should work (only some #ifdef's added for OS/2 port).
+
+cord not ported. Watcom C fails to compile it, from first attempt.
+Since I don't use it, I don't try to fix it.
+
+cpp_test succeeds, but not compiled automaticaly with WCC_MAKEFILE.
+
+
+My changes:
+
+ * config.h Added definitions for Watcom C/C++.
+ Undefined MPROTECT_VDB for Watcom C/C++ MSWIN32,
+ I don't have idea why it not work.
+
+ * gc.h Explicitly declared GC_noop. This prevents
+ program crash, compiled with -5r option.
+
+ * gc_priv.h Changed declaration for GC_push_one to make
+ compiler happy.
+ Added GC_dos4gw_get_mem declaration and
+ GET_MEM uses it in DOS4GW environment.
+
+ * os_dep.c Added __WATCOMC__ and DOS4GW #ifdef's.
+ Added GC_dos4gw_get_mem.
+
+ * mach_dep.c For Watcom used setjmp method of marking registers.
+
+ * WCC_MAKEFILE New file. Makefile for Watcom C/C++.
+
+ * gc_watcom.asm New file. Some functions for DOS4GW.
+ This functions may (probably) be done in C,
+ but I can't figure out how do this for all
+ possible options of compiler.
+
+ * README.watcom This file.
+
+
+ Ivan Demakov (email: dem@tgrad.nsk.su)
+
diff --git a/WCC_MAKEFILE b/WCC_MAKEFILE
new file mode 100644
index 00000000..cc0ef136
--- /dev/null
+++ b/WCC_MAKEFILE
@@ -0,0 +1,123 @@
+# Makefile for Watcom C/C++ 10.5, 10.6, 11.0 on NT, OS2 and DOS4GW .
+# May work with Watcom 10.0 .
+#
+
+#
+# Uncoment one of line for cross compiling
+#SYSTEM=DOS4GW
+#SYSTEM=MSWIN32
+#SYSTEM=OS2
+
+!ifndef SYSTEM
+
+!ifdef __MSDOS__
+SYSTEM=DOS4GW
+!endif
+
+!ifdef __NT__
+SYSTEM=MSWIN32
+!endif
+
+!ifdef __OS2__
+SYSTEM=OS2
+!endif
+
+D_SYSTEM=
+
+!else
+
+D_SYSTEM=-D$(SYSTEM)
+
+!endif
+
+!define $(SYSTEM)
+
+
+CC=wcc386
+CXX=wpp386
+AS=wasm
+
+
+# Watcom before 11.0 not support option -oh
+# Remove it if you get error
+OPTIM=-oneatxh -s
+
+CALLING=-5s
+
+DEFS=-DALL_INTERIOR_POINTERS -DSILENT #-DSMALL_CONFIG #-DGC_DEBUG
+
+# ! -DUSE_GENERIC required !
+CFLAGS=$(OPTIM) -zp4 $(CALLING) -zc -DUSE_GENERIC $(D_SYSTEM) $(DEFS)
+CXXFLAGS= $(CFLAGS)
+ASFLAGS=$(CALLING)
+
+OBJS= alloc.obj reclaim.obj allchblk.obj misc.obj &
+ mach_dep.obj os_dep.obj mark_rts.obj headers.obj mark.obj &
+ obj_map.obj blacklst.obj finalize.obj new_hblk.obj &
+ dbg_mlc.obj malloc.obj stubborn.obj dyn_load.obj &
+ typd_mlc.obj ptr_chck.obj gc_cpp.obj mallocx.obj
+
+
+all: gc.lib gctest.exe
+
+# this file required for DOS4GW only
+gc_watcom.obj: gc_watcom.asm WCC_MAKEFILE
+ $(AS) $(ASFLAGS) gc_watcom.asm
+
+!ifdef DOS4GW
+gc.lib: $(OBJS) gc_watcom.obj
+ @%create $*.lb1
+ @for %i in ($(OBJS)) do @%append $*.lb1 +'%i'
+ @@%append $*.lb1 +'gc_watcom.obj'
+ *wlib -b -c -n -p=512 $@ @$*.lb1
+!else
+gc.lib: $(OBJS)
+ @%create $*.lb1
+ @for %i in ($(OBJS)) do @%append $*.lb1 +'%i'
+ *wlib -b -c -n -p=512 $@ @$*.lb1
+!endif
+
+
+test.obj: test.c
+ $(CC) $(CFLAGS) $*.c
+
+gctest.exe: test.obj gc.lib
+ %create $*.lnk
+!ifdef DOS4GW
+ @%append $*.lnk sys dos4g
+!endif
+!ifdef MSWIN32
+ @%append $*.lnk sys nt
+!endif
+!ifdef OS2
+ @%append $*.lnk sys os2v2
+!endif
+ @%append $*.lnk op case
+ @%append $*.lnk op stack=256K
+ @%append $*.lnk name $*
+ @%append $*.lnk file test.obj
+ @%append $*.lnk library gc.lib
+ *wlink @$*.lnk
+
+
+
+.c.obj: .AUTODEPEND
+ $(CC) $(CFLAGS) $*.c
+
+.cc.obj: .AUTODEPEND
+ $(CXX) $(CXXFLAGS) $*.cc
+
+.cpp.obj: .AUTODEPEND
+ $(CXX) $(CXXFLAGS) $*.cpp
+
+clean : .SYMBOLIC
+ @if exist *.obj del *.obj
+ @if exist *.map del *.map
+ @if exist *.lnk del *.lnk
+ @if exist *.lb1 del *.lb1
+ @if exist *.sym del *.sym
+ @if exist *.err del *.err
+ @if exist *.tmp del *.tmp
+ @if exist *.lst del *.lst
+ @if exist *.exe del *.exe
+ @if exist *.log del *.log
diff --git a/allchblk.c b/allchblk.c
index 338675c9..3179c934 100644
--- a/allchblk.c
+++ b/allchblk.c
@@ -222,6 +222,7 @@ unsigned char flags; /* IGNORE_OFF_PAGE or 0 */
struct hblk * limit = hbp + (hhdr->hb_sz/HBLKSIZE);
struct hblk * h;
+ GC_words_wasted += hhdr->hb_sz;
phdr -> hb_next = hhdr -> hb_next;
for (h = hbp; h < limit; h++) {
if (h == hbp || GC_install_header(h)) {
@@ -256,7 +257,10 @@ unsigned char flags; /* IGNORE_OFF_PAGE or 0 */
} else {
hbp = (struct hblk *)
(((word)thishbp) + size_needed);
- if (!GC_install_header(hbp)) continue;
+ if (!GC_install_header(hbp)) {
+ hbp = thishbp;
+ continue;
+ }
hhdr = HDR(hbp);
GC_invalidate_map(hhdr);
hhdr->hb_next = thishdr->hb_next;
@@ -292,6 +296,14 @@ unsigned char flags; /* IGNORE_OFF_PAGE or 0 */
|| sz > MAXOBJSZ && GC_obj_kinds[kind].ok_init) {
BZERO(thishbp + HDR_BYTES, size_needed - HDR_BYTES);
}
+
+ /* We just successfully allocated a block. Restart count of */
+ /* consecutive failures. */
+ {
+ extern unsigned GC_fail_count;
+
+ GC_fail_count = 0;
+ }
return( thishbp );
}
diff --git a/alloc.c b/alloc.c
index f9a117cd..d9584e1e 100644
--- a/alloc.c
+++ b/alloc.c
@@ -64,11 +64,14 @@ int GC_full_freq = 4; /* Every 5th collection is a full */
/* collection. */
char * GC_copyright[] =
-{"Copyright 1988,1989 Hans-J. Boehm and Alan J. Demers",
-"Copyright (c) 1991-1995 by Xerox Corporation. All rights reserved.",
+{"Copyright 1988,1989 Hans-J. Boehm and Alan J. Demers ",
+"Copyright (c) 1991-1995 by Xerox Corporation. All rights reserved. ",
+"Copyright (c) 1996-1997 by Silicon Graphics. All rights reserved. ",
"THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY",
-" EXPRESSED OR IMPLIED. ANY USE IS AT YOUR OWN RISK."};
+" EXPRESSED OR IMPLIED. ANY USE IS AT YOUR OWN RISK.",
+"See source code for details." };
+# include "version.h"
/* some more variables */
@@ -191,6 +194,13 @@ bool GC_should_collect()
return(GC_adj_words_allocd() >= min_words_allocd());
}
+void GC_notify_full_gc()
+{
+ if (GC_start_call_back != (void (*)())0) {
+ (*GC_start_call_back)();
+ }
+}
+
/*
* Initiate a garbage collection if appropriate.
* Choose judiciously
@@ -202,6 +212,7 @@ void GC_maybe_gc()
static int n_partial_gcs = 0;
if (GC_should_collect()) {
if (!GC_incremental) {
+ GC_notify_full_gc();
GC_gcollect_inner();
n_partial_gcs = 0;
return;
@@ -216,6 +227,7 @@ void GC_maybe_gc()
(void)GC_reclaim_all((GC_stop_func)0, TRUE);
GC_clear_marks();
n_partial_gcs = 0;
+ GC_notify_full_gc();
} else {
n_partial_gcs++;
}
@@ -553,6 +565,7 @@ void GC_finish_collection()
void GC_gcollect GC_PROTO(())
{
+ GC_notify_full_gc();
(void)GC_try_to_collect(GC_never_stop_func);
}
@@ -664,6 +677,12 @@ word n;
if (n < MINHINCR) n = MINHINCR;
bytes = n * HBLKSIZE;
+ /* Make sure bytes is a multiple of GC_page_size */
+ {
+ word mask = GC_page_size - 1;
+ bytes += mask;
+ bytes &= ~mask;
+ }
if (GC_max_heapsize != 0 && GC_heapsize + bytes > GC_max_heapsize) {
/* Exceeded self-imposed limit */
@@ -726,13 +745,17 @@ word n;
return(result);
}
+unsigned GC_fail_count = 0;
+ /* How many consecutive GC/expansion failures? */
+ /* Reset by GC_allochblk. */
+
bool GC_collect_or_expand(needed_blocks, ignore_off_page)
word needed_blocks;
bool ignore_off_page;
{
- static unsigned count = 0; /* How many failures? */
if (!GC_incremental && !GC_dont_gc && GC_should_collect()) {
+ GC_notify_full_gc();
GC_gcollect_inner();
} else {
word blocks_to_get = GC_heapsize/(HBLKSIZE*GC_free_space_divisor)
@@ -755,18 +778,18 @@ bool ignore_off_page;
}
if (!GC_expand_hp_inner(blocks_to_get)
&& !GC_expand_hp_inner(needed_blocks)) {
- if (count++ < GC_max_retries) {
+ if (GC_fail_count++ < GC_max_retries) {
WARN("Out of Memory! Trying to continue ...\n", 0);
+ GC_notify_full_gc();
GC_gcollect_inner();
} else {
WARN("Out of Memory! Returning NIL!\n", 0);
return(FALSE);
}
- } else if (count) {
+ } else if (GC_fail_count) {
# ifdef PRINTSTATS
GC_printf0("Memory available again ...\n");
# endif
- count = 0;
}
}
return(TRUE);
diff --git a/blacklst.c b/blacklst.c
index 7b27993c..5917eb7a 100644
--- a/blacklst.c
+++ b/blacklst.c
@@ -46,7 +46,7 @@ word * GC_incomplete_normal_bl;
word * GC_old_stack_bl;
word * GC_incomplete_stack_bl;
-word GC_total_black_listed;
+word GC_total_stack_black_listed;
word GC_black_list_spacing = MINHINCR*HBLKSIZE; /* Initial rough guess */
@@ -89,7 +89,7 @@ word *new, *old;
BCOPY(old, new, sizeof(page_hash_table));
}
-static word total_black_listed();
+static word total_stack_black_listed();
/* Signal the completion of a collection. Turn the incomplete black */
/* lists into new black lists, etc. */
@@ -106,13 +106,14 @@ void GC_promote_black_lists()
GC_clear_bl(very_old_stack_bl);
GC_incomplete_normal_bl = very_old_normal_bl;
GC_incomplete_stack_bl = very_old_stack_bl;
- GC_total_black_listed = total_black_listed();
+ GC_total_stack_black_listed = total_stack_black_listed();
# ifdef PRINTSTATS
- GC_printf1("%ld blacklisted bytes in heap\n",
- (unsigned long)GC_total_black_listed);
+ GC_printf1("%ld bytes in heap blacklisted for interior pointers\n",
+ (unsigned long)GC_total_stack_black_listed);
# endif
- if (GC_total_black_listed != 0) {
- GC_black_list_spacing = HBLKSIZE*(GC_heapsize/GC_total_black_listed);
+ if (GC_total_stack_black_listed != 0) {
+ GC_black_list_spacing =
+ HBLKSIZE*(GC_heapsize/GC_total_stack_black_listed);
}
if (GC_black_list_spacing < 3 * HBLKSIZE) {
GC_black_list_spacing = 3 * HBLKSIZE;
@@ -230,7 +231,7 @@ struct hblk *start, *endp1;
/* Return the total number of (stack) black-listed bytes. */
-static word total_black_listed()
+static word total_stack_black_listed()
{
register unsigned i;
word total = 0;
diff --git a/config.h b/config.h
index f0e1d4ab..cffbf6e8 100644
--- a/config.h
+++ b/config.h
@@ -49,7 +49,7 @@
# endif
# if defined(mips) || defined(__mips)
# define MIPS
-# if defined(ultrix) || defined(__ultrix)
+# if defined(ultrix) || defined(__ultrix) || defined(__NetBSD__)
# define ULTRIX
# else
# if defined(_SYSTYPE_SVR4) || defined(SYSTYPE_SVR4) || defined(__SYSTYPE_SVR4__)
@@ -119,6 +119,11 @@
# define LINUX
# define mach_type_known
# endif
+# if defined(linux) && defined(powerpc)
+# define POWERPC
+# define LINUX
+# define mach_type_known
+# endif
# if defined(__alpha) || defined(__alpha__)
# define ALPHA
# if defined(linux) || defined(__linux__)
@@ -183,12 +188,12 @@
/* DGUX defined */
# define mach_type_known
# endif
-# if defined(_MSDOS) && (_M_IX86 == 300) || (_M_IX86 == 400)
+# if (defined(_MSDOS) || defined(_MSC_VER)) && (_M_IX86 >= 300)
# define I386
# define MSWIN32 /* or Win32s */
# define mach_type_known
# endif
-# if defined(GO32)
+# if defined(__DJGPP__)
# define I386
# define DJGPP /* MSDOS running the DJGPP port of GCC */
# define mach_type_known
@@ -206,6 +211,23 @@
# if defined(_UTS) && !defined(mach_type_known)
# define S370
# define UTS4
+# define mach_type_known
+# endif
+/* Ivan Demakov */
+# if defined(__WATCOMC__) && defined(__386__)
+# define I386
+# if !defined(OS2) && !defined(MSWIN32) && !defined(DOS4GW)
+# if defined(__OS2__)
+# define OS2
+# else
+# if defined(__WINDOWS_386__) || defined(__NT__)
+# define MSWIN32
+# else
+# define DOS4GW
+# endif
+# endif
+# endif
+# define mach_type_known
# endif
/* Feel free to add more clauses here */
@@ -356,6 +378,8 @@
# define DATASTART ((ptr_t)((((word) (&etext)) + 0xfff) & ~0xfff))
# define STACKBOTTOM ((ptr_t) 0xffeffffc)
/* empirically determined. seems to work. */
+# include <unistd.h>
+# define GETPAGESIZE() sysconf(_SC_PAGE_SIZE)
# endif
# ifdef SYSV
# define OS_TYPE "SYSV"
@@ -375,12 +399,15 @@
/* that the stack direction is incorrect. Two */
/* bytes down from 0x0 should be safe enough. */
/* --Parag */
+# include <sys/mmu.h>
+# define GETPAGESIZE() PAGESIZE /* Is this still right? */
# endif
# ifdef AMIGA
# define OS_TYPE "AMIGA"
/* STACKBOTTOM and DATASTART handled specially */
/* in os_dep.c */
# define DATAEND /* not needed */
+# define GETPAGESIZE() 4096
# endif
# ifdef MACOS
# ifndef __LOWMEM__
@@ -390,6 +417,7 @@
/* see os_dep.c for details of global data segments. */
# define STACKBOTTOM ((ptr_t) LMGetCurStackBase())
# define DATAEND /* not needed */
+# define GETPAGESIZE() 4096
# endif
# ifdef NEXT
# define OS_TYPE "NEXT"
@@ -411,6 +439,13 @@
# define STACKBOTTOM ((ptr_t) LMGetCurStackBase())
# define DATAEND /* not needed */
# endif
+# ifdef LINUX
+# define OS_TYPE "LINUX"
+# define STACKBOTTOM ((ptr_t)0x80000000)
+# define DATASTART GC_data_start
+ extern int _end;
+# define DATAEND (&_end)
+# endif
# endif
# ifdef VAX
@@ -448,6 +483,14 @@
extern char * GC_SysVGetDataStart();
# define DATASTART (ptr_t)GC_SysVGetDataStart(0x10000, &_etext)
# define DATAEND (&_end)
+# ifndef USE_MMAP
+# define USE_MMAP
+# endif
+# ifdef USE_MMAP
+# define HEAP_START (ptr_t)0x40000000
+# else
+# define HEAP_START DATAEND
+# endif
# define PROC_VDB
# define HEURISTIC1
# endif
@@ -486,6 +529,11 @@
# define ALIGNMENT 4 /* Appears to hold for all "32 bit" compilers */
/* except Borland. The -a4 option fixes */
/* Borland. */
+ /* Ivan Demakov: For Watcom the option is -zp4. */
+# ifndef SMALL_CONFIG
+# define ALIGN_DOUBLE /* Not strictly necessary, but may give speed */
+ /* improvement on Pentiums. */
+# endif
# ifdef SEQUENT
# define OS_TYPE "SEQUENT"
extern int etext;
@@ -498,7 +546,17 @@
extern char * GC_SysVGetDataStart();
# define DATASTART GC_SysVGetDataStart(0x1000, &etext)
# define STACKBOTTOM ((ptr_t)(&_start))
-# define PROC_VDB
+/** At least in Solaris 2.5, PROC_VDB gives wrong values for dirty bits. */
+/*# define PROC_VDB*/
+# define DYNAMIC_LOADING
+# ifndef USE_MMAP
+# define USE_MMAP
+# endif
+# ifdef USE_MMAP
+# define HEAP_START (ptr_t)0x40000000
+# else
+# define HEAP_START DATAEND
+# endif
# endif
# ifdef SCO
# define OS_TYPE "SCO"
@@ -510,13 +568,33 @@
# endif
# ifdef LINUX
# define OS_TYPE "LINUX"
- extern int etext;
-# define DATASTART ((ptr_t)((((word) (&etext)) + 0xfff) & ~0xfff))
# define STACKBOTTOM ((ptr_t)0xc0000000)
# define MPROTECT_VDB
# ifdef __ELF__
# define DYNAMIC_LOADING
# endif
+# ifdef __ELF__
+# define DYNAMIC_LOADING
+# ifdef UNDEFINED /* includes ro data */
+ extern int _etext;
+# define DATASTART ((ptr_t)((((word) (&_etext)) + 0xfff) & ~0xfff))
+# endif
+ extern char **__environ;
+# define DATASTART ((ptr_t)(&__environ))
+ /* hideous kludge: __environ is the first */
+ /* word in crt0.o, and delimits the start */
+ /* of the data segment, no matter which */
+ /* ld options were passed through. */
+ /* We could use _etext instead, but that */
+ /* would include .rodata, which may */
+ /* contain large read-only data tables */
+ /* that we'd rather not scan. */
+ extern int _end;
+# define DATAEND (&_end)
+# else
+ extern int etext;
+# define DATASTART ((ptr_t)((((word) (&etext)) + 0xfff) & ~0xfff))
+# endif
# endif
# ifdef CYGWIN32
# define OS_TYPE "CYGWIN32"
@@ -524,6 +602,9 @@
# define DATASTART ((ptr_t)&_bss_start__)
extern int _data_end__;
# define DATAEND ((ptr_t)&_data_end__)
+# undef STACK_GRAN
+# define STACK_GRAN 0x10000
+# define HEURISTIC1
# endif
# ifdef OS2
# define OS_TYPE "OS2"
@@ -536,15 +617,20 @@
# define OS_TYPE "MSWIN32"
/* STACKBOTTOM and DATASTART are handled specially in */
/* os_dep.c. */
-# define MPROTECT_VDB
+# ifndef __WATCOMC__
+# define MPROTECT_VDB
+# endif
# define DATAEND /* not needed */
# endif
# ifdef DJGPP
# define OS_TYPE "DJGPP"
+# include "stubinfo.h"
extern int etext;
-# define DATASTART ((ptr_t)(&etext))
-# define STACKBOTTOM ((ptr_t)0x00080000)
- /* This may not be right. It's rumored to vary. */
+ extern int _stklen;
+# define DATASTART ((ptr_t)((((word) (&etext)) + 0x1ff) & ~0x1ff))
+# define STACKBOTTOM ((ptr_t)((word) _stubinfo + _stubinfo->size \
+ + _stklen))
+ /* This may not be right. */
# endif
# ifdef FREEBSD
# define OS_TYPE "FREEBSD"
@@ -571,6 +657,21 @@
# define STACKBOTTOM ((ptr_t)0xc0000000)
# define DATAEND /* not needed */
# endif
+# ifdef DOS4GW
+# define OS_TYPE "DOS4GW"
+ /* Get_DATASTART, Get_DATAEND, Get_STACKBOTTOM
+ * Defined in gc-watcom.asm
+ */
+ extern char* Get_DATASTART (void);
+ extern char* Get_DATAEND (void);
+ extern char* Get_STACKBOTTOM (void);
+# pragma aux Get_DATASTART "*" value [eax];
+# pragma aux Get_DATAEND "*" value [eax];
+# pragma aux Get_STACKBOTTOM "*" value [eax];
+# define DATASTART ((ptr_t) Get_DATASTART())
+# define STACKBOTTOM ((ptr_t) Get_STACKBOTTOM())
+# define DATAEND ((ptr_t) Get_DATAEND())
+# endif
# endif
# ifdef NS32K
@@ -638,10 +739,10 @@
# define MACH_TYPE "RS6000"
# define ALIGNMENT 4
# define DATASTART ((ptr_t)0x20000000)
-# define STACKBOTTOM ((ptr_t)0x2ff80000)
- /* This is known to break under 4.X, under some circumstances. */
- /* But there doesn't seem to be a good alternative. Set */
- /* GC_stackbottom manually. */
+ extern int errno;
+# define STACKBOTTOM ((ptr_t)((ulong)&errno + 2*sizeof(int)))
+# define DYNAMIC_LOADING
+ /* For really old versions of AIX, this may have to be removed. */
# endif
# ifdef HP_PA
@@ -664,6 +765,8 @@
# endif
# define STACK_GROWS_UP
# define DYNAMIC_LOADING
+# include <unistd.h>
+# define GETPAGESIZE() sysconf(_SC_PAGE_SIZE)
# endif
# ifdef ALPHA
@@ -695,9 +798,6 @@
# endif
extern int _end;
# define DATAEND (&_end)
-# ifdef __ELF__
-# define DYNAMIC_LOADING
-# endif
/* As of 1.3.90, I couldn't find a way to retrieve the correct */
/* fault address from a signal handler. */
/* Hence MPROTECT_VDB is broken. */
@@ -710,9 +810,11 @@
# define ALIGN_DOUBLE
extern int etext;
# ifdef CX_UX
+# define OS_TYPE "CX_UX"
# define DATASTART ((((word)&etext + 0x3fffff) & ~0x3fffff) + 0x10000)
# endif
# ifdef DGUX
+# define OS_TYPE "DGUX"
extern char * GC_SysVGetDataStart();
# define DATASTART (ptr_t)GC_SysVGetDataStart(0x10000, &etext)
# endif
@@ -749,6 +851,18 @@
# define DATAEND (&end)
# endif
+# if defined(SVR4) && !defined(GETPAGESIZE)
+# include <unistd.h>
+ int
+ GC_getpagesize()
+ {
+ return sysconf(_SC_PAGESIZE);
+ }
+# endif
+# ifndef GETPAGESIZE
+# define GETPAGESIZE() getpagesize()
+# endif
+
# if defined(SUNOS5) || defined(DRSNX) || defined(UTS4)
/* OS has SVR4 generic features. Probably others also qualify. */
# define SVR4
diff --git a/cord/gc.h b/cord/gc.h
index 16070cca..1e00c2f5 100644
--- a/cord/gc.h
+++ b/cord/gc.h
@@ -31,6 +31,9 @@
# define __GC
# include <stddef.h>
+#if defined(__CYGWIN32__) && defined(GC_USE_DLL)
+#include "libgc_globals.h"
+#endif
#if defined(_MSC_VER) && defined(_DLL)
#ifdef GC_BUILD
@@ -76,7 +79,7 @@ GC_API GC_word GC_gc_no;/* Counter incremented per collection. */
/* Public R/W variables */
-GC_API void * (*GC_oom_fn) GC_PROTO((size_t bytes_requested));
+GC_API GC_PTR (*GC_oom_fn) GC_PROTO((size_t bytes_requested));
/* When there is insufficient memory to satisfy */
/* an allocation request, we return */
/* (*GC_oom_fn)(). By default this just */
@@ -202,6 +205,13 @@ GC_API int GC_expand_hp GC_PROTO((size_t number_of_bytes));
/* n == 0 ==> unbounded. This is the default. */
GC_API void GC_set_max_heap_size GC_PROTO((GC_word n));
+/* Inform the collector that a certain section of statically allocated */
+/* memory contains no pointers to garbage collected memory. Thus it */
+/* need not be scanned. This is sometimes important if the application */
+/* maps large read/write files into the address space, which could be */
+/* mistaken for dynamic library data segments on some systems. */
+GC_API void GC_exclude_static_roots GC_PROTO((GC_PTR start, GC_PTR finish));
+
/* Clear the set of root segments. Wizards only. */
GC_API void GC_clear_roots GC_PROTO((void));
@@ -592,6 +602,19 @@ GC_API void (*GC_is_visible_print_proc)
int GC_thr_continue(thread_t target_thread);
void * GC_dlopen(const char *path, int mode);
+# ifdef _SOLARIS_PTHREADS
+# include <pthread.h>
+ extern int GC_pthread_create(pthread_t *new_thread,
+ const pthread_attr_t *attr,
+ void * (*thread_execp)(void *), void *arg);
+ extern int GC_pthread_join(pthread_t wait_for, void **status);
+
+# undef thread_t
+
+# define pthread_join GC_pthread_join
+# define pthread_create GC_pthread_create
+#endif
+
# define thr_create GC_thr_create
# define thr_join GC_thr_join
# define thr_suspend GC_thr_suspend
@@ -600,6 +623,7 @@ GC_API void (*GC_is_visible_print_proc)
# endif /* SOLARIS_THREADS */
+
#ifdef IRIX_THREADS
/* We treat these similarly. */
# include <pthread.h>
@@ -624,6 +648,7 @@ GC_API void (*GC_is_visible_print_proc)
GC_PTR GC_malloc_many(size_t lb);
#define GC_NEXT(p) (*(GC_PTR *)(p)) /* Retrieve the next element */
/* in returned list. */
+extern void GC_thr_init(); /* Needed for Solaris/X86 */
#endif /* SOLARIS_THREADS */
@@ -637,7 +662,22 @@ GC_PTR GC_malloc_many(size_t lb);
# define GC_INIT() { extern end, etext; \
GC_noop(&end, &etext); }
#else
+# if defined(__CYGWIN32__) && defined(GC_USE_DLL)
+ /*
+ * Similarly gnu-win32 DLLs need explicit initialization
+ */
+# define GC_INIT() { GC_add_roots(DATASTART, DATAEND); }
+# else
# define GC_INIT()
+# endif
+#endif
+
+#ifdef __WATCOMC__
+ /* Ivan Demakov: Programs compiled by Watcom C with -5r option
+ * crash without this declaration
+ * HB: Could this go into gc_priv.h?
+ */
+ void GC_noop(void*, ...);
#endif
#ifdef __cplusplus
diff --git a/dbg_mlc.c b/dbg_mlc.c
index cd6ad35d..094614a5 100644
--- a/dbg_mlc.c
+++ b/dbg_mlc.c
@@ -448,11 +448,13 @@ word dummy;
p = (word *)(hbp->hb_body);
word_no = HDR_WORDS;
- plim = (word *)((((word)hbp) + HBLKSIZE)
- - WORDS_TO_BYTES(sz));
-
+ if (sz > MAXOBJSZ) {
+ plim = p;
+ } else {
+ plim = (word *)((((word)hbp) + HBLKSIZE) - WORDS_TO_BYTES(sz));
+ }
/* go through all words in block */
- do {
+ while( p <= plim ) {
if( mark_bit_from_hdr(hhdr, word_no)
&& GC_has_debug_info((ptr_t)p)) {
ptr_t clobbered = GC_check_annotated_obj((oh *)p);
@@ -465,7 +467,7 @@ word dummy;
}
word_no += sz;
p += sz;
- } while( p <= plim );
+ }
}
diff --git a/dyn_load.c b/dyn_load.c
index ab51647f..b19cddac 100644
--- a/dyn_load.c
+++ b/dyn_load.c
@@ -1,5 +1,6 @@
/*
* Copyright (c) 1991-1994 by Xerox Corporation. All rights reserved.
+ * Copyright (c) 1997 by Silicon Graphics. All rights reserved.
*
* THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
* OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
@@ -13,7 +14,6 @@
* Original author: Bill Janssen
* Heavily modified by Hans Boehm and others
*/
-/* Boehm, September 21, 1995 5:57 pm PDT */
/*
* This is incredibly OS specific code for tracking down data sections in
@@ -45,7 +45,10 @@
# endif
#if (defined(DYNAMIC_LOADING) || defined(MSWIN32)) && !defined(PCR)
-#if !defined(SUNOS4) && !defined(SUNOS5DL) && !defined(IRIX5) && !defined(MSWIN32) && !(defined(ALPHA) && defined(OSF1)) &&!defined(HP_PA) && (!defined(LINUX) && !defined(__ELF__))
+#if !defined(SUNOS4) && !defined(SUNOS5DL) && !defined(IRIX5) && \
+ !defined(MSWIN32) && !(defined(ALPHA) && defined(OSF1)) && \
+ !defined(HP_PA) && (!defined(LINUX) && !defined(__ELF__)) && \
+ !defined(RS6000)
--> We only know how to find data segments of dynamic libraries for the
--> above. Additional SVR4 variants might not be too
--> hard to add.
@@ -68,7 +71,7 @@
#endif
-#ifdef SUNOS5DL
+#if defined(SUNOS5DL) && !defined(USE_PROC_FOR_LIBRARIES)
#ifdef LINT
Elf32_Dyn _DYNAMIC;
@@ -114,9 +117,9 @@ GC_FirstDLOpenedLinkMap()
return cachedResult;
}
-#endif
+#endif /* SUNOS5DL ... */
-#ifdef SUNOS4
+#if defined(SUNOS4) && !defined(USE_PROC_FOR_LIBRARIES)
#ifdef LINT
struct link_dynamic _DYNAMIC;
@@ -154,7 +157,7 @@ static ptr_t GC_first_common()
return(result);
}
-#endif
+#endif /* SUNOS4 ... */
# if defined(SUNOS4) || defined(SUNOS5DL)
/* Add dynamic library data sections to the root set. */
@@ -171,23 +174,28 @@ static ptr_t GC_first_common()
/* and friends. */
# include <thread.h>
# include <synch.h>
-
+
void * GC_dlopen(const char *path, int mode)
{
void * result;
- mutex_lock(&GC_allocate_ml);
+# ifndef USE_PROC_FOR_LIBRARIES
+ mutex_lock(&GC_allocate_ml);
+# endif
result = dlopen(path, mode);
- mutex_unlock(&GC_allocate_ml);
+# ifndef USE_PROC_FOR_LIBRARIES
+ mutex_unlock(&GC_allocate_ml);
+# endif
return(result);
}
-# endif
+# endif /* SOLARIS_THREADS */
/* BTL: added to fix circular dlopen definition if SOLARIS_THREADS defined */
# if defined(GC_must_restore_redefined_dlopen)
# define dlopen GC_dlopen
# endif
+# ifndef USE_PROC_FOR_LIBRARIES
void GC_register_dynamic_libraries()
{
struct link_map *lm = GC_FirstDLOpenedLinkMap();
@@ -249,6 +257,7 @@ void GC_register_dynamic_libraries()
# endif
}
+# endif /* !USE_PROC ... */
# endif /* SUNOS */
#if defined(LINUX) && defined(__ELF__)
@@ -264,7 +273,7 @@ void GC_register_dynamic_libraries()
/* Newer versions of Linux/Alpha and Linux/x86 define this macro. We
* define it for those older versions that don't. */
# ifndef ElfW
-# if ELF_CLASS == ELFCLASS32
+# if !defined(ELF_CLASS) || ELF_CLASS == ELFCLASS32
# define ElfW(type) Elf32_##type
# else
# define ElfW(type) Elf64_##type
@@ -279,6 +288,9 @@ GC_FirstDLOpenedLinkMap()
struct r_debug *r;
static struct link_map *cachedResult = 0;
+ if( _DYNAMIC == 0) {
+ return(0);
+ }
if( cachedResult == 0 ) {
int tag;
for( dp = _DYNAMIC; (tag = dp->d_tag) != 0; dp++ ) {
@@ -329,7 +341,7 @@ void GC_register_dynamic_libraries()
#endif
-#ifdef IRIX5
+#if defined(IRIX5) || defined(USE_PROC_FOR_LIBRARIES)
#include <sys/procfs.h>
#include <sys/stat.h>
@@ -358,6 +370,10 @@ void GC_register_dynamic_libraries()
ptr_t heap_start = (ptr_t)HEAP_START;
ptr_t heap_end = heap_start;
+# ifdef SUNOS5DL
+# define MA_PHYS 0
+# endif /* SUNOS5DL */
+
if (fd < 0) {
sprintf(buf, "/proc/%d", getpid());
fd = open(buf, O_RDONLY);
@@ -375,7 +391,8 @@ void GC_register_dynamic_libraries()
addr_map = (prmap_t *)GC_scratch_alloc(current_sz * sizeof(prmap_t));
}
if (ioctl(fd, PIOCMAP, addr_map) < 0) {
- GC_err_printf2("fd = %d, errno = %d\n", fd, errno);
+ GC_err_printf4("fd = %d, errno = %d, needed_sz = %d, addr_map = 0x%X\n",
+ fd, errno, needed_sz, addr_map);
ABORT("/proc PIOCMAP ioctl failed");
};
if (GC_n_heap_sects > 0) {
@@ -396,6 +413,10 @@ void GC_register_dynamic_libraries()
if (GC_roots_present(start)) goto irrelevant;
if (start < heap_end && start >= heap_start)
goto irrelevant;
+# ifdef MMAP_STACKS
+ if (GC_is_thread_stack(start)) goto irrelevant;
+# endif /* MMAP_STACKS */
+
limit = start + addr_map[i].pr_size;
if (addr_map[i].pr_off == 0 && strncmp(start, ELFMAG, 4) == 0) {
/* Discard text segments, i.e. 0-offset mappings against */
@@ -434,7 +455,7 @@ void GC_register_dynamic_libraries()
fd = -1;
}
-#endif /* IRIX5 */
+# endif /* USE_PROC || IRIX5 */
# ifdef MSWIN32
@@ -471,7 +492,7 @@ void GC_register_dynamic_libraries()
GC_add_roots_inner(curr_base, next_stack_lo, TRUE);
curr_base = next_stack_hi;
}
- if (curr_base < limit) GC_add_roots_inner(curr_base, limit);
+ if (curr_base < limit) GC_add_roots_inner(curr_base, limit, TRUE);
}
# else
if (limit > stack_top && base < GC_stackbottom) {
@@ -631,6 +652,7 @@ void GC_register_dynamic_libraries()
#if defined(HP_PA)
+#include <errno.h>
#include <dl.h>
extern int errno;
@@ -685,6 +707,40 @@ void GC_register_dynamic_libraries()
}
#endif /* HP_PA */
+#ifdef RS6000
+#pragma alloca
+#include <sys/ldr.h>
+#include <sys/errno.h>
+void GC_register_dynamic_libraries()
+{
+ int len;
+ char *ldibuf;
+ int ldibuflen;
+ struct ld_info *ldi;
+
+ ldibuf = alloca(ldibuflen = 8192);
+
+ while ( (len = loadquery(L_GETINFO,ldibuf,ldibuflen)) < 0) {
+ if (errno != ENOMEM) {
+ ABORT("loadquery failed");
+ }
+ ldibuf = alloca(ldibuflen *= 2);
+ }
+
+ ldi = (struct ld_info *)ldibuf;
+ while (ldi) {
+ len = ldi->ldinfo_next;
+ GC_add_roots_inner(
+ ldi->ldinfo_dataorg,
+ (unsigned long)ldi->ldinfo_dataorg
+ + ldi->ldinfo_datasize,
+ TRUE);
+ ldi = len ? (struct ld_info *)((char *)ldi + len) : 0;
+ }
+}
+#endif /* RS6000 */
+
+
#else /* !DYNAMIC_LOADING */
diff --git a/gc.h b/gc.h
index 16070cca..1e00c2f5 100644
--- a/gc.h
+++ b/gc.h
@@ -31,6 +31,9 @@
# define __GC
# include <stddef.h>
+#if defined(__CYGWIN32__) && defined(GC_USE_DLL)
+#include "libgc_globals.h"
+#endif
#if defined(_MSC_VER) && defined(_DLL)
#ifdef GC_BUILD
@@ -76,7 +79,7 @@ GC_API GC_word GC_gc_no;/* Counter incremented per collection. */
/* Public R/W variables */
-GC_API void * (*GC_oom_fn) GC_PROTO((size_t bytes_requested));
+GC_API GC_PTR (*GC_oom_fn) GC_PROTO((size_t bytes_requested));
/* When there is insufficient memory to satisfy */
/* an allocation request, we return */
/* (*GC_oom_fn)(). By default this just */
@@ -202,6 +205,13 @@ GC_API int GC_expand_hp GC_PROTO((size_t number_of_bytes));
/* n == 0 ==> unbounded. This is the default. */
GC_API void GC_set_max_heap_size GC_PROTO((GC_word n));
+/* Inform the collector that a certain section of statically allocated */
+/* memory contains no pointers to garbage collected memory. Thus it */
+/* need not be scanned. This is sometimes important if the application */
+/* maps large read/write files into the address space, which could be */
+/* mistaken for dynamic library data segments on some systems. */
+GC_API void GC_exclude_static_roots GC_PROTO((GC_PTR start, GC_PTR finish));
+
/* Clear the set of root segments. Wizards only. */
GC_API void GC_clear_roots GC_PROTO((void));
@@ -592,6 +602,19 @@ GC_API void (*GC_is_visible_print_proc)
int GC_thr_continue(thread_t target_thread);
void * GC_dlopen(const char *path, int mode);
+# ifdef _SOLARIS_PTHREADS
+# include <pthread.h>
+ extern int GC_pthread_create(pthread_t *new_thread,
+ const pthread_attr_t *attr,
+ void * (*thread_execp)(void *), void *arg);
+ extern int GC_pthread_join(pthread_t wait_for, void **status);
+
+# undef thread_t
+
+# define pthread_join GC_pthread_join
+# define pthread_create GC_pthread_create
+#endif
+
# define thr_create GC_thr_create
# define thr_join GC_thr_join
# define thr_suspend GC_thr_suspend
@@ -600,6 +623,7 @@ GC_API void (*GC_is_visible_print_proc)
# endif /* SOLARIS_THREADS */
+
#ifdef IRIX_THREADS
/* We treat these similarly. */
# include <pthread.h>
@@ -624,6 +648,7 @@ GC_API void (*GC_is_visible_print_proc)
GC_PTR GC_malloc_many(size_t lb);
#define GC_NEXT(p) (*(GC_PTR *)(p)) /* Retrieve the next element */
/* in returned list. */
+extern void GC_thr_init(); /* Needed for Solaris/X86 */
#endif /* SOLARIS_THREADS */
@@ -637,7 +662,22 @@ GC_PTR GC_malloc_many(size_t lb);
# define GC_INIT() { extern end, etext; \
GC_noop(&end, &etext); }
#else
+# if defined(__CYGWIN32__) && defined(GC_USE_DLL)
+ /*
+ * Similarly gnu-win32 DLLs need explicit initialization
+ */
+# define GC_INIT() { GC_add_roots(DATASTART, DATAEND); }
+# else
# define GC_INIT()
+# endif
+#endif
+
+#ifdef __WATCOMC__
+ /* Ivan Demakov: Programs compiled by Watcom C with -5r option
+ * crash without this declaration
+ * HB: Could this go into gc_priv.h?
+ */
+ void GC_noop(void*, ...);
#endif
#ifdef __cplusplus
diff --git a/gc_alloc.h b/gc_alloc.h
index f64c1127..85cb7cdb 100644
--- a/gc_alloc.h
+++ b/gc_alloc.h
@@ -22,10 +22,12 @@
// Some of this could be faster in the explicit deallocation case. In particular,
// we spend too much time clearing objects on the free lists. That could be avoided.
//
-// This uses template classes with static members, and hence soes not work
+// This uses template classes with static members, and hence does not work
// with g++ 2.7.2 and earlier.
//
+#include "gc.h"
+
#ifndef GC_ALLOC_H
#define GC_ALLOC_H
@@ -70,8 +72,6 @@ extern "C" {
extern void GC_incr_mem_freed(size_t words);
extern char * GC_generic_malloc_words_small(size_t word, int kind);
-
- extern void * GC_malloc_atomic_uncollectable(size_t bytes);
}
// Object kinds; must match PTRFREE, NORMAL, UNCOLLECTABLE, and
@@ -93,13 +93,13 @@ inline void * &GC_obj_link(void * p)
// Compute a number of words >= n+1 bytes.
// The +1 allows for pointers one past the end.
-inline GC_round_up(size_t n)
+inline size_t GC_round_up(size_t n)
{
return ((n + GC_byte_alignment)/GC_byte_alignment)*GC_word_alignment;
}
// The same but don't allow for extra byte.
-inline GC_round_up_uncollectable(size_t n)
+inline size_t GC_round_up_uncollectable(size_t n)
{
return ((n + GC_byte_alignment - 1)/GC_byte_alignment)*GC_word_alignment;
}
@@ -367,6 +367,6 @@ __GC_SPECIALIZE(unsigned, single_client_alloc)
__GC_SPECIALIZE(float, single_client_alloc)
__GC_SPECIALIZE(double, single_client_alloc)
-#endif _SGI_SOURCE
+#endif /* _SGI_SOURCE */
#endif /* GC_ALLOC_H */
diff --git a/gc_cpp.h b/gc_cpp.h
index 812bb653..e2f456fb 100644
--- a/gc_cpp.h
+++ b/gc_cpp.h
@@ -137,7 +137,7 @@ uses explicit invocation.
# define OPERATOR_NEW_ARRAY
#endif
-enum GCPlacement {GC, NoGC};
+enum GCPlacement {GC, NoGC, PointerFreeGC};
class gc {public:
inline void* operator new( size_t size );
@@ -263,6 +263,8 @@ inline void* operator new(
if (cleanup != 0)
GC_REGISTER_FINALIZER_IGNORE_SELF(
obj, cleanup, clientData, 0, 0 );}
+ else if (gcp == PointerFreeGC) {
+ obj = GC_MALLOC_ATOMIC( size );}
else {
obj = GC_MALLOC_UNCOLLECTABLE( size );};
return obj;}
diff --git a/gc_priv.h b/gc_priv.h
index 65e53b34..49a916d0 100644
--- a/gc_priv.h
+++ b/gc_priv.h
@@ -20,7 +20,7 @@
#if defined(mips) && defined(SYSTYPE_BSD) && defined(sony_news)
/* sony RISC NEWS, NEWSOS 4 */
# define BSD_TIME
- typedef long ptrdiff_t;
+/* typedef long ptrdiff_t; -- necessary on some really old systems */
#endif
#if defined(mips) && defined(SYSTYPE_BSD43)
@@ -57,6 +57,9 @@ typedef GC_signed_word signed_word;
# if defined(_SGI_SOURCE) && !defined(_BOOL)
typedef int bool;
# endif
+# if defined(__SUNPRO_CC) && __SUNPRO_CC <= 0x410
+ typedef int bool;
+# endif
# if defined(__cplusplus) && defined(_MSC_VER) && _MSC_VER <= 1020
/* Visual C++ 4.2 does not have bool type. */
typedef int bool;
@@ -320,18 +323,19 @@ void GC_print_callers (/* struct callinfo info[NFRAMES] */);
/* space is assumed to be cleared. */
# ifdef PCR
char * real_malloc();
-# define GET_MEM(bytes) HBLKPTR(real_malloc((size_t)bytes + HBLKSIZE) \
- + HBLKSIZE-1)
+# define GET_MEM(bytes) HBLKPTR(real_malloc((size_t)bytes + GC_page_size) \
+ + GC_page_size-1)
# else
# ifdef OS2
void * os2_alloc(size_t bytes);
-# define GET_MEM(bytes) HBLKPTR((ptr_t)os2_alloc((size_t)bytes + HBLKSIZE) \
- + HBLKSIZE-1)
+# define GET_MEM(bytes) HBLKPTR((ptr_t)os2_alloc((size_t)bytes \
+ + GC_page_size) \
+ + GC_page_size-1)
# else
-# if defined(AMIGA) || defined(NEXT)
+# if defined(AMIGA) || defined(NEXT) || defined(DOS4GW)
# define GET_MEM(bytes) HBLKPTR((size_t) \
- calloc(1, (size_t)bytes + HBLKSIZE) \
- + HBLKSIZE-1)
+ calloc(1, (size_t)bytes + GC_page_size) \
+ + GC_page_size-1)
# else
# ifdef MSWIN32
extern ptr_t GC_win32_get_mem();
@@ -342,14 +346,15 @@ void GC_print_callers (/* struct callinfo info[NFRAMES] */);
extern Ptr GC_MacTemporaryNewPtr(size_t size,
Boolean clearMemory);
# define GET_MEM(bytes) HBLKPTR( \
- GC_MacTemporaryNewPtr(bytes + HBLKSIZE, true) + HBLKSIZE-1)
+ GC_MacTemporaryNewPtr(bytes + GC_page_size, true) \
+ + GC_page_size-1)
# else
# define GET_MEM(bytes) HBLKPTR( \
- NewPtrClear(bytes + HBLKSIZE) + HBLKSIZE-1)
+ NewPtrClear(bytes + GC_page_size) + GC_page_size-1)
# endif
# else
- extern ptr_t GC_unix_get_mem();
-# define GET_MEM(bytes) (struct hblk *)GC_unix_get_mem(bytes)
+ extern ptr_t GC_unix_get_mem();
+# define GET_MEM(bytes) (struct hblk *)GC_unix_get_mem(bytes)
# endif
# endif
# endif
@@ -436,7 +441,7 @@ void GC_print_callers (/* struct callinfo info[NFRAMES] */);
# else
# define LOCK() { if (__test_and_set(&GC_allocate_lock, 1)) GC_lock(); }
# if __mips >= 3 && (defined (_ABIN32) || defined(_ABI64))
-# define UNLOCK() __lock_release(lock)
+# define UNLOCK() __lock_release(&GC_allocate_lock)
# else
# define UNLOCK() GC_allocate_lock = 0
# endif
@@ -601,18 +606,43 @@ extern GC_warn_proc GC_current_warn_proc;
/* heap block size, bytes. Should be power of 2 */
-#ifdef SMALL_CONFIG
+#ifndef HBLKSIZE
+# ifdef SMALL_CONFIG
# define CPP_LOG_HBLKSIZE 10
+# else
+# if CPP_WORDSZ == 32
+# define CPP_LOG_HBLKSIZE 12
+# else
+# define CPP_LOG_HBLKSIZE 13
+# endif
+# endif
#else
-# if CPP_WORDSZ == 32
+# if HBLKSIZE == 512
+# define CPP_LOG_HBLKSIZE 9
+# endif
+# if HBLKSIZE == 1024
+# define CPP_LOG_HBLKSIZE 10
+# endif
+# if HBLKSIZE == 2048
+# define CPP_LOG_HBLKSIZE 11
+# endif
+# if HBLKSIZE == 4096
# define CPP_LOG_HBLKSIZE 12
-# else
+# endif
+# if HBLKSIZE == 8192
# define CPP_LOG_HBLKSIZE 13
# endif
+# if HBLKSIZE == 16384
+# define CPP_LOG_HBLKSIZE 14
+# endif
+# ifndef CPP_LOG_HBLKSIZE
+ --> fix HBLKSIZE
+# endif
+# undef HBLKSIZE
#endif
-#define LOG_HBLKSIZE ((word)CPP_LOG_HBLKSIZE)
-#define CPP_HBLKSIZE (1 << CPP_LOG_HBLKSIZE)
-#define HBLKSIZE ((word)CPP_HBLKSIZE)
+# define CPP_HBLKSIZE (1 << CPP_LOG_HBLKSIZE)
+# define LOG_HBLKSIZE ((word)CPP_LOG_HBLKSIZE)
+# define HBLKSIZE ((word)CPP_HBLKSIZE)
/* max size objects supported by freelist (larger objects may be */
@@ -798,8 +828,9 @@ struct _GC_arrays {
word _words_allocd;
/* Number of words allocated during this collection cycle */
word _words_wasted;
- /* Number of words wasted due to internal fragmentation */
- /* in large objects allocated since last gc. Approximate.*/
+ /* Number of words wasted due to internal fragmentation */
+ /* in large objects, or due to dropping blacklisted */
+ /* blocks, since last gc. Approximate. */
word _words_finalized;
/* Approximate number of words in objects (and headers) */
/* That became ready for finalization in the last */
@@ -1017,16 +1048,21 @@ extern int GC_n_kinds;
extern word GC_n_heap_sects; /* Number of separately added heap */
/* sections. */
+extern word GC_page_size;
+
# ifdef MSWIN32
extern word GC_n_heap_bases; /* See GC_heap_bases. */
# endif
-extern word GC_total_black_listed;
+extern word GC_total_stack_black_listed;
/* Number of bytes on stack blacklist. */
extern word GC_black_list_spacing;
/* Average number of bytes between blacklisted */
/* blocks. Approximate. */
+ /* Counts only blocks that are */
+ /* "stack-blacklisted", i.e. that are */
+ /* problematic in the interior of an object. */
extern char * GC_invalid_map;
/* Pointer to the nowhere valid hblk map */
@@ -1139,11 +1175,23 @@ extern void (*GC_push_other_roots)();
/* predfined to be non-zero. A client supplied */
/* replacement should also call the original */
/* function. */
+extern void (*GC_start_call_back)(/* void */);
+ /* Called at start of full collections. */
+ /* Not called if 0. Called with allocation */
+ /* lock held. */
+ /* 0 by default. */
void GC_push_regs(); /* Push register contents onto mark stack. */
void GC_remark(); /* Mark from all marked objects. Used */
/* only if we had to drop something. */
void GC_push_one(/*p*/); /* If p points to an object, mark it */
/* and push contents on the mark stack */
+/* Ivan Demakov: Watcom C error'ed without this */
+# if defined(MSWIN32) && defined(__WATCOMC__)
+ void __cdecl GC_push_one();
+# else
+ void GC_push_one(/*p*/); /* If p points to an object, mark it */
+ /* and push contents on the mark stack */
+# endif
void GC_push_one_checked(/*p*/); /* Ditto, omits plausibility test */
void GC_push_marked(/* struct hblk h, hdr * hhdr */);
/* Push contents of all marked objects in h onto */
@@ -1284,12 +1332,17 @@ void GC_collect_a_little_inner(/* int n */);
ptr_t GC_generic_malloc(/* bytes, kind */);
/* Allocate an object of the given */
/* kind. By default, there are only */
- /* two kinds: composite, and atomic. */
+ /* a few kinds: composite(pointerfree), */
+ /* atomic, uncollectable, etc. */
/* We claim it's possible for clever */
/* client code that understands GC */
/* internals to add more, e.g. to */
/* communicate object layout info */
/* to the collector. */
+ptr_t GC_generic_malloc_ignore_off_page(/* bytes, kind */);
+ /* As above, but pointers past the */
+ /* first page of the resulting object */
+ /* are ignored. */
ptr_t GC_generic_malloc_inner(/* bytes, kind */);
/* Ditto, but I already hold lock, etc. */
ptr_t GC_generic_malloc_words_small GC_PROTO((size_t words, int kind));
@@ -1417,4 +1470,5 @@ void GC_err_puts(/* char *s */);
/* Write s to stderr, don't buffer, don't add */
/* newlines, don't ... */
+
# endif /* GC_PRIVATE_H */
diff --git a/gc_typed.h b/gc_typed.h
index ea20e765..e4a6b947 100644
--- a/gc_typed.h
+++ b/gc_typed.h
@@ -57,12 +57,15 @@ GC_API GC_descr GC_make_descriptor GC_PROTO((GC_bitmap bm, size_t len));
/* is intended to be called once per type, not once */
/* per allocation. */
-GC_API void * GC_malloc_explicitly_typed
+GC_API GC_PTR GC_malloc_explicitly_typed
GC_PROTO((size_t size_in_bytes, GC_descr d));
/* Allocate an object whose layout is described by d. */
/* The resulting object MAY NOT BE PASSED TO REALLOC. */
+
+GC_API GC_PTR GC_malloc_explicitly_typed_ignore_off_page
+ GC_PROTO((size_t size_in_bytes, GC_descr d));
-GC_API void * GC_calloc_explicitly_typed
+GC_API GC_PTR GC_calloc_explicitly_typed
GC_PROTO((size_t nelements,
size_t element_size_in_bytes,
GC_descr d));
diff --git a/gc_watcom.asm b/gc_watcom.asm
new file mode 100644
index 00000000..5131ab96
--- /dev/null
+++ b/gc_watcom.asm
@@ -0,0 +1,51 @@
+
+ name gc_watcom
+
+.386p
+
+ extrn _edata : byte ; end of DATA (start of BSS)
+ extrn _end : byte ; end of BSS (start of STACK)
+ extrn __nullarea : word
+
+ extrn "C",_STACKLOW : dword
+ extrn "C",_STACKTOP : dword
+
+
+DGROUP group _DATA
+
+_DATA segment dword public 'DATA'
+_DATA ends
+
+_TEXT segment para public use32 'CODE'
+ assume cs:_TEXT, ds:DGROUP, ss:DGROUP
+
+ public Get_DATASTART
+ align 4
+Get_DATASTART proc near
+
+ mov eax,offset DGROUP:__nullarea
+ ret
+
+Get_DATASTART endp
+
+ public Get_DATAEND
+ align 4
+Get_DATAEND proc near
+
+ mov eax,offset DGROUP:_end
+ ret
+
+Get_DATAEND endp
+
+ public Get_STACKBOTTOM
+ align 4
+Get_STACKBOTTOM proc near
+
+ mov eax,_STACKTOP
+ ret
+
+Get_STACKBOTTOM endp
+
+_TEXT ends
+
+ end
diff --git a/if_mach.c b/if_mach.c
index f339ab3e..da2b7f90 100644
--- a/if_mach.c
+++ b/if_mach.c
@@ -12,6 +12,7 @@ char ** envp;
if (strcmp(MACH_TYPE, argv[1]) != 0) return(0);
if (strcmp(OS_TYPE, "") != 0 && strcmp(argv[2], "") != 0
&& strcmp(OS_TYPE, argv[2]) != 0) return(0);
+ printf("^^^^Starting command^^^^\n");
execvp(argv[3], argv+3);
perror("Couldn't execute");
diff --git a/if_not_there.c b/if_not_there.c
index 392393c5..9616309d 100644
--- a/if_not_there.c
+++ b/if_not_there.c
@@ -15,6 +15,7 @@ char ** envp;
fclose(f);
return(0);
}
+ printf("^^^^Starting command^^^^\n");
execvp(argv[2], argv+2);
exit(1);
diff --git a/include/gc.h b/include/gc.h
index 16070cca..1e00c2f5 100644
--- a/include/gc.h
+++ b/include/gc.h
@@ -31,6 +31,9 @@
# define __GC
# include <stddef.h>
+#if defined(__CYGWIN32__) && defined(GC_USE_DLL)
+#include "libgc_globals.h"
+#endif
#if defined(_MSC_VER) && defined(_DLL)
#ifdef GC_BUILD
@@ -76,7 +79,7 @@ GC_API GC_word GC_gc_no;/* Counter incremented per collection. */
/* Public R/W variables */
-GC_API void * (*GC_oom_fn) GC_PROTO((size_t bytes_requested));
+GC_API GC_PTR (*GC_oom_fn) GC_PROTO((size_t bytes_requested));
/* When there is insufficient memory to satisfy */
/* an allocation request, we return */
/* (*GC_oom_fn)(). By default this just */
@@ -202,6 +205,13 @@ GC_API int GC_expand_hp GC_PROTO((size_t number_of_bytes));
/* n == 0 ==> unbounded. This is the default. */
GC_API void GC_set_max_heap_size GC_PROTO((GC_word n));
+/* Inform the collector that a certain section of statically allocated */
+/* memory contains no pointers to garbage collected memory. Thus it */
+/* need not be scanned. This is sometimes important if the application */
+/* maps large read/write files into the address space, which could be */
+/* mistaken for dynamic library data segments on some systems. */
+GC_API void GC_exclude_static_roots GC_PROTO((GC_PTR start, GC_PTR finish));
+
/* Clear the set of root segments. Wizards only. */
GC_API void GC_clear_roots GC_PROTO((void));
@@ -592,6 +602,19 @@ GC_API void (*GC_is_visible_print_proc)
int GC_thr_continue(thread_t target_thread);
void * GC_dlopen(const char *path, int mode);
+# ifdef _SOLARIS_PTHREADS
+# include <pthread.h>
+ extern int GC_pthread_create(pthread_t *new_thread,
+ const pthread_attr_t *attr,
+ void * (*thread_execp)(void *), void *arg);
+ extern int GC_pthread_join(pthread_t wait_for, void **status);
+
+# undef thread_t
+
+# define pthread_join GC_pthread_join
+# define pthread_create GC_pthread_create
+#endif
+
# define thr_create GC_thr_create
# define thr_join GC_thr_join
# define thr_suspend GC_thr_suspend
@@ -600,6 +623,7 @@ GC_API void (*GC_is_visible_print_proc)
# endif /* SOLARIS_THREADS */
+
#ifdef IRIX_THREADS
/* We treat these similarly. */
# include <pthread.h>
@@ -624,6 +648,7 @@ GC_API void (*GC_is_visible_print_proc)
GC_PTR GC_malloc_many(size_t lb);
#define GC_NEXT(p) (*(GC_PTR *)(p)) /* Retrieve the next element */
/* in returned list. */
+extern void GC_thr_init(); /* Needed for Solaris/X86 */
#endif /* SOLARIS_THREADS */
@@ -637,7 +662,22 @@ GC_PTR GC_malloc_many(size_t lb);
# define GC_INIT() { extern end, etext; \
GC_noop(&end, &etext); }
#else
+# if defined(__CYGWIN32__) && defined(GC_USE_DLL)
+ /*
+ * Similarly gnu-win32 DLLs need explicit initialization
+ */
+# define GC_INIT() { GC_add_roots(DATASTART, DATAEND); }
+# else
# define GC_INIT()
+# endif
+#endif
+
+#ifdef __WATCOMC__
+ /* Ivan Demakov: Programs compiled by Watcom C with -5r option
+ * crash without this declaration
+ * HB: Could this go into gc_priv.h?
+ */
+ void GC_noop(void*, ...);
#endif
#ifdef __cplusplus
diff --git a/include/gc_alloc.h b/include/gc_alloc.h
index f64c1127..85cb7cdb 100644
--- a/include/gc_alloc.h
+++ b/include/gc_alloc.h
@@ -22,10 +22,12 @@
// Some of this could be faster in the explicit deallocation case. In particular,
// we spend too much time clearing objects on the free lists. That could be avoided.
//
-// This uses template classes with static members, and hence soes not work
+// This uses template classes with static members, and hence does not work
// with g++ 2.7.2 and earlier.
//
+#include "gc.h"
+
#ifndef GC_ALLOC_H
#define GC_ALLOC_H
@@ -70,8 +72,6 @@ extern "C" {
extern void GC_incr_mem_freed(size_t words);
extern char * GC_generic_malloc_words_small(size_t word, int kind);
-
- extern void * GC_malloc_atomic_uncollectable(size_t bytes);
}
// Object kinds; must match PTRFREE, NORMAL, UNCOLLECTABLE, and
@@ -93,13 +93,13 @@ inline void * &GC_obj_link(void * p)
// Compute a number of words >= n+1 bytes.
// The +1 allows for pointers one past the end.
-inline GC_round_up(size_t n)
+inline size_t GC_round_up(size_t n)
{
return ((n + GC_byte_alignment)/GC_byte_alignment)*GC_word_alignment;
}
// The same but don't allow for extra byte.
-inline GC_round_up_uncollectable(size_t n)
+inline size_t GC_round_up_uncollectable(size_t n)
{
return ((n + GC_byte_alignment - 1)/GC_byte_alignment)*GC_word_alignment;
}
@@ -367,6 +367,6 @@ __GC_SPECIALIZE(unsigned, single_client_alloc)
__GC_SPECIALIZE(float, single_client_alloc)
__GC_SPECIALIZE(double, single_client_alloc)
-#endif _SGI_SOURCE
+#endif /* _SGI_SOURCE */
#endif /* GC_ALLOC_H */
diff --git a/include/gc_cpp.h b/include/gc_cpp.h
index 812bb653..e2f456fb 100644
--- a/include/gc_cpp.h
+++ b/include/gc_cpp.h
@@ -137,7 +137,7 @@ uses explicit invocation.
# define OPERATOR_NEW_ARRAY
#endif
-enum GCPlacement {GC, NoGC};
+enum GCPlacement {GC, NoGC, PointerFreeGC};
class gc {public:
inline void* operator new( size_t size );
@@ -263,6 +263,8 @@ inline void* operator new(
if (cleanup != 0)
GC_REGISTER_FINALIZER_IGNORE_SELF(
obj, cleanup, clientData, 0, 0 );}
+ else if (gcp == PointerFreeGC) {
+ obj = GC_MALLOC_ATOMIC( size );}
else {
obj = GC_MALLOC_UNCOLLECTABLE( size );};
return obj;}
diff --git a/include/gc_typed.h b/include/gc_typed.h
index ea20e765..e4a6b947 100644
--- a/include/gc_typed.h
+++ b/include/gc_typed.h
@@ -57,12 +57,15 @@ GC_API GC_descr GC_make_descriptor GC_PROTO((GC_bitmap bm, size_t len));
/* is intended to be called once per type, not once */
/* per allocation. */
-GC_API void * GC_malloc_explicitly_typed
+GC_API GC_PTR GC_malloc_explicitly_typed
GC_PROTO((size_t size_in_bytes, GC_descr d));
/* Allocate an object whose layout is described by d. */
/* The resulting object MAY NOT BE PASSED TO REALLOC. */
+
+GC_API GC_PTR GC_malloc_explicitly_typed_ignore_off_page
+ GC_PROTO((size_t size_in_bytes, GC_descr d));
-GC_API void * GC_calloc_explicitly_typed
+GC_API GC_PTR GC_calloc_explicitly_typed
GC_PROTO((size_t nelements,
size_t element_size_in_bytes,
GC_descr d));
diff --git a/include/private/gc_priv.h b/include/private/gc_priv.h
index 65e53b34..49a916d0 100644
--- a/include/private/gc_priv.h
+++ b/include/private/gc_priv.h
@@ -20,7 +20,7 @@
#if defined(mips) && defined(SYSTYPE_BSD) && defined(sony_news)
/* sony RISC NEWS, NEWSOS 4 */
# define BSD_TIME
- typedef long ptrdiff_t;
+/* typedef long ptrdiff_t; -- necessary on some really old systems */
#endif
#if defined(mips) && defined(SYSTYPE_BSD43)
@@ -57,6 +57,9 @@ typedef GC_signed_word signed_word;
# if defined(_SGI_SOURCE) && !defined(_BOOL)
typedef int bool;
# endif
+# if defined(__SUNPRO_CC) && __SUNPRO_CC <= 0x410
+ typedef int bool;
+# endif
# if defined(__cplusplus) && defined(_MSC_VER) && _MSC_VER <= 1020
/* Visual C++ 4.2 does not have bool type. */
typedef int bool;
@@ -320,18 +323,19 @@ void GC_print_callers (/* struct callinfo info[NFRAMES] */);
/* space is assumed to be cleared. */
# ifdef PCR
char * real_malloc();
-# define GET_MEM(bytes) HBLKPTR(real_malloc((size_t)bytes + HBLKSIZE) \
- + HBLKSIZE-1)
+# define GET_MEM(bytes) HBLKPTR(real_malloc((size_t)bytes + GC_page_size) \
+ + GC_page_size-1)
# else
# ifdef OS2
void * os2_alloc(size_t bytes);
-# define GET_MEM(bytes) HBLKPTR((ptr_t)os2_alloc((size_t)bytes + HBLKSIZE) \
- + HBLKSIZE-1)
+# define GET_MEM(bytes) HBLKPTR((ptr_t)os2_alloc((size_t)bytes \
+ + GC_page_size) \
+ + GC_page_size-1)
# else
-# if defined(AMIGA) || defined(NEXT)
+# if defined(AMIGA) || defined(NEXT) || defined(DOS4GW)
# define GET_MEM(bytes) HBLKPTR((size_t) \
- calloc(1, (size_t)bytes + HBLKSIZE) \
- + HBLKSIZE-1)
+ calloc(1, (size_t)bytes + GC_page_size) \
+ + GC_page_size-1)
# else
# ifdef MSWIN32
extern ptr_t GC_win32_get_mem();
@@ -342,14 +346,15 @@ void GC_print_callers (/* struct callinfo info[NFRAMES] */);
extern Ptr GC_MacTemporaryNewPtr(size_t size,
Boolean clearMemory);
# define GET_MEM(bytes) HBLKPTR( \
- GC_MacTemporaryNewPtr(bytes + HBLKSIZE, true) + HBLKSIZE-1)
+ GC_MacTemporaryNewPtr(bytes + GC_page_size, true) \
+ + GC_page_size-1)
# else
# define GET_MEM(bytes) HBLKPTR( \
- NewPtrClear(bytes + HBLKSIZE) + HBLKSIZE-1)
+ NewPtrClear(bytes + GC_page_size) + GC_page_size-1)
# endif
# else
- extern ptr_t GC_unix_get_mem();
-# define GET_MEM(bytes) (struct hblk *)GC_unix_get_mem(bytes)
+ extern ptr_t GC_unix_get_mem();
+# define GET_MEM(bytes) (struct hblk *)GC_unix_get_mem(bytes)
# endif
# endif
# endif
@@ -436,7 +441,7 @@ void GC_print_callers (/* struct callinfo info[NFRAMES] */);
# else
# define LOCK() { if (__test_and_set(&GC_allocate_lock, 1)) GC_lock(); }
# if __mips >= 3 && (defined (_ABIN32) || defined(_ABI64))
-# define UNLOCK() __lock_release(lock)
+# define UNLOCK() __lock_release(&GC_allocate_lock)
# else
# define UNLOCK() GC_allocate_lock = 0
# endif
@@ -601,18 +606,43 @@ extern GC_warn_proc GC_current_warn_proc;
/* heap block size, bytes. Should be power of 2 */
-#ifdef SMALL_CONFIG
+#ifndef HBLKSIZE
+# ifdef SMALL_CONFIG
# define CPP_LOG_HBLKSIZE 10
+# else
+# if CPP_WORDSZ == 32
+# define CPP_LOG_HBLKSIZE 12
+# else
+# define CPP_LOG_HBLKSIZE 13
+# endif
+# endif
#else
-# if CPP_WORDSZ == 32
+# if HBLKSIZE == 512
+# define CPP_LOG_HBLKSIZE 9
+# endif
+# if HBLKSIZE == 1024
+# define CPP_LOG_HBLKSIZE 10
+# endif
+# if HBLKSIZE == 2048
+# define CPP_LOG_HBLKSIZE 11
+# endif
+# if HBLKSIZE == 4096
# define CPP_LOG_HBLKSIZE 12
-# else
+# endif
+# if HBLKSIZE == 8192
# define CPP_LOG_HBLKSIZE 13
# endif
+# if HBLKSIZE == 16384
+# define CPP_LOG_HBLKSIZE 14
+# endif
+# ifndef CPP_LOG_HBLKSIZE
+ --> fix HBLKSIZE
+# endif
+# undef HBLKSIZE
#endif
-#define LOG_HBLKSIZE ((word)CPP_LOG_HBLKSIZE)
-#define CPP_HBLKSIZE (1 << CPP_LOG_HBLKSIZE)
-#define HBLKSIZE ((word)CPP_HBLKSIZE)
+# define CPP_HBLKSIZE (1 << CPP_LOG_HBLKSIZE)
+# define LOG_HBLKSIZE ((word)CPP_LOG_HBLKSIZE)
+# define HBLKSIZE ((word)CPP_HBLKSIZE)
/* max size objects supported by freelist (larger objects may be */
@@ -798,8 +828,9 @@ struct _GC_arrays {
word _words_allocd;
/* Number of words allocated during this collection cycle */
word _words_wasted;
- /* Number of words wasted due to internal fragmentation */
- /* in large objects allocated since last gc. Approximate.*/
+ /* Number of words wasted due to internal fragmentation */
+ /* in large objects, or due to dropping blacklisted */
+ /* blocks, since last gc. Approximate. */
word _words_finalized;
/* Approximate number of words in objects (and headers) */
/* That became ready for finalization in the last */
@@ -1017,16 +1048,21 @@ extern int GC_n_kinds;
extern word GC_n_heap_sects; /* Number of separately added heap */
/* sections. */
+extern word GC_page_size;
+
# ifdef MSWIN32
extern word GC_n_heap_bases; /* See GC_heap_bases. */
# endif
-extern word GC_total_black_listed;
+extern word GC_total_stack_black_listed;
/* Number of bytes on stack blacklist. */
extern word GC_black_list_spacing;
/* Average number of bytes between blacklisted */
/* blocks. Approximate. */
+ /* Counts only blocks that are */
+ /* "stack-blacklisted", i.e. that are */
+ /* problematic in the interior of an object. */
extern char * GC_invalid_map;
/* Pointer to the nowhere valid hblk map */
@@ -1139,11 +1175,23 @@ extern void (*GC_push_other_roots)();
/* predfined to be non-zero. A client supplied */
/* replacement should also call the original */
/* function. */
+extern void (*GC_start_call_back)(/* void */);
+ /* Called at start of full collections. */
+ /* Not called if 0. Called with allocation */
+ /* lock held. */
+ /* 0 by default. */
void GC_push_regs(); /* Push register contents onto mark stack. */
void GC_remark(); /* Mark from all marked objects. Used */
/* only if we had to drop something. */
void GC_push_one(/*p*/); /* If p points to an object, mark it */
/* and push contents on the mark stack */
+/* Ivan Demakov: Watcom C error'ed without this */
+# if defined(MSWIN32) && defined(__WATCOMC__)
+ void __cdecl GC_push_one();
+# else
+ void GC_push_one(/*p*/); /* If p points to an object, mark it */
+ /* and push contents on the mark stack */
+# endif
void GC_push_one_checked(/*p*/); /* Ditto, omits plausibility test */
void GC_push_marked(/* struct hblk h, hdr * hhdr */);
/* Push contents of all marked objects in h onto */
@@ -1284,12 +1332,17 @@ void GC_collect_a_little_inner(/* int n */);
ptr_t GC_generic_malloc(/* bytes, kind */);
/* Allocate an object of the given */
/* kind. By default, there are only */
- /* two kinds: composite, and atomic. */
+ /* a few kinds: composite(pointerfree), */
+ /* atomic, uncollectable, etc. */
/* We claim it's possible for clever */
/* client code that understands GC */
/* internals to add more, e.g. to */
/* communicate object layout info */
/* to the collector. */
+ptr_t GC_generic_malloc_ignore_off_page(/* bytes, kind */);
+ /* As above, but pointers past the */
+ /* first page of the resulting object */
+ /* are ignored. */
ptr_t GC_generic_malloc_inner(/* bytes, kind */);
/* Ditto, but I already hold lock, etc. */
ptr_t GC_generic_malloc_words_small GC_PROTO((size_t words, int kind));
@@ -1417,4 +1470,5 @@ void GC_err_puts(/* char *s */);
/* Write s to stderr, don't buffer, don't add */
/* newlines, don't ... */
+
# endif /* GC_PRIVATE_H */
diff --git a/irix_threads.c b/irix_threads.c
index d33e1c98..5e191d11 100644
--- a/irix_threads.c
+++ b/irix_threads.c
@@ -31,7 +31,9 @@
#undef pthread_sigmask
#undef pthread_join
-#ifdef UNDEFINED
+void GC_thr_init();
+
+#if 0
void GC_print_sig_mask()
{
sigset_t blocked;
@@ -83,9 +85,9 @@ GC_thread GC_lookup_thread(pthread_t id);
/*
* The only way to suspend threads given the pthread interface is to send
* signals. Unfortunately, this means we have to reserve
- * SIGUSR2, and intercept client calls to change the signal mask.
+ * a signal, and intercept client calls to change the signal mask.
*/
-# define SIG_SUSPEND SIGUSR2
+# define SIG_SUSPEND (SIGRTMIN + 6)
pthread_mutex_t GC_suspend_lock = PTHREAD_MUTEX_INITIALIZER;
volatile unsigned GC_n_stopped = 0;
@@ -295,6 +297,8 @@ void GC_stop_world()
}
pthread_mutex_lock(&GC_suspend_lock);
while(GC_n_stopped < n_live_threads) {
+ /* GC_printf3("\nwaiting:%d %d %d\n", GC_gc_no,
+ GC_n_stopped, n_live_threads); */
pthread_cond_wait(&GC_suspend_ack_cv, &GC_suspend_lock);
}
pthread_mutex_unlock(&GC_suspend_lock);
@@ -312,6 +316,25 @@ void GC_start_world()
pthread_cond_broadcast(&GC_continue_cv);
}
+# ifdef MMAP_STACKS
+--> not really supported yet.
+int GC_is_thread_stack(ptr_t addr)
+{
+ register int i;
+ register GC_thread p;
+
+ for (i = 0; i < THREAD_TABLE_SZ; i++) {
+ for (p = GC_threads[i]; p != 0; p = p -> next) {
+ if (p -> stack_size != 0) {
+ if (p -> stack <= addr &&
+ addr < p -> stack + p -> stack_size)
+ return 1;
+ }
+ }
+ }
+ return 0;
+}
+# endif
extern ptr_t GC_approx_sp();
@@ -347,7 +370,7 @@ void GC_push_all_stacks()
/* We hold the allocation lock. */
-GC_thr_init()
+void GC_thr_init()
{
GC_thread t;
@@ -389,7 +412,7 @@ void GC_thread_exit_proc(void *dummy)
if (me -> flags & DETACHED) {
GC_delete_thread(pthread_self());
} else {
- me -> flags != FINISHED;
+ me -> flags |= FINISHED;
}
UNLOCK();
}
diff --git a/mach_dep.c b/mach_dep.c
index 931e619f..06463d16 100644
--- a/mach_dep.c
+++ b/mach_dep.c
@@ -168,7 +168,9 @@ void GC_push_regs()
# endif /* __MWERKS__ */
# endif /* MACOS */
-# if defined(I386) &&!defined(OS2) &&!defined(SVR4) &&!defined(MSWIN32) && !defined(SCO) && (!defined(LINUX) || !defined(__ELF__))
+# if defined(I386) &&!defined(OS2) &&!defined(SVR4) &&!defined(MSWIN32) \
+ && !defined(SCO) && !(defined(LINUX) && defined(__ELF__)) \
+ && !defined(DOS4GW)
/* I386 code, generic code does not appear to work */
/* It does appear to work under OS2, and asms dont */
/* This is used for some 38g UNIX variants and for CYGWIN32 */
@@ -317,7 +319,7 @@ void GC_push_regs()
for (; (char *)i < lim; i++) {
*i = 0;
}
-# if defined(POWERPC) || defined(MSWIN32)
+# if defined(POWERPC) || defined(MSWIN32) || defined(UTS4)
(void) setjmp(regs);
# else
(void) _setjmp(regs);
diff --git a/malloc.c b/malloc.c
index 1596e050..6b8c0921 100644
--- a/malloc.c
+++ b/malloc.c
@@ -216,6 +216,13 @@ DCL_LOCK_STATE;
/* It might help to manually inline the GC_malloc call here. */
/* But any decent compiler should reduce the extra procedure call */
/* to at most a jump instruction in this case. */
+# if defined(I386) && defined(SOLARIS_THREADS)
+ /*
+ * Thread initialisation can call malloc before
+ * we're ready for it.
+ */
+ if (!GC_is_initialized) return sbrk(lb);
+# endif /* I386 && SOLARIS_THREADS */
return(REDIRECT_MALLOC(lb));
}
diff --git a/mallocx.c b/mallocx.c
index 6d1d5d12..a1fc2f4d 100644
--- a/mallocx.c
+++ b/mallocx.c
@@ -25,6 +25,7 @@
extern ptr_t GC_clear_stack(); /* in misc.c, behaves like identity */
void GC_extend_size_map(); /* in misc.c. */
+bool GC_alloc_reclaim_list(); /* in malloc.c */
/* Some externally visible but unadvertised variables to allow access to */
/* free lists from inlined allocators without including gc_priv.h */
diff --git a/mark.c b/mark.c
index 32e3970e..1935b5b6 100644
--- a/mark.c
+++ b/mark.c
@@ -78,9 +78,11 @@ struct obj_kind GC_obj_kinds[MAXOBJKINDS] = {
# endif
-# define INITIAL_MARK_STACK_SIZE (1*HBLKSIZE)
+# ifndef INITIAL_MARK_STACK_SIZE
+# define INITIAL_MARK_STACK_SIZE (1*HBLKSIZE)
/* INITIAL_MARK_STACK_SIZE * sizeof(mse) should be a */
/* multiple of HBLKSIZE. */
+# endif
/*
* Limits of stack for GC_mark routine.
@@ -494,17 +496,14 @@ word n;
GC_mark_stack_too_small = FALSE;
if (GC_mark_stack_size != 0) {
if (new_stack != 0) {
- word displ = HBLKDISPL(GC_mark_stack);
+ word displ = (word)GC_mark_stack & (GC_page_size - 1);
word size = GC_mark_stack_size * sizeof(struct ms_entry);
/* Recycle old space */
- if (displ == 0) {
- GC_add_to_heap((struct hblk *)GC_mark_stack, size);
- } else {
+ if (0 != displ) displ = GC_page_size - displ;
+ size = (size - displ) & ~(GC_page_size - 1);
GC_add_to_heap((struct hblk *)
- ((word)GC_mark_stack - displ + HBLKSIZE),
- size - HBLKSIZE);
- }
+ ((word)GC_mark_stack + displ), size);
GC_mark_stack = new_stack;
GC_mark_stack_size = n;
# ifdef PRINTSTATS
@@ -620,6 +619,7 @@ void (*push_fn)(/* ptr_t bottom, ptr_t top */);
void GC_push_conditional(bottom, top, all)
ptr_t bottom;
ptr_t top;
+int all;
{
if (all) {
if (GC_dirty_maintained) {
@@ -934,7 +934,12 @@ register hdr * hhdr;
register mse * mark_stack_limit = &(GC_mark_stack[GC_mark_stack_size]);
/* Some quick shortcuts: */
- if (hhdr -> hb_obj_kind == PTRFREE) return;
+ {
+ struct obj_kind *ok = &(GC_obj_kinds[hhdr -> hb_obj_kind]);
+ if ((0 | DS_LENGTH) == ok -> ok_descriptor
+ && FALSE == ok -> ok_relocate_descr)
+ return;
+ }
if (GC_block_empty(hhdr)/* nothing marked */) return;
# ifdef GATHERSTATS
GC_n_rescuing_pages++;
diff --git a/mark_rts.c b/mark_rts.c
index c5883fa7..8e12d533 100644
--- a/mark_rts.c
+++ b/mark_rts.c
@@ -15,6 +15,8 @@
# include <stdio.h>
# include "gc_priv.h"
+/* MAX_ROOT_SETS is the maximum number of ranges that can be */
+/* registered as static roots. */
# ifdef LARGE_CONFIG
# define MAX_ROOT_SETS 4096
# else
@@ -31,6 +33,9 @@
# endif
# endif
+# define MAX_EXCLUSIONS (MAX_ROOT_SETS/4)
+/* Maximum number of segments that can be excluded from root sets. */
+
/* Data structure for list of root sets. */
/* We keep a hash table, so that we can filter out duplicate additions. */
/* Under Win32, we need to do a better job of filtering overlaps, so */
@@ -184,20 +189,6 @@ bool tmp;
{
struct roots * old;
- /* We exclude GC data structures from root sets. It's usually safe */
- /* to mark from those, but it is a waste of time. */
- if ( (ptr_t)b < endGC_arrays && (ptr_t)e > beginGC_arrays) {
- if ((ptr_t)e <= endGC_arrays) {
- if ((ptr_t)b >= beginGC_arrays) return;
- e = (char *)beginGC_arrays;
- } else if ((ptr_t)b >= beginGC_arrays) {
- b = (char *)endGC_arrays;
- } else {
- GC_add_roots_inner(b, (char *)beginGC_arrays, tmp);
- GC_add_roots_inner((char *)endGC_arrays, e, tmp);
- return;
- }
- }
# ifdef MSWIN32
/* Spend the time to ensure that there are no overlapping */
/* or adjacent intervals. */
@@ -329,6 +320,97 @@ ptr_t GC_approx_sp()
}
/*
+ * Data structure for excluded static roots.
+ */
+struct exclusion {
+ ptr_t e_start;
+ ptr_t e_end;
+};
+
+struct exclusion excl_table[MAX_EXCLUSIONS];
+ /* Array of exclusions, ascending */
+ /* address order. */
+size_t excl_table_entries = 0; /* Number of entries in use. */
+
+/* Return the first exclusion range that includes an address >= start_addr */
+/* Assumes the exclusion table contains at least one entry (namely the */
+/* GC data structures). */
+struct exclusion * GC_next_exclusion(start_addr)
+ptr_t start_addr;
+{
+ size_t low = 0;
+ size_t high = excl_table_entries - 1;
+ size_t mid;
+
+ while (high > low) {
+ mid = (low + high) >> 1;
+ /* low <= mid < high */
+ if ((word) excl_table[mid].e_end <= (word) start_addr) {
+ low = mid + 1;
+ } else {
+ high = mid;
+ }
+ }
+ if ((word) excl_table[low].e_end <= (word) start_addr) return 0;
+ return excl_table + low;
+}
+
+void GC_exclude_static_roots(start, finish)
+GC_PTR start;
+GC_PTR finish;
+{
+ struct exclusion * next;
+ size_t next_index, i;
+
+ if (0 == excl_table_entries) {
+ next = 0;
+ } else {
+ next = GC_next_exclusion(start);
+ }
+ if (0 != next) {
+ if ((word)(next -> e_start) < (word) finish) {
+ /* incomplete error check. */
+ ABORT("exclusion ranges overlap");
+ }
+ if ((word)(next -> e_start) == (word) finish) {
+ /* extend old range backwards */
+ next -> e_start = (ptr_t)start;
+ return;
+ }
+ next_index = next - excl_table;
+ for (i = excl_table_entries - 1; i >= next_index; --i) {
+ excl_table[i+1] = excl_table[i];
+ }
+ } else {
+ next_index = excl_table_entries;
+ }
+ if (excl_table_entries == MAX_EXCLUSIONS) ABORT("Too many exclusions");
+ excl_table[next_index].e_start = (ptr_t)start;
+ excl_table[next_index].e_end = (ptr_t)finish;
+ ++excl_table_entries;
+}
+
+/* Invoke push_conditional on ranges that are not excluded. */
+void GC_push_conditional_with_exclusions(bottom, top, all)
+ptr_t bottom;
+ptr_t top;
+int all;
+{
+ struct exclusion * next;
+ ptr_t excl_start;
+
+ while (bottom < top) {
+ next = GC_next_exclusion(bottom);
+ if (0 == next || (excl_start = next -> e_start) >= top) {
+ GC_push_conditional(bottom, top, all);
+ return;
+ }
+ if (excl_start > bottom) GC_push_conditional(bottom, excl_start, all);
+ bottom = next -> e_end;
+ }
+}
+
+/*
* Call the mark routines (GC_tl_push for a single pointer, GC_push_conditional
* on groups of pointers) on every top level accessible pointer.
* If all is FALSE, arrange to push only possibly altered values.
@@ -357,7 +439,8 @@ bool all;
# endif
/* Mark everything in static data areas */
for (i = 0; i < n_root_sets; i++) {
- GC_push_conditional(static_roots[i].r_start,
+ GC_push_conditional_with_exclusions(
+ static_roots[i].r_start,
static_roots[i].r_end, all);
}
diff --git a/misc.c b/misc.c
index 5e6edf59..a2af3a6f 100644
--- a/misc.c
+++ b/misc.c
@@ -64,6 +64,8 @@ bool GC_debugging_started = FALSE;
void (*GC_check_heap)() = (void (*)())0;
+void (*GC_start_call_back)() = (void (*)())0;
+
ptr_t GC_stackbottom = 0;
bool GC_dont_gc = 0;
@@ -71,12 +73,12 @@ bool GC_dont_gc = 0;
bool GC_quiet = 0;
/*ARGSUSED*/
-void * GC_default_oom_fn GC_PROTO((size_t bytes_requested))
+GC_PTR GC_default_oom_fn GC_PROTO((size_t bytes_requested))
{
return(0);
}
-void * (*GC_oom_fn) GC_PROTO((size_t bytes_requested)) = GC_default_oom_fn;
+GC_PTR (*GC_oom_fn) GC_PROTO((size_t bytes_requested)) = GC_default_oom_fn;
extern signed_word GC_mem_found;
@@ -151,12 +153,11 @@ extern signed_word GC_mem_found;
/* If we can fit the same number of larger objects in a block, */
/* do so. */
{
+ size_t number_of_objs = BODY_SZ/word_sz;
+ word_sz = BODY_SZ/number_of_objs;
# ifdef ALIGN_DOUBLE
-# define INCR 2
-# else
-# define INCR 1
+ word_sz &= ~1;
# endif
- while (BODY_SZ/word_sz == BODY_SZ/(word_sz + INCR)) word_sz += INCR;
}
byte_sz = WORDS_TO_BYTES(word_sz);
# ifdef ADD_BYTE_AT_END
@@ -178,7 +179,11 @@ extern signed_word GC_mem_found;
* sections of the stack whenever we get control.
*/
word GC_stack_last_cleared = 0; /* GC_no when we last did this */
-# define CLEAR_SIZE 213
+# ifdef THREADS
+# define CLEAR_SIZE 2048
+# else
+# define CLEAR_SIZE 213
+# endif
# define DEGRADE_RATE 50
word GC_min_sp; /* Coolest stack pointer value from which we've */
@@ -237,7 +242,7 @@ ptr_t arg;
{
register word sp = (word)GC_approx_sp(); /* Hotter than actual sp */
# ifdef THREADS
- word dummy[CLEAR_SIZE];;
+ word dummy[CLEAR_SIZE];
# else
register word limit;
# endif
@@ -389,6 +394,10 @@ size_t GC_get_bytes_since_gc GC_PROTO(())
bool GC_is_initialized = FALSE;
+#if defined(SOLARIS_THREADS) || defined(IRIX_THREADS)
+ extern void GC_thr_init();
+#endif
+
void GC_init()
{
DCL_LOCK_STATE;
@@ -405,9 +414,7 @@ void GC_init()
extern void GC_init_win32();
#endif
-#if defined(SOLARIS_THREADS) || defined(IRIX_THREADS)
- extern void GC_thr_init();
-#endif
+extern void GC_setpagesize();
void GC_init_inner()
{
@@ -416,9 +423,14 @@ void GC_init_inner()
# endif
if (GC_is_initialized) return;
+ GC_setpagesize();
+ GC_exclude_static_roots(beginGC_arrays, endGC_arrays);
# ifdef MSWIN32
GC_init_win32();
# endif
+# if defined(LINUX) && defined(POWERPC)
+ GC_init_linuxppc();
+# endif
# ifdef SOLARIS_THREADS
GC_thr_init();
/* We need dirty bits in order to find live stack sections. */
@@ -454,9 +466,11 @@ void GC_init_inner()
if ((word)(&dummy) > (word)GC_stackbottom) {
GC_err_printf0(
"STACK_GROWS_DOWN is defd, but stack appears to grow up\n");
- GC_err_printf2("sp = 0x%lx, GC_stackbottom = 0x%lx\n",
- (unsigned long) (&dummy),
- (unsigned long) GC_stackbottom);
+# ifndef UTS4 /* Compiler bug workaround */
+ GC_err_printf2("sp = 0x%lx, GC_stackbottom = 0x%lx\n",
+ (unsigned long) (&dummy),
+ (unsigned long) GC_stackbottom);
+# endif
ABORT("stack direction 3\n");
}
# else
@@ -485,10 +499,10 @@ void GC_init_inner()
}
/* Add initial guess of root sets. Do this first, since sbrk(0) */
- /* mightbe used. */
+ /* might be used. */
GC_register_data_segments();
GC_init_headers();
- GC_bl_init();
+ GC_bl_init();
GC_mark_init();
if (!GC_expand_hp_inner((word)MINHINCR)) {
GC_err_printf0("Can't start up: not enough memory\n");
@@ -546,6 +560,7 @@ void GC_enable_incremental GC_PROTO(())
DISABLE_SIGNALS();
LOCK();
if (GC_incremental) goto out;
+ GC_setpagesize();
# ifdef MSWIN32
{
extern bool GC_is_win32s();
diff --git a/os_dep.c b/os_dep.c
index 8da9359f..3c5ae5aa 100644
--- a/os_dep.c
+++ b/os_dep.c
@@ -1,5 +1,6 @@
/*
* Copyright (c) 1991-1995 by Xerox Corporation. All rights reserved.
+ * Copyright (c) 1996-1997 by Silicon Graphics. All rights reserved.
*
* THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
* OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
@@ -10,20 +11,28 @@
* provided the above notices are retained, and a notice that the code was
* modified is included with the above copyright notice.
*/
-/* Boehm, March 8, 1996 12:00 pm PST */
# include "gc_priv.h"
-# ifdef LINUX
- /* Ugly hack to get struct sigcontext_struct definition. Required */
- /* for some early 1.3.X releases. Will hopefully go away soon. */
- /* in some later Linux releases, asm/sigcontext.h may have to */
- /* be included instead. */
-# define __KERNEL__
-# include <asm/signal.h>
-# undef __KERNEL__
+
+# if defined(LINUX) && !defined(POWERPC)
+# include <linux/version.h>
+# if (LINUX_VERSION_CODE <= 0x10400)
+ /* Ugly hack to get struct sigcontext_struct definition. Required */
+ /* for some early 1.3.X releases. Will hopefully go away soon. */
+ /* in some later Linux releases, asm/sigcontext.h may have to */
+ /* be included instead. */
+# define __KERNEL__
+# include <asm/signal.h>
+# undef __KERNEL__
+# elif (LINUX_VERSION_CODE < 0x20100)
+# include <asm/sigcontext.h>
+# endif
# endif
# if !defined(OS2) && !defined(PCR) && !defined(AMIGA) && !defined(MACOS)
# include <sys/types.h>
+# if !defined(MSWIN32) && !defined(SUNOS4)
+# include <unistd.h>
+# endif
# endif
# include <stdio.h>
# include <signal.h>
@@ -47,6 +56,10 @@
# define NEED_FIND_LIMIT
# endif
+# if defined(LINUX) && defined(POWERPC)
+# define NEED_FIND_LIMIT
+# endif
+
#ifdef NEED_FIND_LIMIT
# include <setjmp.h>
#endif
@@ -74,11 +87,13 @@
#ifdef IRIX5
# include <sys/uio.h>
+# include <malloc.h> /* for locking */
+#endif
+#ifdef USE_MMAP
# include <sys/types.h>
# include <sys/mman.h>
# include <sys/stat.h>
# include <fcntl.h>
-# include <malloc.h> /* for locking */
#endif
#ifdef SUNOS5SIGS
@@ -93,7 +108,7 @@
#ifdef DJGPP
/* Apparently necessary for djgpp 2.01. May casuse problems with */
/* other versions. */
- typedef caddr_t long unsigned int;
+ typedef long unsigned int caddr_t;
#endif
#ifdef PCR
@@ -102,17 +117,28 @@
# include "mm/PCR_MM.h"
#endif
-#if defined(PROT_EXEC) && !defined(NO_EXECUTE_PERMISSION)
+#if !defined(NO_EXECUTE_PERMISSION)
# define OPT_PROT_EXEC PROT_EXEC
#else
# define OPT_PROT_EXEC 0
#endif
+#if defined(LINUX) && defined(POWERPC)
+ ptr_t GC_data_start;
+
+ void GC_init_linuxppc()
+ {
+ extern ptr_t GC_find_limit();
+ extern char **_environ;
+ GC_data_start = GC_find_limit((ptr_t)&_environ, FALSE);
+ }
+#endif
+
# ifdef OS2
# include <stddef.h>
-# ifndef __IBMC__ /* e.g. EMX */
+# if !defined(__IBMC__) && !defined(__WATCOMC__) /* e.g. EMX */
struct exe_hdr {
unsigned short magic_number;
@@ -212,7 +238,7 @@ void GC_enable_signals(void)
# else
# if !defined(PCR) && !defined(AMIGA) && !defined(MSWIN32) \
- && !defined(MACOS) && !defined(DJGPP)
+ && !defined(MACOS) && !defined(DJGPP) && !defined(DOS4GW)
# if defined(sigmask) && !defined(UTS4)
/* Use the traditional BSD interface */
@@ -286,28 +312,46 @@ void GC_enable_signals()
# endif /*!OS/2 */
-/*
- * Find the base of the stack.
- * Used only in single-threaded environment.
- * With threads, GC_mark_roots needs to know how to do this.
- * Called with allocator lock held.
- */
-# ifdef MSWIN32
+/* Ivan Demakov: simplest way (to me) */
+#ifdef DOS4GW
+ void GC_disable_signals() { }
+ void GC_enable_signals() { }
+#endif
-/* Get the page size. */
-word GC_page_size = 0;
+/* Find the page size */
+word GC_page_size;
-word GC_getpagesize()
-{
+# ifdef MSWIN32
+ void GC_setpagesize()
+ {
SYSTEM_INFO sysinfo;
- if (GC_page_size == 0) {
- GetSystemInfo(&sysinfo);
- GC_page_size = sysinfo.dwPageSize;
- }
- return(GC_page_size);
-}
+ GetSystemInfo(&sysinfo);
+ GC_page_size = sysinfo.dwPageSize;
+ }
+
+# else
+# if defined(MPROTECT_VDB) || defined(PROC_VDB)
+ void GC_setpagesize()
+ {
+ GC_page_size = GETPAGESIZE();
+ }
+# else
+ /* It's acceptable to fake it. */
+ void GC_setpagesize()
+ {
+ GC_page_size = HBLKSIZE;
+ }
+# endif
+# endif
+/*
+ * Find the base of the stack.
+ * Used only in single-threaded environment.
+ * With threads, GC_mark_roots needs to know how to do this.
+ * Called with allocator lock held.
+ */
+# ifdef MSWIN32
# define is_writable(prot) ((prot) == PAGE_READWRITE \
|| (prot) == PAGE_WRITECOPY \
|| (prot) == PAGE_EXECUTE_READWRITE \
@@ -337,7 +381,7 @@ ptr_t GC_get_stack_base()
{
int dummy;
ptr_t sp = (ptr_t)(&dummy);
- ptr_t trunc_sp = (ptr_t)((word)sp & ~(GC_getpagesize() - 1));
+ ptr_t trunc_sp = (ptr_t)((word)sp & ~(GC_page_size - 1));
word size = GC_get_writable_length(trunc_sp, 0);
return(trunc_sp + size);
@@ -672,9 +716,9 @@ void GC_register_data_segments()
GetSystemInfo(&sysinfo);
limit = sysinfo.lpMinimumApplicationAddress;
- p = (ptr_t)((word)start & ~(GC_getpagesize() - 1));
+ p = (ptr_t)((word)start & ~(GC_page_size - 1));
for (;;) {
- q = (LPVOID)(p - GC_getpagesize());
+ q = (LPVOID)(p - GC_page_size);
if ((ptr_t)q > (ptr_t)p /* underflow */ || q < limit) break;
result = VirtualQuery(q, &buf, sizeof(buf));
if (result != sizeof(buf) || buf.AllocationBase == 0) break;
@@ -818,7 +862,9 @@ int * etext_addr;
if (setjmp(GC_jmp_buf) == 0) {
/* Try writing to the address. */
*result = *result;
+ GC_reset_fault_handler();
} else {
+ GC_reset_fault_handler();
/* We got here via a longjmp. The address is not readable. */
/* This is known to happen under Solaris 2.4 + gcc, which place */
/* string constants in the text segment, but after etext. */
@@ -826,7 +872,6 @@ int * etext_addr;
/* text and data segments, so plan A bought us something. */
result = (char *)GC_find_limit((ptr_t)(DATAEND) - MIN_PAGE_SIZE, FALSE);
}
- GC_reset_fault_handler();
return((char *)result);
}
# endif
@@ -888,9 +933,11 @@ void GC_register_data_segments()
*/
# if !defined(OS2) && !defined(PCR) && !defined(AMIGA) \
- && !defined(MSWIN32) && !defined(MACOS)
+ && !defined(MSWIN32) && !defined(MACOS) && !defined(DOS4GW)
-extern caddr_t sbrk();
+# ifdef SUNOS4
+ extern caddr_t sbrk();
+# endif
# ifdef __STDC__
# define SBRK_ARG_T ptrdiff_t
# else
@@ -906,23 +953,23 @@ word bytes;
{
caddr_t cur_brk = sbrk(0);
caddr_t result;
- SBRK_ARG_T lsbs = (word)cur_brk & (HBLKSIZE-1);
+ SBRK_ARG_T lsbs = (word)cur_brk & (GC_page_size-1);
static caddr_t my_brk_val = 0;
if ((SBRK_ARG_T)bytes < 0) return(0); /* too big */
if (lsbs != 0) {
- if(sbrk(HBLKSIZE - lsbs) == (caddr_t)(-1)) return(0);
+ if(sbrk(GC_page_size - lsbs) == (caddr_t)(-1)) return(0);
}
if (cur_brk == my_brk_val) {
/* Use the extra block we allocated last time. */
result = (ptr_t)sbrk((SBRK_ARG_T)bytes);
if (result == (caddr_t)(-1)) return(0);
- result -= HBLKSIZE;
+ result -= GC_page_size;
} else {
- result = (ptr_t)sbrk(HBLKSIZE + (SBRK_ARG_T)bytes);
+ result = (ptr_t)sbrk(GC_page_size + (SBRK_ARG_T)bytes);
if (result == (caddr_t)(-1)) return(0);
}
- my_brk_val = result + bytes + HBLKSIZE; /* Always HBLKSIZE aligned */
+ my_brk_val = result + bytes + GC_page_size; /* Always page aligned */
return((ptr_t)result);
}
@@ -938,46 +985,44 @@ word bytes;
static int fd;
void *result;
static ptr_t last_addr = HEAP_START;
- static size_t page_size;
if (!initialized) {
fd = open("/dev/zero", O_RDONLY);
- page_size = getpagesize();
initialized = TRUE;
}
result = mmap(last_addr, bytes, PROT_READ | PROT_WRITE | OPT_PROT_EXEC,
MAP_PRIVATE | MAP_FIXED, fd, 0/* offset */);
if (result == MAP_FAILED) return(0);
- last_addr = (ptr_t)result + bytes + page_size - 1;
- last_addr = (ptr_t)((word)last_addr & ~(page_size - 1));
+ last_addr = (ptr_t)result + bytes + GC_page_size - 1;
+ last_addr = (ptr_t)((word)last_addr & ~(GC_page_size - 1));
return((ptr_t)result);
}
-#else /* Not RS6000, USE_MMAP */
+#else /* Not RS6000, not USE_MMAP */
ptr_t GC_unix_get_mem(bytes)
word bytes;
{
- caddr_t result;
+ ptr_t result;
# ifdef IRIX5
/* Bare sbrk isn't thread safe. Play by malloc rules. */
/* The equivalent may be needed on other systems as well. */
__LOCK_MALLOC();
# endif
{
- caddr_t cur_brk = sbrk(0);
- SBRK_ARG_T lsbs = (word)cur_brk & (HBLKSIZE-1);
+ ptr_t cur_brk = (ptr_t)sbrk(0);
+ SBRK_ARG_T lsbs = (word)cur_brk & (GC_page_size-1);
if ((SBRK_ARG_T)bytes < 0) return(0); /* too big */
if (lsbs != 0) {
- if(sbrk(HBLKSIZE - lsbs) == (caddr_t)(-1)) return(0);
+ if((ptr_t)sbrk(GC_page_size - lsbs) == (ptr_t)(-1)) return(0);
}
- result = sbrk((SBRK_ARG_T)bytes);
- if (result == (caddr_t)(-1)) result = 0;
+ result = (ptr_t)sbrk((SBRK_ARG_T)bytes);
+ if (result == (ptr_t)(-1)) result = 0;
}
# ifdef IRIX5
__UNLOCK_MALLOC();
# endif
- return((ptr_t)result);
+ return(result);
}
#endif /* Not USE_MMAP */
@@ -1307,27 +1352,6 @@ struct hblk *h;
VOLATILE page_hash_table GC_dirty_pages;
/* Pages dirtied since last GC_read_dirty. */
-word GC_page_size;
-
-bool GC_just_outside_heap(addr)
-word addr;
-{
- register unsigned i;
- register word start;
- register word end;
- word mask = GC_page_size-1;
-
- for (i = 0; i < GC_n_heap_sects; i++) {
- start = (word) GC_heap_sects[i].hs_start;
- end = start + (word)GC_heap_sects[i].hs_bytes;
- if (addr < ((start + mask) & ~mask) && addr >= (start & ~mask)
- || addr >= (end & ~mask) && addr < ((end + mask) & ~mask)) {
- return(TRUE);
- }
- }
- return(FALSE);
-}
-
#if defined(SUNOS4) || defined(FREEBSD)
typedef void (* SIG_PF)();
#endif
@@ -1347,7 +1371,12 @@ word addr;
typedef void (* REAL_SIG_PF)(int, struct siginfo *, void *);
#endif
#if defined(LINUX)
- typedef void (* REAL_SIG_PF)(int, struct sigcontext_struct);
+# include <linux/version.h>
+# if (LINUX_VERSION_CODE >= 0x20100)
+ typedef void (* REAL_SIG_PF)(int, struct sigcontext);
+# else
+ typedef void (* REAL_SIG_PF)(int, struct sigcontext_struct);
+# endif
# endif
SIG_PF GC_old_bus_handler;
@@ -1382,7 +1411,11 @@ SIG_PF GC_old_segv_handler; /* Also old MSWIN32 ACCESS_VIOLATION filter */
# endif
# endif
# if defined(LINUX)
- void GC_write_fault_handler(int sig, struct sigcontext_struct sc)
+# if (LINUX_VERSION_CODE >= 0x20100)
+ void GC_write_fault_handler(int sig, struct sigcontext sc)
+# else
+ void GC_write_fault_handler(int sig, struct sigcontext_struct sc)
+# endif
# define SIG_OK (sig == SIGSEGV)
# define CODE_OK TRUE
/* Empirically c.trapno == 14, but is that useful? */
@@ -1404,7 +1437,7 @@ SIG_PF GC_old_segv_handler; /* Also old MSWIN32 ACCESS_VIOLATION filter */
{
register unsigned i;
# ifdef IRIX5
- char * addr = (char *) (scp -> sc_badvaddr);
+ char * addr = (char *) (size_t) (scp -> sc_badvaddr);
# endif
# if defined(OSF1) && defined(ALPHA)
char * addr = (char *) (scp -> sc_traparg_a0);
@@ -1441,7 +1474,8 @@ SIG_PF GC_old_segv_handler; /* Also old MSWIN32 ACCESS_VIOLATION filter */
# else
in_allocd_block = (HDR(addr) != 0);
# endif
- if (!in_allocd_block && !GC_just_outside_heap((word)addr)) {
+ if (!in_allocd_block) {
+ /* Heap blocks now begin and end on page boundaries */
SIG_PF old_handler;
if (sig == SIGSEGV) {
@@ -1529,21 +1563,6 @@ struct hblk *h;
}
}
-#if defined(SVR4)
-#include <unistd.h>
-int
-GC_getpagesize()
-{
- return sysconf(_SC_PAGESIZE);
-}
-#else
-# ifdef MSWIN32
- /* GC_getpagesize() defined above */
-# else
-# define GC_getpagesize() getpagesize()
-# endif
-#endif
-
void GC_dirty_init()
{
#if defined(SUNOS5SIGS)
@@ -1556,7 +1575,6 @@ void GC_dirty_init()
GC_printf0("Inititalizing mprotect virtual dirty bit implementation\n");
# endif
GC_dirty_maintained = TRUE;
- GC_page_size = GC_getpagesize();
if (GC_page_size % HBLKSIZE != 0) {
GC_err_printf0("Page size not multiple of HBLKSIZE\n");
ABORT("Page size not multiple of HBLKSIZE");
@@ -1618,18 +1636,13 @@ void GC_dirty_init()
void GC_protect_heap()
{
- word ps = GC_page_size;
- word pmask = (ps-1);
ptr_t start;
- word offset;
word len;
unsigned i;
for (i = 0; i < GC_n_heap_sects; i++) {
- offset = (word)(GC_heap_sects[i].hs_start) & pmask;
- start = GC_heap_sects[i].hs_start - offset;
- len = GC_heap_sects[i].hs_bytes + offset;
- len += ps-1; len &= ~pmask;
+ start = GC_heap_sects[i].hs_start;
+ len = GC_heap_sects[i].hs_bytes;
PROTECT(start, len);
}
}
@@ -1701,14 +1714,19 @@ word len;
/* Replacement for UNIX system call. */
/* Other calls that write to the heap */
/* should be handled similarly. */
-# ifndef LINT
- int read(fd, buf, nbyte)
+# if defined(__STDC__) && !defined(SUNOS4)
+# include <unistd.h>
+ ssize_t read(int fd, void *buf, size_t nbyte)
# else
- int GC_read(fd, buf, nbyte)
+# ifndef LINT
+ int read(fd, buf, nbyte)
+# else
+ int GC_read(fd, buf, nbyte)
+# endif
+ int fd;
+ char *buf;
+ int nbyte;
# endif
-int fd;
-char *buf;
-int nbyte;
{
int result;
@@ -1767,6 +1785,7 @@ word n;
* address space), but it avoids intercepting system calls.
*/
+#include <errno.h>
#include <sys/types.h>
#include <sys/signal.h>
#include <sys/fault.h>
@@ -1831,6 +1850,7 @@ void GC_dirty_init()
ABORT("/proc open failed");
}
GC_proc_fd = syscall(SYS_ioctl, fd, PIOCOPENPD, 0);
+ close(fd);
if (GC_proc_fd < 0) {
ABORT("/proc ioctl failed");
}
@@ -1891,6 +1911,7 @@ int dummy;
WARN("Insufficient space for /proc read\n", 0);
/* Punt: */
memset(GC_grungy_pages, 0xff, sizeof (page_hash_table));
+ memset(GC_written_pages, 0xff, sizeof(page_hash_table));
# ifdef SOLARIS_THREADS
BZERO(GC_fresh_pages,
MAX_FRESH_PAGES * sizeof (struct hblk *));
@@ -2083,6 +2104,7 @@ struct hblk *h;
--> We only know how to to get the first 6 arguments
# endif
+#ifdef SAVE_CALL_CHAIN
/* Fill in the pc and argument information for up to NFRAMES of my */
/* callers. Ignore my frame and my callers frame. */
void GC_save_callers (info)
@@ -2107,6 +2129,7 @@ struct callinfo info[NFRAMES];
if (nframes < NFRAMES) info[nframes].ci_pc = 0;
}
+#endif /* SAVE_CALL_CHAIN */
#endif /* SPARC */
#ifdef SAVE_CALL_CHAIN
diff --git a/reclaim.c b/reclaim.c
index 2a505f4a..6e480ecc 100644
--- a/reclaim.c
+++ b/reclaim.c
@@ -17,7 +17,7 @@
#include "gc_priv.h"
signed_word GC_mem_found = 0;
- /* Number of longwords of memory GC_reclaimed */
+ /* Number of words of memory reclaimed */
# ifdef FIND_LEAK
static report_leak(p, sz)
diff --git a/setjmp_t.c b/setjmp_t.c
index df30b7b3..9ed92138 100644
--- a/setjmp_t.c
+++ b/setjmp_t.c
@@ -27,42 +27,9 @@
#include <string.h>
#include "config.h"
-#ifdef __hpux
-#include <unistd.h>
-int
-getpagesize()
-{
- return sysconf(_SC_PAGE_SIZE);
-}
-#endif
-
-#if defined(SVR4)
-#include <unistd.h>
-int
-getpagesize()
-{
- return sysconf(_SC_PAGESIZE);
-}
-#endif
-
-#ifdef _AUX_SOURCE
-#include <sys/mmu.h>
-int
-getpagesize()
-{
- return PAGESIZE;
-}
-#endif
-
-#if defined(AMIGA) || defined(MACOS)
-int
-getpagesize()
-{
- return(4096);
-}
-#endif
-
#ifdef OS2
+/* GETPAGESIZE() is set to getpagesize() by default, but that */
+/* doesn't really exist, and the collector doesn't need it. */
#define INCL_DOSFILEMGR
#define INCL_DOSMISC
#define INCL_DOSERRORS
@@ -94,7 +61,7 @@ int * nested_sp()
main()
{
int dummy;
- long ps = getpagesize();
+ long ps = GETPAGESIZE();
jmp_buf b;
register int x = (int)strlen("a"); /* 1, slightly disguised */
static int y = 0;
@@ -102,18 +69,18 @@ main()
printf("This appears to be a %s running %s\n", MACH_TYPE, OS_TYPE);
if (nested_sp() < &dummy) {
printf("Stack appears to grow down, which is the default.\n");
- printf("A good guess for STACKBOTTOM on this machine is 0x%X.\n",
- ((long)(&dummy) + ps) & ~(ps-1));
+ printf("A good guess for STACKBOTTOM on this machine is 0x%lx.\n",
+ ((unsigned long)(&dummy) + ps) & ~(ps-1));
} else {
printf("Stack appears to grow up.\n");
printf("Define STACK_GROWS_UP in gc_private.h\n");
- printf("A good guess for STACKBOTTOM on this machine is 0x%X.\n",
- ((long)(&dummy) + ps) & ~(ps-1));
+ printf("A good guess for STACKBOTTOM on this machine is 0x%lx.\n",
+ ((unsigned long)(&dummy) + ps) & ~(ps-1));
}
printf("Note that this may vary between machines of ostensibly\n");
printf("the same architecture (e.g. Sun 3/50s and 3/80s).\n");
printf("On many machines the value is not fixed.\n");
- printf("A good guess for ALIGNMENT on this machine is %d.\n",
+ printf("A good guess for ALIGNMENT on this machine is %ld.\n",
(unsigned long)(&(a.a_b))-(unsigned long)(&a));
/* Encourage the compiler to keep x in a callee-save register */
diff --git a/solaris_pthreads.c b/solaris_pthreads.c
new file mode 100644
index 00000000..cc72b2dc
--- /dev/null
+++ b/solaris_pthreads.c
@@ -0,0 +1,170 @@
+/*
+ * Copyright (c) 1994 by Xerox Corporation. All rights reserved.
+ *
+ * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
+ * OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
+ *
+ * Permission is hereby granted to use or copy this program
+ * for any purpose, provided the above notices are retained on all copies.
+ * Permission to modify the code and to distribute modified code is granted,
+ * provided the above notices are retained, and a notice that the code was
+ * modified is included with the above copyright notice.
+ */
+/*
+ * Support code for Solaris threads. Provides functionality we wish Sun
+ * had provided. Relies on some information we probably shouldn't rely on.
+ * Modified Peter C. for Solaris Posix Threads.
+ */
+/* Boehm, September 14, 1994 4:44 pm PDT */
+/* $Id: solaris_pthreads.c,v 1.10 1997/05/13 23:09:09 peterc Exp $ */
+
+# if defined(_SOLARIS_PTHREADS)
+# include "gc_priv.h"
+# include <pthread.h>
+# include <thread.h>
+# include <signal.h>
+# include <fcntl.h>
+# include <sys/types.h>
+# include <sys/mman.h>
+# include <sys/time.h>
+# include <sys/resource.h>
+# include <sys/stat.h>
+# include <sys/syscall.h>
+# include <sys/procfs.h>
+# include <sys/lwp.h>
+# include <sys/reg.h>
+# define _CLASSIC_XOPEN_TYPES
+# include <unistd.h>
+# include <errno.h>
+
+#undef pthread_join
+#undef pthread_create
+
+pthread_cond_t GC_prom_join_cv; /* Broadcast when any thread terminates */
+pthread_cond_t GC_create_cv; /* Signalled when a new undetached */
+ /* thread starts. */
+
+extern bool GC_multithreaded;
+
+/* We use the allocation lock to protect thread-related data structures. */
+
+/* We stop the world using /proc primitives. This makes some */
+/* minimal assumptions about the threads implementation. */
+/* We don't play by the rules, since the rules make this */
+/* impossible (as of Solaris 2.3). Also note that as of */
+/* Solaris 2.3 the various thread and lwp suspension */
+/* primitives failed to stop threads by the time the request */
+/* is completed. */
+
+
+
+int GC_pthread_join(pthread_t wait_for, void **status)
+{
+ return GC_thr_join((thread_t)wait_for, NULL, status);
+}
+
+
+int
+GC_pthread_create(pthread_t *new_thread,
+ const pthread_attr_t *attr_in,
+ void * (*thread_execp)(void *), void *arg)
+{
+ int result;
+ GC_thread t;
+ pthread_t my_new_thread;
+ pthread_attr_t attr;
+ word my_flags = 0;
+ int flag;
+ void * stack;
+ size_t stack_size;
+ int n;
+ struct sched_param schedparam;
+
+ (void)pthread_attr_getstacksize(attr_in, &stack_size);
+ (void)pthread_attr_getstackaddr(attr_in, &stack);
+ (void)pthread_attr_init(&attr);
+
+ LOCK();
+ if (!GC_thr_initialized) {
+ GC_thr_init();
+ }
+ GC_multithreaded++;
+
+ if (stack == 0) {
+ if (stack_size == 0)
+ stack_size = GC_min_stack_sz;
+ else
+ stack_size += thr_min_stack();
+
+ stack = (void *)GC_stack_alloc(&stack_size);
+ if (stack == 0) {
+ GC_multithreaded--;
+ UNLOCK();
+ errno = ENOMEM;
+ return -1;
+ }
+ } else {
+ my_flags |= CLIENT_OWNS_STACK;
+ }
+ (void)pthread_attr_setstacksize(&attr, stack_size);
+ (void)pthread_attr_setstackaddr(&attr, stack);
+ (void)pthread_attr_getscope(attr_in, &n);
+ (void)pthread_attr_setscope(&attr, n);
+ (void)pthread_attr_getschedparam(attr_in, &schedparam);
+ (void)pthread_attr_setschedparam(&attr, &schedparam);
+ (void)pthread_attr_getschedpolicy(attr_in, &n);
+ (void)pthread_attr_setschedpolicy(&attr, n);
+ (void)pthread_attr_getinheritsched(attr_in, &n);
+ (void)pthread_attr_setinheritsched(&attr, n);
+
+ (void)pthread_attr_getdetachstate(attr_in, &flag);
+ if (flag == PTHREAD_CREATE_DETACHED) {
+ my_flags |= DETACHED;
+ }
+ (void)pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
+ /*
+ * thr_create can call malloc(), which if redirected will
+ * attempt to acquire the allocation lock.
+ * Unlock here to prevent deadlock.
+ */
+
+
+#if 0
+#ifdef I386
+ UNLOCK();
+#endif
+#endif
+ result =
+ pthread_create(&my_new_thread, &attr, thread_execp, arg);
+#if 0
+#ifdef I386
+ LOCK();
+#endif
+#endif
+ if (result == 0) {
+ t = GC_new_thread(my_new_thread);
+ t -> flags = my_flags;
+ if (!(my_flags & DETACHED)) cond_init(&(t->join_cv), USYNC_THREAD, 0);
+ t -> stack = stack;
+ t -> stack_size = stack_size;
+ if (new_thread != 0) *new_thread = my_new_thread;
+ pthread_cond_signal(&GC_create_cv);
+ } else {
+ if (!(my_flags & CLIENT_OWNS_STACK)) {
+ GC_stack_free(stack, stack_size);
+ }
+ GC_multithreaded--;
+ }
+ UNLOCK();
+ pthread_attr_destroy(&attr);
+ return(result);
+}
+
+# else
+
+#ifndef LINT
+ int GC_no_sunOS_threads;
+#endif
+
+# endif /* SOLARIS_THREADS */
+
diff --git a/solaris_threads.c b/solaris_threads.c
index 01e631f3..d83ffbb5 100644
--- a/solaris_threads.c
+++ b/solaris_threads.c
@@ -19,6 +19,7 @@
# if defined(SOLARIS_THREADS)
# include "gc_priv.h"
+# include "solaris_threads.h"
# include <thread.h>
# include <synch.h>
# include <signal.h>
@@ -34,8 +35,16 @@
# include <sys/reg.h>
# define _CLASSIC_XOPEN_TYPES
# include <unistd.h>
+# include <errno.h>
-# define MAX_LWPS 32
+/*
+ * This is the default size of the LWP arrays. If there are more LWPs
+ * than this when a stop-the-world GC happens, set_max_lwps will be
+ * called to cope.
+ * This must be higher than the number of LWPs at startup time.
+ * The threads library creates a thread early on, so the min. is 3
+ */
+# define DEFAULT_MAX_LWPS 4
#undef thr_join
#undef thr_create
@@ -47,6 +56,10 @@ cond_t GC_create_cv; /* Signalled when a new undetached */
/* thread starts. */
+#ifdef MMAP_STACKS
+static int GC_zfd;
+#endif /* MMAP_STACKS */
+
/* We use the allocation lock to protect thread-related data structures. */
/* We stop the world using /proc primitives. This makes some */
@@ -59,7 +72,6 @@ cond_t GC_create_cv; /* Signalled when a new undetached */
static sigset_t old_mask;
-# define MAX_LWPS 32
/* Sleep for n milliseconds, n < 1000 */
void GC_msec_sleep(int n)
@@ -81,6 +93,7 @@ void preempt_off()
sigset_t set;
(void)sigfillset(&set);
+ sigdelset(&set, SIGABRT);
syscall(SYS_sigprocmask, SIG_SETMASK, &set, &old_mask);
}
@@ -91,12 +104,17 @@ void preempt_on()
int GC_main_proc_fd = -1;
+
struct lwp_cache_entry {
lwpid_t lc_id;
int lc_descr; /* /proc file descriptor. */
-} GC_lwp_cache[MAX_LWPS];
+} GC_lwp_cache_default[DEFAULT_MAX_LWPS];
-prgregset_t GC_lwp_registers[MAX_LWPS];
+static int max_lwps = DEFAULT_MAX_LWPS;
+static struct lwp_cache_entry *GC_lwp_cache = GC_lwp_cache_default;
+
+static prgregset_t GC_lwp_registers_default[DEFAULT_MAX_LWPS];
+static prgregset_t *GC_lwp_registers = GC_lwp_registers_default;
/* Return a file descriptor for the /proc entry corresponding */
/* to the given lwp. The file descriptor may be stale if the */
@@ -107,17 +125,35 @@ static int open_lwp(lwpid_t id)
static int next_victim = 0;
register int i;
- for (i = 0; i < MAX_LWPS; i++) {
+ for (i = 0; i < max_lwps; i++) {
if (GC_lwp_cache[i].lc_id == id) return(GC_lwp_cache[i].lc_descr);
}
- if ((result = syscall(SYS_ioctl, GC_main_proc_fd, PIOCOPENLWP, &id)) < 0) {
+ result = syscall(SYS_ioctl, GC_main_proc_fd, PIOCOPENLWP, &id);
+ /*
+ * If PIOCOPENLWP fails, try closing fds in the cache until it succeeds.
+ */
+ if (result < 0 && errno == EMFILE) {
+ for (i = 0; i < max_lwps; i++) {
+ if (GC_lwp_cache[i].lc_id != 0) {
+ (void)syscall(SYS_close, GC_lwp_cache[i].lc_descr);
+ result = syscall(SYS_ioctl, GC_main_proc_fd, PIOCOPENLWP, &id);
+ if (result >= 0 || (result < 0 && errno != EMFILE))
+ break;
+ }
+ }
+ }
+ if (result < 0) {
+ if (errno == EMFILE) {
+ ABORT("Too many open files");
+ }
return(-1) /* exited? */;
}
if (GC_lwp_cache[next_victim].lc_id != 0)
(void)syscall(SYS_close, GC_lwp_cache[next_victim].lc_descr);
GC_lwp_cache[next_victim].lc_id = id;
GC_lwp_cache[next_victim].lc_descr = result;
- next_victim++;
+ if (++next_victim >= max_lwps)
+ next_victim = 0;
return(result);
}
@@ -125,7 +161,7 @@ static void uncache_lwp(lwpid_t id)
{
register int i;
- for (i = 0; i < MAX_LWPS; i++) {
+ for (i = 0; i < max_lwps; i++) {
if (GC_lwp_cache[i].lc_id == id) {
(void)syscall(SYS_close, GC_lwp_cache[id].lc_descr);
GC_lwp_cache[i].lc_id = 0;
@@ -133,8 +169,54 @@ static void uncache_lwp(lwpid_t id)
}
}
}
+ /* Sequence of current lwp ids */
+static lwpid_t GC_current_ids_default[DEFAULT_MAX_LWPS + 1];
+static lwpid_t *GC_current_ids = GC_current_ids_default;
+
+ /* Temporary used below (can be big if large number of LWPs) */
+static lwpid_t last_ids_default[DEFAULT_MAX_LWPS + 1];
+static lwpid_t *last_ids = last_ids_default;
+
+
+#define ROUNDUP(n) WORDS_TO_BYTES(ROUNDED_UP_WORDS(n))
+
+static void set_max_lwps(GC_word n)
+{
+ char *mem;
+ char *oldmem;
+ int required_bytes = ROUNDUP(n * sizeof(struct lwp_cache_entry))
+ + ROUNDUP(n * sizeof(prgregset_t))
+ + ROUNDUP((n + 1) * sizeof(lwpid_t))
+ + ROUNDUP((n + 1) * sizeof(lwpid_t));
+
+ GC_expand_hp_inner(divHBLKSZ((word)required_bytes));
+ oldmem = mem = GC_scratch_alloc(required_bytes);
+ if (0 == mem) ABORT("No space for lwp data structures");
+
+ /*
+ * We can either flush the old lwp cache or copy it over. Do the latter.
+ */
+ memcpy(mem, GC_lwp_cache, max_lwps * sizeof(struct lwp_cache_entry));
+ GC_lwp_cache = (struct lwp_cache_entry*)mem;
+ mem += ROUNDUP(n * sizeof(struct lwp_cache_entry));
+
+ BZERO(GC_lwp_registers, max_lwps * sizeof(GC_lwp_registers[0]));
+ GC_lwp_registers = (prgregset_t *)mem;
+ mem += ROUNDUP(n * sizeof(prgregset_t));
+
+
+ GC_current_ids = (lwpid_t *)mem;
+ mem += ROUNDUP((n + 1) * sizeof(lwpid_t));
+
+ last_ids = (lwpid_t *)mem;
+ mem += ROUNDUP((n + 1)* sizeof(lwpid_t));
+
+ if (mem > oldmem + required_bytes)
+ ABORT("set_max_lwps buffer overflow");
+
+ max_lwps = n;
+}
-lwpid_t GC_current_ids[MAX_LWPS + 1]; /* Sequence of current lwp ids */
/* Stop all lwps in process. Assumes preemption is off. */
/* Caller has allocation lock (and any other locks he may */
@@ -144,7 +226,6 @@ static void stop_all_lwps()
int lwp_fd;
char buf[30];
prstatus_t status;
- lwpid_t last_ids[MAX_LWPS + 1];
register int i;
bool changed;
lwpid_t me = _lwp_self();
@@ -153,24 +234,35 @@ static void stop_all_lwps()
sprintf(buf, "/proc/%d", getpid());
GC_main_proc_fd = syscall(SYS_open, buf, O_RDONLY);
if (GC_main_proc_fd < 0) {
- ABORT("/proc open failed");
+ if (errno == EMFILE)
+ ABORT("/proc open failed: too many open files");
+ GC_printf1("/proc open failed: errno %d", errno);
+ abort();
}
}
+ BZERO(GC_lwp_registers, sizeof (prgregset_t) * max_lwps);
+ for (i = 0; i < max_lwps; i++)
+ last_ids[i] = 0;
+ for (;;) {
if (syscall(SYS_ioctl, GC_main_proc_fd, PIOCSTATUS, &status) < 0)
ABORT("Main PIOCSTATUS failed");
- if (status.pr_nlwp < 1 || status.pr_nlwp > MAX_LWPS) {
- ABORT("Too many lwps");
- /* Only a heuristic. There seems to be no way to do this right, */
- /* since there can be intervening forks. */
+ if (status.pr_nlwp < 1)
+ ABORT("Invalid number of lwps returned by PIOCSTATUS");
+ if (status.pr_nlwp >= max_lwps) {
+ set_max_lwps(status.pr_nlwp*2 + 10);
+ /*
+ * The data in the old GC_current_ids and
+ * GC_lwp_registers has been trashed. Cleaning out last_ids
+ * will make sure every LWP gets re-examined.
+ */
+ for (i = 0; i < max_lwps; i++)
+ last_ids[i] = 0;
+ continue;
}
- BZERO(GC_lwp_registers, sizeof GC_lwp_registers);
- for (i = 0; i <= MAX_LWPS; i++) last_ids[i] = 0;
- for (;;) {
- if (syscall(SYS_ioctl, GC_main_proc_fd, PIOCLWPIDS, GC_current_ids) < 0) {
+ if (syscall(SYS_ioctl, GC_main_proc_fd, PIOCLWPIDS, GC_current_ids) < 0)
ABORT("PIOCLWPIDS failed");
- }
changed = FALSE;
- for (i = 0; GC_current_ids[i] != 0; i++) {
+ for (i = 0; GC_current_ids[i] != 0 && i < max_lwps; i++) {
if (GC_current_ids[i] != last_ids[i]) {
changed = TRUE;
if (GC_current_ids[i] != me) {
@@ -184,14 +276,24 @@ static void stop_all_lwps()
}
}
}
- if (i >= MAX_LWPS) ABORT("Too many lwps");
}
+ /*
+ * In the unlikely event something does a fork between the
+ * PIOCSTATUS and the PIOCLWPIDS.
+ */
+ if (i >= max_lwps)
+ continue;
/* All lwps in GC_current_ids != me have been suspended. Note */
/* that _lwp_suspend is idempotent. */
for (i = 0; GC_current_ids[i] != 0; i++) {
if (GC_current_ids[i] != last_ids[i]) {
if (GC_current_ids[i] != me) {
lwp_fd = open_lwp(GC_current_ids[i]);
+ if (lwp_fd == -1)
+ {
+ GC_current_ids[i] = me;
+ continue;
+ }
/* LWP should be stopped. Empirically it sometimes */
/* isn't, and more frequently the PR_STOPPED flag */
/* is not set. Wait for PR_STOPPED. */
@@ -217,7 +319,10 @@ static void stop_all_lwps()
}
}
if (status.pr_who != GC_current_ids[i]) {
- ABORT("Wrong lwp");
+ /* can happen if thread was on death row */
+ uncache_lwp(GC_current_ids[i]);
+ GC_current_ids[i] = me; /* handle next time. */
+ continue;
}
/* Save registers where collector can */
/* find them. */
@@ -228,7 +333,7 @@ static void stop_all_lwps()
}
}
if (!changed) break;
- for (i = 0; i <= MAX_LWPS; i++) last_ids[i] = GC_current_ids[i];
+ for (i = 0; i < max_lwps; i++) last_ids[i] = GC_current_ids[i];
}
}
@@ -246,7 +351,6 @@ static void restart_all_lwps()
if (GC_current_ids[i] != me) {
int lwp_fd = open_lwp(GC_current_ids[i]);
prstatus_t status;
- gwindows_t windows;
if (lwp_fd < 0) ABORT("open_lwp failed");
if (syscall(SYS_ioctl, lwp_fd,
@@ -255,16 +359,29 @@ static void restart_all_lwps()
}
if (memcmp(status.pr_reg, GC_lwp_registers[i],
sizeof (prgregset_t)) != 0) {
+ int j;
+
+ for(j = 0; j < NGREG; j++)
+ {
+ GC_printf3("%i: %x -> %x\n", j,
+ GC_lwp_registers[i][j],
+ status.pr_reg[j]);
+ }
ABORT("Register contents changed");
}
if (!status.pr_flags & PR_STOPPED) {
ABORT("lwp no longer stopped");
}
- if (syscall(SYS_ioctl, lwp_fd,
+#ifdef SPARC
+ {
+ gwindows_t windows;
+ if (syscall(SYS_ioctl, lwp_fd,
PIOCGWIN, &windows) < 0) {
ABORT("PIOCSTATUS failed in restart_all_lwps");
+ }
+ if (windows.wbcnt > 0) ABORT("unsaved register windows");
}
- if (windows.wbcnt > 0) ABORT("unsaved register windows");
+#endif
}
# endif /* PARANOID */
if (GC_current_ids[i] == me) continue;
@@ -272,7 +389,7 @@ static void restart_all_lwps()
ABORT("Failed to restart lwp");
}
}
- if (i >= MAX_LWPS) ABORT("Too many lwps");
+ if (i >= max_lwps) ABORT("Too many lwps");
}
bool GC_multithreaded = 0;
@@ -291,7 +408,7 @@ void GC_start_world()
preempt_on();
}
-void GC_thr_init();
+void GC_thr_init(void);
bool GC_thr_initialized = FALSE;
@@ -299,12 +416,20 @@ size_t GC_min_stack_sz;
size_t GC_page_sz;
+/*
+ * stack_head is stored at the top of free stacks
+ */
+struct stack_head {
+ struct stack_head *next;
+ ptr_t base;
+ thread_t owner;
+};
# define N_FREE_LISTS 25
-ptr_t GC_stack_free_lists[N_FREE_LISTS] = { 0 };
+struct stack_head *GC_stack_free_lists[N_FREE_LISTS] = { 0 };
/* GC_stack_free_lists[i] is free list for stacks of */
/* size GC_min_stack_sz*2**i. */
- /* Free lists are linked through first word. */
+ /* Free lists are linked through stack_head stored */ /* at top of stack. */
/* Return a stack of size at least *stack_size. *stack_size is */
/* replaced by the actual stack size. */
@@ -314,7 +439,8 @@ ptr_t GC_stack_alloc(size_t * stack_size)
register size_t requested_sz = *stack_size;
register size_t search_sz = GC_min_stack_sz;
register int index = 0; /* = log2(search_sz/GC_min_stack_sz) */
- register ptr_t result;
+ register ptr_t base;
+ register struct stack_head *result;
while (search_sz < requested_sz) {
search_sz *= 2;
@@ -326,19 +452,44 @@ ptr_t GC_stack_alloc(size_t * stack_size)
search_sz *= 2; index++;
}
if (result != 0) {
- GC_stack_free_lists[index] = *(ptr_t *)result;
+ base = GC_stack_free_lists[index]->base;
+ GC_stack_free_lists[index] = GC_stack_free_lists[index]->next;
} else {
- result = (ptr_t) GC_scratch_alloc(search_sz + 2*GC_page_sz);
- result = (ptr_t)(((word)result + GC_page_sz) & ~(GC_page_sz - 1));
+#ifdef MMAP_STACKS
+ base = (ptr_t)mmap(0, search_sz + GC_page_sz,
+ PROT_READ|PROT_WRITE, MAP_PRIVATE |MAP_NORESERVE,
+ GC_zfd, 0);
+ if (base == (ptr_t)-1)
+ {
+ *stack_size = 0;
+ return NULL;
+ }
+
+ mprotect(base, GC_page_sz, PROT_NONE);
+ /* Should this use divHBLKSZ(search_sz + GC_page_sz) ? -- cf */
+ GC_is_fresh((struct hblk *)base, divHBLKSZ(search_sz));
+ base += GC_page_sz;
+
+#else
+ base = (ptr_t) GC_scratch_alloc(search_sz + 2*GC_page_sz);
+ if (base == NULL)
+ {
+ *stack_size = 0;
+ return NULL;
+ }
+
+ base = (ptr_t)(((word)base + GC_page_sz) & ~(GC_page_sz - 1));
/* Protect hottest page to detect overflow. */
# ifdef SOLARIS23_MPROTECT_BUG_FIXED
- mprotect(result, GC_page_sz, PROT_NONE);
+ mprotect(base, GC_page_sz, PROT_NONE);
# endif
- GC_is_fresh((struct hblk *)result, divHBLKSZ(search_sz));
- result += GC_page_sz;
+ GC_is_fresh((struct hblk *)base, divHBLKSZ(search_sz));
+
+ base += GC_page_sz;
+#endif
}
*stack_size = search_sz;
- return(result);
+ return(base);
}
/* Caller holds allocationlock. */
@@ -346,14 +497,23 @@ void GC_stack_free(ptr_t stack, size_t size)
{
register int index = 0;
register size_t search_sz = GC_min_stack_sz;
+ register struct stack_head *head;
+#ifdef MMAP_STACKS
+ /* Zero pointers */
+ mmap(stack, size, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_NORESERVE|MAP_FIXED,
+ GC_zfd, 0);
+#endif
while (search_sz < size) {
search_sz *= 2;
index++;
}
if (search_sz != size) ABORT("Bad stack size");
- *(ptr_t *)stack = GC_stack_free_lists[index];
- GC_stack_free_lists[index] = stack;
+
+ head = (struct stack_head *)(stack + search_sz - sizeof(struct stack_head));
+ head->next = GC_stack_free_lists[index];
+ head->base = stack;
+ GC_stack_free_lists[index] = head;
}
void GC_my_stack_limits();
@@ -363,16 +523,20 @@ void GC_my_stack_limits();
/* Caller holds allocation lock. */
void GC_old_stacks_are_fresh()
{
+/* No point in doing this for MMAP stacks - and pointers are zero'd out */
+/* by the mmap in GC_stack_free */
+#ifndef MMAP_STACKS
register int i;
+ register struct stack_head *s;
register ptr_t p;
register size_t sz;
register struct hblk * h;
int dummy;
- GC_thr_init();
for (i = 0, sz= GC_min_stack_sz; i < N_FREE_LISTS;
i++, sz *= 2) {
- for (p = GC_stack_free_lists[i]; p != 0; p = *(ptr_t *)p) {
+ for (s = GC_stack_free_lists[i]; s != 0; s = s->next) {
+ p = s->base;
h = (struct hblk *)(((word)p + HBLKSIZE-1) & ~(HBLKSIZE-1));
if ((ptr_t)h == p) {
GC_is_fresh((struct hblk *)p, divHBLKSZ(sz));
@@ -382,6 +546,7 @@ void GC_old_stacks_are_fresh()
}
}
}
+#endif /* MMAP_STACKS */
GC_my_stack_limits();
}
@@ -389,24 +554,6 @@ void GC_old_stacks_are_fresh()
/* joins. We never actually create detached threads. We allocate all */
/* new thread stacks ourselves. These allow us to maintain this */
/* data structure. */
-/* Protected by GC_thr_lock. */
-/* Some of this should be declared vaolatile, but that's incosnsistent */
-/* with some library routine declarations. In particular, the */
-/* definition of cond_t doesn't mention volatile! */
-typedef struct GC_Thread_Rep {
- struct GC_Thread_Rep * next;
- thread_t id;
- word flags;
-# define FINISHED 1 /* Thread has exited. */
-# define DETACHED 2 /* Thread is intended to be detached. */
-# define CLIENT_OWNS_STACK 4
- /* Stack was supplied by client. */
-# define SUSPENDED 8 /* Currently suspended. */
- ptr_t stack;
- size_t stack_size;
- cond_t join_cv;
- void * status;
-} * GC_thread;
# define THREAD_TABLE_SZ 128 /* Must be power of 2 */
volatile GC_thread GC_threads[THREAD_TABLE_SZ];
@@ -516,7 +663,9 @@ void GC_push_all_stacks()
} else { \
GC_push_all_stack((bottom), (top)); \
}
- GC_thr_init();
+ GC_push_all_stack((ptr_t)GC_lwp_registers,
+ (ptr_t)GC_lwp_registers
+ + max_lwps * sizeof(GC_lwp_registers[0]));
for (i = 0; i < THREAD_TABLE_SZ; i++) {
for (p = GC_threads[i]; p != 0; p = p -> next) {
if (p -> stack_size != 0) {
@@ -534,6 +683,25 @@ void GC_push_all_stacks()
}
}
+
+int GC_is_thread_stack(ptr_t addr)
+{
+ register int i;
+ register GC_thread p;
+ register ptr_t bottom, top;
+ struct rlimit rl;
+
+ for (i = 0; i < THREAD_TABLE_SZ; i++) {
+ for (p = GC_threads[i]; p != 0; p = p -> next) {
+ if (p -> stack_size != 0) {
+ if (p -> stack <= addr &&
+ addr < p -> stack + p -> stack_size)
+ return 1;
+ }
+ }
+ }
+}
+
/* The only thread that ever really performs a thr_join. */
void * GC_thr_daemon(void * dummy)
{
@@ -579,16 +747,24 @@ void * GC_thr_daemon(void * dummy)
}
}
-/* We hold the allocation lock. */
-void GC_thr_init()
+/* We hold the allocation lock, or caller ensures that 2 instances */
+/* cannot be invoked concurrently. */
+void GC_thr_init(void)
{
GC_thread t;
+ thread_t tid;
- if (GC_thr_initialized) return;
+ if (GC_thr_initialized)
+ return;
GC_thr_initialized = TRUE;
- GC_min_stack_sz = ((thr_min_stack() + 128*1024 + HBLKSIZE-1)
+ GC_min_stack_sz = ((thr_min_stack() + 32*1024 + HBLKSIZE-1)
& ~(HBLKSIZE - 1));
GC_page_sz = sysconf(_SC_PAGESIZE);
+#ifdef MMAP_STACKS
+ GC_zfd = open("/dev/zero", O_RDONLY);
+ if (GC_zfd == -1)
+ ABORT("Can't open /dev/zero");
+#endif /* MMAP_STACKS */
cond_init(&GC_prom_join_cv, USYNC_THREAD, 0);
cond_init(&GC_create_cv, USYNC_THREAD, 0);
/* Add the initial thread, so we can stop it. */
@@ -597,10 +773,10 @@ void GC_thr_init()
t -> flags = DETACHED | CLIENT_OWNS_STACK;
if (thr_create(0 /* stack */, 0 /* stack_size */, GC_thr_daemon,
0 /* arg */, THR_DETACHED | THR_DAEMON,
- 0 /* thread_id */) != 0) {
+ &tid /* thread_id */) != 0) {
ABORT("Cant fork daemon");
}
-
+ thr_setprio(tid, 126);
}
/* We acquire the allocation lock to prevent races with */
@@ -705,12 +881,16 @@ GC_thr_create(void *stack_base, size_t stack_size,
void * stack = stack_base;
LOCK();
+ if (!GC_thr_initialized)
+ {
GC_thr_init();
+ }
GC_multithreaded++;
if (stack == 0) {
if (stack_size == 0) stack_size = GC_min_stack_sz;
stack = (void *)GC_stack_alloc(&stack_size);
if (stack == 0) {
+ GC_multithreaded--;
UNLOCK();
return(ENOMEM);
}
@@ -739,11 +919,9 @@ GC_thr_create(void *stack_base, size_t stack_size,
return(result);
}
-# else
+# else /* SOLARIS_THREADS */
#ifndef LINT
int GC_no_sunOS_threads;
#endif
-
-# endif /* SOLARIS_THREADS */
-
+#endif
diff --git a/solaris_threads.h b/solaris_threads.h
new file mode 100644
index 00000000..d13dd554
--- /dev/null
+++ b/solaris_threads.h
@@ -0,0 +1,34 @@
+#ifdef SOLARIS_THREADS
+
+/* The set of all known threads. We intercept thread creation and */
+/* joins. We never actually create detached threads. We allocate all */
+/* new thread stacks ourselves. These allow us to maintain this */
+/* data structure. */
+/* Protected by GC_thr_lock. */
+/* Some of this should be declared volatile, but that's incosnsistent */
+/* with some library routine declarations. In particular, the */
+/* definition of cond_t doesn't mention volatile! */
+ typedef struct GC_Thread_Rep {
+ struct GC_Thread_Rep * next;
+ thread_t id;
+ word flags;
+# define FINISHED 1 /* Thread has exited. */
+# define DETACHED 2 /* Thread is intended to be detached. */
+# define CLIENT_OWNS_STACK 4
+ /* Stack was supplied by client. */
+# define SUSPENDED 8 /* Currently suspended. */
+ ptr_t stack;
+ size_t stack_size;
+ cond_t join_cv;
+ void * status;
+ } * GC_thread;
+ extern GC_thread GC_new_thread(thread_t id);
+
+ extern bool GC_thr_initialized;
+ extern volatile GC_thread GC_threads[];
+ extern size_t GC_min_stack_sz;
+ extern size_t GC_page_sz;
+ extern void GC_thr_init(void);
+
+# endif /* SOLARIS_THREADS */
+
diff --git a/sparc_sunos4_mach_dep.s b/sparc_sunos4_mach_dep.s
new file mode 100644
index 00000000..7accadd3
--- /dev/null
+++ b/sparc_sunos4_mach_dep.s
@@ -0,0 +1,38 @@
+! SPARCompiler 3.0 and later apparently no loner handles
+! asm outside functions. So we need a separate .s file
+! This is only set up for SunOS 4.
+! Assumes this is called before the stack contents are
+! examined.
+
+ .seg "text"
+ .globl _GC_save_regs_in_stack
+ .globl _GC_push_regs
+_GC_save_regs_in_stack:
+_GC_push_regs:
+ ta 0x3 ! ST_FLUSH_WINDOWS
+ mov %sp,%o0
+ retl
+ nop
+
+ .globl _GC_clear_stack_inner
+_GC_clear_stack_inner:
+ mov %sp,%o2 ! Save sp
+ add %sp,-8,%o3 ! p = sp-8
+ clr %g1 ! [g0,g1] = 0
+ add %o1,-0x60,%sp ! Move sp out of the way,
+ ! so that traps still work.
+ ! Includes some extra words
+ ! so we can be sloppy below.
+loop:
+ std %g0,[%o3] ! *(long long *)p = 0
+ cmp %o3,%o1
+ bgu loop ! if (p > limit) goto loop
+ add %o3,-8,%o3 ! p -= 8 (delay slot)
+ retl
+ mov %o2,%sp ! Restore sp., delay slot
+
+
+
+
+
+
diff --git a/test.c b/test.c
index eae72432..cdc8b7f4 100644
--- a/test.c
+++ b/test.c
@@ -921,8 +921,16 @@ void SetMinimumStack(long minSize)
int main()
#endif
{
+# if defined(DJGPP)
+ int dummy;
+# endif
n_tests = 0;
+# if defined(DJGPP)
+ /* No good way to determine stack base from library; do it */
+ /* manually on this platform. */
+ GC_stackbottom = (GC_PTR)(&dummy);
+# endif
# if defined(MACOS)
/* Make sure we have lots and lots of stack space. */
SetMinimumStack(cMinStackSpace);
diff --git a/test_cpp.cc b/test_cpp.cc
index 6eb8f7a8..058022c4 100644
--- a/test_cpp.cc
+++ b/test_cpp.cc
@@ -27,6 +27,7 @@ few minutes to complete.
#include "gc_cpp.h"
#include <stdio.h>
#include <stdlib.h>
+#include <string.h>
#ifndef __GNUC__
# include "gc_alloc.h"
#endif
diff --git a/typd_mlc.c b/typd_mlc.c
index 7336e335..9ddda983 100644
--- a/typd_mlc.c
+++ b/typd_mlc.c
@@ -630,10 +630,13 @@ ptr_t GC_clear_stack();
#define GENERAL_MALLOC(lb,k) \
(GC_PTR)GC_clear_stack(GC_generic_malloc((word)lb, k))
+#define GENERAL_MALLOC_IOP(lb,k) \
+ (GC_PTR)GC_clear_stack(GC_generic_malloc_ignore_off_page((word)lb, k))
+
#if defined(__STDC__) || defined(__cplusplus)
- extern void * GC_malloc_explicitly_typed(size_t lb, GC_descr d)
+ void * GC_malloc_explicitly_typed(size_t lb, GC_descr d)
#else
- extern char * GC_malloc_explicitly_typed(lb, d)
+ char * GC_malloc_explicitly_typed(lb, d)
size_t lb;
GC_descr d;
#endif
@@ -666,9 +669,53 @@ DCL_LOCK_STATE;
}
} else {
op = (ptr_t)GENERAL_MALLOC((word)lb, GC_explicit_kind);
- if (0 == op) return(0);
+ if (op != NULL)
+ lw = BYTES_TO_WORDS(GC_size(op));
+ }
+ if (op != NULL)
+ ((word *)op)[lw - 1] = d;
+ return((GC_PTR) op);
+}
+
+#if defined(__STDC__) || defined(__cplusplus)
+ void * GC_malloc_explicitly_typed_ignore_off_page(size_t lb, GC_descr d)
+#else
+ char * GC_malloc_explicitly_typed_ignore_off_page(lb, d)
+ size_t lb;
+ GC_descr d;
+#endif
+{
+register ptr_t op;
+register ptr_t * opp;
+register word lw;
+DCL_LOCK_STATE;
+
+ lb += EXTRA_BYTES;
+ if( SMALL_OBJ(lb) ) {
+# ifdef MERGE_SIZES
+ lw = GC_size_map[lb];
+# else
+ lw = ALIGNED_WORDS(lb);
+# endif
+ opp = &(GC_eobjfreelist[lw]);
+ FASTLOCK();
+ if( !FASTLOCK_SUCCEEDED() || (op = *opp) == 0 ) {
+ FASTUNLOCK();
+ op = (ptr_t)GENERAL_MALLOC_IOP((word)lb, GC_explicit_kind);
+# ifdef MERGE_SIZES
+ lw = GC_size_map[lb]; /* May have been uninitialized. */
+# endif
+ } else {
+ *opp = obj_link(op);
+ GC_words_allocd += lw;
+ FASTUNLOCK();
+ }
+ } else {
+ op = (ptr_t)GENERAL_MALLOC_IOP((word)lb, GC_explicit_kind);
+ if (op != NULL)
lw = BYTES_TO_WORDS(GC_size(op));
}
+ if (op != NULL)
((word *)op)[lw - 1] = d;
return((GC_PTR) op);
}
diff --git a/version.h b/version.h
new file mode 100644
index 00000000..6bda1048
--- /dev/null
+++ b/version.h
@@ -0,0 +1,11 @@
+#define GC_VERSION_MAJOR 4
+#define GC_VERSION_MINOR 12
+#define GC_ALPHA_VERSION GC_NOT_ALPHA
+
+# define GC_NOT_ALPHA 0xff
+
+#ifndef GC_NO_VERSION_VAR
+
+unsigned GC_version = ((GC_VERSION_MAJOR << 16) | (GC_VERSION_MINOR << 8) | GC_ALPHA_VERSION);
+
+#endif /* GC_NO_VERSION_VAR */