summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHans Boehm <boehm@acm.org>1998-12-08 00:00:00 +0000
committerIvan Maidanski <ivmai@mail.ru>2014-05-17 17:40:40 +0400
commit36137b3333873cb3fb5019cd04add97d12dfc205 (patch)
treeca69195041d9c02ec4408e8cb380f6156378113e
parentefe21032c5ea5430724682514fe136e98a7d047e (diff)
downloadbdwgc-gc4_13alpha3.tar.gz
gc4.13alpha3 tarball importgc4_13alpha3
-rw-r--r--BCC_MAKEFILE2
-rw-r--r--EMX_MAKEFILE2
-rw-r--r--MacOS.c17
-rw-r--r--Makefile71
-rw-r--r--Makefile.dj12
-rw-r--r--PCR-Makefile2
-rw-r--r--README43
-rw-r--r--README.Mac2
-rw-r--r--README.alpha7
-rw-r--r--README.hp4
-rw-r--r--README.linux17
-rw-r--r--README.rs60003
-rw-r--r--README.sgi4
-rw-r--r--README.solaris24
-rw-r--r--README.win3255
-rw-r--r--SMakefile.amiga2
-rw-r--r--WCC_MAKEFILE179
-rw-r--r--allchblk.c5
-rw-r--r--alloc.c87
-rw-r--r--cord/de_win.c1
-rw-r--r--cord/gc.h36
-rw-r--r--dbg_mlc.c30
-rw-r--r--dyn_load.c2
-rw-r--r--finalize.c5
-rw-r--r--gc.h36
-rw-r--r--gc.mak92
-rw-r--r--gc_cpp.cc14
-rw-r--r--gc_cpp.h3
-rw-r--r--gc_mark.h9
-rw-r--r--gc_priv.h134
-rw-r--r--gcconfig.h (renamed from config.h)130
-rw-r--r--headers.c2
-rw-r--r--if_mach.c6
-rw-r--r--if_not_there.c2
-rw-r--r--include/gc.h36
-rw-r--r--include/gc_cpp.h3
-rw-r--r--include/javaxfc.h41
-rw-r--r--include/new_gc_alloc.h456
-rw-r--r--include/private/gc_priv.h134
-rw-r--r--include/private/gcconfig.h (renamed from include/private/config.h)130
-rw-r--r--irix_threads.c66
-rw-r--r--linux_threads.c65
-rw-r--r--malloc.c9
-rw-r--r--mark.c9
-rw-r--r--mark_rts.c145
-rw-r--r--misc.c20
-rw-r--r--os_dep.c94
-rw-r--r--setjmp_t.c2
-rw-r--r--test.c117
-rw-r--r--threadlibs.c2
-rw-r--r--version.h2
-rwxr-xr-xwin32_threads.c55
52 files changed, 1935 insertions, 471 deletions
diff --git a/BCC_MAKEFILE b/BCC_MAKEFILE
index c65a73e2..225a1ed4 100644
--- a/BCC_MAKEFILE
+++ b/BCC_MAKEFILE
@@ -39,7 +39,7 @@ OBJS= $(XXXOBJS:XXX=)
all: gctest.exe cord\de.exe test_cpp.exe
-$(OBJS) test.obj: gc_priv.h gc_hdrs.h gc.h config.h MAKEFILE
+$(OBJS) test.obj: gc_priv.h gc_hdrs.h gc.h gcconfig.h MAKEFILE
gc.lib: $(OBJS)
-del gc.lib
diff --git a/EMX_MAKEFILE b/EMX_MAKEFILE
index 1ade12ad..54a06ce3 100644
--- a/EMX_MAKEFILE
+++ b/EMX_MAKEFILE
@@ -72,7 +72,7 @@ SPECIALCFLAGS =
all: gc.a gctest.exe
$(OBJS) test.o: $(srcdir)/gc_priv.h $(srcdir)/gc_hdrs.h $(srcdir)/gc.h \
- $(srcdir)/config.h $(srcdir)/gc_typed.h
+ $(srcdir)/gcconfig.h $(srcdir)/gc_typed.h
# The dependency on Makefile is needed. Changing
# options such as -DSILENT affects the size of GC_arrays,
# invalidating all .o files that rely on gc_priv.h
diff --git a/MacOS.c b/MacOS.c
index 420ea500..cc12cd15 100644
--- a/MacOS.c
+++ b/MacOS.c
@@ -135,3 +135,20 @@ void GC_MacFreeTemporaryMemory()
# endif
}
}
+
+#if __option(far_data)
+
+ void* GC_MacGetDataEnd()
+ {
+ CodeZeroHandle code0 = (CodeZeroHandle)GetResource('CODE', 0);
+ if (code0) {
+ long aboveA5Size = (**code0).aboveA5;
+ ReleaseResource((Handle)code0);
+ return (LMGetCurrentA5() + aboveA5Size);
+ }
+ fprintf(stderr, "Couldn't load the jump table.");
+ exit(-1);
+ return 0;
+ }
+
+#endif /* __option(far_data) */
diff --git a/Makefile b/Makefile
index 056df2f6..f8b9f0ff 100644
--- a/Makefile
+++ b/Makefile
@@ -18,6 +18,9 @@ AS=as $(ABI_FLAG)
CFLAGS= -O -DATOMIC_UNCOLLECTABLE -DNO_SIGNALS -DALL_INTERIOR_POINTERS -DNO_EXECUTE_PERMISSION -DSILENT
+# For dynamic library builds, it may be necessary to add flags to generate
+# PIC code, e.g. -fPIC on Linux.
+
# Setjmp_test may yield overly optimistic results when compiled
# without optimization.
# -DSILENT disables statistics printing, and improves performance.
@@ -30,10 +33,12 @@ CFLAGS= -O -DATOMIC_UNCOLLECTABLE -DNO_SIGNALS -DALL_INTERIOR_POINTERS -DNO_EXEC
# -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.)
-# Must also define -D_REENTRANT
+# 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.
+# _DLINUX_THREADS enables support for Xavier Leroy's Linux threads.
+# see README.linux. -D_REENTRANT may also be required.
# -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,
@@ -104,6 +109,8 @@ CFLAGS= -O -DATOMIC_UNCOLLECTABLE -DNO_SIGNALS -DALL_INTERIOR_POINTERS -DNO_EXEC
# allocation strategy. The new strategy tries harder to minimize
# fragmentation, sometimes at the expense of spending more time in the
# large block allocator and/or collecting more frequently.
+# If you expect the allocator to promtly use an explicitly expanded
+# heap, this is highly recommended.
#
@@ -134,16 +141,17 @@ 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 \
+ gcconfig.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 \
- sparc_sunos4_mach_dep.s solaris_threads.h $(CORD_SRCS)
+ include/new_gc_alloc.h include/javaxfc.h 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 \
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/ec.h include/private/cord_pos.h include/private/gcconfig.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 \
@@ -177,12 +185,12 @@ SPECIALCFLAGS =
all: gc.a gctest
-pcr: PCR-Makefile gc_private.h gc_hdrs.h gc.h config.h mach_dep.o $(SRCS)
+pcr: PCR-Makefile gc_private.h gc_hdrs.h gc.h gcconfig.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
+ $(srcdir)/gcconfig.h $(srcdir)/gc_typed.h Makefile
# The dependency on Makefile is needed. Changing
# options such as -DSILENT affects the size of GC_arrays,
# invalidating all .o files that rely on gc_priv.h
@@ -191,28 +199,19 @@ mark.o typd_mlc.o finalize.o: $(srcdir)/gc_mark.h
base_lib gc.a: $(OBJS) dyn_load.o $(UTILS)
echo > base_lib
- rm -f on_sparc_sunos5
- ./if_mach SPARC SUNOS5 touch on_sparc_sunos5
+ rm -f on_sparc_sunos5_1
+ ./if_mach SPARC SUNOS5 touch on_sparc_sunos5_1
./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 || cat /dev/null
+ ./if_not_there on_sparc_sunos5_1 $(AR) ru gc.a $(OBJS) dyn_load.o
+ ./if_not_there on_sparc_sunos5_1 $(RANLIB) gc.a || cat /dev/null
# ignore ranlib failure; that usually means it doesn't exist, and isn't needed
-libgc.a:
- make CFLAGS="$(LIBGC_CFLAGS)" clean gc.a gcc_support.o
- mv gc.a libgc.a
- rm -f 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
-
cords: $(CORD_OBJS) cord/cordtest $(UTILS)
- rm -f on_sparc_sunos5
- ./if_mach SPARC SUNOS5 touch on_sparc_sunos5
+ rm -f on_sparc_sunos5_3
+ ./if_mach SPARC SUNOS5 touch on_sparc_sunos5_3
./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_3 $(AR) ru gc.a $(CORD_OBJS)
+ ./if_not_there on_sparc_sunos5_3 $(RANLIB) gc.a || cat /dev/null
gc_cpp.o: $(srcdir)/gc_cpp.cc $(srcdir)/gc_cpp.h $(srcdir)/gc.h Makefile
$(CXX) -c $(CXXFLAGS) $(srcdir)/gc_cpp.cc
@@ -224,11 +223,11 @@ base_lib $(UTILS)
./if_not_there test_cpp $(CXX) $(CXXFLAGS) -o test_cpp $(srcdir)/test_cpp.cc gc_cpp.o gc.a `./threadlibs`
c++: gc_cpp.o $(srcdir)/gc_cpp.h test_cpp
- rm -f on_sparc_sunos5
- ./if_mach SPARC SUNOS5 touch on_sparc_sunos5
+ rm -f on_sparc_sunos5_4
+ ./if_mach SPARC SUNOS5 touch on_sparc_sunos5_4
./if_mach SPARC SUNOS5 $(AR) rus gc.a gc_cpp.o
- ./if_not_there on_sparc_sunos5 $(AR) ru gc.a gc_cpp.o
- ./if_not_there on_sparc_sunos5 $(RANLIB) gc.a || cat /dev/null
+ ./if_not_there on_sparc_sunos5_4 $(AR) ru gc.a gc_cpp.o
+ ./if_not_there on_sparc_sunos5_4 $(RANLIB) gc.a || cat /dev/null
./test_cpp 1
echo > c++
@@ -236,8 +235,9 @@ dyn_load_sunos53.o: dyn_load.c
$(CC) $(CFLAGS) -DSUNOS53_SHARED_LIB -c $(srcdir)/dyn_load.c -o $@
# SunOS5 shared library version of the collector
-libgc.so: $(OBJS) dyn_load_sunos53.o
- $(CC) -G -o libgc.so $(OBJS) dyn_load_sunos53.o -ldl
+sunos5gc.so: $(OBJS) dyn_load_sunos53.o
+ $(CC) -G -o sunos5gc.so $(OBJS) dyn_load_sunos53.o -ldl
+ ln sunos5gc.so libgc.so
# Alpha/OSF shared library version of the collector
libalphagc.so: $(OBJS)
@@ -249,6 +249,11 @@ libirixgc.so: $(OBJS) dyn_load.o
ld -shared $(ABI_FLAG) -o libirixgc.so $(OBJS) dyn_load.o -lc
ln libirixgc.so libgc.so
+# Linux shared library version of the collector
+liblinuxgc.so: $(OBJS) dyn_load.o
+ gcc -shared -o liblinuxgc.so $(OBJS) dyn_load.o -lo
+ ln liblinuxgc.so libgc.so
+
mach_dep.o: $(srcdir)/mach_dep.c $(srcdir)/mips_sgi_mach_dep.s $(srcdir)/mips_ultrix_mach_dep.s $(srcdir)/rs6000_mach_dep.s $(UTILS)
rm -f mach_dep.o
./if_mach MIPS IRIX5 $(AS) -o mach_dep.o $(srcdir)/mips_sgi_mach_dep.s
@@ -290,17 +295,17 @@ cord/cordtest: $(srcdir)/cord/cordtest.c $(CORD_OBJS) gc.a $(UTILS)
cord/de: $(srcdir)/cord/de.c cord/cordbscs.o cord/cordxtra.o gc.a $(UTILS)
rm -f cord/de
- ./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 SPARC DRSNX $(CC) $(CFLAGS) -o cord/de $(srcdir)/cord/de.c cord/cordbscs.o cord/cordxtra.o gc.a $(CURSES) -lucb `./threadlibs`
./if_mach HP_PA "" $(CC) $(CFLAGS) -o cord/de $(srcdir)/cord/de.c cord/cordbscs.o cord/cordxtra.o gc.a $(CURSES) -ldld
./if_mach RS6000 "" $(CC) $(CFLAGS) -o cord/de $(srcdir)/cord/de.c cord/cordbscs.o cord/cordxtra.o gc.a -lcurses
- ./if_mach I386 LINUX $(CC) $(CFLAGS) -o cord/de $(srcdir)/cord/de.c cord/cordbscs.o cord/cordxtra.o gc.a -lcurses
+ ./if_mach I386 LINUX $(CC) $(CFLAGS) -o cord/de $(srcdir)/cord/de.c cord/cordbscs.o cord/cordxtra.o gc.a -lcurses `./threadlibs`
./if_mach ALPHA LINUX $(CC) $(CFLAGS) -o cord/de $(srcdir)/cord/de.c 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) `./threadlibs`
-if_mach: $(srcdir)/if_mach.c $(srcdir)/config.h
+if_mach: $(srcdir)/if_mach.c $(srcdir)/gcconfig.h
$(CC) $(CFLAGS) -o if_mach $(srcdir)/if_mach.c
-threadlibs: $(srcdir)/threadlibs.c $(srcdir)/config.h Makefile
+threadlibs: $(srcdir)/threadlibs.c $(srcdir)/gcconfig.h Makefile
$(CC) $(CFLAGS) -o threadlibs $(srcdir)/threadlibs.c
if_not_there: $(srcdir)/if_not_there.c
diff --git a/Makefile.dj b/Makefile.dj
index 979ac6f3..8e0a66b6 100644
--- a/Makefile.dj
+++ b/Makefile.dj
@@ -108,7 +108,7 @@ 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 \
+ gcconfig.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)
@@ -117,7 +117,7 @@ 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/ec.h include/private/cord_pos.h include/private/gcconfig.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 \
@@ -149,12 +149,12 @@ SPECIALCFLAGS =
all: gc.a gctest$(EXE_SUFFIX)
-pcr: PCR-Makefile gc_private.h gc_hdrs.h gc.h config.h mach_dep.o $(SRCS)
+pcr: PCR-Makefile gc_private.h gc_hdrs.h gc.h gcconfig.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
+ $(srcdir)/gcconfig.h $(srcdir)/gc_typed.h Makefile
# The dependency on Makefile is needed. Changing
# options such as -DSILENT affects the size of GC_arrays,
# invalidating all .o files that rely on gc_priv.h
@@ -249,11 +249,11 @@ 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
+if_mach$(EXE_SUFFIX): $(srcdir)/if_mach.c $(srcdir)/gcconfig.h
$(CC) $(CFLAGS) -o if_mach $(srcdir)/if_mach.c
-$(RM) if_mach
-threadlibs$(EXE_SUFFIX): $(srcdir)/threadlibs.c $(srcdir)/config.h Makefile
+threadlibs$(EXE_SUFFIX): $(srcdir)/threadlibs.c $(srcdir)/gcconfig.h Makefile
$(CC) $(CFLAGS) -o threadlibs $(srcdir)/threadlibs.c
-$(RM) threadlibs
diff --git a/PCR-Makefile b/PCR-Makefile
index 7b80637f..1eae3672 100644
--- a/PCR-Makefile
+++ b/PCR-Makefile
@@ -59,7 +59,7 @@ mach_dep.o: mach_dep.c mips_mach_dep.s rs6000_mach_dep.s if_mach if_not_there
./if_mach SPARC SUNOS5 as -o mach_dep.o sparc_mach_dep.s
./if_not_there mach_dep.o $(CC) -c $(SPECIALCFLAGS) mach_dep.c
-if_mach: if_mach.c config.h
+if_mach: if_mach.c gcconfig.h
$(CC) $(CFLAGS) -o if_mach if_mach.c
if_not_there: if_not_there.c
diff --git a/README b/README
index 98fce1ee..6789ad8c 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.13alpha2 of a conservative garbage collector for C and C++.
+This is version 4.13alpha3 of a conservative garbage collector for C and C++.
You might find a more recent version of this at
@@ -256,7 +256,7 @@ or win16 is hard.
For machines not already mentioned, or for nonstandard compilers, the
following are likely to require change:
-1. The parameters in config.h.
+1. The parameters in gcconfig.h.
The parameters that will usually require adjustment are
STACKBOTTOM, ALIGNMENT and DATASTART. Setjmp_test
prints its guesses of the first two.
@@ -273,7 +273,7 @@ following are likely to require change:
On some machines, it is difficult to obtain such a value that is
valid across a variety of MMUs, OS releases, etc. A number of
alternatives exist for using the collector in spite of this. See the
- discussion in config.h immediately preceding the various
+ discussion in gcconfig.h immediately preceding the various
definitions of STACKBOTTOM.
2. mach_dep.c.
@@ -310,7 +310,7 @@ following are likely to require change:
in gc_priv.h will need to be suitably redefined.
The incremental collector requires page dirty information, which
is acquired through routines defined in os_dep.c. Unless directed
- otherwise by config.h, these are implemented as stubs that simply
+ otherwise by gcconfig.h, these are implemented as stubs that simply
treat all pages as dirty. (This of course makes the incremental
collector much less useful.)
@@ -322,7 +322,7 @@ following are likely to require change:
For a different version of UN*X or different machines using the
Motorola 68000, Vax, SPARC, 80386, NS 32000, PC/RT, or MIPS architecture,
-it should frequently suffice to change definitions in config.h.
+it should frequently suffice to change definitions in gcconfig.h.
THE C INTERFACE TO THE ALLOCATOR
@@ -1368,9 +1368,36 @@ Since alpha1:
- USE_MMAP had some serious bugs. This caused the collector to fail
consistently on Solaris with -DSMALL_CONFIG.
- Added Linux threads support, thanks largely to Fergus Henderson.
+Since alpha2:
+ - Fixed more Linux threads problems.
+ - Changed default GC_free_space_divisor to 3 with new large block allocation.
+ (Thanks to Matthew Flatt for some measurements that suggest the old
+ value sometimes favors space too much over time.)
+ - More CYGWIN32 fixes.
+ - Integrated Tyson-Dowd's Linux-M68K port.
+ - Minor HP PA and DEC UNIX fixes from Fergus Henderson.
+ - Integrated Christoffe Raffali's Linux-SPARC changes.
+ - Allowed for one more GC fixup iteration after a full GC in incremental
+ mode. Some quick measurements suggested that this significantly
+ reduces pause times even with smaller GC_RATE values.
+ - Moved some more GC data structures into GC_arrays. This decreases
+ pause times and GC overhead, but makes debugging slightly less convenient.
+ - Fixed namespace pollution problem ("excl_table").
+ - Made GC_incremental a constant for -DSMALL_CONFIG, hopefully shrinking
+ that slightly.
+ - Added some win32 threads fixes.
+ - Integrated Ivan Demakov and David Stes' Watcom fixes.
+ - Various other minor fixes contributed by many people.
+ - Renamed config.h to gcconfig.h, since config.h tends to be used for
+ many other things.
+ - Integrated Matthew Flatt's support for 68K MacOS "far globals".
+ - Fixed up some of the dynamic library Makefile targets for consistency
+ across platforms.
+ - Fixed a USE_MMAP typo that caused out-of-memory handling to fail on Solaris.
+ - Added code to test.c to test thread creation a bit more.
+ - Integrated GC_win32_free_heap, as suggested by Ivan Demakov.
To do:
- - I have a backlog of unintegrated contributed platform-specific changes.
- 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
@@ -1383,4 +1410,8 @@ To do:
be possible to conditionally intercept mmap and use GC_exclude_static_roots.
The real fix is to walk rld data structures, which looks possible.
- Integrate MIT and DEC pthreads ports.
+ - Deal with very uneven black-listing distributions. If all the black listed
+ blocks reside in the newly allocated heap section, the heuristic for
+ temporarily ignoring black-listing fails, and the heap grows too much.
+ (This was observed in only one case, and could be worked around, but ...)
diff --git a/README.Mac b/README.Mac
index 6d2fa743..04f46825 100644
--- a/README.Mac
+++ b/README.Mac
@@ -320,7 +320,7 @@ Very few. Just one tiny in the GC, not strictly needed.
alloc dummy_to_fool_the_compiler_into_doing_things_it_currently_cant_handle;
------------
-- config.h
+- config.h [now gcconfig.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...
diff --git a/README.alpha b/README.alpha
index b187fd5b..213a13e3 100644
--- a/README.alpha
+++ b/README.alpha
@@ -5,6 +5,13 @@ 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.
+Currently there is no thread support in the standard distribution. There
+exists a separate port to DEC Unix pthreads. It should be possible to
+port the X86 Linux threads support to Alpha without much trouble.
+
+If you get asssembler errors, be sure to read the first few lines of the
+Makefile.
+
From Philippe Queinnec:
System: DEC/Alpha OSF1 v3.2, vendor cc
diff --git a/README.hp b/README.hp
index 869aaea6..b290590d 100644
--- a/README.hp
+++ b/README.hp
@@ -1,9 +1,11 @@
Dynamic loading support requires that executables be linked with -ldld.
The alternative is to build the collector without defining DYNAMIC_LOADING
-in config.h and ensuring that all garbage collectable objects are
+in gcconfig.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.
+
+There is currently no thread support.
diff --git a/README.linux b/README.linux
index ffe735bc..b4f136af 100644
--- a/README.linux
+++ b/README.linux
@@ -1,7 +1,11 @@
-See README.alpha for Linux on DEC AXP info. This file applies to
-Linux/Intel.
+See README.alpha for Linux on DEC AXP info.
-Incremental GC is supported.
+This file applies mostly to Linux/Intel IA32. Ports to Linux on an M68K
+and PowerPC are also integrated. They should behave similarly, except that
+the PowerPC port lacks incremental GC support, and it is unknown to what
+extent the Linux threads code is functional.
+
+Incremental GC is supported on Intel IA32 and M68K.
Dynamic libraries are supported on an ELF system. A static executable
should be linked with the gcc option "-Wl,-defsym,_DYNAMIC=0".
@@ -37,3 +41,10 @@ To use threads, you need to abide by the following requirements:
probably be an inconsistent state when a thread calling the loader is
is stopped for GC. (It's possible that this is fixable in the
same way it is handled for SOLARIS_THREADS, with GC_dlopen.)
+
+5) The combination of LINUX_THREADS, REDIRECT_MALLOC, and incremental
+ collection fails in seemingly random places. This hasn't been tracked
+ down yet, but is perhaps not completely astonishing. The thread package
+ uses malloc, and thus can presumably get SIGSEGVs while inside the
+ package. There is no real guarantee that signals are handled properly
+ at that point.
diff --git a/README.rs6000 b/README.rs6000
index 0444ac4c..f5630b20 100644
--- a/README.rs6000
+++ b/README.rs6000
@@ -4,3 +4,6 @@ startup. The supplied value sometimes causes failure under AIX 4.1, though
it appears to work under 3.X. HEURISTIC2 seems to work under 4.1, but
involves a substantial performance penalty, and will fail if there is
no limit on stack size.
+
+There is no thread support. (I assume recent versions of AIX provide
+pthreads? I no longer have access to a machine ...)
diff --git a/README.sgi b/README.sgi
index 186e4977..e67124b5 100644
--- a/README.sgi
+++ b/README.sgi
@@ -35,3 +35,7 @@ The garbage collector uses signals to stop threads.)
initiated. Applications with many such threads may not exhibit acceptable
performance with the collector. (Increasing the heap size may help.)
+6) The collector should not be compiled with -DREDIRECT_MALLOC. This
+confuses some library calls made by the pthreads implementation, which
+expect the standard malloc.
+
diff --git a/README.solaris2 b/README.solaris2
index 9ef4648d..e5935131 100644
--- a/README.solaris2
+++ b/README.solaris2
@@ -1,7 +1,7 @@
The collector supports both incremental collection and threads under
Solaris 2. The incremental collector normally retrieves page dirty information
through the appropriate /proc calls. But it can also be configured
-(by defining MPROTECT_VDB instead of PROC_VDB in config.h) to use mprotect
+(by defining MPROTECT_VDB instead of PROC_VDB in gcconfig.h) to use mprotect
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.
@@ -14,7 +14,7 @@ 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.
Nonetheless, under Solaris2, the collector now (since 4.12) allocates
-memory using mmap by default. (It defines USE_MMAP in config.h.)
+memory using mmap by default. (It defines USE_MMAP in gcconfig.h.)
You may want to reverse this decisions if you use -DREDIRECT_MALLOC=...
diff --git a/README.win32 b/README.win32
index 76c4c6e3..c8ea3ae5 100644
--- a/README.win32
+++ b/README.win32
@@ -23,7 +23,11 @@ the two systems, and under different versions of win32s.)
The collector test program "gctest" is linked as a GUI application,
but does not open any windows. Its output appears in the file
"gc.log". It may be started from the file manager. The hour glass
-cursor will appear as long as it's running.
+cursor will appear as long as it's running. If it is started from the
+command line, it will usually run in the background. Wait a few
+minutes (a few seconds on a modern machine) before you check the output.
+You should see either a failure indication or a "Collector appears to
+work" message.
The cord test program has not been ported (but should port
easily). A toy editor (cord/de.exe) based on cords (heavyweight
@@ -46,7 +50,7 @@ the line "include Makefile.DLLs". The latter should be necessary only
if you want to package the collector as a DLL. The GNU-win32 port is
believed to work only for b18, not b19, probably dues to linker changes
in b19. This is probably fixable with a different definition of
-DATASTART and DATAEND in config.h.
+DATASTART and DATAEND in gcconfig.h.
For Borland tools, use BCC_MAKEFILE. Note that
Borland's compiler defaults to 1 byte alignment in structures (-a1),
@@ -56,7 +60,7 @@ LEAST 4 BYTE ALIGNMENT. Thus the BORLAND DEFAULT MUST
BE OVERRIDDEN. (In my opinion, it should usually be anyway.
I expect that -a1 introduces major performance penalties on a
486 or Pentium.) Note that this changes structure layouts. (As a last
-resort, config.h can be changed to allow 1 byte alignment. But
+resort, gcconfig.h can be changed to allow 1 byte alignment. But
this has significant negative performance implications.)
The Makefile is set up to assume Borland 4.5. If you have another
version, change the line near the top. By default, it does not
@@ -97,41 +101,54 @@ test with VC++ from the command line, use
nmake /F ".\gc.mak" CFG="gctest - Win32 Release"
This requires that the subdirectory gctest\Release exist.
+The test program and DLL will reside in the Release directory.
This version relies on the collector residing in a dll.
This version currently supports incremental collection only if it is
enabled before any additional threads are created.
-It is known to not be completely solid. At a minimum it can deadlock
-if a thread starts in the middle of an allocation. There may be
-other problems. If you need solid support for win32 threads, you
-check with Geodesic Systems. I haven't tried it, but they claim
-to support it.
+Version 4.13 attempts to fix some of the earlier problems, but there
+may be other issues. If you need solid support for win32 threads, you
+might check with Geodesic Systems. Their collector must be licensed,
+but they have invested far more time in win32-specific issues.
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. ]
+The collector has been compiled with Watcom C 10.6 and 11.0.
+It runs under win32, win32s, and even under msdos with dos4gw
+dos-extender. It should also run under OS/2, though this isn't
+tested. Under win32 the collector can be built either as dll
+or as static library.
-Watcom C/C++ 10.5, 10.6, 11.0 tested.
+Note that all compilations were done under Windows 95 or NT.
+For unknown reason compiling under Windows 3.11 for NT (one
+attempt has been made) leads to broken executables.
-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.
+Incremental collection is not supported.
-OS/2 not tested, but should work (only some #ifdef's added for OS/2 port).
+cord is not ported.
-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.
+Before compiling you may need to edit WCC_MAKEFILE to set target
+platform, library type (dynamic or static), calling conventions, and
+optimization options.
-cpp_test succeeds, but not compiled automaticaly with WCC_MAKEFILE.
+To compile the collector and testing programs use the command:
+ wmake -f WCC_MAKEFILE
+All programs using gc should be compiled with 4-byte alignment.
+For further explanations on this see comments about Borland.
+
+If gc compiled as dll, the macro ``GC_DLL'' should be defined before
+including "gc.h" (for example, with -DGC_DLL compiler option). It's
+important, otherwise resulting programs will not run.
+
+Ivan Demakov (email: ivan@tgrad.nsk.su)
My changes:
- * config.h Added definitions for Watcom C/C++.
+ * gcconfig.h Added definitions for Watcom C/C++.
Undefined MPROTECT_VDB for Watcom C/C++ MSWIN32,
I don't have idea why it not work.
diff --git a/SMakefile.amiga b/SMakefile.amiga
index b1aa340e..e9602c08 100644
--- a/SMakefile.amiga
+++ b/SMakefile.amiga
@@ -1,6 +1,6 @@
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 real_malloc.o dyn_load.o dbg_mlc.o malloc.o stubborn.o checksums.o typd_mlc.o ptr_chck.o
-INC= gc_private.h gc_hdrs.h gc.h config.h
+INC= gc_private.h gc_hdrs.h gc.h gcconfig.h
all: gctest setjmp_t
diff --git a/WCC_MAKEFILE b/WCC_MAKEFILE
index cc0ef136..087ff6a3 100644
--- a/WCC_MAKEFILE
+++ b/WCC_MAKEFILE
@@ -1,95 +1,130 @@
-# Makefile for Watcom C/C++ 10.5, 10.6, 11.0 on NT, OS2 and DOS4GW .
-# May work with Watcom 10.0 .
-#
+# 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
+# Uncoment one of the lines below for cross compilation.
+SYSTEM=MSWIN32
#SYSTEM=DOS4GW
-#SYSTEM=MSWIN32
#SYSTEM=OS2
-!ifndef SYSTEM
+# The collector can be built either as dynamic or as static library.
+# Select the library type you need.
+#MAKE_AS_DLL=1
+MAKE_AS_LIB=1
-!ifdef __MSDOS__
-SYSTEM=DOS4GW
-!endif
+# Select calling conventions.
+# Possible choices are r and s.
+CALLING=s
-!ifdef __NT__
-SYSTEM=MSWIN32
-!endif
+# Select target CPU.
+# Possible choices are 3, 4, 5, and 6.
+# The last choice available only since version 11.0.
+CPU=5
-!ifdef __OS2__
-SYSTEM=OS2
-!endif
+# Set optimization options.
+# Watcom before 11.0 does not support option "-oh".
+OPTIM=-oneatx -s
+#OPTIM=-ohneatx -s
-D_SYSTEM=
+DEFS=-DALL_INTERIOR_POINTERS -DSILENT -DNO_SIGNALS #-DSMALL_CONFIG #-DGC_DEBUG
-!else
-D_SYSTEM=-D$(SYSTEM)
+#####
+!ifndef SYSTEM
+!ifdef __MSDOS__
+SYSTEM=DOS4GW
+!else ifdef __NT__
+SYSTEM=MSWIN32
+!else ifdef __OS2__
+SYSTEM=OS2
+!else
+SYSTEM=Unknown
+!endif
!endif
!define $(SYSTEM)
+!ifdef DOS4GW
+SYSFLAG=-DDOS4GW -bt=dos
+!else ifdef MSWIN32
+SYSFLAG=-DMSWIN32 -bt=nt
+!else ifdef OS2
+SYSFLAG=-DOS2 -bt=os2
+!else
+!error undefined or unsupported target platform: $(SYSTEM)
+!endif
+!ifdef MAKE_AS_DLL
+DLLFLAG=-bd -DGC_DLL
+TEST_DLLFLAG=-DGC_DLL
+!else ifdef MAKE_AS_LIB
+DLLFLAG=
+TEST_DLLFLAG=
+!else
+!error Either MAKE_AS_LIB or MAKE_AS_DLL should be defined
+!endif
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)
+# -DUSE_GENERIC is required !
+CFLAGS=-$(CPU)$(CALLING) $(OPTIM) -zp4 -zc $(SYSFLAG) $(DLLFLAG) -DGC_BUILD -DUSE_GENERIC $(DEFS)
CXXFLAGS= $(CFLAGS)
-ASFLAGS=$(CALLING)
+TEST_CFLAGS=-$(CPU)$(CALLING) $(OPTIM) -zp4 -zc $(SYSFLAG) $(TEST_DLLFLAG) $(DEFS)
+TEST_CXXFLAGS= $(TEST_CFLAGS)
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
+ typd_mlc.obj ptr_chck.obj mallocx.obj
+all: gc.lib gctest.exe test_cpp.exe
-all: gc.lib gctest.exe
+!ifdef MAKE_AS_DLL
-# this file required for DOS4GW only
-gc_watcom.obj: gc_watcom.asm WCC_MAKEFILE
- $(AS) $(ASFLAGS) gc_watcom.asm
+gc.lib: gc.dll gc_cpp.obj
+ *wlib -b -c -n -p=512 $@ +gc.dll +gc_cpp.obj
+gc.dll: $(OBJS) .AUTODEPEND
+ @%create $*.lnk
!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
+ @%append $*.lnk sys os2v2_dll
+!else ifdef MSWIN32
+ @%append $*.lnk sys nt_dll
+!else ifdef OS2
+ @%append $*.lnk sys os2v2_dll
+!endif
+ @%append $*.lnk name $*
+ @for %i in ($(OBJS)) do @%append $*.lnk file '%i'
+!ifeq CALLING s
+ @%append $*.lnk export GC_is_marked
+ @%append $*.lnk export GC_incr_words_allocd
+ @%append $*.lnk export GC_incr_mem_freed
+ @%append $*.lnk export GC_generic_malloc_words_small
+!else
+ @%append $*.lnk export GC_is_marked_
+ @%append $*.lnk export GC_incr_words_allocd_
+ @%append $*.lnk export GC_incr_mem_freed_
+ @%append $*.lnk export GC_generic_malloc_words_small_
+!endif
+ *wlink @$*.lnk
!else
-gc.lib: $(OBJS)
+gc.lib: $(OBJS) gc_cpp.obj
@%create $*.lb1
@for %i in ($(OBJS)) do @%append $*.lb1 +'%i'
+ @%append $*.lb1 +'gc_cpp.obj'
*wlib -b -c -n -p=512 $@ @$*.lb1
-!endif
+!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
+!else ifdef MSWIN32
@%append $*.lnk sys nt
-!endif
-!ifdef OS2
+!else ifdef OS2
@%append $*.lnk sys os2v2
!endif
@%append $*.lnk op case
@@ -97,8 +132,47 @@ gctest.exe: test.obj gc.lib
@%append $*.lnk name $*
@%append $*.lnk file test.obj
@%append $*.lnk library gc.lib
+!ifdef MAKE_AS_DLL
+!ifeq CALLING s
+ @%append $*.lnk import GC_is_marked gc
+!else
+ @%append $*.lnk import GC_is_marked_ gc
+!endif
+!endif
+ *wlink @$*.lnk
+test_cpp.exe: test_cpp.obj gc.lib
+ %create $*.lnk
+!ifdef DOS4GW
+ @%append $*.lnk sys dos4g
+!else ifdef MSWIN32
+ @%append $*.lnk sys nt
+!else ifdef OS2
+ @%append $*.lnk sys os2v2
+!endif
+ @%append $*.lnk op case
+ @%append $*.lnk op stack=256K
+ @%append $*.lnk name $*
+ @%append $*.lnk file test_cpp.obj
+ @%append $*.lnk library gc.lib
+!ifdef MAKE_AS_DLL
+!ifeq CALLING s
+ @%append $*.lnk import GC_incr_words_allocd gc
+ @%append $*.lnk import GC_incr_mem_freed gc
+ @%append $*.lnk import GC_generic_malloc_words_small gc
+!else
+ @%append $*.lnk import GC_incr_words_allocd_ gc
+ @%append $*.lnk import GC_incr_mem_freed_ gc
+ @%append $*.lnk import GC_generic_malloc_words_small_ gc
+!endif
+!endif
*wlink @$*.lnk
+gc_cpp.obj: gc_cpp.cc .AUTODEPEND
+ $(CXX) $(TEST_CXXFLAGS) -iinclude $*.cc
+test.obj: test.c .AUTODEPEND
+ $(CC) $(TEST_CFLAGS) $*.c
+test_cpp.obj: test_cpp.cc .AUTODEPEND
+ $(CXX) $(TEST_CXXFLAGS) -iinclude $*.cc
.c.obj: .AUTODEPEND
@@ -107,9 +181,6 @@ gctest.exe: test.obj gc.lib
.cc.obj: .AUTODEPEND
$(CXX) $(CXXFLAGS) $*.cc
-.cpp.obj: .AUTODEPEND
- $(CXX) $(CXXFLAGS) $*.cpp
-
clean : .SYMBOLIC
@if exist *.obj del *.obj
@if exist *.map del *.map
@@ -121,3 +192,5 @@ clean : .SYMBOLIC
@if exist *.lst del *.lst
@if exist *.exe del *.exe
@if exist *.log del *.log
+ @if exist *.lib del *.lib
+ @if exist *.dll del *.dll
diff --git a/allchblk.c b/allchblk.c
index 7a5a3a1c..45614ebd 100644
--- a/allchblk.c
+++ b/allchblk.c
@@ -105,6 +105,8 @@ unsigned char flags;
#else
# define LAST_TRIP 1
#endif
+
+word GC_max_hblk_size = HBLKSIZE;
/*
* Allocate (and return pointer to) a heap block
@@ -133,6 +135,8 @@ unsigned char flags; /* IGNORE_OFF_PAGE or 0 */
int trip_count = 0;
size_needed = HBLKSIZE * OBJ_SZ_TO_BLOCKS(sz);
+ if ((word)size_needed > GC_max_hblk_size)
+ GC_max_hblk_size = size_needed;
/* search for a big enough block in free list */
hbp = GC_savhbp;
@@ -159,6 +163,7 @@ unsigned char flags; /* IGNORE_OFF_PAGE or 0 */
# ifdef PRESERVE_LAST
if (size_avail != size_needed
&& !GC_incremental
+ && (word)size_needed <= GC_max_hblk_size/2
&& GC_in_last_heap_sect(hbp) && GC_should_collect()) {
continue;
}
diff --git a/alloc.c b/alloc.c
index d60544a3..d00ff07e 100644
--- a/alloc.c
+++ b/alloc.c
@@ -1,6 +1,7 @@
/*
* Copyright 1988, 1989 Hans-J. Boehm, Alan J. Demers
* Copyright (c) 1991-1994 by Xerox Corporation. All rights reserved.
+ * Copyright (c) 1998 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.
@@ -12,7 +13,6 @@
* modified is included with the above copyright notice.
*
*/
-/* Boehm, February 16, 1996 2:26 pm PST */
# include "gc_priv.h"
@@ -58,7 +58,9 @@ word GC_non_gc_bytes = 0; /* Number of bytes not intended to be collected */
word GC_gc_no = 0;
-int GC_incremental = 0; /* By default, stop the world. */
+#ifndef SMALL_CONFIG
+ int GC_incremental = 0; /* By default, stop the world. */
+#endif
int GC_full_freq = 4; /* Every 5th collection is a full */
/* collection. */
@@ -66,7 +68,7 @@ int GC_full_freq = 4; /* Every 5th collection is a full */
char * GC_copyright[] =
{"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. ",
+"Copyright (c) 1996-1998 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.",
"See source code for details." };
@@ -86,10 +88,17 @@ extern GC_bool GC_collection_in_progress();
int GC_never_stop_func GC_PROTO((void)) { return(0); }
-CLOCK_TYPE GC_start_time;
+CLOCK_TYPE GC_start_time; /* Time at which we stopped world. */
+ /* used only in GC_timeout_stop_func. */
-int GC_timeout_stop_func GC_PROTO((void))
-{
+int GC_n_attempts = 0; /* Number of attempts at finishing */
+ /* collection within TIME_LIMIT */
+
+#ifdef SMALL_CONFIG
+# define GC_timeout_stop_func GC_never_stop_func
+#else
+ int GC_timeout_stop_func GC_PROTO((void))
+ {
CLOCK_TYPE current_time;
static unsigned count = 0;
unsigned long time_diff;
@@ -100,12 +109,14 @@ int GC_timeout_stop_func GC_PROTO((void))
if (time_diff >= TIME_LIMIT) {
# ifdef PRINTSTATS
GC_printf0("Abandoning stopped marking after ");
- GC_printf1("%lu msecs\n", (unsigned long)time_diff);
+ GC_printf1("%lu msecs", (unsigned long)time_diff);
+ GC_printf1("(attempt %d)\n", (unsigned long) GC_n_attempts);
# endif
return(1);
}
return(0);
-}
+ }
+#endif /* !SMALL_CONFIG */
/* Return the minimum number of words that must be allocated between */
/* collections to amortize the collection cost. */
@@ -210,6 +221,8 @@ void GC_notify_full_gc()
void GC_maybe_gc()
{
static int n_partial_gcs = 0;
+ GC_bool is_full_gc = FALSE;
+
if (GC_should_collect()) {
if (!GC_incremental) {
GC_notify_full_gc();
@@ -228,6 +241,7 @@ void GC_maybe_gc()
GC_clear_marks();
n_partial_gcs = 0;
GC_notify_full_gc();
+ is_full_gc = TRUE;
} else {
n_partial_gcs++;
}
@@ -240,7 +254,12 @@ void GC_maybe_gc()
GC_save_callers(GC_last_stack);
# endif
GC_finish_collection();
- }
+ } else {
+ if (!is_full_gc) {
+ /* Count this as the first attempt */
+ GC_n_attempts++;
+ }
+ }
}
}
@@ -302,13 +321,20 @@ GC_stop_func stop_func;
/*
* Perform n units of garbage collection work. A unit is intended to touch
- * roughly a GC_RATE pages. Every once in a while, we do more than that.
+ * roughly GC_RATE pages. Every once in a while, we do more than that.
+ * This needa to be a fairly large number with our current incremental
+ * GC strategy, since otherwise we allocate too much during GC, and the
+ * cleanup gets expensive.
*/
-# define GC_RATE 8
+# define GC_RATE 10
+# define MAX_PRIOR_ATTEMPTS 1
+ /* Maximum number of prior attempts at world stop marking */
+ /* A value of 1 means that we finish the seconf time, no matter */
+ /* how long it takes. Doesn't count the initial root scan */
+ /* for a full GC. */
int GC_deficit = 0; /* The number of extra calls to GC_mark_some */
/* that we have made. */
- /* Negative values are equivalent to 0. */
void GC_collect_a_little_inner(n)
int n;
@@ -322,12 +348,21 @@ int n;
# ifdef SAVE_CALL_CHAIN
GC_save_callers(GC_last_stack);
# endif
- (void) GC_stopped_mark(GC_never_stop_func);
+ if (GC_n_attempts < MAX_PRIOR_ATTEMPTS) {
+ GET_TIME(GC_start_time);
+ if (!GC_stopped_mark(GC_timeout_stop_func)) {
+ GC_n_attempts++;
+ break;
+ }
+ } else {
+ (void)GC_stopped_mark(GC_never_stop_func);
+ }
GC_finish_collection();
break;
}
}
if (GC_deficit > 0) GC_deficit -= GC_RATE*n;
+ if (GC_deficit < 0) GC_deficit = 0;
} else {
GC_maybe_gc();
}
@@ -522,6 +557,7 @@ void GC_finish_collection()
(unsigned long)WORDS_TO_BYTES(GC_composite_in_use));
# endif
+ GC_n_attempts = 0;
/* Reset or increment counters for next cycle */
GC_words_allocd_before_gc += GC_words_allocd;
GC_non_gc_bytes_at_gc = GC_non_gc_bytes;
@@ -611,13 +647,19 @@ word bytes;
}
#ifdef PRESERVE_LAST
+
+GC_bool GC_protect_last_block = FALSE;
+
GC_bool GC_in_last_heap_sect(p)
ptr_t p;
{
- struct HeapSect * last_heap_sect = &(GC_heap_sects[GC_n_heap_sects-1]);
- ptr_t start = last_heap_sect -> hs_start;
+ struct HeapSect * last_heap_sect;
+ ptr_t start;
ptr_t end;
+ if (!GC_protect_last_block) return FALSE;
+ last_heap_sect = &(GC_heap_sects[GC_n_heap_sects-1]);
+ start = last_heap_sect -> hs_start;
if (p < start) return FALSE;
end = start + last_heap_sect -> hs_bytes;
if (p >= end) return FALSE;
@@ -755,6 +797,9 @@ word n;
LOCK();
if (!GC_is_initialized) GC_init_inner();
result = (int)GC_expand_hp_inner(divHBLKSZ((word)bytes));
+# ifdef PRESERVE_LAST
+ if (result) GC_protect_last_block = FALSE;
+# endif
UNLOCK();
ENABLE_SIGNALS();
return(result);
@@ -801,10 +846,18 @@ GC_bool ignore_off_page;
WARN("Out of Memory! Returning NIL!\n", 0);
return(FALSE);
}
- } else if (GC_fail_count) {
+ } else {
# ifdef PRINTSTATS
- GC_printf0("Memory available again ...\n");
+ if (GC_fail_count) {
+ GC_printf0("Memory available again ...\n");
+ }
# endif
+# ifdef PRESERVE_LAST
+ if (needed_blocks > 1) GC_protect_last_block = TRUE;
+ /* We were forced to expand the heap as the result */
+ /* of a large block allocation. Avoid breaking up */
+ /* new block into small pieces. */
+# endif
}
}
return(TRUE);
diff --git a/cord/de_win.c b/cord/de_win.c
index 119d0fa0..fedbfbe6 100644
--- a/cord/de_win.c
+++ b/cord/de_win.c
@@ -268,6 +268,7 @@ LRESULT CALLBACK WndProc (HWND hwnd, UINT message,
case WM_DESTROY:
PostQuitMessage (0);
+ GC_win32_free_heap();
return 0;
case WM_PAINT:
diff --git a/cord/gc.h b/cord/gc.h
index 09c8ca81..eb9a7f60 100644
--- a/cord/gc.h
+++ b/cord/gc.h
@@ -36,11 +36,19 @@
#endif
#if defined(_MSC_VER) && defined(_DLL)
-#ifdef GC_BUILD
-#define GC_API __declspec(dllexport)
-#else
-#define GC_API __declspec(dllimport)
+# ifdef GC_BUILD
+# define GC_API __declspec(dllexport)
+# else
+# define GC_API __declspec(dllimport)
+# endif
#endif
+
+#if defined(__WATCOMC__) && defined(GC_DLL)
+# ifdef GC_BUILD
+# define GC_API extern __declspec(dllexport)
+# else
+# define GC_API extern __declspec(dllimport)
+# endif
#endif
#ifndef GC_API
@@ -193,8 +201,8 @@ GC_API size_t GC_size GC_PROTO((GC_PTR object_addr));
/* If the argument is stubborn, the result will have changes enabled. */
/* It is an error to have changes enabled for the original object. */
/* Follows ANSI comventions for NULL old_object. */
-GC_API GC_PTR GC_realloc GC_PROTO((GC_PTR old_object,
- size_t new_size_in_bytes));
+GC_API GC_PTR GC_realloc
+ GC_PROTO((GC_PTR old_object, size_t new_size_in_bytes));
/* Explicitly increase the heap size. */
/* Returns 0 on failure, 1 on success. */
@@ -604,6 +612,10 @@ GC_API void (*GC_is_valid_displacement_print_proc)
GC_API void (*GC_is_visible_print_proc)
GC_PROTO((GC_PTR p));
+#if defined(_SOLARIS_PTHREADS) && !defined(SOLARIS_THREADS)
+# define SOLARIS_THREADS
+#endif
+
#ifdef SOLARIS_THREADS
/* We need to intercept calls to many of the threads primitives, so */
/* that we can locate thread stacks and stop the world. */
@@ -660,7 +672,10 @@ GC_API void (*GC_is_visible_print_proc)
#endif /* IRIX_THREADS || LINUX_THREADS */
-#if defined(THREADS) && !defined(SRC_M3)
+# if defined(PCR) || defined(SOLARIS_THREADS) || defined(WIN32_THREADS) || \
+ defined(IRIX_THREADS) || defined(LINUX_THREADS) || \
+ defined(IRIX_JDK_THREADS)
+ /* Any flavor of threads except SRC_M3. */
/* This returns a list of objects, linked through their first */
/* word. Its use can greatly reduce lock contention problems, since */
/* the allocation lock can be acquired and released many fewer times. */
@@ -691,6 +706,13 @@ extern void GC_thr_init(); /* Needed for Solaris/X86 */
# endif
#endif
+#if (defined(_MSDOS) || defined(_MSC_VER)) && (_M_IX86 >= 300) \
+ || defined(_WIN32)
+ /* win32S may not free all resources on process exit. */
+ /* This explicitly deallocates the heap. */
+ GC_API void GC_win32_free_heap ();
+#endif
+
#ifdef __cplusplus
} /* end of extern "C" */
#endif
diff --git a/dbg_mlc.c b/dbg_mlc.c
index 6c4b2ba5..f9ed6f3f 100644
--- a/dbg_mlc.c
+++ b/dbg_mlc.c
@@ -15,6 +15,11 @@
/* Boehm, October 9, 1995 1:16 pm PDT */
# include "gc_priv.h"
+void GC_default_print_heap_obj_proc();
+GC_API void GC_register_finalizer_no_order
+ GC_PROTO((GC_PTR obj, GC_finalization_proc fn, GC_PTR cd,
+ GC_finalization_proc *ofn, GC_PTR *ocd));
+
/* Do we want to and know how to save the call stack at the time of */
/* an allocation? How much space do we want to use in each object? */
@@ -604,6 +609,31 @@ struct closure {
}
# ifdef __STDC__
+ void GC_debug_register_finalizer_no_order
+ (GC_PTR obj, GC_finalization_proc fn,
+ GC_PTR cd, GC_finalization_proc *ofn,
+ GC_PTR *ocd)
+# else
+ void GC_debug_register_finalizer_no_order
+ (obj, fn, cd, ofn, ocd)
+ GC_PTR obj;
+ GC_finalization_proc fn;
+ GC_PTR cd;
+ GC_finalization_proc *ofn;
+ GC_PTR *ocd;
+# endif
+{
+ ptr_t base = GC_base(obj);
+ if (0 == base || (ptr_t)obj - base != sizeof(oh)) {
+ GC_err_printf1(
+ "GC_register_finalizer_no_order called with non-base-pointer 0x%lx\n",
+ obj);
+ }
+ GC_register_finalizer_no_order(base, GC_debug_invoke_finalizer,
+ GC_make_closure(fn,cd), ofn, ocd);
+ }
+
+# ifdef __STDC__
void GC_debug_register_finalizer_ignore_self
(GC_PTR obj, GC_finalization_proc fn,
GC_PTR cd, GC_finalization_proc *ofn,
diff --git a/dyn_load.c b/dyn_load.c
index 0785a6e9..c2284470 100644
--- a/dyn_load.c
+++ b/dyn_load.c
@@ -47,7 +47,7 @@
#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__)) && \
+ !defined(HP_PA) && !(defined(LINUX) && defined(__ELF__)) && \
!defined(RS6000) && !defined(SCO_ELF)
--> We only know how to find data segments of dynamic libraries for the
--> above. Additional SVR4 variants might not be too
diff --git a/finalize.c b/finalize.c
index d825bf91..8a65b936 100644
--- a/finalize.c
+++ b/finalize.c
@@ -648,8 +648,9 @@ void GC_enqueue_all_finalizers()
* which can make the runtime guarantee that all finalizers are run.
* Unfortunately, the Java standard implies we have to keep running
* finalizers until there are no more left, a potential infinite loop.
- * YUCK. * This routine is externally callable, so is called without
- * the allocation lock
+ * YUCK.
+ * This routine is externally callable, so is called without
+ * the allocation lock.
*/
void GC_finalize_all()
{
diff --git a/gc.h b/gc.h
index 09c8ca81..eb9a7f60 100644
--- a/gc.h
+++ b/gc.h
@@ -36,11 +36,19 @@
#endif
#if defined(_MSC_VER) && defined(_DLL)
-#ifdef GC_BUILD
-#define GC_API __declspec(dllexport)
-#else
-#define GC_API __declspec(dllimport)
+# ifdef GC_BUILD
+# define GC_API __declspec(dllexport)
+# else
+# define GC_API __declspec(dllimport)
+# endif
#endif
+
+#if defined(__WATCOMC__) && defined(GC_DLL)
+# ifdef GC_BUILD
+# define GC_API extern __declspec(dllexport)
+# else
+# define GC_API extern __declspec(dllimport)
+# endif
#endif
#ifndef GC_API
@@ -193,8 +201,8 @@ GC_API size_t GC_size GC_PROTO((GC_PTR object_addr));
/* If the argument is stubborn, the result will have changes enabled. */
/* It is an error to have changes enabled for the original object. */
/* Follows ANSI comventions for NULL old_object. */
-GC_API GC_PTR GC_realloc GC_PROTO((GC_PTR old_object,
- size_t new_size_in_bytes));
+GC_API GC_PTR GC_realloc
+ GC_PROTO((GC_PTR old_object, size_t new_size_in_bytes));
/* Explicitly increase the heap size. */
/* Returns 0 on failure, 1 on success. */
@@ -604,6 +612,10 @@ GC_API void (*GC_is_valid_displacement_print_proc)
GC_API void (*GC_is_visible_print_proc)
GC_PROTO((GC_PTR p));
+#if defined(_SOLARIS_PTHREADS) && !defined(SOLARIS_THREADS)
+# define SOLARIS_THREADS
+#endif
+
#ifdef SOLARIS_THREADS
/* We need to intercept calls to many of the threads primitives, so */
/* that we can locate thread stacks and stop the world. */
@@ -660,7 +672,10 @@ GC_API void (*GC_is_visible_print_proc)
#endif /* IRIX_THREADS || LINUX_THREADS */
-#if defined(THREADS) && !defined(SRC_M3)
+# if defined(PCR) || defined(SOLARIS_THREADS) || defined(WIN32_THREADS) || \
+ defined(IRIX_THREADS) || defined(LINUX_THREADS) || \
+ defined(IRIX_JDK_THREADS)
+ /* Any flavor of threads except SRC_M3. */
/* This returns a list of objects, linked through their first */
/* word. Its use can greatly reduce lock contention problems, since */
/* the allocation lock can be acquired and released many fewer times. */
@@ -691,6 +706,13 @@ extern void GC_thr_init(); /* Needed for Solaris/X86 */
# endif
#endif
+#if (defined(_MSDOS) || defined(_MSC_VER)) && (_M_IX86 >= 300) \
+ || defined(_WIN32)
+ /* win32S may not free all resources on process exit. */
+ /* This explicitly deallocates the heap. */
+ GC_API void GC_win32_free_heap ();
+#endif
+
#ifdef __cplusplus
} /* end of extern "C" */
#endif
diff --git a/gc.mak b/gc.mak
index fdd0c9c6..0fd22b70 100644
--- a/gc.mak
+++ b/gc.mak
@@ -5,7 +5,7 @@
# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102
!IF "$(CFG)" == ""
-CFG=cord - Win32 Debug
+CFG=gctest - Win32 Release
!MESSAGE No configuration specified. Defaulting to cord - Win32 Debug.
!ENDIF
@@ -768,7 +768,7 @@ SOURCE=.\reclaim.c
!IF "$(CFG)" == "gc - Win32 Release"
DEP_CPP_RECLA=\
- ".\config.h"\
+ ".\gcconfig.h"\
".\gc.h"\
".\gc_hdrs.h"\
".\gc_priv.h"\
@@ -788,7 +788,7 @@ NODEP_CPP_RECLA=\
!ELSEIF "$(CFG)" == "gc - Win32 Debug"
DEP_CPP_RECLA=\
- ".\config.h"\
+ ".\gcconfig.h"\
".\gc.h"\
".\gc_hdrs.h"\
".\gc_priv.h"\
@@ -816,7 +816,7 @@ SOURCE=.\os_dep.c
!IF "$(CFG)" == "gc - Win32 Release"
DEP_CPP_OS_DE=\
- ".\config.h"\
+ ".\gcconfig.h"\
".\gc.h"\
".\gc_hdrs.h"\
".\gc_priv.h"\
@@ -840,7 +840,7 @@ NODEP_CPP_OS_DE=\
!ELSEIF "$(CFG)" == "gc - Win32 Debug"
DEP_CPP_OS_DE=\
- ".\config.h"\
+ ".\gcconfig.h"\
".\gc.h"\
".\gc_hdrs.h"\
".\gc_priv.h"\
@@ -872,7 +872,7 @@ SOURCE=.\misc.c
!IF "$(CFG)" == "gc - Win32 Release"
DEP_CPP_MISC_=\
- ".\config.h"\
+ ".\gcconfig.h"\
".\gc.h"\
".\gc_hdrs.h"\
".\gc_priv.h"\
@@ -893,7 +893,7 @@ NODEP_CPP_MISC_=\
!ELSEIF "$(CFG)" == "gc - Win32 Debug"
DEP_CPP_MISC_=\
- ".\config.h"\
+ ".\gcconfig.h"\
".\gc.h"\
".\gc_hdrs.h"\
".\gc_priv.h"\
@@ -922,7 +922,7 @@ SOURCE=.\mark_rts.c
!IF "$(CFG)" == "gc - Win32 Release"
DEP_CPP_MARK_=\
- ".\config.h"\
+ ".\gcconfig.h"\
".\gc.h"\
".\gc_hdrs.h"\
".\gc_priv.h"\
@@ -942,7 +942,7 @@ NODEP_CPP_MARK_=\
!ELSEIF "$(CFG)" == "gc - Win32 Debug"
DEP_CPP_MARK_=\
- ".\config.h"\
+ ".\gcconfig.h"\
".\gc.h"\
".\gc_hdrs.h"\
".\gc_priv.h"\
@@ -970,7 +970,7 @@ SOURCE=.\mach_dep.c
!IF "$(CFG)" == "gc - Win32 Release"
DEP_CPP_MACH_=\
- ".\config.h"\
+ ".\gcconfig.h"\
".\gc.h"\
".\gc_hdrs.h"\
".\gc_priv.h"\
@@ -990,7 +990,7 @@ NODEP_CPP_MACH_=\
!ELSEIF "$(CFG)" == "gc - Win32 Debug"
DEP_CPP_MACH_=\
- ".\config.h"\
+ ".\gcconfig.h"\
".\gc.h"\
".\gc_hdrs.h"\
".\gc_priv.h"\
@@ -1018,7 +1018,7 @@ SOURCE=.\headers.c
!IF "$(CFG)" == "gc - Win32 Release"
DEP_CPP_HEADE=\
- ".\config.h"\
+ ".\gcconfig.h"\
".\gc.h"\
".\gc_hdrs.h"\
".\gc_priv.h"\
@@ -1038,7 +1038,7 @@ NODEP_CPP_HEADE=\
!ELSEIF "$(CFG)" == "gc - Win32 Debug"
DEP_CPP_HEADE=\
- ".\config.h"\
+ ".\gcconfig.h"\
".\gc.h"\
".\gc_hdrs.h"\
".\gc_priv.h"\
@@ -1066,7 +1066,7 @@ SOURCE=.\alloc.c
!IF "$(CFG)" == "gc - Win32 Release"
DEP_CPP_ALLOC=\
- ".\config.h"\
+ ".\gcconfig.h"\
".\gc.h"\
".\gc_hdrs.h"\
".\gc_priv.h"\
@@ -1086,7 +1086,7 @@ NODEP_CPP_ALLOC=\
!ELSEIF "$(CFG)" == "gc - Win32 Debug"
DEP_CPP_ALLOC=\
- ".\config.h"\
+ ".\gcconfig.h"\
".\gc.h"\
".\gc_hdrs.h"\
".\gc_priv.h"\
@@ -1114,7 +1114,7 @@ SOURCE=.\allchblk.c
!IF "$(CFG)" == "gc - Win32 Release"
DEP_CPP_ALLCH=\
- ".\config.h"\
+ ".\gcconfig.h"\
".\gc.h"\
".\gc_hdrs.h"\
".\gc_priv.h"\
@@ -1134,7 +1134,7 @@ NODEP_CPP_ALLCH=\
!ELSEIF "$(CFG)" == "gc - Win32 Debug"
DEP_CPP_ALLCH=\
- ".\config.h"\
+ ".\gcconfig.h"\
".\gc.h"\
".\gc_hdrs.h"\
".\gc_priv.h"\
@@ -1162,7 +1162,7 @@ SOURCE=.\stubborn.c
!IF "$(CFG)" == "gc - Win32 Release"
DEP_CPP_STUBB=\
- ".\config.h"\
+ ".\gcconfig.h"\
".\gc.h"\
".\gc_hdrs.h"\
".\gc_priv.h"\
@@ -1182,7 +1182,7 @@ NODEP_CPP_STUBB=\
!ELSEIF "$(CFG)" == "gc - Win32 Debug"
DEP_CPP_STUBB=\
- ".\config.h"\
+ ".\gcconfig.h"\
".\gc.h"\
".\gc_hdrs.h"\
".\gc_priv.h"\
@@ -1210,7 +1210,7 @@ SOURCE=.\obj_map.c
!IF "$(CFG)" == "gc - Win32 Release"
DEP_CPP_OBJ_M=\
- ".\config.h"\
+ ".\gcconfig.h"\
".\gc.h"\
".\gc_hdrs.h"\
".\gc_priv.h"\
@@ -1230,7 +1230,7 @@ NODEP_CPP_OBJ_M=\
!ELSEIF "$(CFG)" == "gc - Win32 Debug"
DEP_CPP_OBJ_M=\
- ".\config.h"\
+ ".\gcconfig.h"\
".\gc.h"\
".\gc_hdrs.h"\
".\gc_priv.h"\
@@ -1258,7 +1258,7 @@ SOURCE=.\new_hblk.c
!IF "$(CFG)" == "gc - Win32 Release"
DEP_CPP_NEW_H=\
- ".\config.h"\
+ ".\gcconfig.h"\
".\gc.h"\
".\gc_hdrs.h"\
".\gc_priv.h"\
@@ -1278,7 +1278,7 @@ NODEP_CPP_NEW_H=\
!ELSEIF "$(CFG)" == "gc - Win32 Debug"
DEP_CPP_NEW_H=\
- ".\config.h"\
+ ".\gcconfig.h"\
".\gc.h"\
".\gc_hdrs.h"\
".\gc_priv.h"\
@@ -1306,7 +1306,7 @@ SOURCE=.\mark.c
!IF "$(CFG)" == "gc - Win32 Release"
DEP_CPP_MARK_C=\
- ".\config.h"\
+ ".\gcconfig.h"\
".\gc.h"\
".\gc_hdrs.h"\
".\gc_mark.h"\
@@ -1327,7 +1327,7 @@ NODEP_CPP_MARK_C=\
!ELSEIF "$(CFG)" == "gc - Win32 Debug"
DEP_CPP_MARK_C=\
- ".\config.h"\
+ ".\gcconfig.h"\
".\gc.h"\
".\gc_hdrs.h"\
".\gc_mark.h"\
@@ -1356,7 +1356,7 @@ SOURCE=.\malloc.c
!IF "$(CFG)" == "gc - Win32 Release"
DEP_CPP_MALLO=\
- ".\config.h"\
+ ".\gcconfig.h"\
".\gc.h"\
".\gc_hdrs.h"\
".\gc_priv.h"\
@@ -1376,7 +1376,7 @@ NODEP_CPP_MALLO=\
!ELSEIF "$(CFG)" == "gc - Win32 Debug"
DEP_CPP_MALLO=\
- ".\config.h"\
+ ".\gcconfig.h"\
".\gc.h"\
".\gc_hdrs.h"\
".\gc_priv.h"\
@@ -1404,7 +1404,7 @@ SOURCE=.\mallocx.c
!IF "$(CFG)" == "gc - Win32 Release"
DEP_CPP_MALLX=\
- ".\config.h"\
+ ".\gcconfig.h"\
".\gc.h"\
".\gc_hdrs.h"\
".\gc_priv.h"\
@@ -1424,7 +1424,7 @@ NODEP_CPP_MALLX=\
!ELSEIF "$(CFG)" == "gc - Win32 Debug"
DEP_CPP_MALLX=\
- ".\config.h"\
+ ".\gcconfig.h"\
".\gc.h"\
".\gc_hdrs.h"\
".\gc_priv.h"\
@@ -1452,7 +1452,7 @@ SOURCE=.\finalize.c
!IF "$(CFG)" == "gc - Win32 Release"
DEP_CPP_FINAL=\
- ".\config.h"\
+ ".\gcconfig.h"\
".\gc.h"\
".\gc_hdrs.h"\
".\gc_mark.h"\
@@ -1473,7 +1473,7 @@ NODEP_CPP_FINAL=\
!ELSEIF "$(CFG)" == "gc - Win32 Debug"
DEP_CPP_FINAL=\
- ".\config.h"\
+ ".\gcconfig.h"\
".\gc.h"\
".\gc_hdrs.h"\
".\gc_mark.h"\
@@ -1502,7 +1502,7 @@ SOURCE=.\dbg_mlc.c
!IF "$(CFG)" == "gc - Win32 Release"
DEP_CPP_DBG_M=\
- ".\config.h"\
+ ".\gcconfig.h"\
".\gc.h"\
".\gc_hdrs.h"\
".\gc_priv.h"\
@@ -1522,7 +1522,7 @@ NODEP_CPP_DBG_M=\
!ELSEIF "$(CFG)" == "gc - Win32 Debug"
DEP_CPP_DBG_M=\
- ".\config.h"\
+ ".\gcconfig.h"\
".\gc.h"\
".\gc_hdrs.h"\
".\gc_priv.h"\
@@ -1550,7 +1550,7 @@ SOURCE=.\blacklst.c
!IF "$(CFG)" == "gc - Win32 Release"
DEP_CPP_BLACK=\
- ".\config.h"\
+ ".\gcconfig.h"\
".\gc.h"\
".\gc_hdrs.h"\
".\gc_priv.h"\
@@ -1570,7 +1570,7 @@ NODEP_CPP_BLACK=\
!ELSEIF "$(CFG)" == "gc - Win32 Debug"
DEP_CPP_BLACK=\
- ".\config.h"\
+ ".\gcconfig.h"\
".\gc.h"\
".\gc_hdrs.h"\
".\gc_priv.h"\
@@ -1598,7 +1598,7 @@ SOURCE=.\typd_mlc.c
!IF "$(CFG)" == "gc - Win32 Release"
DEP_CPP_TYPD_=\
- ".\config.h"\
+ ".\gcconfig.h"\
".\gc.h"\
".\gc_hdrs.h"\
".\gc_mark.h"\
@@ -1620,7 +1620,7 @@ NODEP_CPP_TYPD_=\
!ELSEIF "$(CFG)" == "gc - Win32 Debug"
DEP_CPP_TYPD_=\
- ".\config.h"\
+ ".\gcconfig.h"\
".\gc.h"\
".\gc_hdrs.h"\
".\gc_mark.h"\
@@ -1650,7 +1650,7 @@ SOURCE=.\ptr_chck.c
!IF "$(CFG)" == "gc - Win32 Release"
DEP_CPP_PTR_C=\
- ".\config.h"\
+ ".\gcconfig.h"\
".\gc.h"\
".\gc_hdrs.h"\
".\gc_mark.h"\
@@ -1671,7 +1671,7 @@ NODEP_CPP_PTR_C=\
!ELSEIF "$(CFG)" == "gc - Win32 Debug"
DEP_CPP_PTR_C=\
- ".\config.h"\
+ ".\gcconfig.h"\
".\gc.h"\
".\gc_hdrs.h"\
".\gc_mark.h"\
@@ -1700,7 +1700,7 @@ SOURCE=.\dyn_load.c
!IF "$(CFG)" == "gc - Win32 Release"
DEP_CPP_DYN_L=\
- ".\config.h"\
+ ".\gcconfig.h"\
".\gc.h"\
".\gc_hdrs.h"\
".\gc_priv.h"\
@@ -1723,7 +1723,7 @@ NODEP_CPP_DYN_L=\
!ELSEIF "$(CFG)" == "gc - Win32 Debug"
DEP_CPP_DYN_L=\
- ".\config.h"\
+ ".\gcconfig.h"\
".\gc.h"\
".\gc_hdrs.h"\
".\gc_priv.h"\
@@ -1754,7 +1754,7 @@ SOURCE=.\win32_threads.c
!IF "$(CFG)" == "gc - Win32 Release"
DEP_CPP_WIN32=\
- ".\config.h"\
+ ".\gcconfig.h"\
".\gc.h"\
".\gc_hdrs.h"\
".\gc_priv.h"\
@@ -1774,7 +1774,7 @@ NODEP_CPP_WIN32=\
!ELSEIF "$(CFG)" == "gc - Win32 Debug"
DEP_CPP_WIN32=\
- ".\config.h"\
+ ".\gcconfig.h"\
".\gc.h"\
".\gc_hdrs.h"\
".\gc_priv.h"\
@@ -1802,7 +1802,7 @@ SOURCE=.\checksums.c
!IF "$(CFG)" == "gc - Win32 Release"
DEP_CPP_CHECK=\
- ".\config.h"\
+ ".\gcconfig.h"\
".\gc.h"\
".\gc_hdrs.h"\
".\gc_priv.h"\
@@ -1822,7 +1822,7 @@ NODEP_CPP_CHECK=\
!ELSEIF "$(CFG)" == "gc - Win32 Debug"
DEP_CPP_CHECK=\
- ".\config.h"\
+ ".\gcconfig.h"\
".\gc.h"\
".\gc_hdrs.h"\
".\gc_priv.h"\
@@ -1878,7 +1878,7 @@ NODEP_CPP_CHECK=\
SOURCE=.\test.c
DEP_CPP_TEST_=\
- ".\config.h"\
+ ".\gcconfig.h"\
".\gc.h"\
".\gc_hdrs.h"\
".\gc_priv.h"\
diff --git a/gc_cpp.cc b/gc_cpp.cc
index a766a01a..547c56f9 100644
--- a/gc_cpp.cc
+++ b/gc_cpp.cc
@@ -32,6 +32,20 @@ void* operator new( size_t size ) {
void operator delete( void* obj ) {
GC_FREE( obj );}
+#ifdef _MSC_VER
+// This new operator is used by VC++ in case of Debug builds !
+void* operator new( size_t size,
+ int ,//nBlockUse,
+ const char * szFileName,
+ int nLine
+ ) {
+# ifndef GC_DEBUG
+ return GC_malloc_uncollectable( size );
+# else
+ return GC_debug_malloc_uncollectable(size, szFileName, nLine);
+# endif
+}
+#endif
#ifdef OPERATOR_NEW_ARRAY
diff --git a/gc_cpp.h b/gc_cpp.h
index e2f456fb..a591d368 100644
--- a/gc_cpp.h
+++ b/gc_cpp.h
@@ -133,7 +133,8 @@ uses explicit invocation.
#endif
#if ! defined( OPERATOR_NEW_ARRAY ) \
- && (__BORLANDC__ >= 0x450 || (__GNUC__ >= 2 && __GNUC_MINOR__ >= 6))
+ && (__BORLANDC__ >= 0x450 || (__GNUC__ >= 2 && __GNUC_MINOR__ >= 6) \
+ || __WATCOMC__ >= 1050)
# define OPERATOR_NEW_ARRAY
#endif
diff --git a/gc_mark.h b/gc_mark.h
index ade98a91..d19f7f20 100644
--- a/gc_mark.h
+++ b/gc_mark.h
@@ -38,12 +38,17 @@
/* subset of the places the conservative marker would. It must be safe */
/* to invoke the normal mark procedure instead. */
# define PROC_BYTES 100
-typedef struct ms_entry * (*mark_proc)(/* word * addr, mark_stack_ptr,
- mark_stack_limit, env */);
+/* The real declarations of the following are in gc_priv.h, so that */
+/* we can avoid scanning the following table. */
+/*
+typedef struct ms_entry * (*mark_proc)( word * addr, mark_stack_ptr,
+ mark_stack_limit, env );
# define LOG_MAX_MARK_PROCS 6
# define MAX_MARK_PROCS (1 << LOG_MAX_MARK_PROCS)
extern mark_proc GC_mark_procs[MAX_MARK_PROCS];
+*/
+
extern word GC_n_mark_procs;
/* Object descriptors on mark stack or in objects. Low order two */
diff --git a/gc_priv.h b/gc_priv.h
index 96ba1da1..df7db8e9 100644
--- a/gc_priv.h
+++ b/gc_priv.h
@@ -42,7 +42,7 @@ typedef GC_word word;
typedef GC_signed_word signed_word;
# ifndef CONFIG_H
-# include "config.h"
+# include "gcconfig.h"
# endif
# ifndef HEADERS_H
@@ -475,7 +475,7 @@ void GC_print_callers (/* struct callinfo info[NFRAMES] */);
}
# define EXIT_GC() GC_collecting = 0;
# endif /* LINUX_THREADS */
-# ifdef IRIX_THREADS
+# if defined(IRIX_THREADS) || defined(IRIX_JDK_THREADS)
# include <pthread.h>
# include <mutex.h>
@@ -513,7 +513,7 @@ void GC_print_callers (/* struct callinfo info[NFRAMES] */);
GC_collecting = 1; \
}
# define EXIT_GC() GC_collecting = 0;
-# endif /* IRIX_THREADS */
+# endif /* IRIX_THREADS || IRIX_JDK_THREADS */
# ifdef WIN32_THREADS
# include <windows.h>
GC_API CRITICAL_SECTION GC_allocate_ml;
@@ -567,7 +567,7 @@ void GC_print_callers (/* struct callinfo info[NFRAMES] */);
# if defined(SRC_M3) || defined(AMIGA) || defined(SOLARIS_THREADS) \
|| defined(MSWIN32) || defined(MACOS) || defined(DJGPP) \
|| defined(NO_SIGNALS) || defined(IRIX_THREADS) \
- || defined(LINUX_THREADS)
+ || defined(IRIX_JDK_THREADS) || defined(LINUX_THREADS)
/* Also useful for debugging. */
/* Should probably use thr_sigsetmask for SOLARIS_THREADS. */
# define DISABLE_SIGNALS()
@@ -595,7 +595,8 @@ void GC_print_callers (/* struct callinfo info[NFRAMES] */);
PCR_waitForever);
# else
# if defined(SOLARIS_THREADS) || defined(WIN32_THREADS) \
- || defined(IRIX_THREADS) || defined(LINUX_THREADS)
+ || defined(IRIX_THREADS) || defined(LINUX_THREADS) \
+ || defined(IRIX_JDK_THREADS)
void GC_stop_world();
void GC_start_world();
# define STOP_WORLD() GC_stop_world()
@@ -864,7 +865,69 @@ struct hblk {
/* Object free list link */
# define obj_link(p) (*(ptr_t *)(p))
-/* lists of all heap blocks and free lists */
+/* The type of mark procedures. This really belongs in gc_mark.h. */
+/* But we put it here, so that we can avoid scanning the mark proc */
+/* table. */
+typedef struct ms_entry * (*mark_proc)(/* word * addr, mark_stack_ptr,
+ mark_stack_limit, env */);
+# define LOG_MAX_MARK_PROCS 6
+# define MAX_MARK_PROCS (1 << LOG_MAX_MARK_PROCS)
+
+/* Root sets. Logically private to mark_rts.c. But we don't want the */
+/* tables scanned, so we put them here. */
+/* 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
+# ifdef PCR
+# define MAX_ROOT_SETS 1024
+# else
+# ifdef MSWIN32
+# define MAX_ROOT_SETS 512
+ /* Under NT, we add only written pages, which can result */
+ /* in many small root sets. */
+# else
+# define MAX_ROOT_SETS 64
+# endif
+# endif
+# endif
+
+# define MAX_EXCLUSIONS (MAX_ROOT_SETS/4)
+/* Maximum number of segments that can be excluded from root sets. */
+
+/*
+ * Data structure for excluded static roots.
+ */
+struct exclusion {
+ ptr_t e_start;
+ ptr_t e_end;
+};
+
+/* 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 */
+/* we resort to sequential search, and pay the price. */
+struct roots {
+ ptr_t r_start;
+ ptr_t r_end;
+# ifndef MSWIN32
+ struct roots * r_next;
+# endif
+ GC_bool r_tmp;
+ /* Delete before registering new dynamic libraries */
+};
+
+#ifndef MSWIN32
+ /* Size of hash table index to roots. */
+# define LOG_RT_SIZE 6
+# define RT_SIZE (1 << LOG_RT_SIZE) /* Power of 2, may be != MAX_ROOT_SETS */
+#endif
+
+/* Lists of all heap blocks and free lists */
+/* as well as other random data structures */
+/* that should not be scanned by the */
+/* collector. */
/* These are grouped together in a struct */
/* so that they can be easily skipped by the */
/* GC_mark routine. */
@@ -904,7 +967,10 @@ struct _GC_arrays {
word _mem_freed;
/* Number of explicitly deallocated words of memory */
/* since last collection. */
-
+ mark_proc _mark_procs[MAX_MARK_PROCS];
+ /* Table of user-defined mark procedures. There is */
+ /* a small number of these, which can be referenced */
+ /* by DS_PROC mark descriptors. See gc_mark.h. */
ptr_t _objfreelist[MAXOBJSZ+1];
/* free list for objects */
ptr_t _aobjfreelist[MAXOBJSZ+1];
@@ -986,17 +1052,24 @@ struct _GC_arrays {
/* GC_modws_valid_offsets[i%sizeof(word)] */
# endif
# ifdef STUBBORN_ALLOC
- page_hash_table _changed_pages;
+ page_hash_table _changed_pages;
/* Stubborn object pages that were changes since last call to */
/* GC_read_changed. */
- page_hash_table _prev_changed_pages;
+ page_hash_table _prev_changed_pages;
/* Stubborn object pages that were changes before last call to */
/* GC_read_changed. */
# endif
# if defined(PROC_VDB) || defined(MPROTECT_VDB)
- page_hash_table _grungy_pages; /* Pages that were dirty at last */
+ page_hash_table _grungy_pages; /* Pages that were dirty at last */
/* GC_read_dirty. */
# endif
+# ifdef MPROTECT_VDB
+ VOLATILE page_hash_table _dirty_pages;
+ /* Pages dirtied since last GC_read_dirty. */
+# endif
+# ifdef PROC_VDB
+ page_hash_table _written_pages; /* Pages ever dirtied */
+# endif
# ifdef LARGE_CONFIG
# if CPP_WORDSZ > 32
# define MAX_HEAP_SECTS 4096 /* overflows at roughly 64 GB */
@@ -1013,6 +1086,11 @@ struct _GC_arrays {
ptr_t _heap_bases[MAX_HEAP_SECTS];
/* Start address of memory regions obtained from kernel. */
# endif
+ struct roots _static_roots[MAX_ROOT_SETS];
+# ifndef MSWIN32
+ struct roots * _root_index[RT_SIZE];
+# endif
+ struct exclusion _excl_table[MAX_EXCLUSIONS];
/* Block header index; see gc_headers.h */
bottom_index * _all_nils;
bottom_index * _top_index [TOP_SZ];
@@ -1049,6 +1127,7 @@ GC_API GC_FAR struct _GC_arrays GC_arrays;
# define GC_words_finalized GC_arrays._words_finalized
# define GC_non_gc_bytes_at_gc GC_arrays._non_gc_bytes_at_gc
# define GC_mem_freed GC_arrays._mem_freed
+# define GC_mark_procs GC_arrays._mark_procs
# define GC_heapsize GC_arrays._heapsize
# define GC_max_heapsize GC_arrays._max_heapsize
# define GC_words_allocd_before_gc GC_arrays._words_allocd_before_gc
@@ -1057,11 +1136,20 @@ GC_API GC_FAR struct _GC_arrays GC_arrays;
# ifdef MSWIN32
# define GC_heap_bases GC_arrays._heap_bases
# endif
+# define GC_static_roots GC_arrays._static_roots
+# define GC_root_index GC_arrays._root_index
+# define GC_excl_table GC_arrays._excl_table
# define GC_all_nils GC_arrays._all_nils
# define GC_top_index GC_arrays._top_index
# if defined(PROC_VDB) || defined(MPROTECT_VDB)
# define GC_grungy_pages GC_arrays._grungy_pages
# endif
+# ifdef MPROTECT_VDB
+# define GC_dirty_pages GC_arrays._dirty_pages
+# endif
+# ifdef PROC_VDB
+# define GC_written_pages GC_arrays._written_pages
+# endif
# ifdef GATHERSTATS
# define GC_composite_in_use GC_arrays._composite_in_use
# define GC_atomic_in_use GC_arrays._atomic_in_use
@@ -1073,11 +1161,9 @@ GC_API GC_FAR struct _GC_arrays GC_arrays;
# define beginGC_arrays ((ptr_t)(&GC_arrays))
# define endGC_arrays (((ptr_t)(&GC_arrays)) + (sizeof GC_arrays))
-GC_API word GC_fo_entries;
-
+/* Object kinds: */
# define MAXOBJKINDS 16
-/* Object kinds: */
extern struct obj_kind {
ptr_t *ok_freelist; /* Array of free listheaders for this kind of object */
/* Point either to GC_arrays or to storage allocated */
@@ -1091,8 +1177,14 @@ extern struct obj_kind {
/* Add object size in bytes to descriptor */
/* template to obtain descriptor. Otherwise */
/* template is used as is. */
- GC_bool ok_init; /* Clear objects before putting them on the free list. */
+ GC_bool ok_init; /* Clear objects before putting them on the free list. */
} GC_obj_kinds[MAXOBJKINDS];
+
+# define endGC_obj_kinds (((ptr_t)(&GC_obj_kinds)) + (sizeof GC_obj_kinds))
+
+# define end_gc_area ((ptr_t)endGC_arrays == (ptr_t)(&GC_obj_kinds) ? \
+ endGC_obj_kinds : endGC_arrays)
+
/* Predefined kinds: */
# define PTRFREE 0
# define NORMAL 1
@@ -1108,6 +1200,8 @@ extern struct obj_kind {
extern int GC_n_kinds;
+GC_API word GC_fo_entries;
+
extern word GC_n_heap_sects; /* Number of separately added heap */
/* sections. */
@@ -1142,7 +1236,13 @@ extern GC_bool GC_is_initialized; /* GC_init() has been run. */
extern GC_bool GC_objects_are_marked; /* There are marked objects in */
/* the heap. */
-extern GC_bool GC_incremental; /* Using incremental/generational collection. */
+#ifndef SMALL_CONFIG
+ extern GC_bool GC_incremental;
+ /* Using incremental/generational collection. */
+#else
+# define GC_incremental TRUE
+ /* Hopefully allow optimizer to remove some code. */
+#endif
extern GC_bool GC_dirty_maintained;
/* Dirty bits are being maintained, */
@@ -1403,7 +1503,7 @@ GC_bool GC_collect_or_expand(/* needed_blocks */);
/* blocks available. Should be called */
/* until the blocks are available or */
/* until it fails by returning FALSE. */
-void GC_init(); /* Initialize collector. */
+GC_API void GC_init(); /* Initialize collector. */
void GC_collect_a_little_inner(/* int n */);
/* Do n units worth of garbage */
/* collection work, if appropriate. */
@@ -1491,7 +1591,7 @@ void GC_write_hint(/* struct hblk * h */);
void GC_dirty_init();
/* Slow/general mark bit manipulation: */
-GC_bool GC_is_marked();
+GC_API GC_bool GC_is_marked();
void GC_clear_mark_bit();
void GC_set_mark_bit();
diff --git a/config.h b/gcconfig.h
index fc8004ce..e550e944 100644
--- a/config.h
+++ b/gcconfig.h
@@ -22,6 +22,11 @@
/* Machine specific parts contributed by various people. See README file. */
+/* First a unified test for Linux: */
+# if defined(linux) || defined(__linux__)
+# define LINUX
+# endif
+
/* Determine the machine type: */
# if defined(sun) && defined(mc68000)
# define M68K
@@ -90,7 +95,7 @@
# endif
# define mach_type_known
# endif
-# if defined(sparc) && defined(unix) && !defined(sun)
+# if defined(sparc) && defined(unix) && !defined(sun) && !defined(linux)
# define SPARC
# define DRSNX
# define mach_type_known
@@ -114,25 +119,31 @@
# define SYSV
# define mach_type_known
# endif
-# if defined(_PA_RISC1_0) || defined(_PA_RISC1_1)
+# if defined(_PA_RISC1_0) || defined(_PA_RISC1_1) \
+ || defined(hppa) || defined(__hppa__)
# define HP_PA
# define mach_type_known
# endif
-# if defined(linux) && defined(i386)
+# if defined(LINUX) && defined(i386)
# define I386
-# define LINUX
# define mach_type_known
# endif
-# if defined(linux) && defined(powerpc)
+# if defined(LINUX) && defined(powerpc)
# define POWERPC
+# define mach_type_known
+# endif
+# if defined(LINUX) && defined(__mc68000__)
+# define M68K
+# define mach_type_known
+# endif
+# if defined(linux) && defined(sparc)
+# define SPARC
# define LINUX
# define mach_type_known
# endif
# if defined(__alpha) || defined(__alpha__)
# define ALPHA
-# if defined(linux) || defined(__linux__)
-# define LINUX
-# else
+# if !defined(LINUX)
# define OSF1 /* a.k.a Digital Unix */
# endif
# define mach_type_known
@@ -192,7 +203,8 @@
/* DGUX defined */
# define mach_type_known
# endif
-# if (defined(_MSDOS) || defined(_MSC_VER)) && (_M_IX86 >= 300)
+# if (defined(_MSDOS) || defined(_MSC_VER)) && (_M_IX86 >= 300) \
+ || defined(_WIN32)
# define I386
# define MSWIN32 /* or Win32s */
# define mach_type_known
@@ -254,7 +266,7 @@
/* I386 ==> Intel 386 */
/* (SEQUENT, OS2, SCO, LINUX, NETBSD, */
/* FREEBSD, THREE86BSD, MSWIN32, */
- /* BSDI, SUNOS5, NEXT variants) */
+ /* BSDI,SUNOS5, NEXT, other variants) */
/* NS32K ==> Encore Multimax */
/* MIPS ==> R2000 or R3000 */
/* (RISCOS, ULTRIX variants) */
@@ -371,6 +383,29 @@
extern char etext;
# define DATASTART ((ptr_t)(&etext))
# endif
+# ifdef LINUX
+# define OS_TYPE "LINUX"
+# define STACKBOTTOM ((ptr_t)0xf0000000)
+# define MPROTECT_VDB
+# ifdef __ELF__
+# define DYNAMIC_LOADING
+ 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 SUNOS4
# define OS_TYPE "SUNOS4"
extern char etext;
@@ -498,11 +533,15 @@
# define HEAP_START DATAEND
# endif
# define PROC_VDB
-# define HEURISTIC1
+/* HEURISTIC1 reportedly no longer works under 2.7. Thus we */
+/* switched to HEURISTIC2, eventhough it creates some debugging */
+/* issues. */
+# define HEURISTIC2
# include <unistd.h>
# define GETPAGESIZE() sysconf(_SC_PAGESIZE)
/* getpagesize() appeared to be missing from at least one */
/* Solaris 5.4 installation. Weird. */
+# define DYNAMIC_LOADING
# endif
# ifdef SUNOS4
# define OS_TYPE "SUNOS4"
@@ -521,6 +560,7 @@
# define DATASTART ((ptr_t)(*(int *)(TEXTSTART+0x4)+TEXTSTART))
# define MPROTECT_VDB
# define HEURISTIC1
+# define DYNAMIC_LOADING
# endif
# ifdef DRSNX
# define CPP_WORDSZ 32
@@ -530,8 +570,21 @@
# define DATASTART (ptr_t)GC_SysVGetDataStart(0x10000, &etext)
# define MPROTECT_VDB
# define STACKBOTTOM ((ptr_t) 0xdfff0000)
+# define DYNAMIC_LOADING
+# endif
+# ifdef LINUX
+# define OS_TYPE "LINUX"
+# ifdef __ELF__
+# define DATASTART GC_data_start
+# define DYNAMIC_LOADING
+# else
+ Linux Sparc non elf ?
+# endif
+ extern int _end;
+# define DATAEND (&_end)
+# define SVR4
+# define STACKBOTTOM ((ptr_t) 0xf0000000)
# endif
-# define DYNAMIC_LOADING
# endif
# ifdef I386
@@ -590,16 +643,21 @@
/* Appears to be 0xe0000000 for at least one 2.1.91 kernel. */
/* Probably needs to be more flexible, but I don't yet */
/* fully understand how flexible. */
-# define MPROTECT_VDB
+# if !defined(LINUX_THREADS) || !defined(REDIRECT_MALLOC)
+# define MPROTECT_VDB
+# else
+ /* We seem to get random errors in incremental mode, */
+ /* possibly because Linux threads is itself a malloc client */
+ /* and can't deal with the signals. */
+# endif
# ifdef __ELF__
# define DYNAMIC_LOADING
# ifdef UNDEFINED /* includes ro data */
extern int _etext;
# define DATASTART ((ptr_t)((((word) (&_etext)) + 0xfff) & ~0xfff))
# endif
-# include <linux/version.h>
# include <features.h>
-# if LINUX_VERSION_CODE >= 0x20000 && defined(__GLIBC__) && __GLIBC__ >= 2
+# if defined(__GLIBC__) && __GLIBC__ >= 2
extern int __data_start;
# define DATASTART ((ptr_t)(&__data_start))
# else
@@ -622,6 +680,7 @@
# endif
# endif
# ifdef CYGWIN32
+# define OS_TYPE "CYGWIN32"
extern int _data_start__;
extern int _data_end__;
extern int _bss_start__;
@@ -636,8 +695,8 @@
/* minumum/maximum of the two. */
# define MAX(x,y) ((x) > (y) ? (x) : (y))
# define MIN(x,y) ((x) < (y) ? (x) : (y))
-# define DATASTART ((ptr_t) MIN(_data_start__, _bss_start__))
-# define DATAEND ((ptr_t) MAX(_data_end__, _bss_end__))
+# define DATASTART ((ptr_t) MIN(&_data_start__, &_bss_start__))
+# define DATAEND ((ptr_t) MAX(&_data_end__, &_bss_end__))
# undef STACK_GRAN
# define STACK_GRAN 0x10000
# define HEURISTIC1
@@ -695,18 +754,18 @@
# 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())
+ extern long __nullarea;
+ extern char _end;
+ extern char *_STACKTOP;
+ /* Depending on calling conventions Watcom C either precedes
+ or does not precedes with undescore names of C-variables.
+ Make sure startup code variables always have the same names. */
+ #pragma aux __nullarea "*";
+ #pragma aux _end "*";
+# define STACKBOTTOM ((ptr_t) _STACKTOP)
+ /* confused? me too. */
+# define DATASTART ((ptr_t) &__nullarea)
+# define DATAEND ((ptr_t) &_end)
# endif
# endif
@@ -810,6 +869,8 @@
# ifdef OSF1
# define OS_TYPE "OSF1"
# define DATASTART ((ptr_t) 0x140000000)
+ extern _end;
+# define DATAEND ((ptr_t) &_end)
# define HEURISTIC2
/* Normally HEURISTIC2 is too conervative, since */
/* the text segment immediately follows the stack. */
@@ -941,9 +1002,15 @@
# define DEFAULT_VDB
# endif
+# if defined(_SOLARIS_PTHREADS) && !defined(SOLARIS_THREADS)
+# define SOLARIS_THREADS
+# endif
# if defined(IRIX_THREADS) && !defined(IRIX5)
--> inconsistent configuration
# endif
+# if defined(IRIX_JDK_THREADS) && !defined(IRIX5)
+--> inconsistent configuration
+# endif
# if defined(LINUX_THREADS) && !defined(LINUX)
--> inconsistent configuration
# endif
@@ -952,11 +1019,12 @@
# endif
# if defined(PCR) || defined(SRC_M3) || \
defined(SOLARIS_THREADS) || defined(WIN32_THREADS) || \
- defined(IRIX_THREADS) || defined(LINUX_THREADS)
+ defined(IRIX_THREADS) || defined(LINUX_THREADS) || \
+ defined(IRIX_JDK_THREADS)
# define THREADS
# endif
-# if defined(SPARC)
+# if defined(SPARC) && !defined(LINUX)
# define SAVE_CALL_CHAIN
# define ASM_CLEAR_CODE /* Stack clearing is crucial, and we */
/* include assembly code to do it well. */
diff --git a/headers.c b/headers.c
index b5cc1af8..05a76c0b 100644
--- a/headers.c
+++ b/headers.c
@@ -90,7 +90,7 @@ register word bytes;
bytes_to_get = bytes;
# ifdef USE_MMAP
bytes_to_get += GC_page_size - 1;
- bytes_to_get &= (GC_page_size - 1);
+ bytes_to_get &= ~(GC_page_size - 1);
# endif
return((ptr_t)GET_MEM(bytes_to_get));
}
diff --git a/if_mach.c b/if_mach.c
index da2b7f90..af013637 100644
--- a/if_mach.c
+++ b/if_mach.c
@@ -1,6 +1,6 @@
-/* Conditionally execute a command based on machine and OS from config.h */
-/* Boehm, November 21, 1994 1:40 pm PST */
-# include "config.h"
+/* Conditionally execute a command based on machine and OS from gcconfig.h */
+
+# include "gcconfig.h"
# include <stdio.h>
int main(argc, argv, envp)
diff --git a/if_not_there.c b/if_not_there.c
index 9616309d..a93795f1 100644
--- a/if_not_there.c
+++ b/if_not_there.c
@@ -1,6 +1,6 @@
/* Conditionally execute a command based if the file argv[1] doesn't exist */
/* Except for execvp, we stick to ANSI C. */
-# include "config.h"
+# include "gcconfig.h"
# include <stdio.h>
int main(argc, argv, envp)
diff --git a/include/gc.h b/include/gc.h
index 09c8ca81..eb9a7f60 100644
--- a/include/gc.h
+++ b/include/gc.h
@@ -36,11 +36,19 @@
#endif
#if defined(_MSC_VER) && defined(_DLL)
-#ifdef GC_BUILD
-#define GC_API __declspec(dllexport)
-#else
-#define GC_API __declspec(dllimport)
+# ifdef GC_BUILD
+# define GC_API __declspec(dllexport)
+# else
+# define GC_API __declspec(dllimport)
+# endif
#endif
+
+#if defined(__WATCOMC__) && defined(GC_DLL)
+# ifdef GC_BUILD
+# define GC_API extern __declspec(dllexport)
+# else
+# define GC_API extern __declspec(dllimport)
+# endif
#endif
#ifndef GC_API
@@ -193,8 +201,8 @@ GC_API size_t GC_size GC_PROTO((GC_PTR object_addr));
/* If the argument is stubborn, the result will have changes enabled. */
/* It is an error to have changes enabled for the original object. */
/* Follows ANSI comventions for NULL old_object. */
-GC_API GC_PTR GC_realloc GC_PROTO((GC_PTR old_object,
- size_t new_size_in_bytes));
+GC_API GC_PTR GC_realloc
+ GC_PROTO((GC_PTR old_object, size_t new_size_in_bytes));
/* Explicitly increase the heap size. */
/* Returns 0 on failure, 1 on success. */
@@ -604,6 +612,10 @@ GC_API void (*GC_is_valid_displacement_print_proc)
GC_API void (*GC_is_visible_print_proc)
GC_PROTO((GC_PTR p));
+#if defined(_SOLARIS_PTHREADS) && !defined(SOLARIS_THREADS)
+# define SOLARIS_THREADS
+#endif
+
#ifdef SOLARIS_THREADS
/* We need to intercept calls to many of the threads primitives, so */
/* that we can locate thread stacks and stop the world. */
@@ -660,7 +672,10 @@ GC_API void (*GC_is_visible_print_proc)
#endif /* IRIX_THREADS || LINUX_THREADS */
-#if defined(THREADS) && !defined(SRC_M3)
+# if defined(PCR) || defined(SOLARIS_THREADS) || defined(WIN32_THREADS) || \
+ defined(IRIX_THREADS) || defined(LINUX_THREADS) || \
+ defined(IRIX_JDK_THREADS)
+ /* Any flavor of threads except SRC_M3. */
/* This returns a list of objects, linked through their first */
/* word. Its use can greatly reduce lock contention problems, since */
/* the allocation lock can be acquired and released many fewer times. */
@@ -691,6 +706,13 @@ extern void GC_thr_init(); /* Needed for Solaris/X86 */
# endif
#endif
+#if (defined(_MSDOS) || defined(_MSC_VER)) && (_M_IX86 >= 300) \
+ || defined(_WIN32)
+ /* win32S may not free all resources on process exit. */
+ /* This explicitly deallocates the heap. */
+ GC_API void GC_win32_free_heap ();
+#endif
+
#ifdef __cplusplus
} /* end of extern "C" */
#endif
diff --git a/include/gc_cpp.h b/include/gc_cpp.h
index e2f456fb..a591d368 100644
--- a/include/gc_cpp.h
+++ b/include/gc_cpp.h
@@ -133,7 +133,8 @@ uses explicit invocation.
#endif
#if ! defined( OPERATOR_NEW_ARRAY ) \
- && (__BORLANDC__ >= 0x450 || (__GNUC__ >= 2 && __GNUC_MINOR__ >= 6))
+ && (__BORLANDC__ >= 0x450 || (__GNUC__ >= 2 && __GNUC_MINOR__ >= 6) \
+ || __WATCOMC__ >= 1050)
# define OPERATOR_NEW_ARRAY
#endif
diff --git a/include/javaxfc.h b/include/javaxfc.h
new file mode 100644
index 00000000..880020c5
--- /dev/null
+++ b/include/javaxfc.h
@@ -0,0 +1,41 @@
+# ifndef GC_H
+# include "gc.h"
+# endif
+
+/*
+ * Invoke all remaining finalizers that haven't yet been run.
+ * This is needed for strict compliance with the Java standard,
+ * which can make the runtime guarantee that all finalizers are run.
+ * This is problematic for several reasons:
+ * 1) It means that finalizers, and all methods calle by them,
+ * must be prepared to deal with objects that have been finalized in
+ * spite of the fact that they are still referenced by statically
+ * allocated pointer variables.
+ * 1) It may mean that we get stuck in an infinite loop running
+ * finalizers which create new finalizable objects, though that's
+ * probably unlikely.
+ * Thus this is not recommended for general use.
+ */
+void GC_finalize_all();
+
+/*
+ * A version of GC_register_finalizer that allows the object to be
+ * finalized before the objects it references. This is again error
+ * prone, in that it makes it easy to accidentally reference finalized
+ * objects. Again, recommended only for JVM implementors.
+ */
+void GC_register_finalizer_no_order(GC_PTR obj,
+ GC_finalization_proc fn, GC_PTR cd,
+ GC_finalization_proc *ofn, GC_PTR * ocd);
+
+void GC_debug_register_finalizer_no_order(GC_PTR obj,
+ GC_finalization_proc fn, GC_PTR cd,
+ GC_finalization_proc *ofn, GC_PTR * ocd);
+
+#ifdef GC_DEBUG
+# define GC_REGISTER_FINALIZER(p, f, d, of, od) \
+ GC_debug_register_finalizer_no_order(p, f, d, of, od)
+#else
+# define GC_REGISTER_FINALIZER(p, f, d, of, od) \
+ GC_register_finalizer_no_order(p, f, d, of, od)
+#endif
diff --git a/include/new_gc_alloc.h b/include/new_gc_alloc.h
new file mode 100644
index 00000000..57713883
--- /dev/null
+++ b/include/new_gc_alloc.h
@@ -0,0 +1,456 @@
+/*
+ * Copyright (c) 1996-1998 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.
+ *
+ * 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.
+ */
+
+//
+// This is a revision of gc_alloc.h for SGI STL versions > 3.0
+// Unlike earlier versions, it supplements the standard "alloc.h"
+// instead of replacing it.
+//
+// This is sloppy about variable names used in header files.
+// It also doesn't yet understand the new header file names or
+// namespaces.
+//
+// This assumes the collector has been compiled with -DATOMIC_UNCOLLECTABLE
+// and -DALL_INTERIOR_POINTERS. We also recommend
+// -DREDIRECT_MALLOC=GC_uncollectable_malloc.
+//
+// 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 does not work
+// with g++ 2.7.2 and earlier.
+//
+// Unlike its predecessor, this one simply defines
+// gc_alloc
+// single_client_gc_alloc
+// traceable_alloc
+// single_client_traceable_alloc
+//
+// It does not redefine alloc. Nor does it change the default allocator,
+// though the user may wish to do so. (The argument against changing
+// the default allocator is that it may introduce subtle link compatibility
+// problems. The argument for changing it is that the usual default
+// allocator is usually a very bad choice for a garbage collected environment.)
+//
+
+#ifndef GC_ALLOC_H
+
+#include "gc.h"
+#include <alloc.h>
+
+#define GC_ALLOC_H
+
+#include <stddef.h>
+#include <string.h>
+
+// The following need to match collector data structures.
+// We can't include gc_priv.h, since that pulls in way too much stuff.
+// This should eventually be factored out into another include file.
+
+extern "C" {
+ extern void ** const GC_objfreelist_ptr;
+ extern void ** const GC_aobjfreelist_ptr;
+ extern void ** const GC_uobjfreelist_ptr;
+ extern void ** const GC_auobjfreelist_ptr;
+
+ extern void GC_incr_words_allocd(size_t words);
+ extern void GC_incr_mem_freed(size_t words);
+
+ extern char * GC_generic_malloc_words_small(size_t word, int kind);
+}
+
+// Object kinds; must match PTRFREE, NORMAL, UNCOLLECTABLE, and
+// AUNCOLLECTABLE in gc_priv.h.
+
+enum { GC_PTRFREE = 0, GC_NORMAL = 1, GC_UNCOLLECTABLE = 2,
+ GC_AUNCOLLECTABLE = 3 };
+
+enum { GC_max_fast_bytes = 255 };
+
+enum { GC_bytes_per_word = sizeof(char *) };
+
+enum { GC_byte_alignment = 8 };
+
+enum { GC_word_alignment = GC_byte_alignment/GC_bytes_per_word };
+
+inline void * &GC_obj_link(void * p)
+{ return *(void **)p; }
+
+// Compute a number of words >= n+1 bytes.
+// The +1 allows for pointers one past the end.
+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 size_t GC_round_up_uncollectable(size_t n)
+{
+ return ((n + GC_byte_alignment - 1)/GC_byte_alignment)*GC_word_alignment;
+}
+
+template <int dummy>
+class GC_aux_template {
+public:
+ // File local count of allocated words. Occasionally this is
+ // added into the global count. A separate count is necessary since the
+ // real one must be updated with a procedure call.
+ static size_t GC_words_recently_allocd;
+
+ // Same for uncollectable mmory. Not yet reflected in either
+ // GC_words_recently_allocd or GC_non_gc_bytes.
+ static size_t GC_uncollectable_words_recently_allocd;
+
+ // Similar counter for explicitly deallocated memory.
+ static size_t GC_mem_recently_freed;
+
+ // Again for uncollectable memory.
+ static size_t GC_uncollectable_mem_recently_freed;
+
+ static void * GC_out_of_line_malloc(size_t nwords, int kind);
+};
+
+template <int dummy>
+size_t GC_aux_template<dummy>::GC_words_recently_allocd = 0;
+
+template <int dummy>
+size_t GC_aux_template<dummy>::GC_uncollectable_words_recently_allocd = 0;
+
+template <int dummy>
+size_t GC_aux_template<dummy>::GC_mem_recently_freed = 0;
+
+template <int dummy>
+size_t GC_aux_template<dummy>::GC_uncollectable_mem_recently_freed = 0;
+
+template <int dummy>
+void * GC_aux_template<dummy>::GC_out_of_line_malloc(size_t nwords, int kind)
+{
+ GC_words_recently_allocd += GC_uncollectable_words_recently_allocd;
+ GC_non_gc_bytes +=
+ GC_bytes_per_word * GC_uncollectable_words_recently_allocd;
+ GC_uncollectable_words_recently_allocd = 0;
+
+ GC_mem_recently_freed += GC_uncollectable_mem_recently_freed;
+ GC_non_gc_bytes -=
+ GC_bytes_per_word * GC_uncollectable_mem_recently_freed;
+ GC_uncollectable_mem_recently_freed = 0;
+
+ GC_incr_words_allocd(GC_words_recently_allocd);
+ GC_words_recently_allocd = 0;
+
+ GC_incr_mem_freed(GC_mem_recently_freed);
+ GC_mem_recently_freed = 0;
+
+ return GC_generic_malloc_words_small(nwords, kind);
+}
+
+typedef GC_aux_template<0> GC_aux;
+
+// A fast, single-threaded, garbage-collected allocator
+// We assume the first word will be immediately overwritten.
+// In this version, deallocation is not a noop, and explicit
+// deallocation is likely to help performance.
+template <int dummy>
+class single_client_gc_alloc_template {
+ public:
+ static void * allocate(size_t n)
+ {
+ size_t nwords = GC_round_up(n);
+ void ** flh;
+ void * op;
+
+ if (n > GC_max_fast_bytes) return GC_malloc(n);
+ flh = GC_objfreelist_ptr + nwords;
+ if (0 == (op = *flh)) {
+ return GC_aux::GC_out_of_line_malloc(nwords, GC_NORMAL);
+ }
+ *flh = GC_obj_link(op);
+ GC_aux::GC_words_recently_allocd += nwords;
+ return op;
+ }
+ static void * ptr_free_allocate(size_t n)
+ {
+ size_t nwords = GC_round_up(n);
+ void ** flh;
+ void * op;
+
+ if (n > GC_max_fast_bytes) return GC_malloc_atomic(n);
+ flh = GC_aobjfreelist_ptr + nwords;
+ if (0 == (op = *flh)) {
+ return GC_aux::GC_out_of_line_malloc(nwords, GC_PTRFREE);
+ }
+ *flh = GC_obj_link(op);
+ GC_aux::GC_words_recently_allocd += nwords;
+ return op;
+ }
+ static void deallocate(void *p, size_t n)
+ {
+ size_t nwords = GC_round_up(n);
+ void ** flh;
+
+ if (n > GC_max_fast_bytes) {
+ GC_free(p);
+ } else {
+ flh = GC_objfreelist_ptr + nwords;
+ GC_obj_link(p) = *flh;
+ memset((char *)p + GC_bytes_per_word, 0,
+ GC_bytes_per_word * (nwords - 1));
+ *flh = p;
+ GC_aux::GC_mem_recently_freed += nwords;
+ }
+ }
+ static void ptr_free_deallocate(void *p, size_t n)
+ {
+ size_t nwords = GC_round_up(n);
+ void ** flh;
+
+ if (n > GC_max_fast_bytes) {
+ GC_free(p);
+ } else {
+ flh = GC_aobjfreelist_ptr + nwords;
+ GC_obj_link(p) = *flh;
+ *flh = p;
+ GC_aux::GC_mem_recently_freed += nwords;
+ }
+ }
+};
+
+typedef single_client_gc_alloc_template<0> single_client_gc_alloc;
+
+// Once more, for uncollectable objects.
+template <int dummy>
+class single_client_traceable_alloc_template {
+ public:
+ static void * allocate(size_t n)
+ {
+ size_t nwords = GC_round_up_uncollectable(n);
+ void ** flh;
+ void * op;
+
+ if (n > GC_max_fast_bytes) return GC_malloc_uncollectable(n);
+ flh = GC_uobjfreelist_ptr + nwords;
+ if (0 == (op = *flh)) {
+ return GC_aux::GC_out_of_line_malloc(nwords, GC_UNCOLLECTABLE);
+ }
+ *flh = GC_obj_link(op);
+ GC_aux::GC_uncollectable_words_recently_allocd += nwords;
+ return op;
+ }
+ static void * ptr_free_allocate(size_t n)
+ {
+ size_t nwords = GC_round_up_uncollectable(n);
+ void ** flh;
+ void * op;
+
+ if (n > GC_max_fast_bytes) return GC_malloc_atomic_uncollectable(n);
+ flh = GC_auobjfreelist_ptr + nwords;
+ if (0 == (op = *flh)) {
+ return GC_aux::GC_out_of_line_malloc(nwords, GC_AUNCOLLECTABLE);
+ }
+ *flh = GC_obj_link(op);
+ GC_aux::GC_uncollectable_words_recently_allocd += nwords;
+ return op;
+ }
+ static void deallocate(void *p, size_t n)
+ {
+ size_t nwords = GC_round_up_uncollectable(n);
+ void ** flh;
+
+ if (n > GC_max_fast_bytes) {
+ GC_free(p);
+ } else {
+ flh = GC_uobjfreelist_ptr + nwords;
+ GC_obj_link(p) = *flh;
+ *flh = p;
+ GC_aux::GC_uncollectable_mem_recently_freed += nwords;
+ }
+ }
+ static void ptr_free_deallocate(void *p, size_t n)
+ {
+ size_t nwords = GC_round_up_uncollectable(n);
+ void ** flh;
+
+ if (n > GC_max_fast_bytes) {
+ GC_free(p);
+ } else {
+ flh = GC_auobjfreelist_ptr + nwords;
+ GC_obj_link(p) = *flh;
+ *flh = p;
+ GC_aux::GC_uncollectable_mem_recently_freed += nwords;
+ }
+ }
+};
+
+typedef single_client_traceable_alloc_template<0> single_client_traceable_alloc;
+
+template < int dummy >
+class gc_alloc_template {
+ public:
+ static void * allocate(size_t n) { return GC_malloc(n); }
+ static void * ptr_free_allocate(size_t n)
+ { return GC_malloc_atomic(n); }
+ static void deallocate(void *, size_t) { }
+ static void ptr_free_deallocate(void *, size_t) { }
+};
+
+typedef gc_alloc_template < 0 > gc_alloc;
+
+template < int dummy >
+class traceable_alloc_template {
+ public:
+ static void * allocate(size_t n) { return GC_malloc_uncollectable(n); }
+ static void * ptr_free_allocate(size_t n)
+ { return GC_malloc_atomic_uncollectable(n); }
+ static void deallocate(void *p, size_t) { GC_free(p); }
+ static void ptr_free_deallocate(void *p, size_t) { GC_free(p); }
+};
+
+typedef traceable_alloc_template < 0 > traceable_alloc;
+
+#ifdef _SGI_SOURCE
+
+// We want to specialize simple_alloc so that it does the right thing
+// for all pointerfree types. At the moment there is no portable way to
+// even approximate that. The following approximation should work for
+// SGI compilers, and perhaps some others.
+
+# define __GC_SPECIALIZE(T,alloc) \
+class simple_alloc<T, alloc> { \
+public: \
+ static T *allocate(size_t n) \
+ { return 0 == n? 0 : \
+ (T*) alloc::ptr_free_allocate(n * sizeof (T)); } \
+ static T *allocate(void) \
+ { return (T*) alloc::ptr_free_allocate(sizeof (T)); } \
+ static void deallocate(T *p, size_t n) \
+ { if (0 != n) alloc::ptr_free_deallocate(p, n * sizeof (T)); } \
+ static void deallocate(T *p) \
+ { alloc::ptr_free_deallocate(p, sizeof (T)); } \
+};
+
+__GC_SPECIALIZE(char, gc_alloc)
+__GC_SPECIALIZE(int, gc_alloc)
+__GC_SPECIALIZE(unsigned, gc_alloc)
+__GC_SPECIALIZE(float, gc_alloc)
+__GC_SPECIALIZE(double, gc_alloc)
+
+__GC_SPECIALIZE(char, traceable_alloc)
+__GC_SPECIALIZE(int, traceable_alloc)
+__GC_SPECIALIZE(unsigned, traceable_alloc)
+__GC_SPECIALIZE(float, traceable_alloc)
+__GC_SPECIALIZE(double, traceable_alloc)
+
+__GC_SPECIALIZE(char, single_client_gc_alloc)
+__GC_SPECIALIZE(int, single_client_gc_alloc)
+__GC_SPECIALIZE(unsigned, single_client_gc_alloc)
+__GC_SPECIALIZE(float, single_client_gc_alloc)
+__GC_SPECIALIZE(double, single_client_gc_alloc)
+
+__GC_SPECIALIZE(char, single_client_traceable_alloc)
+__GC_SPECIALIZE(int, single_client_traceable_alloc)
+__GC_SPECIALIZE(unsigned, single_client_traceable_alloc)
+__GC_SPECIALIZE(float, single_client_traceable_alloc)
+__GC_SPECIALIZE(double, single_client_traceable_alloc)
+
+#ifdef __STL_USE_STD_ALLOCATORS
+
+__STL_BEGIN_NAMESPACE
+
+template <class _T>
+struct _Alloc_traits<_T, gc_alloc >
+{
+ static const bool _S_instanceless = true;
+ typedef simple_alloc<_T, gc_alloc > _Alloc_type;
+ typedef __allocator<_T, gc_alloc > allocator_type;
+};
+
+inline bool operator==(const gc_alloc&,
+ const gc_alloc&)
+{
+ return true;
+}
+
+inline bool operator!=(const gc_alloc&,
+ const gc_alloc&)
+{
+ return false;
+}
+
+template <class _T>
+struct _Alloc_traits<_T, single_client_gc_alloc >
+{
+ static const bool _S_instanceless = true;
+ typedef simple_alloc<_T, single_client_gc_alloc > _Alloc_type;
+ typedef __allocator<_T, single_client_gc_alloc > allocator_type;
+};
+
+inline bool operator==(const single_client_gc_alloc&,
+ const single_client_gc_alloc&)
+{
+ return true;
+}
+
+inline bool operator!=(const single_client_gc_alloc&,
+ const single_client_gc_alloc&)
+{
+ return false;
+}
+
+template <class _T>
+struct _Alloc_traits<_T, traceable_alloc >
+{
+ static const bool _S_instanceless = true;
+ typedef simple_alloc<_T, traceable_alloc > _Alloc_type;
+ typedef __allocator<_T, traceable_alloc > allocator_type;
+};
+
+inline bool operator==(const traceable_alloc&,
+ const traceable_alloc&)
+{
+ return true;
+}
+
+inline bool operator!=(const traceable_alloc&,
+ const traceable_alloc&)
+{
+ return false;
+}
+
+template <class _T>
+struct _Alloc_traits<_T, single_client_traceable_alloc >
+{
+ static const bool _S_instanceless = true;
+ typedef simple_alloc<_T, single_client_traceable_alloc > _Alloc_type;
+ typedef __allocator<_T, single_client_traceable_alloc > allocator_type;
+};
+
+inline bool operator==(const single_client_traceable_alloc&,
+ const single_client_traceable_alloc&)
+{
+ return true;
+}
+
+inline bool operator!=(const single_client_traceable_alloc&,
+ const single_client_traceable_alloc&)
+{
+ return false;
+}
+
+__STL_END_NAMESPACE
+
+#endif /* __STL_USE_STD_ALLOCATORS */
+
+#endif /* _SGI_SOURCE */
+
+#endif /* GC_ALLOC_H */
diff --git a/include/private/gc_priv.h b/include/private/gc_priv.h
index 96ba1da1..df7db8e9 100644
--- a/include/private/gc_priv.h
+++ b/include/private/gc_priv.h
@@ -42,7 +42,7 @@ typedef GC_word word;
typedef GC_signed_word signed_word;
# ifndef CONFIG_H
-# include "config.h"
+# include "gcconfig.h"
# endif
# ifndef HEADERS_H
@@ -475,7 +475,7 @@ void GC_print_callers (/* struct callinfo info[NFRAMES] */);
}
# define EXIT_GC() GC_collecting = 0;
# endif /* LINUX_THREADS */
-# ifdef IRIX_THREADS
+# if defined(IRIX_THREADS) || defined(IRIX_JDK_THREADS)
# include <pthread.h>
# include <mutex.h>
@@ -513,7 +513,7 @@ void GC_print_callers (/* struct callinfo info[NFRAMES] */);
GC_collecting = 1; \
}
# define EXIT_GC() GC_collecting = 0;
-# endif /* IRIX_THREADS */
+# endif /* IRIX_THREADS || IRIX_JDK_THREADS */
# ifdef WIN32_THREADS
# include <windows.h>
GC_API CRITICAL_SECTION GC_allocate_ml;
@@ -567,7 +567,7 @@ void GC_print_callers (/* struct callinfo info[NFRAMES] */);
# if defined(SRC_M3) || defined(AMIGA) || defined(SOLARIS_THREADS) \
|| defined(MSWIN32) || defined(MACOS) || defined(DJGPP) \
|| defined(NO_SIGNALS) || defined(IRIX_THREADS) \
- || defined(LINUX_THREADS)
+ || defined(IRIX_JDK_THREADS) || defined(LINUX_THREADS)
/* Also useful for debugging. */
/* Should probably use thr_sigsetmask for SOLARIS_THREADS. */
# define DISABLE_SIGNALS()
@@ -595,7 +595,8 @@ void GC_print_callers (/* struct callinfo info[NFRAMES] */);
PCR_waitForever);
# else
# if defined(SOLARIS_THREADS) || defined(WIN32_THREADS) \
- || defined(IRIX_THREADS) || defined(LINUX_THREADS)
+ || defined(IRIX_THREADS) || defined(LINUX_THREADS) \
+ || defined(IRIX_JDK_THREADS)
void GC_stop_world();
void GC_start_world();
# define STOP_WORLD() GC_stop_world()
@@ -864,7 +865,69 @@ struct hblk {
/* Object free list link */
# define obj_link(p) (*(ptr_t *)(p))
-/* lists of all heap blocks and free lists */
+/* The type of mark procedures. This really belongs in gc_mark.h. */
+/* But we put it here, so that we can avoid scanning the mark proc */
+/* table. */
+typedef struct ms_entry * (*mark_proc)(/* word * addr, mark_stack_ptr,
+ mark_stack_limit, env */);
+# define LOG_MAX_MARK_PROCS 6
+# define MAX_MARK_PROCS (1 << LOG_MAX_MARK_PROCS)
+
+/* Root sets. Logically private to mark_rts.c. But we don't want the */
+/* tables scanned, so we put them here. */
+/* 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
+# ifdef PCR
+# define MAX_ROOT_SETS 1024
+# else
+# ifdef MSWIN32
+# define MAX_ROOT_SETS 512
+ /* Under NT, we add only written pages, which can result */
+ /* in many small root sets. */
+# else
+# define MAX_ROOT_SETS 64
+# endif
+# endif
+# endif
+
+# define MAX_EXCLUSIONS (MAX_ROOT_SETS/4)
+/* Maximum number of segments that can be excluded from root sets. */
+
+/*
+ * Data structure for excluded static roots.
+ */
+struct exclusion {
+ ptr_t e_start;
+ ptr_t e_end;
+};
+
+/* 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 */
+/* we resort to sequential search, and pay the price. */
+struct roots {
+ ptr_t r_start;
+ ptr_t r_end;
+# ifndef MSWIN32
+ struct roots * r_next;
+# endif
+ GC_bool r_tmp;
+ /* Delete before registering new dynamic libraries */
+};
+
+#ifndef MSWIN32
+ /* Size of hash table index to roots. */
+# define LOG_RT_SIZE 6
+# define RT_SIZE (1 << LOG_RT_SIZE) /* Power of 2, may be != MAX_ROOT_SETS */
+#endif
+
+/* Lists of all heap blocks and free lists */
+/* as well as other random data structures */
+/* that should not be scanned by the */
+/* collector. */
/* These are grouped together in a struct */
/* so that they can be easily skipped by the */
/* GC_mark routine. */
@@ -904,7 +967,10 @@ struct _GC_arrays {
word _mem_freed;
/* Number of explicitly deallocated words of memory */
/* since last collection. */
-
+ mark_proc _mark_procs[MAX_MARK_PROCS];
+ /* Table of user-defined mark procedures. There is */
+ /* a small number of these, which can be referenced */
+ /* by DS_PROC mark descriptors. See gc_mark.h. */
ptr_t _objfreelist[MAXOBJSZ+1];
/* free list for objects */
ptr_t _aobjfreelist[MAXOBJSZ+1];
@@ -986,17 +1052,24 @@ struct _GC_arrays {
/* GC_modws_valid_offsets[i%sizeof(word)] */
# endif
# ifdef STUBBORN_ALLOC
- page_hash_table _changed_pages;
+ page_hash_table _changed_pages;
/* Stubborn object pages that were changes since last call to */
/* GC_read_changed. */
- page_hash_table _prev_changed_pages;
+ page_hash_table _prev_changed_pages;
/* Stubborn object pages that were changes before last call to */
/* GC_read_changed. */
# endif
# if defined(PROC_VDB) || defined(MPROTECT_VDB)
- page_hash_table _grungy_pages; /* Pages that were dirty at last */
+ page_hash_table _grungy_pages; /* Pages that were dirty at last */
/* GC_read_dirty. */
# endif
+# ifdef MPROTECT_VDB
+ VOLATILE page_hash_table _dirty_pages;
+ /* Pages dirtied since last GC_read_dirty. */
+# endif
+# ifdef PROC_VDB
+ page_hash_table _written_pages; /* Pages ever dirtied */
+# endif
# ifdef LARGE_CONFIG
# if CPP_WORDSZ > 32
# define MAX_HEAP_SECTS 4096 /* overflows at roughly 64 GB */
@@ -1013,6 +1086,11 @@ struct _GC_arrays {
ptr_t _heap_bases[MAX_HEAP_SECTS];
/* Start address of memory regions obtained from kernel. */
# endif
+ struct roots _static_roots[MAX_ROOT_SETS];
+# ifndef MSWIN32
+ struct roots * _root_index[RT_SIZE];
+# endif
+ struct exclusion _excl_table[MAX_EXCLUSIONS];
/* Block header index; see gc_headers.h */
bottom_index * _all_nils;
bottom_index * _top_index [TOP_SZ];
@@ -1049,6 +1127,7 @@ GC_API GC_FAR struct _GC_arrays GC_arrays;
# define GC_words_finalized GC_arrays._words_finalized
# define GC_non_gc_bytes_at_gc GC_arrays._non_gc_bytes_at_gc
# define GC_mem_freed GC_arrays._mem_freed
+# define GC_mark_procs GC_arrays._mark_procs
# define GC_heapsize GC_arrays._heapsize
# define GC_max_heapsize GC_arrays._max_heapsize
# define GC_words_allocd_before_gc GC_arrays._words_allocd_before_gc
@@ -1057,11 +1136,20 @@ GC_API GC_FAR struct _GC_arrays GC_arrays;
# ifdef MSWIN32
# define GC_heap_bases GC_arrays._heap_bases
# endif
+# define GC_static_roots GC_arrays._static_roots
+# define GC_root_index GC_arrays._root_index
+# define GC_excl_table GC_arrays._excl_table
# define GC_all_nils GC_arrays._all_nils
# define GC_top_index GC_arrays._top_index
# if defined(PROC_VDB) || defined(MPROTECT_VDB)
# define GC_grungy_pages GC_arrays._grungy_pages
# endif
+# ifdef MPROTECT_VDB
+# define GC_dirty_pages GC_arrays._dirty_pages
+# endif
+# ifdef PROC_VDB
+# define GC_written_pages GC_arrays._written_pages
+# endif
# ifdef GATHERSTATS
# define GC_composite_in_use GC_arrays._composite_in_use
# define GC_atomic_in_use GC_arrays._atomic_in_use
@@ -1073,11 +1161,9 @@ GC_API GC_FAR struct _GC_arrays GC_arrays;
# define beginGC_arrays ((ptr_t)(&GC_arrays))
# define endGC_arrays (((ptr_t)(&GC_arrays)) + (sizeof GC_arrays))
-GC_API word GC_fo_entries;
-
+/* Object kinds: */
# define MAXOBJKINDS 16
-/* Object kinds: */
extern struct obj_kind {
ptr_t *ok_freelist; /* Array of free listheaders for this kind of object */
/* Point either to GC_arrays or to storage allocated */
@@ -1091,8 +1177,14 @@ extern struct obj_kind {
/* Add object size in bytes to descriptor */
/* template to obtain descriptor. Otherwise */
/* template is used as is. */
- GC_bool ok_init; /* Clear objects before putting them on the free list. */
+ GC_bool ok_init; /* Clear objects before putting them on the free list. */
} GC_obj_kinds[MAXOBJKINDS];
+
+# define endGC_obj_kinds (((ptr_t)(&GC_obj_kinds)) + (sizeof GC_obj_kinds))
+
+# define end_gc_area ((ptr_t)endGC_arrays == (ptr_t)(&GC_obj_kinds) ? \
+ endGC_obj_kinds : endGC_arrays)
+
/* Predefined kinds: */
# define PTRFREE 0
# define NORMAL 1
@@ -1108,6 +1200,8 @@ extern struct obj_kind {
extern int GC_n_kinds;
+GC_API word GC_fo_entries;
+
extern word GC_n_heap_sects; /* Number of separately added heap */
/* sections. */
@@ -1142,7 +1236,13 @@ extern GC_bool GC_is_initialized; /* GC_init() has been run. */
extern GC_bool GC_objects_are_marked; /* There are marked objects in */
/* the heap. */
-extern GC_bool GC_incremental; /* Using incremental/generational collection. */
+#ifndef SMALL_CONFIG
+ extern GC_bool GC_incremental;
+ /* Using incremental/generational collection. */
+#else
+# define GC_incremental TRUE
+ /* Hopefully allow optimizer to remove some code. */
+#endif
extern GC_bool GC_dirty_maintained;
/* Dirty bits are being maintained, */
@@ -1403,7 +1503,7 @@ GC_bool GC_collect_or_expand(/* needed_blocks */);
/* blocks available. Should be called */
/* until the blocks are available or */
/* until it fails by returning FALSE. */
-void GC_init(); /* Initialize collector. */
+GC_API void GC_init(); /* Initialize collector. */
void GC_collect_a_little_inner(/* int n */);
/* Do n units worth of garbage */
/* collection work, if appropriate. */
@@ -1491,7 +1591,7 @@ void GC_write_hint(/* struct hblk * h */);
void GC_dirty_init();
/* Slow/general mark bit manipulation: */
-GC_bool GC_is_marked();
+GC_API GC_bool GC_is_marked();
void GC_clear_mark_bit();
void GC_set_mark_bit();
diff --git a/include/private/config.h b/include/private/gcconfig.h
index fc8004ce..e550e944 100644
--- a/include/private/config.h
+++ b/include/private/gcconfig.h
@@ -22,6 +22,11 @@
/* Machine specific parts contributed by various people. See README file. */
+/* First a unified test for Linux: */
+# if defined(linux) || defined(__linux__)
+# define LINUX
+# endif
+
/* Determine the machine type: */
# if defined(sun) && defined(mc68000)
# define M68K
@@ -90,7 +95,7 @@
# endif
# define mach_type_known
# endif
-# if defined(sparc) && defined(unix) && !defined(sun)
+# if defined(sparc) && defined(unix) && !defined(sun) && !defined(linux)
# define SPARC
# define DRSNX
# define mach_type_known
@@ -114,25 +119,31 @@
# define SYSV
# define mach_type_known
# endif
-# if defined(_PA_RISC1_0) || defined(_PA_RISC1_1)
+# if defined(_PA_RISC1_0) || defined(_PA_RISC1_1) \
+ || defined(hppa) || defined(__hppa__)
# define HP_PA
# define mach_type_known
# endif
-# if defined(linux) && defined(i386)
+# if defined(LINUX) && defined(i386)
# define I386
-# define LINUX
# define mach_type_known
# endif
-# if defined(linux) && defined(powerpc)
+# if defined(LINUX) && defined(powerpc)
# define POWERPC
+# define mach_type_known
+# endif
+# if defined(LINUX) && defined(__mc68000__)
+# define M68K
+# define mach_type_known
+# endif
+# if defined(linux) && defined(sparc)
+# define SPARC
# define LINUX
# define mach_type_known
# endif
# if defined(__alpha) || defined(__alpha__)
# define ALPHA
-# if defined(linux) || defined(__linux__)
-# define LINUX
-# else
+# if !defined(LINUX)
# define OSF1 /* a.k.a Digital Unix */
# endif
# define mach_type_known
@@ -192,7 +203,8 @@
/* DGUX defined */
# define mach_type_known
# endif
-# if (defined(_MSDOS) || defined(_MSC_VER)) && (_M_IX86 >= 300)
+# if (defined(_MSDOS) || defined(_MSC_VER)) && (_M_IX86 >= 300) \
+ || defined(_WIN32)
# define I386
# define MSWIN32 /* or Win32s */
# define mach_type_known
@@ -254,7 +266,7 @@
/* I386 ==> Intel 386 */
/* (SEQUENT, OS2, SCO, LINUX, NETBSD, */
/* FREEBSD, THREE86BSD, MSWIN32, */
- /* BSDI, SUNOS5, NEXT variants) */
+ /* BSDI,SUNOS5, NEXT, other variants) */
/* NS32K ==> Encore Multimax */
/* MIPS ==> R2000 or R3000 */
/* (RISCOS, ULTRIX variants) */
@@ -371,6 +383,29 @@
extern char etext;
# define DATASTART ((ptr_t)(&etext))
# endif
+# ifdef LINUX
+# define OS_TYPE "LINUX"
+# define STACKBOTTOM ((ptr_t)0xf0000000)
+# define MPROTECT_VDB
+# ifdef __ELF__
+# define DYNAMIC_LOADING
+ 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 SUNOS4
# define OS_TYPE "SUNOS4"
extern char etext;
@@ -498,11 +533,15 @@
# define HEAP_START DATAEND
# endif
# define PROC_VDB
-# define HEURISTIC1
+/* HEURISTIC1 reportedly no longer works under 2.7. Thus we */
+/* switched to HEURISTIC2, eventhough it creates some debugging */
+/* issues. */
+# define HEURISTIC2
# include <unistd.h>
# define GETPAGESIZE() sysconf(_SC_PAGESIZE)
/* getpagesize() appeared to be missing from at least one */
/* Solaris 5.4 installation. Weird. */
+# define DYNAMIC_LOADING
# endif
# ifdef SUNOS4
# define OS_TYPE "SUNOS4"
@@ -521,6 +560,7 @@
# define DATASTART ((ptr_t)(*(int *)(TEXTSTART+0x4)+TEXTSTART))
# define MPROTECT_VDB
# define HEURISTIC1
+# define DYNAMIC_LOADING
# endif
# ifdef DRSNX
# define CPP_WORDSZ 32
@@ -530,8 +570,21 @@
# define DATASTART (ptr_t)GC_SysVGetDataStart(0x10000, &etext)
# define MPROTECT_VDB
# define STACKBOTTOM ((ptr_t) 0xdfff0000)
+# define DYNAMIC_LOADING
+# endif
+# ifdef LINUX
+# define OS_TYPE "LINUX"
+# ifdef __ELF__
+# define DATASTART GC_data_start
+# define DYNAMIC_LOADING
+# else
+ Linux Sparc non elf ?
+# endif
+ extern int _end;
+# define DATAEND (&_end)
+# define SVR4
+# define STACKBOTTOM ((ptr_t) 0xf0000000)
# endif
-# define DYNAMIC_LOADING
# endif
# ifdef I386
@@ -590,16 +643,21 @@
/* Appears to be 0xe0000000 for at least one 2.1.91 kernel. */
/* Probably needs to be more flexible, but I don't yet */
/* fully understand how flexible. */
-# define MPROTECT_VDB
+# if !defined(LINUX_THREADS) || !defined(REDIRECT_MALLOC)
+# define MPROTECT_VDB
+# else
+ /* We seem to get random errors in incremental mode, */
+ /* possibly because Linux threads is itself a malloc client */
+ /* and can't deal with the signals. */
+# endif
# ifdef __ELF__
# define DYNAMIC_LOADING
# ifdef UNDEFINED /* includes ro data */
extern int _etext;
# define DATASTART ((ptr_t)((((word) (&_etext)) + 0xfff) & ~0xfff))
# endif
-# include <linux/version.h>
# include <features.h>
-# if LINUX_VERSION_CODE >= 0x20000 && defined(__GLIBC__) && __GLIBC__ >= 2
+# if defined(__GLIBC__) && __GLIBC__ >= 2
extern int __data_start;
# define DATASTART ((ptr_t)(&__data_start))
# else
@@ -622,6 +680,7 @@
# endif
# endif
# ifdef CYGWIN32
+# define OS_TYPE "CYGWIN32"
extern int _data_start__;
extern int _data_end__;
extern int _bss_start__;
@@ -636,8 +695,8 @@
/* minumum/maximum of the two. */
# define MAX(x,y) ((x) > (y) ? (x) : (y))
# define MIN(x,y) ((x) < (y) ? (x) : (y))
-# define DATASTART ((ptr_t) MIN(_data_start__, _bss_start__))
-# define DATAEND ((ptr_t) MAX(_data_end__, _bss_end__))
+# define DATASTART ((ptr_t) MIN(&_data_start__, &_bss_start__))
+# define DATAEND ((ptr_t) MAX(&_data_end__, &_bss_end__))
# undef STACK_GRAN
# define STACK_GRAN 0x10000
# define HEURISTIC1
@@ -695,18 +754,18 @@
# 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())
+ extern long __nullarea;
+ extern char _end;
+ extern char *_STACKTOP;
+ /* Depending on calling conventions Watcom C either precedes
+ or does not precedes with undescore names of C-variables.
+ Make sure startup code variables always have the same names. */
+ #pragma aux __nullarea "*";
+ #pragma aux _end "*";
+# define STACKBOTTOM ((ptr_t) _STACKTOP)
+ /* confused? me too. */
+# define DATASTART ((ptr_t) &__nullarea)
+# define DATAEND ((ptr_t) &_end)
# endif
# endif
@@ -810,6 +869,8 @@
# ifdef OSF1
# define OS_TYPE "OSF1"
# define DATASTART ((ptr_t) 0x140000000)
+ extern _end;
+# define DATAEND ((ptr_t) &_end)
# define HEURISTIC2
/* Normally HEURISTIC2 is too conervative, since */
/* the text segment immediately follows the stack. */
@@ -941,9 +1002,15 @@
# define DEFAULT_VDB
# endif
+# if defined(_SOLARIS_PTHREADS) && !defined(SOLARIS_THREADS)
+# define SOLARIS_THREADS
+# endif
# if defined(IRIX_THREADS) && !defined(IRIX5)
--> inconsistent configuration
# endif
+# if defined(IRIX_JDK_THREADS) && !defined(IRIX5)
+--> inconsistent configuration
+# endif
# if defined(LINUX_THREADS) && !defined(LINUX)
--> inconsistent configuration
# endif
@@ -952,11 +1019,12 @@
# endif
# if defined(PCR) || defined(SRC_M3) || \
defined(SOLARIS_THREADS) || defined(WIN32_THREADS) || \
- defined(IRIX_THREADS) || defined(LINUX_THREADS)
+ defined(IRIX_THREADS) || defined(LINUX_THREADS) || \
+ defined(IRIX_JDK_THREADS)
# define THREADS
# endif
-# if defined(SPARC)
+# if defined(SPARC) && !defined(LINUX)
# define SAVE_CALL_CHAIN
# define ASM_CLEAR_CODE /* Stack clearing is crucial, and we */
/* include assembly code to do it well. */
diff --git a/irix_threads.c b/irix_threads.c
index f45c4631..5efca211 100644
--- a/irix_threads.c
+++ b/irix_threads.c
@@ -25,6 +25,7 @@
# include "gc_priv.h"
# include <pthread.h>
+# include <semaphore.h>
# include <time.h>
# include <errno.h>
# include <unistd.h>
@@ -411,6 +412,7 @@ void GC_thr_init()
GC_thread t;
struct sigaction act;
+ if (GC_thr_initialized) return;
GC_thr_initialized = TRUE;
GC_min_stack_sz = HBLKSIZE;
GC_page_sz = sysconf(_SC_PAGESIZE);
@@ -445,9 +447,14 @@ int GC_pthread_sigmask(int how, const sigset_t *set, sigset_t *oset)
struct start_info {
void *(*start_routine)(void *);
void *arg;
+ word flags;
+ ptr_t stack;
+ size_t stack_size;
+ sem_t registered; /* 1 ==> in our thread table, but */
+ /* parent hasn't yet noticed. */
};
-void GC_thread_exit_proc(void *dummy)
+void GC_thread_exit_proc(void *arg)
{
GC_thread me;
@@ -472,6 +479,9 @@ int GC_pthread_join(pthread_t thread, void **retval)
/* cant have been recycled by pthreads. */
UNLOCK();
result = pthread_join(thread, retval);
+ /* Some versions of the Irix pthreads library can erroneously */
+ /* return EINTR when the call succeeds. */
+ if (EINTR == result) result = 0;
LOCK();
/* Here the pthread thread id may have been recycled. */
GC_delete_gc_thread(thread, thread_gc_id);
@@ -484,12 +494,34 @@ void * GC_start_routine(void * arg)
struct start_info * si = arg;
void * result;
GC_thread me;
-
+ pthread_t my_pthread;
+ void *(*start)(void *);
+ void *start_arg;
+
+ my_pthread = pthread_self();
+ /* If a GC occurs before the thread is registered, that GC will */
+ /* ignore this thread. That's fine, since it will block trying to */
+ /* acquire the allocation lock, and won't yet hold interesting */
+ /* pointers. */
LOCK();
- me = GC_lookup_thread(pthread_self());
+ /* We register the thread here instead of in the parent, so that */
+ /* we don't need to hold the allocation lock during pthread_create. */
+ /* Holding the allocation lock there would make REDIRECT_MALLOC */
+ /* impossible. It probably still doesn't work, but we're a little */
+ /* closer ... */
+ /* This unfortunately means that we have to be careful the parent */
+ /* doesn't try to do a pthread_join before we're registered. */
+ me = GC_new_thread(my_pthread);
+ me -> flags = si -> flags;
+ me -> stack = si -> stack;
+ me -> stack_size = si -> stack_size;
+ me -> stack_ptr = (ptr_t)si -> stack + si -> stack_size - sizeof(word);
UNLOCK();
+ start = si -> start_routine;
+ start_arg = si -> arg;
+ sem_post(&(si -> registered));
pthread_cleanup_push(GC_thread_exit_proc, 0);
- result = (*(si -> start_routine))(si -> arg);
+ result = (*start)(start_arg);
me -> status = result;
me -> flags |= FINISHED;
pthread_cleanup_pop(1);
@@ -506,15 +538,17 @@ GC_pthread_create(pthread_t *new_thread,
{
int result;
GC_thread t;
- pthread_t my_new_thread;
void * stack;
size_t stacksize;
pthread_attr_t new_attr;
int detachstate;
word my_flags = 0;
struct start_info * si = GC_malloc(sizeof(struct start_info));
+ /* This is otherwise saved only in an area mmapped by the thread */
+ /* library, which isn't visible to the collector. */
if (0 == si) return(ENOMEM);
+ sem_init(&(si -> registered), 0, 0);
si -> start_routine = start_routine;
si -> arg = arg;
LOCK();
@@ -540,20 +574,20 @@ GC_pthread_create(pthread_t *new_thread,
my_flags |= CLIENT_OWNS_STACK;
}
if (PTHREAD_CREATE_DETACHED == detachstate) my_flags |= DETACHED;
- result = pthread_create(&my_new_thread, &new_attr, GC_start_routine, si);
- /* No GC can start until the thread is registered, since we hold */
- /* the allocation lock. */
- if (0 == result) {
- t = GC_new_thread(my_new_thread);
- t -> flags = my_flags;
- t -> stack = stack;
- t -> stack_size = stacksize;
- t -> stack_ptr = (ptr_t)stack + stacksize - sizeof(word);
- if (0 != new_thread) *new_thread = my_new_thread;
- } else if (!(my_flags & CLIENT_OWNS_STACK)) {
+ si -> flags = my_flags;
+ si -> stack = stack;
+ si -> stack_size = stacksize;
+ result = pthread_create(new_thread, &new_attr, GC_start_routine, si);
+ if (0 == new_thread && !(my_flags & CLIENT_OWNS_STACK)) {
GC_stack_free(stack, stacksize);
}
UNLOCK();
+ /* Wait until child has been added to the thread table. */
+ /* This also ensures that we hold onto si until the child is done */
+ /* with it. Thus it doesn't matter whether it is otherwise */
+ /* visible to the collector. */
+ if (0 != sem_wait(&(si -> registered))) ABORT("sem_wait failed");
+ sem_destroy(&(si -> registered));
/* pthread_attr_destroy(&new_attr); */
return(result);
}
diff --git a/linux_threads.c b/linux_threads.c
index 12e71cea..4bcdd3a1 100644
--- a/linux_threads.c
+++ b/linux_threads.c
@@ -28,9 +28,13 @@
* there too.
*/
-# if defined(LINUX_THREADS)
+/* #define DEBUG_THREADS 1 */
+/* ANSI C requires that a compilation unit contains something */
# include "gc_priv.h"
+
+# if defined(LINUX_THREADS)
+
# include <pthread.h>
# include <time.h>
# include <errno.h>
@@ -419,6 +423,7 @@ void GC_thr_init()
GC_thread t;
struct sigaction act;
+ if (GC_thr_initialized) return;
GC_thr_initialized = TRUE;
if (sem_init(&GC_suspend_ack_sem, 0, 0) != 0)
@@ -441,7 +446,7 @@ void GC_thr_init()
/* Add the initial thread, so we can stop it. */
t = GC_new_thread(pthread_self());
- t -> stack_ptr = (ptr_t)(&t);
+ t -> stack_ptr = 0;
t -> flags = DETACHED | MAIN_THREAD;
}
@@ -460,11 +465,16 @@ int GC_pthread_sigmask(int how, const sigset_t *set, sigset_t *oset)
struct start_info {
void *(*start_routine)(void *);
void *arg;
+ word flags;
+ sem_t registered; /* 1 ==> in our thread table, but */
+ /* parent hasn't yet noticed. */
};
-void GC_thread_exit_proc(void *dummy)
+
+void GC_thread_exit_proc(void *arg)
{
GC_thread me;
+ struct start_info * si = arg;
LOCK();
me = GC_lookup_thread(pthread_self());
@@ -499,26 +509,37 @@ void * GC_start_routine(void * arg)
struct start_info * si = arg;
void * result;
GC_thread me;
+ pthread_t my_pthread;
+ void *(*start)(void *);
+ void *start_arg;
+ my_pthread = pthread_self();
LOCK();
- me = GC_lookup_thread(pthread_self());
+ me = GC_new_thread(my_pthread);
+ me -> flags = si -> flags;
+ me -> stack_ptr = 0;
+ me -> stack_end = 0;
UNLOCK();
- pthread_cleanup_push(GC_thread_exit_proc, 0);
+ start = si -> start_routine;
+ start_arg = si -> arg;
+ sem_post(&(si -> registered));
+ pthread_cleanup_push(GC_thread_exit_proc, si);
# ifdef DEBUG_THREADS
- GC_printf1("Starting thread 0x%x\n", pthread_self());
+ GC_printf1("Starting thread 0x%lx\n", pthread_self());
GC_printf1("pid = %ld\n", (long) getpid());
GC_printf1("sp = 0x%lx\n", (long) &arg);
+ GC_printf1("start_routine = 0x%lx\n", start);
# endif
- result = (*(si -> start_routine))(si -> arg);
+ result = (*start)(start_arg);
#if DEBUG_THREADS
GC_printf1("Finishing thread 0x%x\n", pthread_self());
#endif
me -> status = result;
me -> flags |= FINISHED;
pthread_cleanup_pop(1);
- /* This involves acquiring the lock, ensuring that we can't exit */
- /* while a collection that thinks we're alive is trying to stop */
- /* us. */
+ /* Cleanup acquires lock, ensuring that we can't exit */
+ /* while a collection that thinks we're alive is trying to stop */
+ /* us. */
return(result);
}
@@ -536,8 +557,11 @@ GC_pthread_create(pthread_t *new_thread,
int detachstate;
word my_flags = 0;
struct start_info * si = GC_malloc(sizeof(struct start_info));
+ /* This is otherwise saved only in an area mmapped by the thread */
+ /* library, which isn't visible to the collector. */
if (0 == si) return(ENOMEM);
+ sem_init(&(si -> registered), 0, 0);
si -> start_routine = start_routine;
si -> arg = arg;
LOCK();
@@ -550,17 +574,16 @@ GC_pthread_create(pthread_t *new_thread,
}
pthread_attr_getdetachstate(&new_attr, &detachstate);
if (PTHREAD_CREATE_DETACHED == detachstate) my_flags |= DETACHED;
- result = pthread_create(&my_new_thread, &new_attr, GC_start_routine, si);
- /* No GC can start until the thread is registered, since we hold */
- /* the allocation lock. */
- if (0 == result) {
- t = GC_new_thread(my_new_thread);
- t -> flags = my_flags;
- t -> stack_ptr = 0;
- t -> stack_end = 0;
- if (0 != new_thread) *new_thread = my_new_thread;
- }
- UNLOCK();
+ si -> flags = my_flags;
+ UNLOCK();
+ result = pthread_create(new_thread, &new_attr, GC_start_routine, si);
+ /* Wait until child has been added to the thread table. */
+ /* This also ensures that we hold onto si until the child is done */
+ /* with it. Thus it doesn't matter whether it is otherwise */
+ /* visible to the collector. */
+ if (0 != sem_wait(&(si -> registered))) ABORT("sem_wait failed");
+ sem_destroy(&(si -> registered));
+ /* pthread_attr_destroy(&new_attr); */
/* pthread_attr_destroy(&new_attr); */
return(result);
}
diff --git a/malloc.c b/malloc.c
index 41553b7f..37da584c 100644
--- a/malloc.c
+++ b/malloc.c
@@ -220,6 +220,9 @@ DCL_LOCK_STATE;
/*
* Thread initialisation can call malloc before
* we're ready for it.
+ * It's not clear that this is enough to help matters.
+ * The thread implementation may well call malloc at other
+ * inopportune times.
*/
if (!GC_is_initialized) return sbrk(lb);
# endif /* I386 && SOLARIS_THREADS */
@@ -375,6 +378,12 @@ int obj_kind;
/* Required by ANSI. It's not my fault ... */
h = HBLKPTR(p);
hhdr = HDR(h);
+# if defined(REDIRECT_MALLOC) && \
+ (defined(SOLARIS_THREADS) || defined(LINUX_THREADS))
+ /* We have to redirect malloc calls during initialization. */
+ /* Don't try to deallocate that memory. */
+ if (0 == hhdr) return;
+# endif
knd = hhdr -> hb_obj_kind;
sz = hhdr -> hb_sz;
ok = &GC_obj_kinds[knd];
diff --git a/mark.c b/mark.c
index 1723a446..0fffcf3c 100644
--- a/mark.c
+++ b/mark.c
@@ -21,7 +21,11 @@
/* We put this here to minimize the risk of inlining. */
/*VARARGS*/
-void GC_noop() {}
+#ifdef __WATCOMC__
+ void GC_noop(void *p, ...) {}
+#else
+ void GC_noop() {}
+#endif
/* Single argument version, robust against whole program analysis. */
void GC_noop1(x)
@@ -32,7 +36,8 @@ word x;
sink = x;
}
-mark_proc GC_mark_procs[MAX_MARK_PROCS] = {0};
+/* mark_proc GC_mark_procs[MAX_MARK_PROCS] = {0} -- declared in gc_priv.h */
+
word GC_n_mark_procs = 0;
/* Initialize GC_obj_kinds properly and standard free lists properly. */
diff --git a/mark_rts.c b/mark_rts.c
index efe6b640..5b8f8b08 100644
--- a/mark_rts.c
+++ b/mark_rts.c
@@ -15,46 +15,27 @@
# 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
-# ifdef PCR
-# define MAX_ROOT_SETS 1024
-# else
-# ifdef MSWIN32
-# define MAX_ROOT_SETS 512
- /* Under NT, we add only written pages, which can result */
- /* in many small root sets. */
-# else
-# define MAX_ROOT_SETS 64
-# endif
-# 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 */
/* we resort to sequential search, and pay the price. */
+/* This is really declared in gc_priv.h:
struct roots {
ptr_t r_start;
ptr_t r_end;
-# ifndef MSWIN32
+ # ifndef MSWIN32
struct roots * r_next;
-# endif
+ # endif
GC_bool r_tmp;
- /* Delete before registering new dynamic libraries */
+ -- Delete before registering new dynamic libraries
};
-static struct roots static_roots[MAX_ROOT_SETS];
+struct roots GC_static_roots[MAX_ROOT_SETS];
+*/
static int n_root_sets = 0;
- /* static_roots[0..n_root_sets) contains the valid root sets. */
+ /* GC_static_roots[0..n_root_sets) contains the valid root sets. */
# if !defined(NO_DEBUGGING)
/* For debugging: */
@@ -65,14 +46,14 @@ void GC_print_static_roots()
for (i = 0; i < n_root_sets; i++) {
GC_printf2("From 0x%lx to 0x%lx ",
- (unsigned long) static_roots[i].r_start,
- (unsigned long) static_roots[i].r_end);
- if (static_roots[i].r_tmp) {
+ (unsigned long) GC_static_roots[i].r_start,
+ (unsigned long) GC_static_roots[i].r_end);
+ if (GC_static_roots[i].r_tmp) {
GC_printf0(" (temporary)\n");
} else {
GC_printf0("\n");
}
- total += static_roots[i].r_end - static_roots[i].r_start;
+ total += GC_static_roots[i].r_end - GC_static_roots[i].r_start;
}
GC_printf1("Total size: %ld\n", (unsigned long) total);
if (GC_root_size != total) {
@@ -92,11 +73,11 @@ ptr_t p;
register int i;
- if (p >= static_roots[last_root_set].r_start
- && p < static_roots[last_root_set].r_end) return(TRUE);
+ if (p >= GC_static_roots[last_root_set].r_start
+ && p < GC_static_roots[last_root_set].r_end) return(TRUE);
for (i = 0; i < n_root_sets; i++) {
- if (p >= static_roots[i].r_start
- && p < static_roots[i].r_end) {
+ if (p >= GC_static_roots[i].r_start
+ && p < GC_static_roots[i].r_end) {
last_root_set = i;
return(TRUE);
}
@@ -105,12 +86,15 @@ ptr_t p;
}
#ifndef MSWIN32
+/*
# define LOG_RT_SIZE 6
-# define RT_SIZE (1 << LOG_RT_SIZE) /* Power of 2, may be != MAX_ROOT_SETS */
+# define RT_SIZE (1 << LOG_RT_SIZE) -- Power of 2, may be != MAX_ROOT_SETS
- static struct roots * root_index[RT_SIZE];
- /* Hash table header. Used only to check whether a range is */
- /* already present. */
+ struct roots * GC_root_index[RT_SIZE];
+ -- Hash table header. Used only to check whether a range is
+ -- already present.
+ -- really defined in gc_priv.h
+*/
static int rt_hash(addr)
char * addr;
@@ -134,7 +118,7 @@ struct roots * GC_roots_present(b)
char *b;
{
register int h = rt_hash(b);
- register struct roots *p = root_index[h];
+ register struct roots *p = GC_root_index[h];
while (p != 0) {
if (p -> r_start == (ptr_t)b) return(p);
@@ -149,8 +133,8 @@ struct roots *p;
{
register int h = rt_hash(p -> r_start);
- p -> r_next = root_index[h];
- root_index[h] = p;
+ p -> r_next = GC_root_index[h];
+ GC_root_index[h] = p;
}
# else /* MSWIN32 */
@@ -200,7 +184,7 @@ GC_bool tmp;
register int i;
for (i = 0; i < n_root_sets; i++) {
- old = static_roots + i;
+ old = GC_static_roots + i;
if ((ptr_t)b <= old -> r_end && (ptr_t)e >= old -> r_start) {
if ((ptr_t)b < old -> r_start) {
old -> r_start = (ptr_t)b;
@@ -219,7 +203,7 @@ GC_bool tmp;
struct roots *other;
for (i++; i < n_root_sets; i++) {
- other = static_roots + i;
+ other = GC_static_roots + i;
b = (char *)(other -> r_start);
e = (char *)(other -> r_end);
if ((ptr_t)b <= old -> r_end && (ptr_t)e >= old -> r_start) {
@@ -234,8 +218,8 @@ GC_bool tmp;
old -> r_tmp &= other -> r_tmp;
/* Delete this entry. */
GC_root_size -= (other -> r_end - other -> r_start);
- other -> r_start = static_roots[n_root_sets-1].r_start;
- other -> r_end = static_roots[n_root_sets-1].r_end;
+ other -> r_start = GC_static_roots[n_root_sets-1].r_start;
+ other -> r_end = GC_static_roots[n_root_sets-1].r_end;
n_root_sets--;
}
}
@@ -255,13 +239,13 @@ GC_bool tmp;
if (n_root_sets == MAX_ROOT_SETS) {
ABORT("Too many root sets\n");
}
- static_roots[n_root_sets].r_start = (ptr_t)b;
- static_roots[n_root_sets].r_end = (ptr_t)e;
- static_roots[n_root_sets].r_tmp = tmp;
+ GC_static_roots[n_root_sets].r_start = (ptr_t)b;
+ GC_static_roots[n_root_sets].r_end = (ptr_t)e;
+ GC_static_roots[n_root_sets].r_tmp = tmp;
# ifndef MSWIN32
- static_roots[n_root_sets].r_next = 0;
+ GC_static_roots[n_root_sets].r_next = 0;
# endif
- add_roots_to_index(static_roots + n_root_sets);
+ add_roots_to_index(GC_static_roots + n_root_sets);
GC_root_size += (ptr_t)e - (ptr_t)b;
n_root_sets++;
}
@@ -278,7 +262,7 @@ void GC_clear_roots GC_PROTO((void))
{
register int i;
- for (i = 0; i < RT_SIZE; i++) root_index[i] = 0;
+ for (i = 0; i < RT_SIZE; i++) GC_root_index[i] = 0;
}
# endif
UNLOCK();
@@ -291,11 +275,12 @@ void GC_remove_tmp_roots()
register int i;
for (i = 0; i < n_root_sets; ) {
- if (static_roots[i].r_tmp) {
- GC_root_size -= (static_roots[i].r_end - static_roots[i].r_start);
- static_roots[i].r_start = static_roots[n_root_sets-1].r_start;
- static_roots[i].r_end = static_roots[n_root_sets-1].r_end;
- static_roots[i].r_tmp = static_roots[n_root_sets-1].r_tmp;
+ if (GC_static_roots[i].r_tmp) {
+ GC_root_size -=
+ (GC_static_roots[i].r_end - GC_static_roots[i].r_start);
+ GC_static_roots[i].r_start = GC_static_roots[n_root_sets-1].r_start;
+ GC_static_roots[i].r_end = GC_static_roots[n_root_sets-1].r_end;
+ GC_static_roots[i].r_tmp = GC_static_roots[n_root_sets-1].r_tmp;
n_root_sets--;
} else {
i++;
@@ -305,8 +290,9 @@ void GC_remove_tmp_roots()
{
register int i;
- for (i = 0; i < RT_SIZE; i++) root_index[i] = 0;
- for (i = 0; i < n_root_sets; i++) add_roots_to_index(static_roots + i);
+ for (i = 0; i < RT_SIZE; i++) GC_root_index[i] = 0;
+ for (i = 0; i < n_root_sets; i++)
+ add_roots_to_index(GC_static_roots + i);
}
# endif
@@ -321,16 +307,19 @@ ptr_t GC_approx_sp()
/*
* Data structure for excluded static roots.
- */
+ * Real declaration is in gc_priv.h.
+
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. */
+struct exclusion GC_excl_table[MAX_EXCLUSIONS];
+ -- Array of exclusions, ascending
+ -- address order.
+*/
+
+size_t GC_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 */
@@ -339,20 +328,20 @@ struct exclusion * GC_next_exclusion(start_addr)
ptr_t start_addr;
{
size_t low = 0;
- size_t high = excl_table_entries - 1;
+ size_t high = GC_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) {
+ if ((word) GC_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;
+ if ((word) GC_excl_table[low].e_end <= (word) start_addr) return 0;
+ return GC_excl_table + low;
}
void GC_exclude_static_roots(start, finish)
@@ -362,7 +351,7 @@ GC_PTR finish;
struct exclusion * next;
size_t next_index, i;
- if (0 == excl_table_entries) {
+ if (0 == GC_excl_table_entries) {
next = 0;
} else {
next = GC_next_exclusion(start);
@@ -377,17 +366,17 @@ GC_PTR finish;
next -> e_start = (ptr_t)start;
return;
}
- next_index = next - excl_table;
- for (i = excl_table_entries; i > next_index; --i) {
- excl_table[i] = excl_table[i-1];
+ next_index = next - GC_excl_table;
+ for (i = GC_excl_table_entries; i > next_index; --i) {
+ GC_excl_table[i] = GC_excl_table[i-1];
}
} else {
- next_index = excl_table_entries;
+ next_index = GC_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;
+ if (GC_excl_table_entries == MAX_EXCLUSIONS) ABORT("Too many exclusions");
+ GC_excl_table[next_index].e_start = (ptr_t)start;
+ GC_excl_table[next_index].e_end = (ptr_t)finish;
+ ++GC_excl_table_entries;
}
/* Invoke push_conditional on ranges that are not excluded. */
@@ -440,8 +429,8 @@ GC_bool all;
/* Mark everything in static data areas */
for (i = 0; i < n_root_sets; i++) {
GC_push_conditional_with_exclusions(
- static_roots[i].r_start,
- static_roots[i].r_end, all);
+ GC_static_roots[i].r_start,
+ GC_static_roots[i].r_end, all);
}
/*
diff --git a/misc.c b/misc.c
index 4c76af81..437ce8e0 100644
--- a/misc.c
+++ b/misc.c
@@ -42,7 +42,8 @@
# ifdef WIN32_THREADS
GC_API CRITICAL_SECTION GC_allocate_ml;
# else
-# if defined(IRIX_THREADS) || defined(LINUX_THREADS)
+# if defined(IRIX_THREADS) || defined(LINUX_THREADS) \
+ || defined(IRIX_JDK_THREADS)
# ifdef UNDEFINED
pthread_mutex_t GC_allocate_ml = PTHREAD_MUTEX_INITIALIZER;
# endif
@@ -417,20 +418,29 @@ void GC_init_inner()
if (GC_is_initialized) return;
GC_setpagesize();
- GC_exclude_static_roots(beginGC_arrays, endGC_arrays);
+ GC_exclude_static_roots(beginGC_arrays, end_gc_area);
+# ifdef PRINTSTATS
+ if ((ptr_t)endGC_arrays != (ptr_t)(&GC_obj_kinds)) {
+ GC_printf0("Reordering linker, didn't exclude obj_kinds\n");
+ }
+# endif
# ifdef MSWIN32
GC_init_win32();
# endif
# if defined(LINUX) && defined(POWERPC)
GC_init_linuxppc();
# endif
+# if defined(LINUX) && defined(SPARC)
+ GC_init_linuxsparc();
+# endif
# ifdef SOLARIS_THREADS
GC_thr_init();
/* We need dirty bits in order to find live stack sections. */
GC_dirty_init();
# endif
-# if defined(IRIX_THREADS) || defined(LINUX_THREADS)
- GC_thr_init();
+# if defined(IRIX_THREADS) || defined(LINUX_THREADS) \
+ || defined(IRIX_JDK_THREADS)
+ GC_thr_init();
# endif
# if !defined(THREADS) || defined(SOLARIS_THREADS) || defined(WIN32_THREADS) \
|| defined(IRIX_THREADS) || defined(LINUX_THREADS)
@@ -548,9 +558,9 @@ void GC_init_inner()
void GC_enable_incremental GC_PROTO(())
{
+# if !defined(FIND_LEAK) && !defined(SMALL_CONFIG)
DCL_LOCK_STATE;
-# ifndef FIND_LEAK
DISABLE_SIGNALS();
LOCK();
if (GC_incremental) goto out;
diff --git a/os_dep.c b/os_dep.c
index d64dd5c0..353074cf 100644
--- a/os_dep.c
+++ b/os_dep.c
@@ -68,7 +68,7 @@
# define NEED_FIND_LIMIT
# endif
-# if defined(LINUX) && defined(POWERPC)
+# if defined(LINUX) && (defined(POWERPC) || defined(SPARC))
# define NEED_FIND_LIMIT
# endif
@@ -148,6 +148,19 @@
}
#endif
+#if defined(LINUX) && defined(SPARC)
+ ptr_t GC_data_start;
+
+ void GC_init_linuxsparc()
+ {
+ extern ptr_t GC_find_limit();
+ extern char **_environ;
+ /* This may need to be environ, without the underscore, for */
+ /* some versions. */
+ GC_data_start = GC_find_limit((ptr_t)&_environ, FALSE);
+ }
+#endif
+
# ifdef OS2
# include <stddef.h>
@@ -938,9 +951,19 @@ void GC_register_data_segments()
# if defined(__MWERKS__)
# if !__POWERPC__
extern void* GC_MacGetDataStart(void);
+ /* MATTHEW: Function to handle Far Globals (CW Pro 3) */
+# if __option(far_data)
+ extern void* GC_MacGetDataEnd(void);
+# endif
/* globals begin above stack and end at a5. */
GC_add_roots_inner((ptr_t)GC_MacGetDataStart(),
(ptr_t)LMGetCurrentA5(), FALSE);
+ /* MATTHEW: Handle Far Globals */
+# if __option(far_data)
+ /* Far globals follow he QD globals: */
+ GC_add_roots_inner((ptr_t)LMGetCurrentA5(),
+ (ptr_t)GC_MacGetDataEnd(), FALSE);
+# endif
# else
extern char __data_start__[], __data_end__[];
GC_add_roots_inner((ptr_t)&__data_start__,
@@ -1007,7 +1030,15 @@ word bytes;
#else /* Not RS6000 */
#if defined(USE_MMAP)
-/* Tested only under IRIX5 */
+/* Tested only under IRIX5 and Solaris 2 */
+
+#ifdef USE_MMAP_FIXED
+# define GC_MMAP_FLAGS MAP_FIXED | MAP_PRIVATE
+ /* Seems to yield better performance on Solaris 2, but can */
+ /* be unreliable if something is already mapped at the address. */
+#else
+# define GC_MMAP_FLAGS MAP_PRIVATE
+#endif
ptr_t GC_unix_get_mem(bytes)
word bytes;
@@ -1023,7 +1054,7 @@ word bytes;
}
if (bytes & (GC_page_size -1)) ABORT("Bad GET_MEM arg");
result = mmap(last_addr, bytes, PROT_READ | PROT_WRITE | OPT_PROT_EXEC,
- MAP_PRIVATE | MAP_FIXED, fd, 0/* offset */);
+ GC_MMAP_FLAGS, fd, 0/* offset */);
if (result == MAP_FAILED) return(0);
last_addr = (ptr_t)result + bytes + GC_page_size - 1;
last_addr = (ptr_t)((word)last_addr & ~(GC_page_size - 1));
@@ -1107,6 +1138,17 @@ word bytes;
return(result);
}
+void GC_win32_free_heap ()
+{
+ if (GC_win32s) {
+ while (GC_n_heap_bases > 0) {
+ GlobalFree (GC_heap_bases[--GC_n_heap_bases]);
+ GC_heap_bases[GC_n_heap_bases] = 0;
+ }
+ }
+}
+
+
# endif
/* Routine for pushing any additional roots. In THREADS */
@@ -1225,7 +1267,8 @@ void GC_default_push_other_roots()
# endif /* SRC_M3 */
# if defined(SOLARIS_THREADS) || defined(WIN32_THREADS) \
- || defined(IRIX_THREADS) || defined LINUX_THREADS
+ || defined(IRIX_THREADS) || defined(LINUX_THREADS) \
+ || defined(IRIX_PCR_THREADS)
extern void GC_push_all_stacks();
@@ -1382,9 +1425,6 @@ struct hblk *h;
# endif
-VOLATILE page_hash_table GC_dirty_pages;
- /* Pages dirtied since last GC_read_dirty. */
-
#if defined(SUNOS4) || defined(FREEBSD)
typedef void (* SIG_PF)();
#endif
@@ -1444,7 +1484,7 @@ SIG_PF GC_old_segv_handler; /* Also old MSWIN32 ACCESS_VIOLATION filter */
# endif
# endif
# if defined(LINUX)
-# if (LINUX_VERSION_CODE >= 0x20100)
+# if (LINUX_VERSION_CODE >= 0x20100) && !defined(M68K)
void GC_write_fault_handler(int sig, struct sigcontext sc)
# else
void GC_write_fault_handler(int sig, struct sigcontext_struct sc)
@@ -1482,7 +1522,35 @@ SIG_PF GC_old_segv_handler; /* Also old MSWIN32 ACCESS_VIOLATION filter */
# ifdef I386
char * addr = (char *) (sc.cr2);
# else
- char * addr = /* As of 1.3.90 there seemed to be no way to do this. */;
+# if defined(M68K)
+ char * addr = NULL;
+
+ struct sigcontext *scp = (struct sigcontext *)(&sc);
+
+ int format = (scp->sc_formatvec >> 12) & 0xf;
+ unsigned long *framedata = (unsigned long *)(scp + 1);
+ unsigned long ea;
+
+ if (format == 0xa || format == 0xb) {
+ /* 68020/030 */
+ ea = framedata[2];
+ } else if (format == 7) {
+ /* 68040 */
+ ea = framedata[3];
+ } else if (format == 4) {
+ /* 68060 */
+ ea = framedata[0];
+ if (framedata[1] & 0x08000000) {
+ /* correct addr on misaligned access */
+ ea = (ea+4095)&(~4095);
+ }
+ }
+ addr = (char *)ea;
+# else
+ char * addr =
+ /* As of 1.3.90 there seemed to be no way to do this
+ on Linux/Alpha */;
+# endif
# endif
# endif
# if defined(MSWIN32)
@@ -1518,6 +1586,7 @@ SIG_PF GC_old_segv_handler; /* Also old MSWIN32 ACCESS_VIOLATION filter */
}
if (old_handler == SIG_DFL) {
# ifndef MSWIN32
+ GC_err_printf1("Segfault at 0x%lx\n", addr);
ABORT("Unexpected bus error or segmentation fault");
# else
return(EXCEPTION_CONTINUE_SEARCH);
@@ -1565,6 +1634,7 @@ SIG_PF GC_old_segv_handler; /* Also old MSWIN32 ACCESS_VIOLATION filter */
#ifdef MSWIN32
return EXCEPTION_CONTINUE_SEARCH;
#else
+ GC_err_printf1("Segfault at 0x%lx\n", addr);
ABORT("Unexpected bus error or segmentation fault");
#endif
}
@@ -1642,7 +1712,7 @@ void GC_dirty_init()
}
# endif
# if defined(SUNOS5SIGS) || defined(IRIX5)
-# ifdef IRIX_THREADS
+# if defined(IRIX_THREADS) || defined(IRIX_PCR_THREADS)
sigaction(SIGSEGV, 0, &oldact);
sigaction(SIGSEGV, &act, 0);
# else
@@ -1843,8 +1913,6 @@ word n;
word GC_proc_buf_size = INITIAL_BUF_SZ;
char *GC_proc_buf;
-page_hash_table GC_written_pages = { 0 }; /* Pages ever dirtied */
-
#ifdef SOLARIS_THREADS
/* We don't have exact sp values for threads. So we count on */
/* occasionally declaring stack pages to be fresh. Thus we */
@@ -2135,7 +2203,7 @@ struct hblk *h;
* Call stack save code for debugging.
* Should probably be in mach_dep.c, but that requires reorganization.
*/
-#if defined(SPARC)
+#if defined(SPARC) && !defined(LINUX)
# if defined(SUNOS4)
# include <machine/frame.h>
# else
diff --git a/setjmp_t.c b/setjmp_t.c
index 9ed92138..1c9253e9 100644
--- a/setjmp_t.c
+++ b/setjmp_t.c
@@ -25,7 +25,7 @@
#include <stdio.h>
#include <setjmp.h>
#include <string.h>
-#include "config.h"
+#include "gcconfig.h"
#ifdef OS2
/* GETPAGESIZE() is set to getpagesize() by default, but that */
diff --git a/test.c b/test.c
index 2fc51e12..0fdb030a 100644
--- a/test.c
+++ b/test.c
@@ -25,7 +25,7 @@
# include "gc.h"
# include "gc_typed.h"
# include "gc_priv.h" /* For output, locking, and some statistics */
-# include "config.h"
+# include "gcconfig.h"
# ifdef MSWIN32
# include <windows.h>
@@ -266,6 +266,72 @@ struct {
#define a A.aa
/*
+ * A tiny list reversal test to check thread creation.
+ */
+#ifdef THREADS
+
+# ifdef WIN32_THREADS
+ unsigned __stdcall tiny_reverse_test(void * arg)
+# else
+ void * tiny_reverse_test(void * arg)
+# endif
+{
+ check_ints(reverse(reverse(ints(1,10))), 1, 10);
+ return 0;
+}
+
+# if defined(IRIX_THREADS) || defined(LINUX_THREADS) \
+ || defined(SOLARIS_PTHREADS)
+ void fork_a_thread()
+ {
+ pthread_t t;
+ int code;
+ if ((code = pthread_create(&t, 0, tiny_reverse_test, 0)) != 0) {
+ (void)GC_printf1("Small thread creation failed %lu\n",
+ (unsigned long)code);
+ FAIL;
+ }
+ if ((code = pthread_join(t, 0)) != 0) {
+ (void)GC_printf1("Small thread join failed %lu\n",
+ (unsigned long)code);
+ FAIL;
+ }
+ }
+
+# elif defined(WIN32_THREADS)
+ void fork_a_thread()
+ {
+ unsigned thread_id;
+ HANDLE h;
+ h = (HANDLE)_beginthreadex(NULL, 0, tiny_reverse_test,
+ 0, 0, &thread_id);
+ if (h == (HANDLE)-1) {
+ (void)GC_printf1("Small thread creation failed %lu\n",
+ (unsigned long)GetLastError());
+ FAIL;
+ }
+ if (WaitForSingleObject(h, INFINITE) != WAIT_OBJECT_0) {
+ (void)GC_printf1("Small thread wait failed %lu\n",
+ (unsigned long)GetLastError());
+ FAIL;
+ }
+ }
+
+/* # elif defined(SOLARIS_THREADS) */
+
+# else
+
+# define fork_a_thread()
+
+# endif
+
+#else
+
+# define fork_a_thread()
+
+#endif
+
+/*
* Repeatedly reverse lists built out of very different sized cons cells.
* Check that we didn't lose anything.
*/
@@ -327,6 +393,7 @@ void reverse_test()
check_ints(b,1,50);
check_ints(a,1,49);
for (i = 0; i < 60; i++) {
+ if (i % 10 == 0) fork_a_thread();
/* This maintains the invariant that a always points to a list of */
/* 49 integers. Thus this is thread safe without locks, */
/* assuming atomic pointer assignments. */
@@ -538,7 +605,7 @@ int n;
chktree(t -> rchild, n-1);
}
-# ifdef SOLARIS_THREADS
+# if defined(SOLARIS_THREADS) && !defined(_SOLARIS_PTHREADS)
thread_key_t fl_key;
void * alloc8bytes()
@@ -575,7 +642,44 @@ void * alloc8bytes()
}
#else
-# define alloc8bytes() GC_MALLOC_ATOMIC(8)
+
+# if defined(_SOLARIS_PTHREADS) || defined(IRIX_THREADS) \
+ || defined(LINUX_THREADS)
+pthread_key_t fl_key;
+
+void * alloc8bytes()
+{
+# ifdef SMALL_CONFIG
+ return(GC_malloc(8));
+# else
+ void ** my_free_list_ptr;
+ void * my_free_list;
+
+ my_free_list_ptr = (void **)pthread_getspecific(fl_key);
+ if (my_free_list_ptr == 0) {
+ my_free_list_ptr = GC_NEW_UNCOLLECTABLE(void *);
+ if (pthread_setspecific(fl_key, my_free_list_ptr) != 0) {
+ (void)GC_printf0("pthread_setspecific failed\n");
+ FAIL;
+ }
+ }
+ my_free_list = *my_free_list_ptr;
+ if (my_free_list == 0) {
+ my_free_list = GC_malloc_many(8);
+ if (my_free_list == 0) {
+ (void)GC_printf0("alloc8bytes out of memory\n");
+ FAIL;
+ }
+ }
+ *my_free_list_ptr = GC_NEXT(my_free_list);
+ GC_NEXT(my_free_list) = 0;
+ return(my_free_list);
+# endif
+}
+
+# else
+# define alloc8bytes() GC_MALLOC_ATOMIC(8)
+# endif
#endif
void alloc_small(n)
@@ -980,6 +1084,9 @@ void SetMinimumStack(long minSize)
GC_set_max_heap_size, GC_get_bytes_since_gc,
GC_pre_incr, GC_post_incr);
# endif
+# ifdef MSWIN32
+ GC_win32_free_heap();
+# endif
return(0);
}
# endif
@@ -1125,6 +1232,10 @@ main()
(void) GC_printf0("Emulating dirty bits with mprotect/signals\n");
# endif
(void) GC_set_warn_proc(warn_proc);
+ if (pthread_key_create(&fl_key, 0) != 0) {
+ (void)GC_printf1("Key creation failed %lu\n", (unsigned long)code);
+ FAIL;
+ }
if ((code = pthread_create(&th1, &attr, thr_run_one_test, 0)) != 0) {
(void)GC_printf1("Thread 1 creation failed %lu\n", (unsigned long)code);
FAIL;
diff --git a/threadlibs.c b/threadlibs.c
index c8530e6f..4a0a6cfc 100644
--- a/threadlibs.c
+++ b/threadlibs.c
@@ -1,4 +1,4 @@
-# include "config.h"
+# include "gcconfig.h"
# include <stdio.h>
int main()
diff --git a/version.h b/version.h
index 56114873..19b20f9d 100644
--- a/version.h
+++ b/version.h
@@ -1,6 +1,6 @@
#define GC_VERSION_MAJOR 4
#define GC_VERSION_MINOR 13
-#define GC_ALPHA_VERSION 2
+#define GC_ALPHA_VERSION 3
# define GC_NOT_ALPHA 0xff
diff --git a/win32_threads.c b/win32_threads.c
index eb485bdc..2b01c5c6 100755
--- a/win32_threads.c
+++ b/win32_threads.c
@@ -8,22 +8,32 @@
#define MAX_THREADS 64
struct thread_entry {
+ LONG in_use;
DWORD id;
HANDLE handle;
- void *stack; /* The cold end of the stack. */
+ void *stack; /* The cold end of the stack. */
+ /* 0 ==> entry not valid. */
+ /* !in_use ==> stack == 0 */
CONTEXT context;
+ GC_bool suspended;
};
-struct thread_entry thread_table[MAX_THREADS];
+volatile GC_bool GC_please_stop = FALSE;
+
+volatile struct thread_entry thread_table[MAX_THREADS];
void GC_stop_world()
{
DWORD thread_id = GetCurrentThreadId();
int i;
+
+ GC_please_stop = TRUE;
for (i = 0; i < MAX_THREADS; i++)
- if (thread_table[i].stack != 0 && thread_table[i].id != thread_id) {
+ if (thread_table[i].stack != 0
+ && thread_table[i].id != thread_id) {
if (SuspendThread(thread_table[i].handle) == (DWORD)-1)
ABORT("SuspendThread failed");
+ thread_table[i].suspended = TRUE;
}
}
@@ -32,10 +42,13 @@ void GC_start_world()
DWORD thread_id = GetCurrentThreadId();
int i;
for (i = 0; i < MAX_THREADS; i++)
- if (thread_table[i].stack != 0 && thread_table[i].id != thread_id) {
+ if (thread_table[i].stack != 0 && thread_table[i].suspended
+ && thread_table[i].id != thread_id) {
if (ResumeThread(thread_table[i].handle) == (DWORD)-1)
ABORT("ResumeThread failed");
+ thread_table[i].suspended = FALSE;
}
+ GC_please_stop = FALSE;
}
ptr_t GC_current_stackbottom()
@@ -117,20 +130,34 @@ BOOL WINAPI DllMain(HINSTANCE inst, ULONG reason, LPVOID reserved)
switch (reason) {
case DLL_PROCESS_ATTACH:
InitializeCriticalSection(&GC_allocate_ml);
+ GC_init(); /* Force initialization before thread attach. */
/* fall through */
case DLL_THREAD_ATTACH:
{
int i;
- LOCK();
+ /* It appears to be unsafe to acquire a lock here, since this */
+ /* code is apparently not preeemptible on some systems. */
+ /* (This is based on complaints, not on Microsoft's official */
+ /* documentation, which says this should perform "only simple */
+ /* inititalization tasks".) */
+ /* Hence we make do with nonblocking synchronization. */
+
/* The following should be a noop according to the win32 */
/* documentation. There is empirical evidence that it */
/* isn't. - HB */
- if (GC_incremental) SetUnhandledExceptionFilter(GC_write_fault_handler);
- for (i = 0; thread_table[i].stack != 0; i++) {
+# ifndef SMALL_CONFIG
+ if (GC_incremental) SetUnhandledExceptionFilter(GC_write_fault_handler);
+# endif
+
+ for (i = 0; InterlockedExchange(&thread_table[i].in_use,1) != 0; i++) {
+ /* Compare-and-swap would make this cleaner, but that's not */
+ /* supported before Windows 98 and NT 4.0. In Windows 2000, */
+ /* InterlockedExchange is supposed to be replaced by */
+ /* InterlockedExchangePointer, but that's not really what I */
+ /* want here. */
if (i == MAX_THREADS - 1)
ABORT("too many threads");
}
- thread_table[i].stack = GC_get_stack_base();
thread_table[i].id = GetCurrentThreadId();
if (!DuplicateHandle(GetCurrentProcess(),
GetCurrentThread(),
@@ -143,7 +170,11 @@ BOOL WINAPI DllMain(HINSTANCE inst, ULONG reason, LPVOID reserved)
GC_printf1("Last error code: %lx\n", last_error);
ABORT("DuplicateHandle failed");
}
- UNLOCK();
+ thread_table[i].stack = GC_get_stack_base();
+ /* If this thread is being created while we are trying to stop */
+ /* the world, wait here. Hopefully this can't happen on any */
+ /* systems that don't allow us to block here. */
+ while (GC_please_stop) Sleep(20);
}
break;
case DLL_PROCESS_DETACH:
@@ -152,10 +183,14 @@ BOOL WINAPI DllMain(HINSTANCE inst, ULONG reason, LPVOID reserved)
int i;
DWORD thread_id = GetCurrentThreadId();
LOCK();
- for (i = 0; thread_table[i].stack == 0 || thread_table[i].id != thread_id; i++)
+ for (i = 0;
+ thread_table[i].stack == 0 || thread_table[i].id != thread_id;
+ i++) {
if (i == MAX_THREADS - 1)
ABORT("thread not found on detach");
+ }
thread_table[i].stack = 0;
+ thread_table[i].in_use = FALSE;
CloseHandle(thread_table[i].handle);
BZERO(&thread_table[i].context, sizeof(CONTEXT));
UNLOCK();