Commit 20bbd3cd by Tom Tromey Committed by Tom Tromey

Merged GC 5.0alpha4 with local changes, plus:

	* Makefile.in: Rebuilt.
	* Makefile.am (gctest_LDADD): Added THREADLIB.
	(TESTS): New macro.
	* configure: Rebuilt.
	* configure.in (INCLUDES): New subst.

From-SVN: r30332
parent c05ddfa7
...@@ -39,7 +39,7 @@ OBJS= $(XXXOBJS:XXX=) ...@@ -39,7 +39,7 @@ OBJS= $(XXXOBJS:XXX=)
all: gctest.exe cord\de.exe test_cpp.exe 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) gc.lib: $(OBJS)
-del gc.lib -del gc.lib
......
1999-11-01 Tom Tromey <tromey@cygnus.com>
* Makefile.in: Rebuilt.
* Makefile.am (gctest_LDADD): Added THREADLIB.
(TESTS): New macro.
* configure: Rebuilt.
* configure.in (INCLUDES): New subst.
1999-09-29 Steve Chamberlain <sac@pobox.com> 1999-09-29 Steve Chamberlain <sac@pobox.com>
* config.h: Added picoJava target. * config.h: Added picoJava target.
......
...@@ -72,7 +72,7 @@ SPECIALCFLAGS = ...@@ -72,7 +72,7 @@ SPECIALCFLAGS =
all: gc.a gctest.exe all: gc.a gctest.exe
$(OBJS) test.o: $(srcdir)/gc_priv.h $(srcdir)/gc_hdrs.h $(srcdir)/gc.h \ $(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 # The dependency on Makefile is needed. Changing
# options such as -DSILENT affects the size of GC_arrays, # options such as -DSILENT affects the size of GC_arrays,
# invalidating all .o files that rely on gc_priv.h # invalidating all .o files that rely on gc_priv.h
......
...@@ -135,3 +135,20 @@ void GC_MacFreeTemporaryMemory() ...@@ -135,3 +135,20 @@ void GC_MacFreeTemporaryMemory()
# endif # 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) */
...@@ -46,8 +46,9 @@ AM_CFLAGS = @BOEHM_GC_CFLAGS@ ...@@ -46,8 +46,9 @@ AM_CFLAGS = @BOEHM_GC_CFLAGS@
check_PROGRAMS = gctest check_PROGRAMS = gctest
gctest_SOURCES = test.c gctest_SOURCES = test.c
gctest_LDADD = ./libgcjgc.la gctest_LDADD = ./libgcjgc.la $(THREADLIB)
TESTS = gctest
## FIXME: relies on internal code generated by automake. ## FIXME: relies on internal code generated by automake.
all_objs = @addobjs@ $(libgcjgc_la_OBJECTS) all_objs = @addobjs@ $(libgcjgc_la_OBJECTS)
......
...@@ -84,6 +84,7 @@ NM = @NM@ ...@@ -84,6 +84,7 @@ NM = @NM@
OBJDUMP = @OBJDUMP@ OBJDUMP = @OBJDUMP@
PACKAGE = @PACKAGE@ PACKAGE = @PACKAGE@
RANLIB = @RANLIB@ RANLIB = @RANLIB@
THREADLIB = @THREADLIB@
VERSION = @VERSION@ VERSION = @VERSION@
addobjs = @addobjs@ addobjs = @addobjs@
boehm_gc_basedir = @boehm_gc_basedir@ boehm_gc_basedir = @boehm_gc_basedir@
...@@ -131,7 +132,9 @@ AM_CFLAGS = @BOEHM_GC_CFLAGS@ ...@@ -131,7 +132,9 @@ AM_CFLAGS = @BOEHM_GC_CFLAGS@
check_PROGRAMS = gctest check_PROGRAMS = gctest
gctest_SOURCES = test.c gctest_SOURCES = test.c
gctest_LDADD = ./libgcjgc.la gctest_LDADD = ./libgcjgc.la $(THREADLIB)
TESTS = gctest
all_objs = @addobjs@ $(libgcjgc_la_OBJECTS) all_objs = @addobjs@ $(libgcjgc_la_OBJECTS)
...@@ -400,11 +403,37 @@ distdir: $(DISTFILES) ...@@ -400,11 +403,37 @@ distdir: $(DISTFILES)
|| cp -p $$d/$$file $(distdir)/$$file || :; \ || cp -p $$d/$$file $(distdir)/$$file || :; \
fi; \ fi; \
done done
check-TESTS: $(TESTS)
@failed=0; all=0; \
srcdir=$(srcdir); export srcdir; \
for tst in $(TESTS); do \
if test -f $$tst; then dir=.; \
else dir="$(srcdir)"; fi; \
if $(TESTS_ENVIRONMENT) $$dir/$$tst; then \
all=`expr $$all + 1`; \
echo "PASS: $$tst"; \
elif test $$? -ne 77; then \
all=`expr $$all + 1`; \
failed=`expr $$failed + 1`; \
echo "FAIL: $$tst"; \
fi; \
done; \
if test "$$failed" -eq 0; then \
banner="All $$all tests passed"; \
else \
banner="$$failed of $$all tests failed"; \
fi; \
dashes=`echo "$$banner" | sed s/./=/g`; \
echo "$$dashes"; \
echo "$$banner"; \
echo "$$dashes"; \
test "$$failed" -eq 0
info-am: info-am:
info: info-am info: info-am
dvi-am: dvi-am:
dvi: dvi-am dvi: dvi-am
check-am: $(check_PROGRAMS) check-am: $(check_PROGRAMS)
$(MAKE) $(AM_MAKEFLAGS) check-TESTS
check: check-am check: check-am
installcheck-am: installcheck-am:
installcheck: installcheck-am installcheck: installcheck-am
...@@ -477,11 +506,11 @@ maintainer-clean-compile mostlyclean-libtool distclean-libtool \ ...@@ -477,11 +506,11 @@ maintainer-clean-compile mostlyclean-libtool distclean-libtool \
clean-libtool maintainer-clean-libtool mostlyclean-checkPROGRAMS \ clean-libtool maintainer-clean-libtool mostlyclean-checkPROGRAMS \
distclean-checkPROGRAMS clean-checkPROGRAMS \ distclean-checkPROGRAMS clean-checkPROGRAMS \
maintainer-clean-checkPROGRAMS tags mostlyclean-tags distclean-tags \ maintainer-clean-checkPROGRAMS tags mostlyclean-tags distclean-tags \
clean-tags maintainer-clean-tags distdir info-am info dvi-am dvi check \ clean-tags maintainer-clean-tags distdir check-TESTS info-am info \
check-am installcheck-am installcheck install-info-am install-info \ dvi-am dvi check check-am installcheck-am installcheck install-info-am \
install-exec-am install-exec install-data-am install-data install-am \ install-info install-exec-am install-exec install-data-am install-data \
install uninstall-am uninstall all-redirect all-am all installdirs \ install-am install uninstall-am uninstall all-redirect all-am all \
mostlyclean-generic distclean-generic clean-generic \ installdirs mostlyclean-generic distclean-generic clean-generic \
maintainer-clean-generic clean mostlyclean distclean maintainer-clean maintainer-clean-generic clean mostlyclean distclean maintainer-clean
$(all_objs) : config.h gc_priv.h gc_hdrs.h gc.h gc_mark.h $(all_objs) : config.h gc_priv.h gc_hdrs.h gc.h gc_mark.h
......
...@@ -59,7 +59,7 @@ mach_dep.o: mach_dep.c mips_mach_dep.s rs6000_mach_dep.s if_mach if_not_there ...@@ -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_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_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 $(CC) $(CFLAGS) -o if_mach if_mach.c
if_not_there: if_not_there.c if_not_there: if_not_there.c
......
...@@ -320,7 +320,7 @@ Very few. Just one tiny in the GC, not strictly needed. ...@@ -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; 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 __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 build a Win32 or BeOS library and soon a Rhapsody library. You may
have to change that #if... have to change that #if...
......
Copyright 1988, 1989 Hans-J. Boehm, Alan J. Demers Copyright 1988, 1989 Hans-J. Boehm, Alan J. Demers
Copyright (c) 1991-1994 by Xerox Corporation. All rights reserved. Copyright (c) 1991-1995 by Xerox Corporation. All rights reserved.
Copyright (c) 1996-1999 by Silicon Graphics. All rights reserved.
Copyright (c) 1999 by Hewlett-Packard. All rights reserved.
THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
OR IMPLIED. ANY USE IS AT YOUR OWN RISK. OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
......
...@@ -5,6 +5,13 @@ Incremental gc not yet supported under Linux because signal handler ...@@ -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 for SIGSEGV can't get a hold of fault address. Dynamic library support
is also missing from Linux/alpha, probably for no good reason. 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: From Philippe Queinnec:
System: DEC/Alpha OSF1 v3.2, vendor cc System: DEC/Alpha OSF1 v3.2, vendor cc
......
===========================================================================
Martin Tauchmann's notes (1-Apr-99)
===========================================================================
Works now, also with the GNU-C compiler V2.7.2.1. <ftp://ftp.unina.it/pub/amiga/geekgadgets/amiga/m68k/snapshots/971125/amiga-bin/>
Modify the `Makefile`
CC=cc $(ABI_FLAG)
to
CC=gcc $(ABI_FLAG)
TECHNICAL NOTES
- `GC_get_stack_base()`, `GC_register_data_segments()` works now with every
C compiler; also Workbench.
- Removed AMIGA_SKIP_SEG, but the Code-Segment must not be scanned by GC.
PROBLEMS
- When the Linker, does`t merge all Code-Segments to an single one. LD of GCC
do it always.
- With ixemul.library V47.3, when an GC program launched from another program
(example: `Make` or `if_mach M68K AMIGA gctest`), `GC_register_data_segments()`
found the Segment-List of the caller program.
Can be fixed, if the run-time initialization code (for C programs, usually *crt0*)
support `__data` and `__bss`.
- PowerPC Amiga currently not supported.
- Dynamic libraries (dyn_load.c) not supported.
TESTED WITH SOFTWARE
`Optimized Oberon 2 C` (oo2c) <http://cognac.informatik.uni-kl.de/download/index.html>
TESTED WITH HARDWARE
MC68030
CONTACT
Please, contact me at <martintauchmann@bigfoot.com>, when you change the
Amiga port. <http://martintauchmann.home.pages.de>
=========================================================================== ===========================================================================
Michel Schinz's notes Michel Schinz's notes
=========================================================================== ===========================================================================
......
Dynamic loading support requires that executables be linked with -ldld. Dynamic loading support requires that executables be linked with -ldld.
The alternative is to build the collector without defining DYNAMIC_LOADING 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 accessible without considering statically allocated variables in dynamic
libraries. libraries.
The collector should compile with either plain cc or cc -Ae. CC -Aa 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 fails to define _HPUX_SOURCE and thus will not configure the collector
correctly. correctly.
Incremental collection support was reccently added, and should now work.
Thread support for HP/UX 11 Pthreads was also recently added. It is still
flakey in this release. (It has only been tested on a uniprocessor. Even
there some fraction of thread creation calls fail with a not-yet-understood
error return from sem_wait.)
See README.alpha for Linux on DEC AXP info. This file applies to See README.alpha for Linux on DEC AXP info.
Linux/Intel.
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 Dynamic libraries are supported on an ELF system. A static executable
should be linked with the gcc option "-Wl,-defsym,_DYNAMIC=0". 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: ...@@ -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 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 is stopped for GC. (It's possible that this is fixable in the
same way it is handled for SOLARIS_THREADS, with GC_dlopen.) 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.
...@@ -4,3 +4,6 @@ startup. The supplied value sometimes causes failure under AIX 4.1, though ...@@ -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 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 involves a substantial performance penalty, and will fail if there is
no limit on stack size. 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 ...)
...@@ -35,3 +35,7 @@ The garbage collector uses signals to stop threads.) ...@@ -35,3 +35,7 @@ The garbage collector uses signals to stop threads.)
initiated. Applications with many such threads may not exhibit acceptable initiated. Applications with many such threads may not exhibit acceptable
performance with the collector. (Increasing the heap size may help.) 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.
The collector supports both incremental collection and threads under The collector supports both incremental collection and threads under
Solaris 2. The incremental collector normally retrieves page dirty information Solaris 2. The incremental collector normally retrieves page dirty information
through the appropriate /proc calls. But it can also be configured 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 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. 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 ...@@ -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 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. seems to be no documentation as to which routines can transitively call malloc.
Nonetheless, under Solaris2, the collector now (since 4.12) allocates 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=... You may want to reverse this decisions if you use -DREDIRECT_MALLOC=...
......
...@@ -23,7 +23,11 @@ the two systems, and under different versions of win32s.) ...@@ -23,7 +23,11 @@ the two systems, and under different versions of win32s.)
The collector test program "gctest" is linked as a GUI application, The collector test program "gctest" is linked as a GUI application,
but does not open any windows. Its output appears in the file 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 "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 The cord test program has not been ported (but should port
easily). A toy editor (cord/de.exe) based on cords (heavyweight 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 ...@@ -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 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 believed to work only for b18, not b19, probably dues to linker changes
in b19. This is probably fixable with a different definition of 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 For Borland tools, use BCC_MAKEFILE. Note that
Borland's compiler defaults to 1 byte alignment in structures (-a1), Borland's compiler defaults to 1 byte alignment in structures (-a1),
...@@ -56,7 +60,7 @@ LEAST 4 BYTE ALIGNMENT. Thus the BORLAND DEFAULT MUST ...@@ -56,7 +60,7 @@ LEAST 4 BYTE ALIGNMENT. Thus the BORLAND DEFAULT MUST
BE OVERRIDDEN. (In my opinion, it should usually be anyway. BE OVERRIDDEN. (In my opinion, it should usually be anyway.
I expect that -a1 introduces major performance penalties on a I expect that -a1 introduces major performance penalties on a
486 or Pentium.) Note that this changes structure layouts. (As a last 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.) this has significant negative performance implications.)
The Makefile is set up to assume Borland 4.5. If you have another 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 version, change the line near the top. By default, it does not
...@@ -97,67 +101,49 @@ test with VC++ from the command line, use ...@@ -97,67 +101,49 @@ test with VC++ from the command line, use
nmake /F ".\gc.mak" CFG="gctest - Win32 Release" nmake /F ".\gc.mak" CFG="gctest - Win32 Release"
This requires that the subdirectory gctest\Release exist. 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 relies on the collector residing in a dll.
This version currently supports incremental collection only if it is This version currently supports incremental collection only if it is
enabled before any additional threads are created. enabled before any additional threads are created.
It is known to not be completely solid. At a minimum it can deadlock Version 4.13 attempts to fix some of the earlier problems, but there
if a thread starts in the middle of an allocation. There may be may be other issues. If you need solid support for win32 threads, you
other problems. If you need solid support for win32 threads, you might check with Geodesic Systems. Their collector must be licensed,
check with Geodesic Systems. I haven't tried it, but they claim but they have invested far more time in win32-specific issues.
to support it.
Hans Hans
Ivan V. Demakov's README for the Watcom port: Ivan V. Demakov's README for the Watcom port:
[ He points out in a later message that there may be a problem compiling The collector has been compiled with Watcom C 10.6 and 11.0.
under Windows-3.11 for Windows NT. ] 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 Incremental collection is not supported.
stack and register based calling conventions (options -5r and -5s).
Incremental collection not supported.
OS/2 not tested, but should work (only some #ifdef's added for OS/2 port). cord is not ported.
cord not ported. Watcom C fails to compile it, from first attempt. Before compiling you may need to edit WCC_MAKEFILE to set target
Since I don't use it, I don't try to fix it. 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.
My changes: 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.
* config.h Added definitions for Watcom C/C++. Ivan Demakov (email: ivan@tgrad.nsk.su)
Undefined MPROTECT_VDB for Watcom C/C++ MSWIN32,
I don't have idea why it not work.
* gc.h Explicitly declared GC_noop. This prevents
program crash, compiled with -5r option.
* gc_priv.h Changed declaration for GC_push_one to make
compiler happy.
Added GC_dos4gw_get_mem declaration and
GET_MEM uses it in DOS4GW environment.
* os_dep.c Added __WATCOMC__ and DOS4GW #ifdef's.
Added GC_dos4gw_get_mem.
* mach_dep.c For Watcom used setjmp method of marking registers.
* WCC_MAKEFILE New file. Makefile for Watcom C/C++.
* gc_watcom.asm New file. Some functions for DOS4GW.
This functions may (probably) be done in C,
but I can't figure out how do this for all
possible options of compiler.
* README.watcom This file.
Ivan Demakov (email: dem@tgrad.nsk.su)
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 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 all: gctest setjmp_t
......
# Makefile for Watcom C/C++ 10.5, 10.6, 11.0 on NT, OS2 and DOS4GW . # Makefile for Watcom C/C++ 10.5, 10.6, 11.0 on NT, OS2 and DOS4GW.
# May work with Watcom 10.0 . # May work with Watcom 10.0.
#
# # Uncoment one of the lines below for cross compilation.
# Uncoment one of line for cross compiling SYSTEM=MSWIN32
#SYSTEM=DOS4GW #SYSTEM=DOS4GW
#SYSTEM=MSWIN32
#SYSTEM=OS2 #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__ # Select calling conventions.
SYSTEM=DOS4GW # Possible choices are r and s.
!endif CALLING=s
!ifdef __NT__ # Select target CPU.
SYSTEM=MSWIN32 # Possible choices are 3, 4, 5, and 6.
!endif # The last choice available only since version 11.0.
CPU=5
!ifdef __OS2__ # Set optimization options.
SYSTEM=OS2 # Watcom before 11.0 does not support option "-oh".
!endif 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 !endif
!define $(SYSTEM) !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 CC=wcc386
CXX=wpp386 CXX=wpp386
AS=wasm
# Watcom before 11.0 not support option -oh
# Remove it if you get error
OPTIM=-oneatxh -s
CALLING=-5s # -DUSE_GENERIC is required !
CFLAGS=-$(CPU)$(CALLING) $(OPTIM) -zp4 -zc $(SYSFLAG) $(DLLFLAG) -DGC_BUILD -DUSE_GENERIC $(DEFS)
DEFS=-DALL_INTERIOR_POINTERS -DSILENT #-DSMALL_CONFIG #-DGC_DEBUG
# ! -DUSE_GENERIC required !
CFLAGS=$(OPTIM) -zp4 $(CALLING) -zc -DUSE_GENERIC $(D_SYSTEM) $(DEFS)
CXXFLAGS= $(CFLAGS) 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 & OBJS= alloc.obj reclaim.obj allchblk.obj misc.obj &
mach_dep.obj os_dep.obj mark_rts.obj headers.obj mark.obj & mach_dep.obj os_dep.obj mark_rts.obj headers.obj mark.obj &
obj_map.obj blacklst.obj finalize.obj new_hblk.obj & obj_map.obj blacklst.obj finalize.obj new_hblk.obj &
dbg_mlc.obj malloc.obj stubborn.obj dyn_load.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.lib: gc.dll gc_cpp.obj
gc_watcom.obj: gc_watcom.asm WCC_MAKEFILE *wlib -b -c -n -p=512 $@ +gc.dll +gc_cpp.obj
$(AS) $(ASFLAGS) gc_watcom.asm
gc.dll: $(OBJS) .AUTODEPEND
@%create $*.lnk
!ifdef DOS4GW !ifdef DOS4GW
gc.lib: $(OBJS) gc_watcom.obj @%append $*.lnk sys os2v2_dll
@%create $*.lb1 !else ifdef MSWIN32
@for %i in ($(OBJS)) do @%append $*.lb1 +'%i' @%append $*.lnk sys nt_dll
@@%append $*.lb1 +'gc_watcom.obj' !else ifdef OS2
*wlib -b -c -n -p=512 $@ @$*.lb1 @%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 !else
gc.lib: $(OBJS) gc.lib: $(OBJS) gc_cpp.obj
@%create $*.lb1 @%create $*.lb1
@for %i in ($(OBJS)) do @%append $*.lb1 +'%i' @for %i in ($(OBJS)) do @%append $*.lb1 +'%i'
@%append $*.lb1 +'gc_cpp.obj'
*wlib -b -c -n -p=512 $@ @$*.lb1 *wlib -b -c -n -p=512 $@ @$*.lb1
!endif
!endif
test.obj: test.c
$(CC) $(CFLAGS) $*.c
gctest.exe: test.obj gc.lib gctest.exe: test.obj gc.lib
%create $*.lnk %create $*.lnk
!ifdef DOS4GW !ifdef DOS4GW
@%append $*.lnk sys dos4g @%append $*.lnk sys dos4g
!endif !else ifdef MSWIN32
!ifdef MSWIN32
@%append $*.lnk sys nt @%append $*.lnk sys nt
!endif !else ifdef OS2
!ifdef OS2
@%append $*.lnk sys os2v2 @%append $*.lnk sys os2v2
!endif !endif
@%append $*.lnk op case @%append $*.lnk op case
...@@ -97,8 +132,47 @@ gctest.exe: test.obj gc.lib ...@@ -97,8 +132,47 @@ gctest.exe: test.obj gc.lib
@%append $*.lnk name $* @%append $*.lnk name $*
@%append $*.lnk file test.obj @%append $*.lnk file test.obj
@%append $*.lnk library gc.lib @%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 *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 .c.obj: .AUTODEPEND
...@@ -107,9 +181,6 @@ gctest.exe: test.obj gc.lib ...@@ -107,9 +181,6 @@ gctest.exe: test.obj gc.lib
.cc.obj: .AUTODEPEND .cc.obj: .AUTODEPEND
$(CXX) $(CXXFLAGS) $*.cc $(CXX) $(CXXFLAGS) $*.cc
.cpp.obj: .AUTODEPEND
$(CXX) $(CXXFLAGS) $*.cpp
clean : .SYMBOLIC clean : .SYMBOLIC
@if exist *.obj del *.obj @if exist *.obj del *.obj
@if exist *.map del *.map @if exist *.map del *.map
...@@ -121,3 +192,5 @@ clean : .SYMBOLIC ...@@ -121,3 +192,5 @@ clean : .SYMBOLIC
@if exist *.lst del *.lst @if exist *.lst del *.lst
@if exist *.exe del *.exe @if exist *.exe del *.exe
@if exist *.log del *.log @if exist *.log del *.log
@if exist *.lib del *.lib
@if exist *.dll del *.dll
...@@ -63,11 +63,16 @@ ptr_t p; ...@@ -63,11 +63,16 @@ ptr_t p;
void (*GC_print_heap_obj)(/* char * s, ptr_t p */) = void (*GC_print_heap_obj)(/* char * s, ptr_t p */) =
GC_default_print_heap_obj_proc; GC_default_print_heap_obj_proc;
void GC_print_source_ptr(ptr_t p) void GC_print_source_ptr(p)
ptr_t p;
{ {
ptr_t base = GC_base(p); ptr_t base = GC_base(p);
if (0 == base) { if (0 == base) {
GC_err_printf0("in root set"); if (0 == p) {
GC_err_printf0("in register");
} else {
GC_err_printf0("in root set");
}
} else { } else {
GC_err_printf0("in object at "); GC_err_printf0("in object at ");
(*GC_print_heap_obj)(base); (*GC_print_heap_obj)(base);
...@@ -140,6 +145,13 @@ void GC_promote_black_lists() ...@@ -140,6 +145,13 @@ void GC_promote_black_lists()
if (GC_black_list_spacing < 3 * HBLKSIZE) { if (GC_black_list_spacing < 3 * HBLKSIZE) {
GC_black_list_spacing = 3 * HBLKSIZE; GC_black_list_spacing = 3 * HBLKSIZE;
} }
if (GC_black_list_spacing > MAXHINCR * HBLKSIZE) {
GC_black_list_spacing = MAXHINCR * HBLKSIZE;
/* Makes it easier to allocate really huge blocks, which otherwise */
/* may have problems with nonuniform blacklist distributions. */
/* This way we should always succeed immediately after growing the */
/* heap. */
}
} }
void GC_unpromote_black_lists() void GC_unpromote_black_lists()
......
...@@ -62,6 +62,7 @@ if test "$THREADS" = yes; then ...@@ -62,6 +62,7 @@ if test "$THREADS" = yes; then
fi fi
INCLUDES= INCLUDES=
THREADLIB=
case "$THREADS" in case "$THREADS" in
no | none | single) no | none | single)
THREADS=none THREADS=none
...@@ -81,10 +82,12 @@ case "$THREADS" in ...@@ -81,10 +82,12 @@ case "$THREADS" in
AC_DEFINE(IRIX_THREADS) AC_DEFINE(IRIX_THREADS)
;; ;;
esac esac
THREADLIB=-lpthread
;; ;;
qt) qt)
AC_DEFINE(QUICK_THREADS) AC_DEFINE(QUICK_THREADS)
INCLUDES="-I${boehm_gc_basedir}/../qthreads" INCLUDES="-I${boehm_gc_basedir}/../qthreads"
THREADLIB=../qthreads/libgcjcoop.la
;; ;;
decosf1 | irix | mach | os2 | solaris | win32 | dce | vxworks) decosf1 | irix | mach | os2 | solaris | win32 | dce | vxworks)
AC_MSG_ERROR(thread package $THREADS not yet supported) AC_MSG_ERROR(thread package $THREADS not yet supported)
...@@ -94,6 +97,7 @@ case "$THREADS" in ...@@ -94,6 +97,7 @@ case "$THREADS" in
;; ;;
esac esac
AC_MSG_RESULT($THREADS) AC_MSG_RESULT($THREADS)
AC_SUBST(THREADLIB)
AC_ARG_ENABLE(java-gc, AC_ARG_ENABLE(java-gc,
changequote(<<,>>)dnl changequote(<<,>>)dnl
......
...@@ -47,7 +47,7 @@ ...@@ -47,7 +47,7 @@
#if (defined(DYNAMIC_LOADING) || defined(MSWIN32)) && !defined(PCR) #if (defined(DYNAMIC_LOADING) || defined(MSWIN32)) && !defined(PCR)
#if !defined(SUNOS4) && !defined(SUNOS5DL) && !defined(IRIX5) && \ #if !defined(SUNOS4) && !defined(SUNOS5DL) && !defined(IRIX5) && \
!defined(MSWIN32) && !(defined(ALPHA) && defined(OSF1)) && \ !defined(MSWIN32) && !(defined(ALPHA) && defined(OSF1)) && \
!defined(HP_PA) && (!defined(LINUX) && !defined(__ELF__)) && \ !defined(HPUX) && !(defined(LINUX) && defined(__ELF__)) && \
!defined(RS6000) && !defined(SCO_ELF) !defined(RS6000) && !defined(SCO_ELF)
--> We only know how to find data segments of dynamic libraries for the --> We only know how to find data segments of dynamic libraries for the
--> above. Additional SVR4 variants might not be too --> above. Additional SVR4 variants might not be too
...@@ -284,11 +284,9 @@ void GC_register_dynamic_libraries() ...@@ -284,11 +284,9 @@ void GC_register_dynamic_libraries()
static struct link_map * static struct link_map *
GC_FirstDLOpenedLinkMap() GC_FirstDLOpenedLinkMap()
{ {
#ifdef __GNUC__ # ifdef __GNUC__
/* On some Linux systems, `_DYNAMIC' will not be defined when a # pragma weak _DYNAMIC
static link is done. */ # endif
# pragma weak _DYNAMIC
#endif
extern ElfW(Dyn) _DYNAMIC[]; extern ElfW(Dyn) _DYNAMIC[];
ElfW(Dyn) *dp; ElfW(Dyn) *dp;
struct r_debug *r; struct r_debug *r;
...@@ -356,6 +354,8 @@ void GC_register_dynamic_libraries() ...@@ -356,6 +354,8 @@ void GC_register_dynamic_libraries()
#include <errno.h> #include <errno.h>
extern void * GC_roots_present(); extern void * GC_roots_present();
/* The type is a lie, since the real type doesn't make sense here, */
/* and we only test for NULL. */
extern ptr_t GC_scratch_last_end_ptr; /* End of GC_scratch_alloc arena */ extern ptr_t GC_scratch_last_end_ptr; /* End of GC_scratch_alloc arena */
...@@ -382,6 +382,8 @@ void GC_register_dynamic_libraries() ...@@ -382,6 +382,8 @@ void GC_register_dynamic_libraries()
if (fd < 0) { if (fd < 0) {
sprintf(buf, "/proc/%d", getpid()); sprintf(buf, "/proc/%d", getpid());
/* The above generates a lint complaint, since pid_t varies. */
/* It's unclear how to improve this. */
fd = open(buf, O_RDONLY); fd = open(buf, O_RDONLY);
if (fd < 0) { if (fd < 0) {
ABORT("/proc open failed"); ABORT("/proc open failed");
...@@ -394,7 +396,8 @@ void GC_register_dynamic_libraries() ...@@ -394,7 +396,8 @@ void GC_register_dynamic_libraries()
if (needed_sz >= current_sz) { if (needed_sz >= current_sz) {
current_sz = needed_sz * 2 + 1; current_sz = needed_sz * 2 + 1;
/* Expansion, plus room for 0 record */ /* Expansion, plus room for 0 record */
addr_map = (prmap_t *)GC_scratch_alloc(current_sz * sizeof(prmap_t)); addr_map = (prmap_t *)GC_scratch_alloc((word)
(current_sz * sizeof(prmap_t)));
} }
if (ioctl(fd, PIOCMAP, addr_map) < 0) { if (ioctl(fd, PIOCMAP, addr_map) < 0) {
GC_err_printf4("fd = %d, errno = %d, needed_sz = %d, addr_map = 0x%X\n", GC_err_printf4("fd = %d, errno = %d, needed_sz = %d, addr_map = 0x%X\n",
...@@ -656,7 +659,7 @@ void GC_register_dynamic_libraries() ...@@ -656,7 +659,7 @@ void GC_register_dynamic_libraries()
} }
#endif #endif
#if defined(HP_PA) #if defined(HPUX)
#include <errno.h> #include <errno.h>
#include <dl.h> #include <dl.h>
...@@ -679,6 +682,11 @@ void GC_register_dynamic_libraries() ...@@ -679,6 +682,11 @@ void GC_register_dynamic_libraries()
/* Check if this is the end of the list or if some error occured */ /* Check if this is the end of the list or if some error occured */
if (status != 0) { if (status != 0) {
# ifdef HPUX_THREADS
/* I've seen errno values of 0. The man page is not clear */
/* as to whether errno should get set on a -1 return. */
break;
# else
if (errno == EINVAL) { if (errno == EINVAL) {
break; /* Moved past end of shared library list --> finished */ break; /* Moved past end of shared library list --> finished */
} else { } else {
...@@ -689,6 +697,7 @@ void GC_register_dynamic_libraries() ...@@ -689,6 +697,7 @@ void GC_register_dynamic_libraries()
} }
ABORT("shl_get failed"); ABORT("shl_get failed");
} }
# endif
} }
# ifdef VERBOSE # ifdef VERBOSE
...@@ -711,7 +720,7 @@ void GC_register_dynamic_libraries() ...@@ -711,7 +720,7 @@ void GC_register_dynamic_libraries()
index++; index++;
} }
} }
#endif /* HP_PA */ #endif /* HPUX */
#ifdef RS6000 #ifdef RS6000
#pragma alloca #pragma alloca
......
/* /*
* Copyright 1988, 1989 Hans-J. Boehm, Alan J. Demers * Copyright 1988, 1989 Hans-J. Boehm, Alan J. Demers
* Copyright (c) 1991-1996 by Xerox Corporation. All rights reserved. * Copyright (c) 1991-1996 by Xerox Corporation. All rights reserved.
* Copyright (c) 1996-1999 by Silicon Graphics. All rights reserved.
* THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
* OR IMPLIED. ANY USE IS AT YOUR OWN RISK. * OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
...@@ -16,6 +17,18 @@ ...@@ -16,6 +17,18 @@
# include "gc_priv.h" # include "gc_priv.h"
# include "gc_mark.h" # include "gc_mark.h"
# ifdef FINALIZE_ON_DEMAND
int GC_finalize_on_demand = 1;
# else
int GC_finalize_on_demand = 0;
# endif
# ifdef JAVA_FINALIZATION
int GC_java_finalization = 1;
# else
int GC_java_finalization = 0;
# endif
/* Type of mark procedure used for marking from finalizable object. */ /* Type of mark procedure used for marking from finalizable object. */
/* This procedure normally does not mark the object, only its */ /* This procedure normally does not mark the object, only its */
/* descendents. */ /* descendents. */
...@@ -249,7 +262,7 @@ out: ...@@ -249,7 +262,7 @@ out:
/* Possible finalization_marker procedures. Note that mark stack */ /* Possible finalization_marker procedures. Note that mark stack */
/* overflow is handled by the caller, and is not a disaster. */ /* overflow is handled by the caller, and is not a disaster. */
void GC_normal_finalize_mark_proc(p) GC_API void GC_normal_finalize_mark_proc(p)
ptr_t p; ptr_t p;
{ {
hdr * hhdr = HDR(p); hdr * hhdr = HDR(p);
...@@ -261,7 +274,7 @@ ptr_t p; ...@@ -261,7 +274,7 @@ ptr_t p;
/* This only pays very partial attention to the mark descriptor. */ /* This only pays very partial attention to the mark descriptor. */
/* It does the right thing for normal and atomic objects, and treats */ /* It does the right thing for normal and atomic objects, and treats */
/* most others as normal. */ /* most others as normal. */
void GC_ignore_self_finalize_mark_proc(p) GC_API void GC_ignore_self_finalize_mark_proc(p)
ptr_t p; ptr_t p;
{ {
hdr * hhdr = HDR(p); hdr * hhdr = HDR(p);
...@@ -278,13 +291,13 @@ ptr_t p; ...@@ -278,13 +291,13 @@ ptr_t p;
for (q = p; q <= scan_limit; q += ALIGNMENT) { for (q = p; q <= scan_limit; q += ALIGNMENT) {
r = *(ptr_t *)q; r = *(ptr_t *)q;
if (r < p || r > target_limit) { if (r < p || r > target_limit) {
GC_PUSH_ONE_HEAP((word)r); GC_PUSH_ONE_HEAP((word)r, q);
} }
} }
} }
/*ARGSUSED*/ /*ARGSUSED*/
void GC_null_finalize_mark_proc(p) GC_API void GC_null_finalize_mark_proc(p)
ptr_t p; ptr_t p;
{ {
} }
...@@ -295,7 +308,11 @@ ptr_t p; ...@@ -295,7 +308,11 @@ ptr_t p;
/* in the nonthreads case, we try to avoid disabling signals, */ /* in the nonthreads case, we try to avoid disabling signals, */
/* since it can be expensive. Threads packages typically */ /* since it can be expensive. Threads packages typically */
/* make it cheaper. */ /* make it cheaper. */
void GC_register_finalizer_inner(obj, fn, cd, ofn, ocd, mp) /* The last parameter is a procedure that determines */
/* marking for finalization ordering. Any objects marked */
/* by that procedure will be guaranteed to not have been */
/* finalized when this finalizer is invoked. */
GC_API void GC_register_finalizer_inner(obj, fn, cd, ofn, ocd, mp)
GC_PTR obj; GC_PTR obj;
GC_finalization_proc fn; GC_finalization_proc fn;
GC_PTR cd; GC_PTR cd;
...@@ -505,6 +522,7 @@ void GC_finalize() ...@@ -505,6 +522,7 @@ void GC_finalize()
for (curr_fo = fo_head[i]; curr_fo != 0; curr_fo = fo_next(curr_fo)) { for (curr_fo = fo_head[i]; curr_fo != 0; curr_fo = fo_next(curr_fo)) {
real_ptr = (ptr_t)REVEAL_POINTER(curr_fo -> fo_hidden_base); real_ptr = (ptr_t)REVEAL_POINTER(curr_fo -> fo_hidden_base);
if (!GC_is_marked(real_ptr)) { if (!GC_is_marked(real_ptr)) {
GC_MARKED_FOR_FINALIZATION(real_ptr);
GC_MARK_FO(real_ptr, curr_fo -> fo_mark_proc); GC_MARK_FO(real_ptr, curr_fo -> fo_mark_proc);
if (GC_is_marked(real_ptr)) { if (GC_is_marked(real_ptr)) {
WARN("Finalization cycle involving %lx\n", real_ptr); WARN("Finalization cycle involving %lx\n", real_ptr);
...@@ -521,9 +539,9 @@ void GC_finalize() ...@@ -521,9 +539,9 @@ void GC_finalize()
while (curr_fo != 0) { while (curr_fo != 0) {
real_ptr = (ptr_t)REVEAL_POINTER(curr_fo -> fo_hidden_base); real_ptr = (ptr_t)REVEAL_POINTER(curr_fo -> fo_hidden_base);
if (!GC_is_marked(real_ptr)) { if (!GC_is_marked(real_ptr)) {
# ifndef JAVA_FINALIZATION if (!GC_java_finalization) {
GC_set_mark_bit(real_ptr); GC_set_mark_bit(real_ptr);
# endif }
/* Delete from hash table */ /* Delete from hash table */
next_fo = fo_next(curr_fo); next_fo = fo_next(curr_fo);
if (prev_fo == 0) { if (prev_fo == 0) {
...@@ -555,20 +573,20 @@ void GC_finalize() ...@@ -555,20 +573,20 @@ void GC_finalize()
} }
} }
# ifdef JAVA_FINALIZATION if (GC_java_finalization) {
/* make sure we mark everything reachable from objects finalized /* make sure we mark everything reachable from objects finalized
using the no_order mark_proc */ using the no_order mark_proc */
for (curr_fo = GC_finalize_now; for (curr_fo = GC_finalize_now;
curr_fo != NULL; curr_fo = fo_next(curr_fo)) { curr_fo != NULL; curr_fo = fo_next(curr_fo)) {
real_ptr = (ptr_t)curr_fo -> fo_hidden_base; real_ptr = (ptr_t)curr_fo -> fo_hidden_base;
if (!GC_is_marked(real_ptr)) { if (!GC_is_marked(real_ptr)) {
if (curr_fo -> fo_mark_proc == GC_null_finalize_mark_proc) { if (curr_fo -> fo_mark_proc == GC_null_finalize_mark_proc) {
GC_MARK_FO(real_ptr, GC_normal_finalize_mark_proc); GC_MARK_FO(real_ptr, GC_normal_finalize_mark_proc);
} }
GC_set_mark_bit(real_ptr); GC_set_mark_bit(real_ptr);
} }
} }
# endif }
/* Remove dangling disappearing links. */ /* Remove dangling disappearing links. */
for (i = 0; i < dl_size; i++) { for (i = 0; i < dl_size; i++) {
...@@ -594,7 +612,7 @@ void GC_finalize() ...@@ -594,7 +612,7 @@ void GC_finalize()
} }
} }
#ifdef JAVA_FINALIZATION #ifndef JAVA_FINALIZATION_NOT_NEEDED
/* Enqueue all remaining finalizers to be run - Assumes lock is /* Enqueue all remaining finalizers to be run - Assumes lock is
* held, and signals are disabled */ * held, and signals are disabled */
...@@ -648,10 +666,16 @@ void GC_enqueue_all_finalizers() ...@@ -648,10 +666,16 @@ void GC_enqueue_all_finalizers()
* which can make the runtime guarantee that all finalizers are run. * which can make the runtime guarantee that all finalizers are run.
* Unfortunately, the Java standard implies we have to keep running * Unfortunately, the Java standard implies we have to keep running
* finalizers until there are no more left, a potential infinite loop. * finalizers until there are no more left, a potential infinite loop.
* YUCK. * This routine is externally callable, so is called without * YUCK.
* the allocation lock * Note that this is even more dangerous than the usual Java
* finalizers, in that objects reachable from static variables
* may have been finalized when these finalizers are run.
* Finalizers run at this point must be prepared to deal with a
* mostly broken world.
* This routine is externally callable, so is called without
* the allocation lock.
*/ */
void GC_finalize_all() GC_API void GC_finalize_all()
{ {
DCL_LOCK_STATE; DCL_LOCK_STATE;
......
...@@ -36,11 +36,19 @@ ...@@ -36,11 +36,19 @@
#endif #endif
#if defined(_MSC_VER) && defined(_DLL) #if defined(_MSC_VER) && defined(_DLL)
#ifdef GC_BUILD # ifdef GC_BUILD
#define GC_API __declspec(dllexport) # define GC_API __declspec(dllexport)
#else # else
#define GC_API __declspec(dllimport) # define GC_API __declspec(dllimport)
# endif
#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 #endif
#ifndef GC_API #ifndef GC_API
...@@ -50,9 +58,11 @@ ...@@ -50,9 +58,11 @@
# if defined(__STDC__) || defined(__cplusplus) # if defined(__STDC__) || defined(__cplusplus)
# define GC_PROTO(args) args # define GC_PROTO(args) args
typedef void * GC_PTR; typedef void * GC_PTR;
# define GC_CONST const
# else # else
# define GC_PROTO(args) () # define GC_PROTO(args) ()
typedef char * GC_PTR; typedef char * GC_PTR;
# define GC_CONST
# endif # endif
# ifdef __cplusplus # ifdef __cplusplus
...@@ -88,11 +98,31 @@ GC_API GC_PTR (*GC_oom_fn) GC_PROTO((size_t bytes_requested)); ...@@ -88,11 +98,31 @@ GC_API GC_PTR (*GC_oom_fn) GC_PROTO((size_t bytes_requested));
/* pointer to a previously allocated heap */ /* pointer to a previously allocated heap */
/* object. */ /* object. */
GC_API int GC_find_leak;
/* Do not actually garbage collect, but simply */
/* report inaccessible memory that was not */
/* deallocated with GC_free. Initial value */
/* is determined by FIND_LEAK macro. */
GC_API int GC_quiet; /* Disable statistics output. Only matters if */ GC_API int GC_quiet; /* Disable statistics output. Only matters if */
/* collector has been compiled with statistics */ /* collector has been compiled with statistics */
/* enabled. This involves a performance cost, */ /* enabled. This involves a performance cost, */
/* and is thus not the default. */ /* and is thus not the default. */
GC_API int GC_finalize_on_demand;
/* If nonzero, finalizers will only be run in */
/* response to an eplit GC_invoke_finalizers */
/* call. The default is determined by whether */
/* the FINALIZE_ON_DEMAND macro is defined */
/* when the collector is built. */
GC_API int GC_java_finalization;
/* Mark objects reachable from finalizable */
/* objects in a separate postpass. This makes */
/* it a bit safer to use non-topologically- */
/* ordered finalization. Default value is */
/* determined by JAVA_FINALIZATION macro. */
GC_API int GC_dont_gc; /* Dont collect unless explicitly requested, e.g. */ GC_API int GC_dont_gc; /* Dont collect unless explicitly requested, e.g. */
/* because it's not safe. */ /* because it's not safe. */
...@@ -103,6 +133,12 @@ GC_API int GC_dont_expand; ...@@ -103,6 +133,12 @@ GC_API int GC_dont_expand;
GC_API int GC_full_freq; /* Number of partial collections between */ GC_API int GC_full_freq; /* Number of partial collections between */
/* full collections. Matters only if */ /* full collections. Matters only if */
/* GC_incremental is set. */ /* GC_incremental is set. */
/* Full collections are also triggered if */
/* the collector detects a substantial */
/* increase in the number of in-use heap */
/* blocks. Values in the tens are now */
/* perfectly reasonable, unlike for */
/* earlier GC versions. */
GC_API GC_word GC_non_gc_bytes; GC_API GC_word GC_non_gc_bytes;
/* Bytes not considered candidates for collection. */ /* Bytes not considered candidates for collection. */
...@@ -126,7 +162,19 @@ GC_API GC_word GC_max_retries; ...@@ -126,7 +162,19 @@ GC_API GC_word GC_max_retries;
/* reporting out of memory after heap */ /* reporting out of memory after heap */
/* expansion fails. Initially 0. */ /* expansion fails. Initially 0. */
GC_API char *GC_stackbottom; /* Cool end of user stack. */
/* May be set in the client prior to */
/* calling any GC_ routines. This */
/* avoids some overhead, and */
/* potentially some signals that can */
/* confuse debuggers. Otherwise the */
/* collector attempts to set it */
/* automatically. */
/* For multithreaded code, this is the */
/* cold end of the stack for the */
/* primordial thread. */
/* Public procedures */ /* Public procedures */
/* /*
* general purpose allocation routines, with roughly malloc calling conv. * general purpose allocation routines, with roughly malloc calling conv.
...@@ -193,8 +241,8 @@ GC_API size_t GC_size GC_PROTO((GC_PTR object_addr)); ...@@ -193,8 +241,8 @@ GC_API size_t GC_size GC_PROTO((GC_PTR object_addr));
/* If the argument is stubborn, the result will have changes enabled. */ /* If the argument is stubborn, the result will have changes enabled. */
/* It is an error to have changes enabled for the original object. */ /* It is an error to have changes enabled for the original object. */
/* Follows ANSI comventions for NULL old_object. */ /* Follows ANSI comventions for NULL old_object. */
GC_API GC_PTR GC_realloc GC_PROTO((GC_PTR old_object, GC_API GC_PTR GC_realloc
size_t new_size_in_bytes)); GC_PROTO((GC_PTR old_object, size_t new_size_in_bytes));
/* Explicitly increase the heap size. */ /* Explicitly increase the heap size. */
/* Returns 0 on failure, 1 on success. */ /* Returns 0 on failure, 1 on success. */
...@@ -248,6 +296,7 @@ GC_API void GC_gcollect GC_PROTO((void)); ...@@ -248,6 +296,7 @@ GC_API void GC_gcollect GC_PROTO((void));
/* than normal pause times for incremental collection. However, */ /* than normal pause times for incremental collection. However, */
/* aborted collections do no useful work; the next collection needs */ /* aborted collections do no useful work; the next collection needs */
/* to start from the beginning. */ /* to start from the beginning. */
/* Return 0 if the collection was aborted, 1 if it succeeded. */
typedef int (* GC_stop_func) GC_PROTO((void)); typedef int (* GC_stop_func) GC_PROTO((void));
GC_API int GC_try_to_collect GC_PROTO((GC_stop_func stop_func)); GC_API int GC_try_to_collect GC_PROTO((GC_stop_func stop_func));
...@@ -256,6 +305,9 @@ GC_API int GC_try_to_collect GC_PROTO((GC_stop_func stop_func)); ...@@ -256,6 +305,9 @@ GC_API int GC_try_to_collect GC_PROTO((GC_stop_func stop_func));
/* Includes some pages that were allocated but never written. */ /* Includes some pages that were allocated but never written. */
GC_API size_t GC_get_heap_size GC_PROTO((void)); GC_API size_t GC_get_heap_size GC_PROTO((void));
/* Return a lower bound on the number of free bytes in the heap. */
GC_API size_t GC_get_free_bytes GC_PROTO((void));
/* Return the number of bytes allocated since the last collection. */ /* Return the number of bytes allocated since the last collection. */
GC_API size_t GC_get_bytes_since_gc GC_PROTO((void)); GC_API size_t GC_get_bytes_since_gc GC_PROTO((void));
...@@ -300,10 +352,11 @@ GC_API GC_PTR GC_malloc_atomic_ignore_off_page GC_PROTO((size_t lb)); ...@@ -300,10 +352,11 @@ GC_API GC_PTR GC_malloc_atomic_ignore_off_page GC_PROTO((size_t lb));
#ifdef GC_ADD_CALLER #ifdef GC_ADD_CALLER
# define GC_EXTRAS GC_RETURN_ADDR, __FILE__, __LINE__ # define GC_EXTRAS GC_RETURN_ADDR, __FILE__, __LINE__
# define GC_EXTRA_PARAMS GC_word ra, char * descr_string, int descr_int # define GC_EXTRA_PARAMS GC_word ra, GC_CONST char * descr_string,
int descr_int
#else #else
# define GC_EXTRAS __FILE__, __LINE__ # define GC_EXTRAS __FILE__, __LINE__
# define GC_EXTRA_PARAMS char * descr_string, int descr_int # define GC_EXTRA_PARAMS GC_CONST char * descr_string, int descr_int
#endif #endif
/* Debugging (annotated) allocation. GC_gcollect will check */ /* Debugging (annotated) allocation. GC_gcollect will check */
...@@ -502,7 +555,7 @@ GC_API int GC_invoke_finalizers GC_PROTO((void)); ...@@ -502,7 +555,7 @@ GC_API int GC_invoke_finalizers GC_PROTO((void));
/* be finalized. Return the number of finalizers */ /* be finalized. Return the number of finalizers */
/* that were run. Normally this is also called */ /* that were run. Normally this is also called */
/* implicitly during some allocations. If */ /* implicitly during some allocations. If */
/* FINALIZE_ON_DEMAND is defined, it must be called */ /* GC-finalize_on_demand is nonzero, it must be called */
/* explicitly. */ /* explicitly. */
/* GC_set_warn_proc can be used to redirect or filter warning messages. */ /* GC_set_warn_proc can be used to redirect or filter warning messages. */
...@@ -617,6 +670,10 @@ GC_API void (*GC_is_valid_displacement_print_proc) ...@@ -617,6 +670,10 @@ GC_API void (*GC_is_valid_displacement_print_proc)
GC_API void (*GC_is_visible_print_proc) GC_API void (*GC_is_visible_print_proc)
GC_PROTO((GC_PTR p)); GC_PROTO((GC_PTR p));
#if defined(_SOLARIS_PTHREADS) && !defined(SOLARIS_THREADS)
# define SOLARIS_THREADS
#endif
#ifdef SOLARIS_THREADS #ifdef SOLARIS_THREADS
/* We need to intercept calls to many of the threads primitives, so */ /* We need to intercept calls to many of the threads primitives, so */
/* that we can locate thread stacks and stop the world. */ /* that we can locate thread stacks and stop the world. */
...@@ -656,7 +713,7 @@ GC_API void (*GC_is_visible_print_proc) ...@@ -656,7 +713,7 @@ GC_API void (*GC_is_visible_print_proc)
# endif /* SOLARIS_THREADS */ # endif /* SOLARIS_THREADS */
#if defined(IRIX_THREADS) || defined(LINUX_THREADS) #if defined(IRIX_THREADS) || defined(LINUX_THREADS) || defined(HPUX_THREADS)
/* We treat these similarly. */ /* We treat these similarly. */
# include <pthread.h> # include <pthread.h>
# include <signal.h> # include <signal.h>
...@@ -673,10 +730,14 @@ GC_API void (*GC_is_visible_print_proc) ...@@ -673,10 +730,14 @@ GC_API void (*GC_is_visible_print_proc)
#endif /* IRIX_THREADS || LINUX_THREADS */ #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) || defined(HPUX_THREADS)
/* Any flavor of threads except SRC_M3. */
/* This returns a list of objects, linked through their first */ /* This returns a list of objects, linked through their first */
/* word. Its use can greatly reduce lock contention problems, since */ /* word. Its use can greatly reduce lock contention problems, since */
/* the allocation lock can be acquired and released many fewer times. */ /* the allocation lock can be acquired and released many fewer times. */
/* lb must be large enough to hold the pointer field. */
GC_PTR GC_malloc_many(size_t lb); GC_PTR GC_malloc_many(size_t lb);
#define GC_NEXT(p) (*(GC_PTR *)(p)) /* Retrieve the next element */ #define GC_NEXT(p) (*(GC_PTR *)(p)) /* Retrieve the next element */
/* in returned list. */ /* in returned list. */
...@@ -704,6 +765,13 @@ extern void GC_thr_init(); /* Needed for Solaris/X86 */ ...@@ -704,6 +765,13 @@ extern void GC_thr_init(); /* Needed for Solaris/X86 */
# endif # endif
#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 #ifdef __cplusplus
} /* end of extern "C" */ } /* end of extern "C" */
#endif #endif
......
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102 # TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102
!IF "$(CFG)" == "" !IF "$(CFG)" == ""
CFG=cord - Win32 Debug CFG=gctest - Win32 Release
!MESSAGE No configuration specified. Defaulting to cord - Win32 Debug. !MESSAGE No configuration specified. Defaulting to cord - Win32 Debug.
!ENDIF !ENDIF
...@@ -768,7 +768,7 @@ SOURCE=.\reclaim.c ...@@ -768,7 +768,7 @@ SOURCE=.\reclaim.c
!IF "$(CFG)" == "gc - Win32 Release" !IF "$(CFG)" == "gc - Win32 Release"
DEP_CPP_RECLA=\ DEP_CPP_RECLA=\
".\config.h"\ ".\gcconfig.h"\
".\gc.h"\ ".\gc.h"\
".\gc_hdrs.h"\ ".\gc_hdrs.h"\
".\gc_priv.h"\ ".\gc_priv.h"\
...@@ -788,7 +788,7 @@ NODEP_CPP_RECLA=\ ...@@ -788,7 +788,7 @@ NODEP_CPP_RECLA=\
!ELSEIF "$(CFG)" == "gc - Win32 Debug" !ELSEIF "$(CFG)" == "gc - Win32 Debug"
DEP_CPP_RECLA=\ DEP_CPP_RECLA=\
".\config.h"\ ".\gcconfig.h"\
".\gc.h"\ ".\gc.h"\
".\gc_hdrs.h"\ ".\gc_hdrs.h"\
".\gc_priv.h"\ ".\gc_priv.h"\
...@@ -816,7 +816,7 @@ SOURCE=.\os_dep.c ...@@ -816,7 +816,7 @@ SOURCE=.\os_dep.c
!IF "$(CFG)" == "gc - Win32 Release" !IF "$(CFG)" == "gc - Win32 Release"
DEP_CPP_OS_DE=\ DEP_CPP_OS_DE=\
".\config.h"\ ".\gcconfig.h"\
".\gc.h"\ ".\gc.h"\
".\gc_hdrs.h"\ ".\gc_hdrs.h"\
".\gc_priv.h"\ ".\gc_priv.h"\
...@@ -840,7 +840,7 @@ NODEP_CPP_OS_DE=\ ...@@ -840,7 +840,7 @@ NODEP_CPP_OS_DE=\
!ELSEIF "$(CFG)" == "gc - Win32 Debug" !ELSEIF "$(CFG)" == "gc - Win32 Debug"
DEP_CPP_OS_DE=\ DEP_CPP_OS_DE=\
".\config.h"\ ".\gcconfig.h"\
".\gc.h"\ ".\gc.h"\
".\gc_hdrs.h"\ ".\gc_hdrs.h"\
".\gc_priv.h"\ ".\gc_priv.h"\
...@@ -872,7 +872,7 @@ SOURCE=.\misc.c ...@@ -872,7 +872,7 @@ SOURCE=.\misc.c
!IF "$(CFG)" == "gc - Win32 Release" !IF "$(CFG)" == "gc - Win32 Release"
DEP_CPP_MISC_=\ DEP_CPP_MISC_=\
".\config.h"\ ".\gcconfig.h"\
".\gc.h"\ ".\gc.h"\
".\gc_hdrs.h"\ ".\gc_hdrs.h"\
".\gc_priv.h"\ ".\gc_priv.h"\
...@@ -893,7 +893,7 @@ NODEP_CPP_MISC_=\ ...@@ -893,7 +893,7 @@ NODEP_CPP_MISC_=\
!ELSEIF "$(CFG)" == "gc - Win32 Debug" !ELSEIF "$(CFG)" == "gc - Win32 Debug"
DEP_CPP_MISC_=\ DEP_CPP_MISC_=\
".\config.h"\ ".\gcconfig.h"\
".\gc.h"\ ".\gc.h"\
".\gc_hdrs.h"\ ".\gc_hdrs.h"\
".\gc_priv.h"\ ".\gc_priv.h"\
...@@ -922,7 +922,7 @@ SOURCE=.\mark_rts.c ...@@ -922,7 +922,7 @@ SOURCE=.\mark_rts.c
!IF "$(CFG)" == "gc - Win32 Release" !IF "$(CFG)" == "gc - Win32 Release"
DEP_CPP_MARK_=\ DEP_CPP_MARK_=\
".\config.h"\ ".\gcconfig.h"\
".\gc.h"\ ".\gc.h"\
".\gc_hdrs.h"\ ".\gc_hdrs.h"\
".\gc_priv.h"\ ".\gc_priv.h"\
...@@ -942,7 +942,7 @@ NODEP_CPP_MARK_=\ ...@@ -942,7 +942,7 @@ NODEP_CPP_MARK_=\
!ELSEIF "$(CFG)" == "gc - Win32 Debug" !ELSEIF "$(CFG)" == "gc - Win32 Debug"
DEP_CPP_MARK_=\ DEP_CPP_MARK_=\
".\config.h"\ ".\gcconfig.h"\
".\gc.h"\ ".\gc.h"\
".\gc_hdrs.h"\ ".\gc_hdrs.h"\
".\gc_priv.h"\ ".\gc_priv.h"\
...@@ -970,7 +970,7 @@ SOURCE=.\mach_dep.c ...@@ -970,7 +970,7 @@ SOURCE=.\mach_dep.c
!IF "$(CFG)" == "gc - Win32 Release" !IF "$(CFG)" == "gc - Win32 Release"
DEP_CPP_MACH_=\ DEP_CPP_MACH_=\
".\config.h"\ ".\gcconfig.h"\
".\gc.h"\ ".\gc.h"\
".\gc_hdrs.h"\ ".\gc_hdrs.h"\
".\gc_priv.h"\ ".\gc_priv.h"\
...@@ -990,7 +990,7 @@ NODEP_CPP_MACH_=\ ...@@ -990,7 +990,7 @@ NODEP_CPP_MACH_=\
!ELSEIF "$(CFG)" == "gc - Win32 Debug" !ELSEIF "$(CFG)" == "gc - Win32 Debug"
DEP_CPP_MACH_=\ DEP_CPP_MACH_=\
".\config.h"\ ".\gcconfig.h"\
".\gc.h"\ ".\gc.h"\
".\gc_hdrs.h"\ ".\gc_hdrs.h"\
".\gc_priv.h"\ ".\gc_priv.h"\
...@@ -1018,7 +1018,7 @@ SOURCE=.\headers.c ...@@ -1018,7 +1018,7 @@ SOURCE=.\headers.c
!IF "$(CFG)" == "gc - Win32 Release" !IF "$(CFG)" == "gc - Win32 Release"
DEP_CPP_HEADE=\ DEP_CPP_HEADE=\
".\config.h"\ ".\gcconfig.h"\
".\gc.h"\ ".\gc.h"\
".\gc_hdrs.h"\ ".\gc_hdrs.h"\
".\gc_priv.h"\ ".\gc_priv.h"\
...@@ -1038,7 +1038,7 @@ NODEP_CPP_HEADE=\ ...@@ -1038,7 +1038,7 @@ NODEP_CPP_HEADE=\
!ELSEIF "$(CFG)" == "gc - Win32 Debug" !ELSEIF "$(CFG)" == "gc - Win32 Debug"
DEP_CPP_HEADE=\ DEP_CPP_HEADE=\
".\config.h"\ ".\gcconfig.h"\
".\gc.h"\ ".\gc.h"\
".\gc_hdrs.h"\ ".\gc_hdrs.h"\
".\gc_priv.h"\ ".\gc_priv.h"\
...@@ -1066,7 +1066,7 @@ SOURCE=.\alloc.c ...@@ -1066,7 +1066,7 @@ SOURCE=.\alloc.c
!IF "$(CFG)" == "gc - Win32 Release" !IF "$(CFG)" == "gc - Win32 Release"
DEP_CPP_ALLOC=\ DEP_CPP_ALLOC=\
".\config.h"\ ".\gcconfig.h"\
".\gc.h"\ ".\gc.h"\
".\gc_hdrs.h"\ ".\gc_hdrs.h"\
".\gc_priv.h"\ ".\gc_priv.h"\
...@@ -1086,7 +1086,7 @@ NODEP_CPP_ALLOC=\ ...@@ -1086,7 +1086,7 @@ NODEP_CPP_ALLOC=\
!ELSEIF "$(CFG)" == "gc - Win32 Debug" !ELSEIF "$(CFG)" == "gc - Win32 Debug"
DEP_CPP_ALLOC=\ DEP_CPP_ALLOC=\
".\config.h"\ ".\gcconfig.h"\
".\gc.h"\ ".\gc.h"\
".\gc_hdrs.h"\ ".\gc_hdrs.h"\
".\gc_priv.h"\ ".\gc_priv.h"\
...@@ -1114,7 +1114,7 @@ SOURCE=.\allchblk.c ...@@ -1114,7 +1114,7 @@ SOURCE=.\allchblk.c
!IF "$(CFG)" == "gc - Win32 Release" !IF "$(CFG)" == "gc - Win32 Release"
DEP_CPP_ALLCH=\ DEP_CPP_ALLCH=\
".\config.h"\ ".\gcconfig.h"\
".\gc.h"\ ".\gc.h"\
".\gc_hdrs.h"\ ".\gc_hdrs.h"\
".\gc_priv.h"\ ".\gc_priv.h"\
...@@ -1134,7 +1134,7 @@ NODEP_CPP_ALLCH=\ ...@@ -1134,7 +1134,7 @@ NODEP_CPP_ALLCH=\
!ELSEIF "$(CFG)" == "gc - Win32 Debug" !ELSEIF "$(CFG)" == "gc - Win32 Debug"
DEP_CPP_ALLCH=\ DEP_CPP_ALLCH=\
".\config.h"\ ".\gcconfig.h"\
".\gc.h"\ ".\gc.h"\
".\gc_hdrs.h"\ ".\gc_hdrs.h"\
".\gc_priv.h"\ ".\gc_priv.h"\
...@@ -1162,7 +1162,7 @@ SOURCE=.\stubborn.c ...@@ -1162,7 +1162,7 @@ SOURCE=.\stubborn.c
!IF "$(CFG)" == "gc - Win32 Release" !IF "$(CFG)" == "gc - Win32 Release"
DEP_CPP_STUBB=\ DEP_CPP_STUBB=\
".\config.h"\ ".\gcconfig.h"\
".\gc.h"\ ".\gc.h"\
".\gc_hdrs.h"\ ".\gc_hdrs.h"\
".\gc_priv.h"\ ".\gc_priv.h"\
...@@ -1182,7 +1182,7 @@ NODEP_CPP_STUBB=\ ...@@ -1182,7 +1182,7 @@ NODEP_CPP_STUBB=\
!ELSEIF "$(CFG)" == "gc - Win32 Debug" !ELSEIF "$(CFG)" == "gc - Win32 Debug"
DEP_CPP_STUBB=\ DEP_CPP_STUBB=\
".\config.h"\ ".\gcconfig.h"\
".\gc.h"\ ".\gc.h"\
".\gc_hdrs.h"\ ".\gc_hdrs.h"\
".\gc_priv.h"\ ".\gc_priv.h"\
...@@ -1210,7 +1210,7 @@ SOURCE=.\obj_map.c ...@@ -1210,7 +1210,7 @@ SOURCE=.\obj_map.c
!IF "$(CFG)" == "gc - Win32 Release" !IF "$(CFG)" == "gc - Win32 Release"
DEP_CPP_OBJ_M=\ DEP_CPP_OBJ_M=\
".\config.h"\ ".\gcconfig.h"\
".\gc.h"\ ".\gc.h"\
".\gc_hdrs.h"\ ".\gc_hdrs.h"\
".\gc_priv.h"\ ".\gc_priv.h"\
...@@ -1230,7 +1230,7 @@ NODEP_CPP_OBJ_M=\ ...@@ -1230,7 +1230,7 @@ NODEP_CPP_OBJ_M=\
!ELSEIF "$(CFG)" == "gc - Win32 Debug" !ELSEIF "$(CFG)" == "gc - Win32 Debug"
DEP_CPP_OBJ_M=\ DEP_CPP_OBJ_M=\
".\config.h"\ ".\gcconfig.h"\
".\gc.h"\ ".\gc.h"\
".\gc_hdrs.h"\ ".\gc_hdrs.h"\
".\gc_priv.h"\ ".\gc_priv.h"\
...@@ -1258,7 +1258,7 @@ SOURCE=.\new_hblk.c ...@@ -1258,7 +1258,7 @@ SOURCE=.\new_hblk.c
!IF "$(CFG)" == "gc - Win32 Release" !IF "$(CFG)" == "gc - Win32 Release"
DEP_CPP_NEW_H=\ DEP_CPP_NEW_H=\
".\config.h"\ ".\gcconfig.h"\
".\gc.h"\ ".\gc.h"\
".\gc_hdrs.h"\ ".\gc_hdrs.h"\
".\gc_priv.h"\ ".\gc_priv.h"\
...@@ -1278,7 +1278,7 @@ NODEP_CPP_NEW_H=\ ...@@ -1278,7 +1278,7 @@ NODEP_CPP_NEW_H=\
!ELSEIF "$(CFG)" == "gc - Win32 Debug" !ELSEIF "$(CFG)" == "gc - Win32 Debug"
DEP_CPP_NEW_H=\ DEP_CPP_NEW_H=\
".\config.h"\ ".\gcconfig.h"\
".\gc.h"\ ".\gc.h"\
".\gc_hdrs.h"\ ".\gc_hdrs.h"\
".\gc_priv.h"\ ".\gc_priv.h"\
...@@ -1306,7 +1306,7 @@ SOURCE=.\mark.c ...@@ -1306,7 +1306,7 @@ SOURCE=.\mark.c
!IF "$(CFG)" == "gc - Win32 Release" !IF "$(CFG)" == "gc - Win32 Release"
DEP_CPP_MARK_C=\ DEP_CPP_MARK_C=\
".\config.h"\ ".\gcconfig.h"\
".\gc.h"\ ".\gc.h"\
".\gc_hdrs.h"\ ".\gc_hdrs.h"\
".\gc_mark.h"\ ".\gc_mark.h"\
...@@ -1327,7 +1327,7 @@ NODEP_CPP_MARK_C=\ ...@@ -1327,7 +1327,7 @@ NODEP_CPP_MARK_C=\
!ELSEIF "$(CFG)" == "gc - Win32 Debug" !ELSEIF "$(CFG)" == "gc - Win32 Debug"
DEP_CPP_MARK_C=\ DEP_CPP_MARK_C=\
".\config.h"\ ".\gcconfig.h"\
".\gc.h"\ ".\gc.h"\
".\gc_hdrs.h"\ ".\gc_hdrs.h"\
".\gc_mark.h"\ ".\gc_mark.h"\
...@@ -1356,7 +1356,7 @@ SOURCE=.\malloc.c ...@@ -1356,7 +1356,7 @@ SOURCE=.\malloc.c
!IF "$(CFG)" == "gc - Win32 Release" !IF "$(CFG)" == "gc - Win32 Release"
DEP_CPP_MALLO=\ DEP_CPP_MALLO=\
".\config.h"\ ".\gcconfig.h"\
".\gc.h"\ ".\gc.h"\
".\gc_hdrs.h"\ ".\gc_hdrs.h"\
".\gc_priv.h"\ ".\gc_priv.h"\
...@@ -1376,7 +1376,7 @@ NODEP_CPP_MALLO=\ ...@@ -1376,7 +1376,7 @@ NODEP_CPP_MALLO=\
!ELSEIF "$(CFG)" == "gc - Win32 Debug" !ELSEIF "$(CFG)" == "gc - Win32 Debug"
DEP_CPP_MALLO=\ DEP_CPP_MALLO=\
".\config.h"\ ".\gcconfig.h"\
".\gc.h"\ ".\gc.h"\
".\gc_hdrs.h"\ ".\gc_hdrs.h"\
".\gc_priv.h"\ ".\gc_priv.h"\
...@@ -1404,7 +1404,7 @@ SOURCE=.\mallocx.c ...@@ -1404,7 +1404,7 @@ SOURCE=.\mallocx.c
!IF "$(CFG)" == "gc - Win32 Release" !IF "$(CFG)" == "gc - Win32 Release"
DEP_CPP_MALLX=\ DEP_CPP_MALLX=\
".\config.h"\ ".\gcconfig.h"\
".\gc.h"\ ".\gc.h"\
".\gc_hdrs.h"\ ".\gc_hdrs.h"\
".\gc_priv.h"\ ".\gc_priv.h"\
...@@ -1424,7 +1424,7 @@ NODEP_CPP_MALLX=\ ...@@ -1424,7 +1424,7 @@ NODEP_CPP_MALLX=\
!ELSEIF "$(CFG)" == "gc - Win32 Debug" !ELSEIF "$(CFG)" == "gc - Win32 Debug"
DEP_CPP_MALLX=\ DEP_CPP_MALLX=\
".\config.h"\ ".\gcconfig.h"\
".\gc.h"\ ".\gc.h"\
".\gc_hdrs.h"\ ".\gc_hdrs.h"\
".\gc_priv.h"\ ".\gc_priv.h"\
...@@ -1452,7 +1452,7 @@ SOURCE=.\finalize.c ...@@ -1452,7 +1452,7 @@ SOURCE=.\finalize.c
!IF "$(CFG)" == "gc - Win32 Release" !IF "$(CFG)" == "gc - Win32 Release"
DEP_CPP_FINAL=\ DEP_CPP_FINAL=\
".\config.h"\ ".\gcconfig.h"\
".\gc.h"\ ".\gc.h"\
".\gc_hdrs.h"\ ".\gc_hdrs.h"\
".\gc_mark.h"\ ".\gc_mark.h"\
...@@ -1473,7 +1473,7 @@ NODEP_CPP_FINAL=\ ...@@ -1473,7 +1473,7 @@ NODEP_CPP_FINAL=\
!ELSEIF "$(CFG)" == "gc - Win32 Debug" !ELSEIF "$(CFG)" == "gc - Win32 Debug"
DEP_CPP_FINAL=\ DEP_CPP_FINAL=\
".\config.h"\ ".\gcconfig.h"\
".\gc.h"\ ".\gc.h"\
".\gc_hdrs.h"\ ".\gc_hdrs.h"\
".\gc_mark.h"\ ".\gc_mark.h"\
...@@ -1502,7 +1502,7 @@ SOURCE=.\dbg_mlc.c ...@@ -1502,7 +1502,7 @@ SOURCE=.\dbg_mlc.c
!IF "$(CFG)" == "gc - Win32 Release" !IF "$(CFG)" == "gc - Win32 Release"
DEP_CPP_DBG_M=\ DEP_CPP_DBG_M=\
".\config.h"\ ".\gcconfig.h"\
".\gc.h"\ ".\gc.h"\
".\gc_hdrs.h"\ ".\gc_hdrs.h"\
".\gc_priv.h"\ ".\gc_priv.h"\
...@@ -1522,7 +1522,7 @@ NODEP_CPP_DBG_M=\ ...@@ -1522,7 +1522,7 @@ NODEP_CPP_DBG_M=\
!ELSEIF "$(CFG)" == "gc - Win32 Debug" !ELSEIF "$(CFG)" == "gc - Win32 Debug"
DEP_CPP_DBG_M=\ DEP_CPP_DBG_M=\
".\config.h"\ ".\gcconfig.h"\
".\gc.h"\ ".\gc.h"\
".\gc_hdrs.h"\ ".\gc_hdrs.h"\
".\gc_priv.h"\ ".\gc_priv.h"\
...@@ -1550,7 +1550,7 @@ SOURCE=.\blacklst.c ...@@ -1550,7 +1550,7 @@ SOURCE=.\blacklst.c
!IF "$(CFG)" == "gc - Win32 Release" !IF "$(CFG)" == "gc - Win32 Release"
DEP_CPP_BLACK=\ DEP_CPP_BLACK=\
".\config.h"\ ".\gcconfig.h"\
".\gc.h"\ ".\gc.h"\
".\gc_hdrs.h"\ ".\gc_hdrs.h"\
".\gc_priv.h"\ ".\gc_priv.h"\
...@@ -1570,7 +1570,7 @@ NODEP_CPP_BLACK=\ ...@@ -1570,7 +1570,7 @@ NODEP_CPP_BLACK=\
!ELSEIF "$(CFG)" == "gc - Win32 Debug" !ELSEIF "$(CFG)" == "gc - Win32 Debug"
DEP_CPP_BLACK=\ DEP_CPP_BLACK=\
".\config.h"\ ".\gcconfig.h"\
".\gc.h"\ ".\gc.h"\
".\gc_hdrs.h"\ ".\gc_hdrs.h"\
".\gc_priv.h"\ ".\gc_priv.h"\
...@@ -1598,7 +1598,7 @@ SOURCE=.\typd_mlc.c ...@@ -1598,7 +1598,7 @@ SOURCE=.\typd_mlc.c
!IF "$(CFG)" == "gc - Win32 Release" !IF "$(CFG)" == "gc - Win32 Release"
DEP_CPP_TYPD_=\ DEP_CPP_TYPD_=\
".\config.h"\ ".\gcconfig.h"\
".\gc.h"\ ".\gc.h"\
".\gc_hdrs.h"\ ".\gc_hdrs.h"\
".\gc_mark.h"\ ".\gc_mark.h"\
...@@ -1620,7 +1620,7 @@ NODEP_CPP_TYPD_=\ ...@@ -1620,7 +1620,7 @@ NODEP_CPP_TYPD_=\
!ELSEIF "$(CFG)" == "gc - Win32 Debug" !ELSEIF "$(CFG)" == "gc - Win32 Debug"
DEP_CPP_TYPD_=\ DEP_CPP_TYPD_=\
".\config.h"\ ".\gcconfig.h"\
".\gc.h"\ ".\gc.h"\
".\gc_hdrs.h"\ ".\gc_hdrs.h"\
".\gc_mark.h"\ ".\gc_mark.h"\
...@@ -1650,7 +1650,7 @@ SOURCE=.\ptr_chck.c ...@@ -1650,7 +1650,7 @@ SOURCE=.\ptr_chck.c
!IF "$(CFG)" == "gc - Win32 Release" !IF "$(CFG)" == "gc - Win32 Release"
DEP_CPP_PTR_C=\ DEP_CPP_PTR_C=\
".\config.h"\ ".\gcconfig.h"\
".\gc.h"\ ".\gc.h"\
".\gc_hdrs.h"\ ".\gc_hdrs.h"\
".\gc_mark.h"\ ".\gc_mark.h"\
...@@ -1671,7 +1671,7 @@ NODEP_CPP_PTR_C=\ ...@@ -1671,7 +1671,7 @@ NODEP_CPP_PTR_C=\
!ELSEIF "$(CFG)" == "gc - Win32 Debug" !ELSEIF "$(CFG)" == "gc - Win32 Debug"
DEP_CPP_PTR_C=\ DEP_CPP_PTR_C=\
".\config.h"\ ".\gcconfig.h"\
".\gc.h"\ ".\gc.h"\
".\gc_hdrs.h"\ ".\gc_hdrs.h"\
".\gc_mark.h"\ ".\gc_mark.h"\
...@@ -1700,7 +1700,7 @@ SOURCE=.\dyn_load.c ...@@ -1700,7 +1700,7 @@ SOURCE=.\dyn_load.c
!IF "$(CFG)" == "gc - Win32 Release" !IF "$(CFG)" == "gc - Win32 Release"
DEP_CPP_DYN_L=\ DEP_CPP_DYN_L=\
".\config.h"\ ".\gcconfig.h"\
".\gc.h"\ ".\gc.h"\
".\gc_hdrs.h"\ ".\gc_hdrs.h"\
".\gc_priv.h"\ ".\gc_priv.h"\
...@@ -1723,7 +1723,7 @@ NODEP_CPP_DYN_L=\ ...@@ -1723,7 +1723,7 @@ NODEP_CPP_DYN_L=\
!ELSEIF "$(CFG)" == "gc - Win32 Debug" !ELSEIF "$(CFG)" == "gc - Win32 Debug"
DEP_CPP_DYN_L=\ DEP_CPP_DYN_L=\
".\config.h"\ ".\gcconfig.h"\
".\gc.h"\ ".\gc.h"\
".\gc_hdrs.h"\ ".\gc_hdrs.h"\
".\gc_priv.h"\ ".\gc_priv.h"\
...@@ -1754,7 +1754,7 @@ SOURCE=.\win32_threads.c ...@@ -1754,7 +1754,7 @@ SOURCE=.\win32_threads.c
!IF "$(CFG)" == "gc - Win32 Release" !IF "$(CFG)" == "gc - Win32 Release"
DEP_CPP_WIN32=\ DEP_CPP_WIN32=\
".\config.h"\ ".\gcconfig.h"\
".\gc.h"\ ".\gc.h"\
".\gc_hdrs.h"\ ".\gc_hdrs.h"\
".\gc_priv.h"\ ".\gc_priv.h"\
...@@ -1774,7 +1774,7 @@ NODEP_CPP_WIN32=\ ...@@ -1774,7 +1774,7 @@ NODEP_CPP_WIN32=\
!ELSEIF "$(CFG)" == "gc - Win32 Debug" !ELSEIF "$(CFG)" == "gc - Win32 Debug"
DEP_CPP_WIN32=\ DEP_CPP_WIN32=\
".\config.h"\ ".\gcconfig.h"\
".\gc.h"\ ".\gc.h"\
".\gc_hdrs.h"\ ".\gc_hdrs.h"\
".\gc_priv.h"\ ".\gc_priv.h"\
...@@ -1802,7 +1802,7 @@ SOURCE=.\checksums.c ...@@ -1802,7 +1802,7 @@ SOURCE=.\checksums.c
!IF "$(CFG)" == "gc - Win32 Release" !IF "$(CFG)" == "gc - Win32 Release"
DEP_CPP_CHECK=\ DEP_CPP_CHECK=\
".\config.h"\ ".\gcconfig.h"\
".\gc.h"\ ".\gc.h"\
".\gc_hdrs.h"\ ".\gc_hdrs.h"\
".\gc_priv.h"\ ".\gc_priv.h"\
...@@ -1822,7 +1822,7 @@ NODEP_CPP_CHECK=\ ...@@ -1822,7 +1822,7 @@ NODEP_CPP_CHECK=\
!ELSEIF "$(CFG)" == "gc - Win32 Debug" !ELSEIF "$(CFG)" == "gc - Win32 Debug"
DEP_CPP_CHECK=\ DEP_CPP_CHECK=\
".\config.h"\ ".\gcconfig.h"\
".\gc.h"\ ".\gc.h"\
".\gc_hdrs.h"\ ".\gc_hdrs.h"\
".\gc_priv.h"\ ".\gc_priv.h"\
...@@ -1878,7 +1878,7 @@ NODEP_CPP_CHECK=\ ...@@ -1878,7 +1878,7 @@ NODEP_CPP_CHECK=\
SOURCE=.\test.c SOURCE=.\test.c
DEP_CPP_TEST_=\ DEP_CPP_TEST_=\
".\config.h"\ ".\gcconfig.h"\
".\gc.h"\ ".\gc.h"\
".\gc_hdrs.h"\ ".\gc_hdrs.h"\
".\gc_priv.h"\ ".\gc_priv.h"\
......
...@@ -13,7 +13,7 @@ ...@@ -13,7 +13,7 @@
// //
// This is a C++ header file that is intended to replace the SGI STL // This is a C++ header file that is intended to replace the SGI STL
// alloc.h. // alloc.h. This assumes SGI STL version < 3.0.
// //
// This assumes the collector has been compiled with -DATOMIC_UNCOLLECTABLE // This assumes the collector has been compiled with -DATOMIC_UNCOLLECTABLE
// and -DALL_INTERIOR_POINTERS. We also recommend // and -DALL_INTERIOR_POINTERS. We also recommend
......
...@@ -32,6 +32,20 @@ void* operator new( size_t size ) { ...@@ -32,6 +32,20 @@ void* operator new( size_t size ) {
void operator delete( void* obj ) { void operator delete( void* obj ) {
GC_FREE( 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 #ifdef OPERATOR_NEW_ARRAY
......
...@@ -133,7 +133,8 @@ uses explicit invocation. ...@@ -133,7 +133,8 @@ uses explicit invocation.
#endif #endif
#if ! defined( OPERATOR_NEW_ARRAY ) \ #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 # define OPERATOR_NEW_ARRAY
#endif #endif
...@@ -212,6 +213,8 @@ inline void* gc::operator new( size_t size ) { ...@@ -212,6 +213,8 @@ inline void* gc::operator new( size_t size ) {
inline void* gc::operator new( size_t size, GCPlacement gcp ) { inline void* gc::operator new( size_t size, GCPlacement gcp ) {
if (gcp == GC) if (gcp == GC)
return GC_MALLOC( size ); return GC_MALLOC( size );
else if (gcp == PointerFreeGC)
return GC_MALLOC_ATOMIC( size );
else else
return GC_MALLOC_UNCOLLECTABLE( size );} return GC_MALLOC_UNCOLLECTABLE( size );}
...@@ -234,7 +237,7 @@ inline void gc::operator delete[]( void* obj ) { ...@@ -234,7 +237,7 @@ inline void gc::operator delete[]( void* obj ) {
inline gc_cleanup::~gc_cleanup() { inline gc_cleanup::~gc_cleanup() {
GC_REGISTER_FINALIZER_IGNORE_SELF( this, 0, 0, 0, 0 );} GC_REGISTER_FINALIZER_IGNORE_SELF( GC_base(this), 0, 0, 0, 0 );}
inline void gc_cleanup::cleanup( void* obj, void* displ ) { inline void gc_cleanup::cleanup( void* obj, void* displ ) {
((gc_cleanup*) ((char*) obj + (ptrdiff_t) displ))->~gc_cleanup();} ((gc_cleanup*) ((char*) obj + (ptrdiff_t) displ))->~gc_cleanup();}
......
...@@ -49,14 +49,16 @@ typedef struct bi { ...@@ -49,14 +49,16 @@ typedef struct bi {
hdr * index[BOTTOM_SZ]; hdr * index[BOTTOM_SZ];
/* /*
* The bottom level index contains one of three kinds of values: * The bottom level index contains one of three kinds of values:
* 0 means we're not responsible for this block. * 0 means we're not responsible for this block,
* or this is a block other than the first one in a free block.
* 1 < (long)X <= MAX_JUMP means the block starts at least * 1 < (long)X <= MAX_JUMP means the block starts at least
* X * HBLKSIZE bytes before the current address. * X * HBLKSIZE bytes before the current address.
* A valid pointer points to a hdr structure. (The above can't be * A valid pointer points to a hdr structure. (The above can't be
* valid pointers due to the GET_MEM return convention.) * valid pointers due to the GET_MEM return convention.)
*/ */
struct bi * asc_link; /* All indices are linked in */ struct bi * asc_link; /* All indices are linked in */
/* ascending order. */ /* ascending order... */
struct bi * desc_link; /* ... and in descending order. */
word key; /* high order address bits. */ word key; /* high order address bits. */
# ifdef HASH_TL # ifdef HASH_TL
struct bi * hash_link; /* Hash chain link. */ struct bi * hash_link; /* Hash chain link. */
......
...@@ -38,12 +38,17 @@ ...@@ -38,12 +38,17 @@
/* subset of the places the conservative marker would. It must be safe */ /* subset of the places the conservative marker would. It must be safe */
/* to invoke the normal mark procedure instead. */ /* to invoke the normal mark procedure instead. */
# define PROC_BYTES 100 # define PROC_BYTES 100
typedef struct ms_entry * (*mark_proc)(/* word * addr, mark_stack_ptr, /* The real declarations of the following are in gc_priv.h, so that */
mark_stack_limit, env */); /* 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 LOG_MAX_MARK_PROCS 6
# define MAX_MARK_PROCS (1 << LOG_MAX_MARK_PROCS) # define MAX_MARK_PROCS (1 << LOG_MAX_MARK_PROCS)
extern mark_proc GC_mark_procs[MAX_MARK_PROCS]; extern mark_proc GC_mark_procs[MAX_MARK_PROCS];
*/
extern word GC_n_mark_procs; extern word GC_n_mark_procs;
/* Object descriptors on mark stack or in objects. Low order two */ /* Object descriptors on mark stack or in objects. Low order two */
...@@ -166,6 +171,8 @@ mse * GC_signal_mark_stack_overflow(); ...@@ -166,6 +171,8 @@ mse * GC_signal_mark_stack_overflow();
/* Mark bit is already set */ \ /* Mark bit is already set */ \
goto exit_label; \ goto exit_label; \
} \ } \
GC_STORE_BACK_PTR((ptr_t)source, (ptr_t)HBLKPTR(current) \
+ WORDS_TO_BYTES(displ)); \
*mark_word_addr = mark_word | mark_bit; \ *mark_word_addr = mark_word | mark_bit; \
} \ } \
PUSH_OBJ(((word *)(HBLKPTR(current)) + displ), hhdr, \ PUSH_OBJ(((word *)(HBLKPTR(current)) + displ), hhdr, \
...@@ -173,18 +180,24 @@ mse * GC_signal_mark_stack_overflow(); ...@@ -173,18 +180,24 @@ mse * GC_signal_mark_stack_overflow();
exit_label: ; \ exit_label: ; \
} }
#ifdef PRINT_BLACK_LIST
# define PUSH_ONE_CHECKED(p, ip, source) \
GC_push_one_checked(p, ip, (ptr_t)(source))
#else
# define PUSH_ONE_CHECKED(p, ip, source) \
GC_push_one_checked(p, ip)
#endif
/* /*
* Push a single value onto mark stack. Mark from the object pointed to by p. * Push a single value onto mark stack. Mark from the object pointed to by p.
* GC_push_one is normally called by GC_push_regs, and thus must be defined.
* P is considered valid even if it is an interior pointer. * P is considered valid even if it is an interior pointer.
* Previously marked objects are not pushed. Hence we make progress even * Previously marked objects are not pushed. Hence we make progress even
* if the mark stack overflows. * if the mark stack overflows.
*/ */
# define GC_PUSH_ONE_STACK(p) \ # define GC_PUSH_ONE_STACK(p, source) \
if ((ptr_t)(p) >= GC_least_plausible_heap_addr \ if ((ptr_t)(p) >= GC_least_plausible_heap_addr \
&& (ptr_t)(p) < GC_greatest_plausible_heap_addr) { \ && (ptr_t)(p) < GC_greatest_plausible_heap_addr) { \
GC_push_one_checked(p,TRUE); \ PUSH_ONE_CHECKED(p, TRUE, source); \
} }
/* /*
...@@ -196,10 +209,10 @@ mse * GC_signal_mark_stack_overflow(); ...@@ -196,10 +209,10 @@ mse * GC_signal_mark_stack_overflow();
# else # else
# define AIP FALSE # define AIP FALSE
# endif # endif
# define GC_PUSH_ONE_HEAP(p) \ # define GC_PUSH_ONE_HEAP(p,source) \
if ((ptr_t)(p) >= GC_least_plausible_heap_addr \ if ((ptr_t)(p) >= GC_least_plausible_heap_addr \
&& (ptr_t)(p) < GC_greatest_plausible_heap_addr) { \ && (ptr_t)(p) < GC_greatest_plausible_heap_addr) { \
GC_push_one_checked(p,AIP); \ PUSH_ONE_CHECKED(p,AIP,source); \
} }
/* /*
...@@ -213,7 +226,7 @@ mse * GC_signal_mark_stack_overflow(); ...@@ -213,7 +226,7 @@ mse * GC_signal_mark_stack_overflow();
while (!GC_mark_stack_empty()) GC_mark_from_mark_stack(); \ while (!GC_mark_stack_empty()) GC_mark_from_mark_stack(); \
if (GC_mark_state != MS_NONE) { \ if (GC_mark_state != MS_NONE) { \
GC_set_mark_bit(real_ptr); \ GC_set_mark_bit(real_ptr); \
while (!GC_mark_some()); \ while (!GC_mark_some((ptr_t)0)); \
} \ } \
} }
...@@ -233,8 +246,8 @@ typedef int mark_state_t; /* Current state of marking, as follows:*/ ...@@ -233,8 +246,8 @@ typedef int mark_state_t; /* Current state of marking, as follows:*/
/* Invariant I: all roots and marked */ /* Invariant I: all roots and marked */
/* objects p are either dirty, or point */ /* objects p are either dirty, or point */
/* objects q that are either marked or */ /* to objects q that are either marked */
/* a pointer to q appears in a range */ /* or a pointer to q appears in a range */
/* on the mark stack. */ /* on the mark stack. */
# define MS_NONE 0 /* No marking in progress. I holds. */ # define MS_NONE 0 /* No marking in progress. I holds. */
......
...@@ -25,6 +25,12 @@ ...@@ -25,6 +25,12 @@
# include "gc_priv.h" # include "gc_priv.h"
bottom_index * GC_all_bottom_indices = 0; bottom_index * GC_all_bottom_indices = 0;
/* Pointer to first (lowest addr) */
/* bottom_index. */
bottom_index * GC_all_bottom_indices_end = 0;
/* Pointer to last (highest addr) */
/* bottom_index. */
/* Non-macro version of header location routine */ /* Non-macro version of header location routine */
hdr * GC_find_header(h) hdr * GC_find_header(h)
...@@ -53,7 +59,6 @@ ptr_t GC_scratch_alloc(bytes) ...@@ -53,7 +59,6 @@ ptr_t GC_scratch_alloc(bytes)
register word bytes; register word bytes;
{ {
register ptr_t result = scratch_free_ptr; register ptr_t result = scratch_free_ptr;
register word bytes_needed = bytes;
# ifdef ALIGN_DOUBLE # ifdef ALIGN_DOUBLE
# define GRANULARITY (2 * sizeof(word)) # define GRANULARITY (2 * sizeof(word))
...@@ -90,7 +95,7 @@ register word bytes; ...@@ -90,7 +95,7 @@ register word bytes;
bytes_to_get = bytes; bytes_to_get = bytes;
# ifdef USE_MMAP # ifdef USE_MMAP
bytes_to_get += GC_page_size - 1; bytes_to_get += GC_page_size - 1;
bytes_to_get &= (GC_page_size - 1); bytes_to_get &= ~(GC_page_size - 1);
# endif # endif
return((ptr_t)GET_MEM(bytes_to_get)); return((ptr_t)GET_MEM(bytes_to_get));
} }
...@@ -126,7 +131,7 @@ hdr * hhdr; ...@@ -126,7 +131,7 @@ hdr * hhdr;
void GC_init_headers() void GC_init_headers()
{ {
register int i; register unsigned i;
GC_all_nils = (bottom_index *)GC_scratch_alloc((word)sizeof(bottom_index)); GC_all_nils = (bottom_index *)GC_scratch_alloc((word)sizeof(bottom_index));
BZERO(GC_all_nils, sizeof(bottom_index)); BZERO(GC_all_nils, sizeof(bottom_index));
...@@ -138,16 +143,17 @@ void GC_init_headers() ...@@ -138,16 +143,17 @@ void GC_init_headers()
/* Make sure that there is a bottom level index block for address addr */ /* Make sure that there is a bottom level index block for address addr */
/* Return FALSE on failure. */ /* Return FALSE on failure. */
static GC_bool get_index(addr) static GC_bool get_index(addr)
register word addr; word addr;
{ {
register word hi = word hi = (word)(addr) >> (LOG_BOTTOM_SZ + LOG_HBLKSIZE);
(word)(addr) >> (LOG_BOTTOM_SZ + LOG_HBLKSIZE); bottom_index * r;
register bottom_index * r; bottom_index * p;
register bottom_index * p; bottom_index ** prev;
register bottom_index ** prev; bottom_index *pi;
# ifdef HASH_TL # ifdef HASH_TL
register unsigned i = TL_HASH(hi); unsigned i = TL_HASH(hi);
register bottom_index * old; bottom_index * old;
old = p = GC_top_index[i]; old = p = GC_top_index[i];
while(p != GC_all_nils) { while(p != GC_all_nils) {
...@@ -165,11 +171,21 @@ register word addr; ...@@ -165,11 +171,21 @@ register word addr;
if (r == 0) return(FALSE); if (r == 0) return(FALSE);
GC_top_index[hi] = r; GC_top_index[hi] = r;
BZERO(r, sizeof (bottom_index)); BZERO(r, sizeof (bottom_index));
# endif # endif
r -> key = hi; r -> key = hi;
/* Add it to the list of bottom indices */ /* Add it to the list of bottom indices */
prev = &GC_all_bottom_indices; prev = &GC_all_bottom_indices; /* pointer to p */
while ((p = *prev) != 0 && p -> key < hi) prev = &(p -> asc_link); pi = 0; /* bottom_index preceding p */
while ((p = *prev) != 0 && p -> key < hi) {
pi = p;
prev = &(p -> asc_link);
}
r -> desc_link = pi;
if (0 == p) {
GC_all_bottom_indices_end = r;
} else {
p -> desc_link = r;
}
r -> asc_link = p; r -> asc_link = p;
*prev = r; *prev = r;
return(TRUE); return(TRUE);
...@@ -186,6 +202,9 @@ register struct hblk * h; ...@@ -186,6 +202,9 @@ register struct hblk * h;
if (!get_index((word) h)) return(FALSE); if (!get_index((word) h)) return(FALSE);
result = alloc_hdr(); result = alloc_hdr();
SET_HDR(h, result); SET_HDR(h, result);
# ifdef USE_MUNMAP
result -> hb_last_reclaimed = GC_gc_no;
# endif
return(result != 0); return(result != 0);
} }
...@@ -262,7 +281,7 @@ word client_data; ...@@ -262,7 +281,7 @@ word client_data;
/* Get the next valid block whose address is at least h */ /* Get the next valid block whose address is at least h */
/* Return 0 if there is none. */ /* Return 0 if there is none. */
struct hblk * GC_next_block(h) struct hblk * GC_next_used_block(h)
struct hblk * h; struct hblk * h;
{ {
register bottom_index * bi; register bottom_index * bi;
...@@ -277,15 +296,16 @@ struct hblk * h; ...@@ -277,15 +296,16 @@ struct hblk * h;
} }
while(bi != 0) { while(bi != 0) {
while (j < BOTTOM_SZ) { while (j < BOTTOM_SZ) {
if (IS_FORWARDING_ADDR_OR_NIL(bi -> index[j])) { hdr * hhdr = bi -> index[j];
if (IS_FORWARDING_ADDR_OR_NIL(hhdr)) {
j++; j++;
} else { } else {
if (bi->index[j]->hb_map != GC_invalid_map) { if (hhdr->hb_map != GC_invalid_map) {
return((struct hblk *) return((struct hblk *)
(((bi -> key << LOG_BOTTOM_SZ) + j) (((bi -> key << LOG_BOTTOM_SZ) + j)
<< LOG_HBLKSIZE)); << LOG_HBLKSIZE));
} else { } else {
j += divHBLKSZ(bi->index[j] -> hb_sz); j += divHBLKSZ(hhdr -> hb_sz);
} }
} }
} }
...@@ -294,3 +314,38 @@ struct hblk * h; ...@@ -294,3 +314,38 @@ struct hblk * h;
} }
return(0); return(0);
} }
/* Get the last (highest address) block whose address is */
/* at most h. Return 0 if there is none. */
/* Unlike the above, this may return a free block. */
struct hblk * GC_prev_block(h)
struct hblk * h;
{
register bottom_index * bi;
register signed_word j = ((word)h >> LOG_HBLKSIZE) & (BOTTOM_SZ-1);
GET_BI(h, bi);
if (bi == GC_all_nils) {
register word hi = (word)h >> (LOG_BOTTOM_SZ + LOG_HBLKSIZE);
bi = GC_all_bottom_indices_end;
while (bi != 0 && bi -> key > hi) bi = bi -> desc_link;
j = BOTTOM_SZ - 1;
}
while(bi != 0) {
while (j >= 0) {
hdr * hhdr = bi -> index[j];
if (0 == hhdr) {
--j;
} else if (IS_FORWARDING_ADDR_OR_NIL(hhdr)) {
j -= (signed_word)hhdr;
} else {
return((struct hblk *)
(((bi -> key << LOG_BOTTOM_SZ) + j)
<< LOG_HBLKSIZE));
}
}
j = BOTTOM_SZ - 1;
bi = bi -> desc_link;
}
return(0);
}
/* Conditionally execute a command based on machine and OS from config.h */ /* Conditionally execute a command based on machine and OS from gcconfig.h */
/* Boehm, November 21, 1994 1:40 pm PST */
# include "config.h" # include "gcconfig.h"
# include <stdio.h> # include <stdio.h>
int main(argc, argv, envp) int main(argc, argv, envp)
......
/* Conditionally execute a command based if the file argv[1] doesn't exist */ /* Conditionally execute a command based if the file argv[1] doesn't exist */
/* Except for execvp, we stick to ANSI C. */ /* Except for execvp, we stick to ANSI C. */
# include "config.h" # include "gcconfig.h"
# include <stdio.h> # include <stdio.h>
int main(argc, argv, envp) int main(argc, argv, envp)
......
...@@ -25,6 +25,7 @@ ...@@ -25,6 +25,7 @@
# include "gc_priv.h" # include "gc_priv.h"
# include <pthread.h> # include <pthread.h>
# include <semaphore.h>
# include <time.h> # include <time.h>
# include <errno.h> # include <errno.h>
# include <unistd.h> # include <unistd.h>
...@@ -411,6 +412,7 @@ void GC_thr_init() ...@@ -411,6 +412,7 @@ void GC_thr_init()
GC_thread t; GC_thread t;
struct sigaction act; struct sigaction act;
if (GC_thr_initialized) return;
GC_thr_initialized = TRUE; GC_thr_initialized = TRUE;
GC_min_stack_sz = HBLKSIZE; GC_min_stack_sz = HBLKSIZE;
GC_page_sz = sysconf(_SC_PAGESIZE); GC_page_sz = sysconf(_SC_PAGESIZE);
...@@ -445,9 +447,14 @@ int GC_pthread_sigmask(int how, const sigset_t *set, sigset_t *oset) ...@@ -445,9 +447,14 @@ int GC_pthread_sigmask(int how, const sigset_t *set, sigset_t *oset)
struct start_info { struct start_info {
void *(*start_routine)(void *); void *(*start_routine)(void *);
void *arg; 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; GC_thread me;
...@@ -472,6 +479,9 @@ int GC_pthread_join(pthread_t thread, void **retval) ...@@ -472,6 +479,9 @@ int GC_pthread_join(pthread_t thread, void **retval)
/* cant have been recycled by pthreads. */ /* cant have been recycled by pthreads. */
UNLOCK(); UNLOCK();
result = pthread_join(thread, retval); 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(); LOCK();
/* Here the pthread thread id may have been recycled. */ /* Here the pthread thread id may have been recycled. */
GC_delete_gc_thread(thread, thread_gc_id); GC_delete_gc_thread(thread, thread_gc_id);
...@@ -484,12 +494,34 @@ void * GC_start_routine(void * arg) ...@@ -484,12 +494,34 @@ void * GC_start_routine(void * arg)
struct start_info * si = arg; struct start_info * si = arg;
void * result; void * result;
GC_thread me; 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(); 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(); UNLOCK();
start = si -> start_routine;
start_arg = si -> arg;
sem_post(&(si -> registered));
pthread_cleanup_push(GC_thread_exit_proc, 0); pthread_cleanup_push(GC_thread_exit_proc, 0);
result = (*(si -> start_routine))(si -> arg); result = (*start)(start_arg);
me -> status = result; me -> status = result;
me -> flags |= FINISHED; me -> flags |= FINISHED;
pthread_cleanup_pop(1); pthread_cleanup_pop(1);
...@@ -506,15 +538,17 @@ GC_pthread_create(pthread_t *new_thread, ...@@ -506,15 +538,17 @@ GC_pthread_create(pthread_t *new_thread,
{ {
int result; int result;
GC_thread t; GC_thread t;
pthread_t my_new_thread;
void * stack; void * stack;
size_t stacksize; size_t stacksize;
pthread_attr_t new_attr; pthread_attr_t new_attr;
int detachstate; int detachstate;
word my_flags = 0; word my_flags = 0;
struct start_info * si = GC_malloc(sizeof(struct start_info)); 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); if (0 == si) return(ENOMEM);
sem_init(&(si -> registered), 0, 0);
si -> start_routine = start_routine; si -> start_routine = start_routine;
si -> arg = arg; si -> arg = arg;
LOCK(); LOCK();
...@@ -540,20 +574,20 @@ GC_pthread_create(pthread_t *new_thread, ...@@ -540,20 +574,20 @@ GC_pthread_create(pthread_t *new_thread,
my_flags |= CLIENT_OWNS_STACK; my_flags |= CLIENT_OWNS_STACK;
} }
if (PTHREAD_CREATE_DETACHED == detachstate) my_flags |= DETACHED; if (PTHREAD_CREATE_DETACHED == detachstate) my_flags |= DETACHED;
result = pthread_create(&my_new_thread, &new_attr, GC_start_routine, si); si -> flags = my_flags;
/* No GC can start until the thread is registered, since we hold */ si -> stack = stack;
/* the allocation lock. */ si -> stack_size = stacksize;
if (0 == result) { result = pthread_create(new_thread, &new_attr, GC_start_routine, si);
t = GC_new_thread(my_new_thread); if (0 == new_thread && !(my_flags & CLIENT_OWNS_STACK)) {
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)) {
GC_stack_free(stack, stacksize); GC_stack_free(stack, stacksize);
} }
UNLOCK(); 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); */ /* pthread_attr_destroy(&new_attr); */
return(result); return(result);
} }
......
...@@ -28,9 +28,13 @@ ...@@ -28,9 +28,13 @@
* there too. * there too.
*/ */
# if defined(LINUX_THREADS) /* #define DEBUG_THREADS 1 */
/* ANSI C requires that a compilation unit contains something */
# include "gc_priv.h" # include "gc_priv.h"
# if defined(LINUX_THREADS)
# include <pthread.h> # include <pthread.h>
# include <time.h> # include <time.h>
# include <errno.h> # include <errno.h>
...@@ -114,17 +118,12 @@ GC_linux_thread_top_of_stack() relies on implementation details of ...@@ -114,17 +118,12 @@ GC_linux_thread_top_of_stack() relies on implementation details of
LinuxThreads, namely that thread stacks are allocated on 2M boundaries LinuxThreads, namely that thread stacks are allocated on 2M boundaries
and grow to no more than 2M. and grow to no more than 2M.
To make sure that we're using LinuxThreads and not some other thread To make sure that we're using LinuxThreads and not some other thread
package, we generate a dummy reference to `__pthread_initial_thread_bos', package, we generate a dummy reference to `pthread_kill_other_threads_np'
(was `__pthread_initial_thread_bos' but that disappeared),
which is a symbol defined in LinuxThreads, but (hopefully) not in other which is a symbol defined in LinuxThreads, but (hopefully) not in other
thread packages. thread packages.
*/ */
#if 0 void (*dummy_var_to_force_linux_threads)() = pthread_kill_other_threads_np;
/* Note: on Caldera OpenLinux, this symbols is `local' in the
libpthread.so (but not in libpthread.a). We don't really need
this, so we just comment it out. */
extern char * __pthread_initial_thread_bos;
char **dummy_var_to_force_linux_threads = &__pthread_initial_thread_bos;
#endif
#define LINUX_THREADS_STACK_SIZE (2 * 1024 * 1024) #define LINUX_THREADS_STACK_SIZE (2 * 1024 * 1024)
...@@ -424,6 +423,7 @@ void GC_thr_init() ...@@ -424,6 +423,7 @@ void GC_thr_init()
GC_thread t; GC_thread t;
struct sigaction act; struct sigaction act;
if (GC_thr_initialized) return;
GC_thr_initialized = TRUE; GC_thr_initialized = TRUE;
if (sem_init(&GC_suspend_ack_sem, 0, 0) != 0) if (sem_init(&GC_suspend_ack_sem, 0, 0) != 0)
...@@ -446,7 +446,7 @@ void GC_thr_init() ...@@ -446,7 +446,7 @@ void GC_thr_init()
/* Add the initial thread, so we can stop it. */ /* Add the initial thread, so we can stop it. */
t = GC_new_thread(pthread_self()); t = GC_new_thread(pthread_self());
t -> stack_ptr = (ptr_t)(&t); t -> stack_ptr = 0;
t -> flags = DETACHED | MAIN_THREAD; t -> flags = DETACHED | MAIN_THREAD;
} }
...@@ -465,11 +465,16 @@ int GC_pthread_sigmask(int how, const sigset_t *set, sigset_t *oset) ...@@ -465,11 +465,16 @@ int GC_pthread_sigmask(int how, const sigset_t *set, sigset_t *oset)
struct start_info { struct start_info {
void *(*start_routine)(void *); void *(*start_routine)(void *);
void *arg; 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; GC_thread me;
struct start_info * si = arg;
LOCK(); LOCK();
me = GC_lookup_thread(pthread_self()); me = GC_lookup_thread(pthread_self());
...@@ -504,26 +509,37 @@ void * GC_start_routine(void * arg) ...@@ -504,26 +509,37 @@ void * GC_start_routine(void * arg)
struct start_info * si = arg; struct start_info * si = arg;
void * result; void * result;
GC_thread me; GC_thread me;
pthread_t my_pthread;
void *(*start)(void *);
void *start_arg;
my_pthread = pthread_self();
LOCK(); 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(); 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 # 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("pid = %ld\n", (long) getpid());
GC_printf1("sp = 0x%lx\n", (long) &arg); GC_printf1("sp = 0x%lx\n", (long) &arg);
GC_printf1("start_routine = 0x%lx\n", start);
# endif # endif
result = (*(si -> start_routine))(si -> arg); result = (*start)(start_arg);
#if DEBUG_THREADS #if DEBUG_THREADS
GC_printf1("Finishing thread 0x%x\n", pthread_self()); GC_printf1("Finishing thread 0x%x\n", pthread_self());
#endif #endif
me -> status = result; me -> status = result;
me -> flags |= FINISHED; me -> flags |= FINISHED;
pthread_cleanup_pop(1); pthread_cleanup_pop(1);
/* This involves acquiring the lock, ensuring that we can't exit */ /* Cleanup acquires lock, ensuring that we can't exit */
/* while a collection that thinks we're alive is trying to stop */ /* while a collection that thinks we're alive is trying to stop */
/* us. */ /* us. */
return(result); return(result);
} }
...@@ -541,8 +557,11 @@ GC_pthread_create(pthread_t *new_thread, ...@@ -541,8 +557,11 @@ GC_pthread_create(pthread_t *new_thread,
int detachstate; int detachstate;
word my_flags = 0; word my_flags = 0;
struct start_info * si = GC_malloc(sizeof(struct start_info)); 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); if (0 == si) return(ENOMEM);
sem_init(&(si -> registered), 0, 0);
si -> start_routine = start_routine; si -> start_routine = start_routine;
si -> arg = arg; si -> arg = arg;
LOCK(); LOCK();
...@@ -555,17 +574,16 @@ GC_pthread_create(pthread_t *new_thread, ...@@ -555,17 +574,16 @@ GC_pthread_create(pthread_t *new_thread,
} }
pthread_attr_getdetachstate(&new_attr, &detachstate); pthread_attr_getdetachstate(&new_attr, &detachstate);
if (PTHREAD_CREATE_DETACHED == detachstate) my_flags |= DETACHED; if (PTHREAD_CREATE_DETACHED == detachstate) my_flags |= DETACHED;
result = pthread_create(&my_new_thread, &new_attr, GC_start_routine, si); si -> flags = my_flags;
/* No GC can start until the thread is registered, since we hold */ UNLOCK();
/* the allocation lock. */ result = pthread_create(new_thread, &new_attr, GC_start_routine, si);
if (0 == result) { /* Wait until child has been added to the thread table. */
t = GC_new_thread(my_new_thread); /* This also ensures that we hold onto si until the child is done */
t -> flags = my_flags; /* with it. Thus it doesn't matter whether it is otherwise */
t -> stack_ptr = 0; /* visible to the collector. */
t -> stack_end = 0; if (0 != sem_wait(&(si -> registered))) ABORT("sem_wait failed");
if (0 != new_thread) *new_thread = my_new_thread; sem_destroy(&(si -> registered));
} /* pthread_attr_destroy(&new_attr); */
UNLOCK();
/* pthread_attr_destroy(&new_attr); */ /* pthread_attr_destroy(&new_attr); */
return(result); return(result);
} }
......
...@@ -20,7 +20,11 @@ ...@@ -20,7 +20,11 @@
# define _longjmp(b,v) longjmp(b,v) # define _longjmp(b,v) longjmp(b,v)
# endif # endif
# ifdef AMIGA # ifdef AMIGA
# include <dos.h> # ifndef __GNUC__
# include <dos/dos.h>
# else
# include <machine/reg.h>
# endif
# endif # endif
#if defined(__MWERKS__) && !defined(POWERPC) #if defined(__MWERKS__) && !defined(POWERPC)
...@@ -58,12 +62,19 @@ asm static void PushMacRegisters() ...@@ -58,12 +62,19 @@ asm static void PushMacRegisters()
#endif /* __MWERKS__ */ #endif /* __MWERKS__ */
# if defined(SPARC) || defined(IA64)
/* Value returned from register flushing routine; either sp (SPARC) */
/* or ar.bsp (IA64) */
word GC_save_regs_ret_val;
# endif
/* Routine to mark from registers that are preserved by the C compiler. */ /* Routine to mark from registers that are preserved by the C compiler. */
/* This must be ported to every new architecture. There is a generic */ /* This must be ported to every new architecture. There is a generic */
/* version at the end, that is likely, but not guaranteed to work */ /* version at the end, that is likely, but not guaranteed to work */
/* on your architecture. Run the test_setjmp program to see whether */ /* on your architecture. Run the test_setjmp program to see whether */
/* there is any chance it will work. */ /* there is any chance it will work. */
#ifndef USE_GENERIC_PUSH_REGS
void GC_push_regs() void GC_push_regs()
{ {
# ifdef RT # ifdef RT
...@@ -125,9 +136,28 @@ void GC_push_regs() ...@@ -125,9 +136,28 @@ void GC_push_regs()
asm("addq.w &0x4,%sp"); /* put stack back where it was */ asm("addq.w &0x4,%sp"); /* put stack back where it was */
# endif /* M68K HP */ # endif /* M68K HP */
# ifdef AMIGA # if defined(M68K) && defined(AMIGA)
/* AMIGA - could be replaced by generic code */ /* AMIGA - could be replaced by generic code */
/* a0, a1, d0 and d1 are caller save */ /* a0, a1, d0 and d1 are caller save */
# ifdef __GNUC__
asm("subq.w &0x4,%sp"); /* allocate word on top of stack */
asm("mov.l %a2,(%sp)"); asm("jsr _GC_push_one");
asm("mov.l %a3,(%sp)"); asm("jsr _GC_push_one");
asm("mov.l %a4,(%sp)"); asm("jsr _GC_push_one");
asm("mov.l %a5,(%sp)"); asm("jsr _GC_push_one");
asm("mov.l %a6,(%sp)"); asm("jsr _GC_push_one");
/* Skip frame pointer and stack pointer */
asm("mov.l %d2,(%sp)"); asm("jsr _GC_push_one");
asm("mov.l %d3,(%sp)"); asm("jsr _GC_push_one");
asm("mov.l %d4,(%sp)"); asm("jsr _GC_push_one");
asm("mov.l %d5,(%sp)"); asm("jsr _GC_push_one");
asm("mov.l %d6,(%sp)"); asm("jsr _GC_push_one");
asm("mov.l %d7,(%sp)"); asm("jsr _GC_push_one");
asm("addq.w &0x4,%sp"); /* put stack back where it was */
# else /* !__GNUC__ */
GC_push_one(getreg(REG_A2)); GC_push_one(getreg(REG_A2));
GC_push_one(getreg(REG_A3)); GC_push_one(getreg(REG_A3));
GC_push_one(getreg(REG_A4)); GC_push_one(getreg(REG_A4));
...@@ -140,7 +170,8 @@ void GC_push_regs() ...@@ -140,7 +170,8 @@ void GC_push_regs()
GC_push_one(getreg(REG_D5)); GC_push_one(getreg(REG_D5));
GC_push_one(getreg(REG_D6)); GC_push_one(getreg(REG_D6));
GC_push_one(getreg(REG_D7)); GC_push_one(getreg(REG_D7));
# endif # endif /* !__GNUC__ */
# endif /* AMIGA */
# if defined(M68K) && defined(MACOS) # if defined(M68K) && defined(MACOS)
# if defined(THINK_C) # if defined(THINK_C)
...@@ -169,8 +200,10 @@ void GC_push_regs() ...@@ -169,8 +200,10 @@ void GC_push_regs()
# endif /* MACOS */ # endif /* MACOS */
# if defined(I386) &&!defined(OS2) &&!defined(SVR4) &&!defined(MSWIN32) \ # if defined(I386) &&!defined(OS2) &&!defined(SVR4) &&!defined(MSWIN32) \
&& !defined(SCO) && !defined(SCO_ELF) && !(defined(LINUX) \ && !defined(SCO) && !defined(SCO_ELF) \
&& defined(__ELF__)) && !defined(DOS4GW) && !defined(FREEBSD) && !(defined(LINUX) && defined(__ELF__)) \
&& !(defined(__FreeBSD__) && defined(__ELF__)) \
&& !defined(DOS4GW)
/* I386 code, generic code does not appear to work */ /* I386 code, generic code does not appear to work */
/* It does appear to work under OS2, and asms dont */ /* It does appear to work under OS2, and asms dont */
/* This is used for some 38g UNIX variants and for CYGWIN32 */ /* This is used for some 38g UNIX variants and for CYGWIN32 */
...@@ -183,8 +216,11 @@ void GC_push_regs() ...@@ -183,8 +216,11 @@ void GC_push_regs()
asm("pushl %ebx"); asm("call _GC_push_one"); asm("addl $4,%esp"); asm("pushl %ebx"); asm("call _GC_push_one"); asm("addl $4,%esp");
# endif # endif
# if defined(I386) && (defined(LINUX) || defined(FREEBSD)) && defined(__ELF__) # if ( defined(I386) && defined(LINUX) && defined(__ELF__) ) \
/* This is modified for Linux/FreeBSD with ELF (Note: _ELF_ only) */ || ( defined(I386) && defined(__FreeBSD__) && defined(__ELF__) )
/* This is modified for Linux with ELF (Note: _ELF_ only) */
/* This section handles FreeBSD with ELF. */
asm("pushl %eax"); asm("call GC_push_one"); asm("addl $4,%esp"); asm("pushl %eax"); asm("call GC_push_one"); asm("addl $4,%esp");
asm("pushl %ecx"); asm("call GC_push_one"); asm("addl $4,%esp"); asm("pushl %ecx"); asm("call GC_push_one"); asm("addl $4,%esp");
asm("pushl %edx"); asm("call GC_push_one"); asm("addl $4,%esp"); asm("pushl %edx"); asm("call GC_push_one"); asm("addl $4,%esp");
...@@ -238,12 +274,12 @@ void GC_push_regs() ...@@ -238,12 +274,12 @@ void GC_push_regs()
asm ("movd r7, tos"); asm ("bsr ?_GC_push_one"); asm ("adjspb $-4"); asm ("movd r7, tos"); asm ("bsr ?_GC_push_one"); asm ("adjspb $-4");
# endif # endif
# ifdef SPARC # if defined(SPARC) || defined(IA64)
{ {
word GC_save_regs_in_stack(); word GC_save_regs_in_stack();
/* generic code will not work */ /* generic code will not work */
(void)GC_save_regs_in_stack(); GC_save_regs_ret_val = GC_save_regs_in_stack();
} }
# endif # endif
...@@ -303,8 +339,32 @@ void GC_push_regs() ...@@ -303,8 +339,32 @@ void GC_push_regs()
# endif /* !__GNUC__ */ # endif /* !__GNUC__ */
# endif /* M68K/SYSV */ # endif /* M68K/SYSV */
# if defined(PJ)
{
register int * sp asm ("optop");
extern int *__libc_stack_end;
# if defined(HP_PA) || defined(M88K) || defined(POWERPC) || (defined(I386) && (defined(OS2) || defined(USE_GENERIC))) || defined(UTS4) GC_push_all_stack (sp, __libc_stack_end);
}
# endif
/* other machines... */
# if !(defined M68K) && !(defined VAX) && !(defined RT)
# if !(defined SPARC) && !(defined I386) && !(defined NS32K)
# if !defined(POWERPC) && !defined(UTS4) && !defined(IA64)
# if !defined(PJ)
--> bad news <--
# endif
# endif
# endif
# endif
}
#endif /* !USE_GENERIC_PUSH_REGS */
#if defined(USE_GENERIC_PUSH_REGS)
void GC_generic_push_regs(cold_gc_frame)
ptr_t cold_gc_frame;
{
/* Generic code */ /* Generic code */
/* The idea is due to Parag Patel at HP. */ /* The idea is due to Parag Patel at HP. */
/* We're not sure whether he would like */ /* We're not sure whether he would like */
...@@ -324,28 +384,10 @@ void GC_push_regs() ...@@ -324,28 +384,10 @@ void GC_push_regs()
# else # else
(void) _setjmp(regs); (void) _setjmp(regs);
# endif # endif
GC_push_all_stack((ptr_t)regs, lim); GC_push_current_stack(cold_gc_frame);
} }
# endif
# if defined(PJ)
{
register int * sp asm ("optop");
extern int *__libc_stack_end;
GC_push_all_stack (sp, __libc_stack_end);
}
# endif
/* other machines... */
# if !(defined M68K) && !(defined VAX) && !(defined RT)
# if !(defined SPARC) && !(defined I386) && !(defined NS32K)
# if !defined(HP_PA) && !defined(M88K) && !defined(POWERPC)
# if !defined(UTS4) && !defined(PJ)
--> bad news <--
# endif
# endif
# endif
# endif
} }
#endif /* USE_GENERIC_PUSH_REGS */
/* On register window machines, we need a way to force registers into */ /* On register window machines, we need a way to force registers into */
/* the stack. Return sp. */ /* the stack. Return sp. */
...@@ -372,6 +414,27 @@ void GC_push_regs() ...@@ -372,6 +414,27 @@ void GC_push_regs()
# endif # endif
# endif # endif
/* On IA64, we also need to flush register windows. But they end */
/* up on the other side of the stack segment. */
/* Returns the backing store pointer for the register stack. */
# ifdef IA64
asm(" .text");
asm(" .psr abi64");
asm(" .psr lsb");
asm(" .lsb");
asm("");
asm(" .text");
asm(" .align 16");
asm(" .global GC_save_regs_in_stack");
asm(" .proc GC_save_regs_in_stack");
asm("GC_save_regs_in_stack:");
asm(" .body");
asm(" flushrs");
asm(" ;;");
asm(" mov r8=ar.bsp");
asm(" br.ret.sptk.few rp");
asm(" .endp GC_save_regs_in_stack");
# endif
/* GC_clear_stack_inner(arg, limit) clears stack area up to limit and */ /* GC_clear_stack_inner(arg, limit) clears stack area up to limit and */
/* returns arg. Stack clearing is crucial on SPARC, so we supply */ /* returns arg. Stack clearing is crucial on SPARC, so we supply */
......
...@@ -93,8 +93,16 @@ register ptr_t *opp; ...@@ -93,8 +93,16 @@ register ptr_t *opp;
if(GC_incremental && !GC_dont_gc) if(GC_incremental && !GC_dont_gc)
GC_collect_a_little_inner((int)n_blocks); GC_collect_a_little_inner((int)n_blocks);
lw = ROUNDED_UP_WORDS(lb); lw = ROUNDED_UP_WORDS(lb);
while ((h = GC_allochblk(lw, k, 0)) == 0 h = GC_allochblk(lw, k, 0);
&& GC_collect_or_expand(n_blocks, FALSE)); # ifdef USE_MUNMAP
if (0 == h) {
GC_merge_unmapped();
h = GC_allochblk(lw, k, 0);
}
# endif
while (0 == h && GC_collect_or_expand(n_blocks, FALSE)) {
h = GC_allochblk(lw, k, 0);
}
if (h == 0) { if (h == 0) {
op = 0; op = 0;
} else { } else {
...@@ -220,6 +228,9 @@ DCL_LOCK_STATE; ...@@ -220,6 +228,9 @@ DCL_LOCK_STATE;
/* /*
* Thread initialisation can call malloc before * Thread initialisation can call malloc before
* we're ready for it. * 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); if (!GC_is_initialized) return sbrk(lb);
# endif /* I386 && SOLARIS_THREADS */ # endif /* I386 && SOLARIS_THREADS */
...@@ -375,6 +386,12 @@ int obj_kind; ...@@ -375,6 +386,12 @@ int obj_kind;
/* Required by ANSI. It's not my fault ... */ /* Required by ANSI. It's not my fault ... */
h = HBLKPTR(p); h = HBLKPTR(p);
hhdr = HDR(h); 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; knd = hhdr -> hb_obj_kind;
sz = hhdr -> hb_sz; sz = hhdr -> hb_sz;
ok = &GC_obj_kinds[knd]; ok = &GC_obj_kinds[knd];
......
...@@ -57,8 +57,16 @@ register int k; ...@@ -57,8 +57,16 @@ register int k;
if(GC_incremental && !GC_dont_gc) if(GC_incremental && !GC_dont_gc)
GC_collect_a_little_inner((int)n_blocks); GC_collect_a_little_inner((int)n_blocks);
lw = ROUNDED_UP_WORDS(lb); lw = ROUNDED_UP_WORDS(lb);
while ((h = GC_allochblk(lw, k, IGNORE_OFF_PAGE)) == 0 h = GC_allochblk(lw, k, IGNORE_OFF_PAGE);
&& GC_collect_or_expand(n_blocks, TRUE)); # ifdef USE_MUNMAP
if (0 == h) {
GC_merge_unmapped();
h = GC_allochblk(lw, k, IGNORE_OFF_PAGE);
}
# endif
while (0 == h && GC_collect_or_expand(n_blocks, TRUE)) {
h = GC_allochblk(lw, k, IGNORE_OFF_PAGE);
}
if (h == 0) { if (h == 0) {
op = 0; op = 0;
} else { } else {
...@@ -130,7 +138,7 @@ void GC_incr_mem_freed(size_t n) ...@@ -130,7 +138,7 @@ void GC_incr_mem_freed(size_t n)
ptr_t GC_generic_malloc_words_small(size_t lw, int k) ptr_t GC_generic_malloc_words_small(size_t lw, int k)
#else #else
ptr_t GC_generic_malloc_words_small(lw, k) ptr_t GC_generic_malloc_words_small(lw, k)
register size_t lw; register word lw;
register int k; register int k;
#endif #endif
{ {
...@@ -148,7 +156,7 @@ DCL_LOCK_STATE; ...@@ -148,7 +156,7 @@ DCL_LOCK_STATE;
GC_init_inner(); GC_init_inner();
} }
if (kind -> ok_reclaim_list != 0 || GC_alloc_reclaim_list(kind)) { if (kind -> ok_reclaim_list != 0 || GC_alloc_reclaim_list(kind)) {
op = GC_clear_stack(GC_allocobj(lw, k)); op = GC_clear_stack(GC_allocobj((word)lw, k));
} }
if (op == 0) { if (op == 0) {
UNLOCK(); UNLOCK();
......
...@@ -42,17 +42,19 @@ ...@@ -42,17 +42,19 @@
# ifdef WIN32_THREADS # ifdef WIN32_THREADS
GC_API CRITICAL_SECTION GC_allocate_ml; GC_API CRITICAL_SECTION GC_allocate_ml;
# else # else
# if defined(IRIX_THREADS) || defined(LINUX_THREADS) # if defined(IRIX_THREADS) || defined(LINUX_THREADS) \
# ifdef UNDEFINED || defined(IRIX_JDK_THREADS)
pthread_mutex_t GC_allocate_ml = PTHREAD_MUTEX_INITIALIZER;
# endif
pthread_t GC_lock_holder = NO_THREAD; pthread_t GC_lock_holder = NO_THREAD;
# else # else
# if defined(QUICK_THREADS) # if defined(HPUX_THREADS)
/* Nothing. */ pthread_mutex_t GC_allocate_ml = PTHREAD_MUTEX_INITIALIZER;
# else # else
--> declare allocator lock here # if defined(QUICK_THREADS)
# endif /* Nothing */
# else
--> declare allocator lock here
# endif
# endif
# endif # endif
# endif # endif
# endif # endif
...@@ -80,6 +82,12 @@ GC_bool GC_dont_gc = 0; ...@@ -80,6 +82,12 @@ GC_bool GC_dont_gc = 0;
GC_bool GC_quiet = 0; GC_bool GC_quiet = 0;
#ifdef FIND_LEAK
int GC_find_leak = 1;
#else
int GC_find_leak = 0;
#endif
/*ARGSUSED*/ /*ARGSUSED*/
GC_PTR GC_default_oom_fn GC_PROTO((size_t bytes_requested)) GC_PTR GC_default_oom_fn GC_PROTO((size_t bytes_requested))
{ {
...@@ -392,6 +400,11 @@ size_t GC_get_heap_size GC_PROTO(()) ...@@ -392,6 +400,11 @@ size_t GC_get_heap_size GC_PROTO(())
return ((size_t) GC_heapsize); return ((size_t) GC_heapsize);
} }
size_t GC_get_free_bytes GC_PROTO(())
{
return ((size_t) GC_large_free_bytes);
}
size_t GC_get_bytes_since_gc GC_PROTO(()) size_t GC_get_bytes_since_gc GC_PROTO(())
{ {
return ((size_t) WORDS_TO_BYTES(GC_words_allocd)); return ((size_t) WORDS_TO_BYTES(GC_words_allocd));
...@@ -429,27 +442,34 @@ void GC_init_inner() ...@@ -429,27 +442,34 @@ void GC_init_inner()
if (GC_is_initialized) return; if (GC_is_initialized) return;
GC_setpagesize(); 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 # ifdef MSWIN32
GC_init_win32(); GC_init_win32();
# endif # endif
# if defined(LINUX) && defined(POWERPC) # if defined(LINUX) && defined(POWERPC)
GC_init_linuxppc(); GC_init_linuxppc();
# endif # endif
# if defined(LINUX) && defined(ALPHA) # if defined(LINUX) && \
GC_init_linuxalpha(); (defined(POWERPC) || defined(ALPHA) || defined(SPARC) || defined(IA64))
GC_init_linux_data_start();
# endif # endif
# ifdef SOLARIS_THREADS # ifdef SOLARIS_THREADS
GC_thr_init(); GC_thr_init();
/* We need dirty bits in order to find live stack sections. */ /* We need dirty bits in order to find live stack sections. */
GC_dirty_init(); GC_dirty_init();
# endif # endif
# if defined(IRIX_THREADS) || defined(LINUX_THREADS) # if defined(IRIX_THREADS) || defined(LINUX_THREADS) \
GC_thr_init(); || defined(IRIX_JDK_THREADS) || defined(HPUX_THREADS)
GC_thr_init();
# endif # endif
# if !defined(THREADS) || defined(SOLARIS_THREADS) || defined(WIN32_THREADS) \ # if !defined(THREADS) || defined(SOLARIS_THREADS) || defined(WIN32_THREADS) \
|| defined(IRIX_THREADS) || defined(LINUX_THREADS) \ || defined(IRIX_THREADS) || defined(LINUX_THREADS) \
|| defined (QUICK_THREADS) || defined(HPUX_THREADS) || defined(QUICK_THREADS)
if (GC_stackbottom == 0) { if (GC_stackbottom == 0) {
GC_stackbottom = GC_get_stack_base(); GC_stackbottom = GC_get_stack_base();
} }
...@@ -564,9 +584,10 @@ void GC_init_inner() ...@@ -564,9 +584,10 @@ void GC_init_inner()
void GC_enable_incremental GC_PROTO(()) void GC_enable_incremental GC_PROTO(())
{ {
# if !defined(SMALL_CONFIG)
if (!GC_find_leak) {
DCL_LOCK_STATE; DCL_LOCK_STATE;
# ifndef FIND_LEAK
DISABLE_SIGNALS(); DISABLE_SIGNALS();
LOCK(); LOCK();
if (GC_incremental) goto out; if (GC_incremental) goto out;
...@@ -602,6 +623,7 @@ void GC_enable_incremental GC_PROTO(()) ...@@ -602,6 +623,7 @@ void GC_enable_incremental GC_PROTO(())
out: out:
UNLOCK(); UNLOCK();
ENABLE_SIGNALS(); ENABLE_SIGNALS();
}
# endif # endif
} }
...@@ -781,7 +803,7 @@ char * msg; ...@@ -781,7 +803,7 @@ char * msg;
void GC_print_callers (info) void GC_print_callers (info)
struct callinfo info[NFRAMES]; struct callinfo info[NFRAMES];
{ {
register int i,j; register int i;
# if NFRAMES == 1 # if NFRAMES == 1
GC_err_printf0("\tCaller at allocation:\n"); GC_err_printf0("\tCaller at allocation:\n");
...@@ -791,6 +813,9 @@ struct callinfo info[NFRAMES]; ...@@ -791,6 +813,9 @@ struct callinfo info[NFRAMES];
for (i = 0; i < NFRAMES; i++) { for (i = 0; i < NFRAMES; i++) {
if (info[i].ci_pc == 0) break; if (info[i].ci_pc == 0) break;
# if NARGS > 0 # if NARGS > 0
{
int j;
GC_err_printf0("\t\targs: "); GC_err_printf0("\t\targs: ");
for (j = 0; j < NARGS; j++) { for (j = 0; j < NARGS; j++) {
if (j != 0) GC_err_printf0(", "); if (j != 0) GC_err_printf0(", ");
...@@ -798,6 +823,7 @@ struct callinfo info[NFRAMES]; ...@@ -798,6 +823,7 @@ struct callinfo info[NFRAMES];
~(info[i].ci_arg[j])); ~(info[i].ci_arg[j]));
} }
GC_err_printf0("\n"); GC_err_printf0("\n");
}
# endif # endif
GC_err_printf1("\t\t##PC##= 0x%X\n", info[i].ci_pc); GC_err_printf1("\t\t##PC##= 0x%X\n", info[i].ci_pc);
} }
......
...@@ -25,7 +25,7 @@ ...@@ -25,7 +25,7 @@
#include <stdio.h> #include <stdio.h>
#include <setjmp.h> #include <setjmp.h>
#include <string.h> #include <string.h>
#include "config.h" #include "gcconfig.h"
#ifdef OS2 #ifdef OS2
/* GETPAGESIZE() is set to getpagesize() by default, but that */ /* GETPAGESIZE() is set to getpagesize() by default, but that */
......
...@@ -616,6 +616,25 @@ GC_thread GC_lookup_thread(thread_t id) ...@@ -616,6 +616,25 @@ GC_thread GC_lookup_thread(thread_t id)
return(p); return(p);
} }
# define MAX_ORIG_STACK_SIZE (8 * 1024 * 1024)
word GC_get_orig_stack_size() {
struct rlimit rl;
static int warned = 0;
int result;
if (getrlimit(RLIMIT_STACK, &rl) != 0) ABORT("getrlimit failed");
result = (word)rl.rlim_cur & ~(HBLKSIZE-1);
if (result > MAX_ORIG_STACK_SIZE) {
if (!warned) {
WARN("Large stack limit(%ld): only scanning 8 MB", result);
warned = 1;
}
result = MAX_ORIG_STACK_SIZE;
}
return result;
}
/* Notify dirty bit implementation of unused parts of my stack. */ /* Notify dirty bit implementation of unused parts of my stack. */
/* Caller holds allocation lock. */ /* Caller holds allocation lock. */
void GC_my_stack_limits() void GC_my_stack_limits()
...@@ -628,12 +647,9 @@ void GC_my_stack_limits() ...@@ -628,12 +647,9 @@ void GC_my_stack_limits()
if (stack_size == 0) { if (stack_size == 0) {
/* original thread */ /* original thread */
struct rlimit rl;
if (getrlimit(RLIMIT_STACK, &rl) != 0) ABORT("getrlimit failed");
/* Empirically, what should be the stack page with lowest */ /* Empirically, what should be the stack page with lowest */
/* address is actually inaccessible. */ /* address is actually inaccessible. */
stack_size = ((word)rl.rlim_cur & ~(HBLKSIZE-1)) - GC_page_sz; stack_size = GC_get_orig_stack_size() - GC_page_sz;
stack = GC_stackbottom - stack_size + GC_page_sz; stack = GC_stackbottom - stack_size + GC_page_sz;
} else { } else {
stack = me -> stack; stack = me -> stack;
...@@ -671,8 +687,7 @@ void GC_push_all_stacks() ...@@ -671,8 +687,7 @@ void GC_push_all_stacks()
top = p -> stack + p -> stack_size; top = p -> stack + p -> stack_size;
} else { } else {
/* The original stack. */ /* The original stack. */
if (getrlimit(RLIMIT_STACK, &rl) != 0) ABORT("getrlimit failed"); bottom = GC_stackbottom - GC_get_orig_stack_size() + GC_page_sz;
bottom = GC_stackbottom - rl.rlim_cur + GC_page_sz;
top = GC_stackbottom; top = GC_stackbottom;
} }
if ((word)sp > (word)bottom && (word)sp < (word)top) bottom = sp; if ((word)sp > (word)bottom && (word)sp < (word)top) bottom = sp;
......
! SPARCompiler 3.0 and later apparently no loner handles ! SPARCompiler 3.0 and later apparently no longer handles
! asm outside functions. So we need a separate .s file ! asm outside functions. So we need a separate .s file
! This is only set up for SunOS 5, not SunOS 4. ! This is only set up for SunOS 5, not SunOS 4.
! Assumes this is called before the stack contents are ! Assumes this is called before the stack contents are
...@@ -35,4 +35,4 @@ loop: ...@@ -35,4 +35,4 @@ loop:
\ No newline at end of file
! SPARCompiler 3.0 and later apparently no loner handles ! SPARCompiler 3.0 and later apparently no longer handles
! asm outside functions. So we need a separate .s file ! asm outside functions. So we need a separate .s file
! This is only set up for SunOS 4. ! This is only set up for SunOS 4.
! Assumes this is called before the stack contents are ! Assumes this is called before the stack contents are
......
...@@ -25,7 +25,7 @@ ...@@ -25,7 +25,7 @@
# include "gc.h" # include "gc.h"
# include "gc_typed.h" # include "gc_typed.h"
# include "gc_priv.h" /* For output, locking, and some statistics */ # include "gc_priv.h" /* For output, locking, and some statistics */
# include "config.h" # include "gcconfig.h"
# ifdef MSWIN32 # ifdef MSWIN32
# include <windows.h> # include <windows.h>
...@@ -45,7 +45,7 @@ ...@@ -45,7 +45,7 @@
# include <synch.h> # include <synch.h>
# endif # endif
# if defined(IRIX_THREADS) || defined(LINUX_THREADS) # if defined(IRIX_THREADS) || defined(LINUX_THREADS) || defined(HPUX_THREADS)
# include <pthread.h> # include <pthread.h>
# endif # endif
...@@ -53,9 +53,6 @@ ...@@ -53,9 +53,6 @@
# include <process.h> # include <process.h>
static CRITICAL_SECTION incr_cs; static CRITICAL_SECTION incr_cs;
# endif # endif
# if defined(PCR) || defined(SOLARIS_THREADS) || defined(WIN32_THREADS)
# define THREADS
# endif
# ifdef AMIGA # ifdef AMIGA
long __stack = 200000; long __stack = 200000;
...@@ -266,6 +263,72 @@ struct { ...@@ -266,6 +263,72 @@ struct {
#define a A.aa #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) || defined(HPUX_THREADS)
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. * Repeatedly reverse lists built out of very different sized cons cells.
* Check that we didn't lose anything. * Check that we didn't lose anything.
*/ */
...@@ -296,14 +359,14 @@ void reverse_test() ...@@ -296,14 +359,14 @@ void reverse_test()
d = uncollectable_ints(1, 100); d = uncollectable_ints(1, 100);
e = uncollectable_ints(1, 1); e = uncollectable_ints(1, 1);
/* Check that realloc updates object descriptors correctly */ /* Check that realloc updates object descriptors correctly */
f = (sexpr *)GC_malloc(4 * sizeof(sexpr)); f = (sexpr *)GC_MALLOC(4 * sizeof(sexpr));
f = (sexpr *)GC_realloc((GC_PTR)f, 6 * sizeof(sexpr)); f = (sexpr *)GC_REALLOC((GC_PTR)f, 6 * sizeof(sexpr));
f[5] = ints(1,17); f[5] = ints(1,17);
g = (sexpr *)GC_malloc(513 * sizeof(sexpr)); g = (sexpr *)GC_MALLOC(513 * sizeof(sexpr));
g = (sexpr *)GC_realloc((GC_PTR)g, 800 * sizeof(sexpr)); g = (sexpr *)GC_REALLOC((GC_PTR)g, 800 * sizeof(sexpr));
g[799] = ints(1,18); g[799] = ints(1,18);
h = (sexpr *)GC_malloc(1025 * sizeof(sexpr)); h = (sexpr *)GC_MALLOC(1025 * sizeof(sexpr));
h = (sexpr *)GC_realloc((GC_PTR)h, 2000 * sizeof(sexpr)); h = (sexpr *)GC_REALLOC((GC_PTR)h, 2000 * sizeof(sexpr));
h[1999] = ints(1,19); h[1999] = ints(1,19);
/* Try to force some collections and reuse of small list elements */ /* Try to force some collections and reuse of small list elements */
for (i = 0; i < 10; i++) { for (i = 0; i < 10; i++) {
...@@ -327,6 +390,7 @@ void reverse_test() ...@@ -327,6 +390,7 @@ void reverse_test()
check_ints(b,1,50); check_ints(b,1,50);
check_ints(a,1,49); check_ints(a,1,49);
for (i = 0; i < 60; i++) { 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 */ /* This maintains the invariant that a always points to a list of */
/* 49 integers. Thus this is thread safe without locks, */ /* 49 integers. Thus this is thread safe without locks, */
/* assuming atomic pointer assignments. */ /* assuming atomic pointer assignments. */
...@@ -386,7 +450,7 @@ VOLATILE int dropped_something = 0; ...@@ -386,7 +450,7 @@ VOLATILE int dropped_something = 0;
static mutex_t incr_lock; static mutex_t incr_lock;
mutex_lock(&incr_lock); mutex_lock(&incr_lock);
# endif # endif
# if defined(IRIX_THREADS) || defined(LINUX_THREADS) # if defined(IRIX_THREADS) || defined(LINUX_THREADS) || defined(HPUX_THREADS)
static pthread_mutex_t incr_lock = PTHREAD_MUTEX_INITIALIZER; static pthread_mutex_t incr_lock = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_lock(&incr_lock); pthread_mutex_lock(&incr_lock);
# endif # endif
...@@ -404,7 +468,7 @@ VOLATILE int dropped_something = 0; ...@@ -404,7 +468,7 @@ VOLATILE int dropped_something = 0;
# ifdef SOLARIS_THREADS # ifdef SOLARIS_THREADS
mutex_unlock(&incr_lock); mutex_unlock(&incr_lock);
# endif # endif
# if defined(IRIX_THREADS) || defined(LINUX_THREADS) # if defined(IRIX_THREADS) || defined(LINUX_THREADS) || defined(HPUX_THREADS)
pthread_mutex_unlock(&incr_lock); pthread_mutex_unlock(&incr_lock);
# endif # endif
# ifdef WIN32_THREADS # ifdef WIN32_THREADS
...@@ -465,7 +529,8 @@ int n; ...@@ -465,7 +529,8 @@ int n;
static mutex_t incr_lock; static mutex_t incr_lock;
mutex_lock(&incr_lock); mutex_lock(&incr_lock);
# endif # endif
# if defined(IRIX_THREADS) || defined(LINUX_THREADS) # if defined(IRIX_THREADS) || defined(LINUX_THREADS) \
|| defined(HPUX_THREADS)
static pthread_mutex_t incr_lock = PTHREAD_MUTEX_INITIALIZER; static pthread_mutex_t incr_lock = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_lock(&incr_lock); pthread_mutex_lock(&incr_lock);
# endif # endif
...@@ -481,7 +546,8 @@ int n; ...@@ -481,7 +546,8 @@ int n;
# ifdef SOLARIS_THREADS # ifdef SOLARIS_THREADS
mutex_unlock(&incr_lock); mutex_unlock(&incr_lock);
# endif # endif
# if defined(IRIX_THREADS) || defined(LINUX_THREADS) # if defined(IRIX_THREADS) || defined(LINUX_THREADS) \
|| defined(HPUX_THREADS)
pthread_mutex_unlock(&incr_lock); pthread_mutex_unlock(&incr_lock);
# endif # endif
# ifdef WIN32_THREADS # ifdef WIN32_THREADS
...@@ -538,13 +604,13 @@ int n; ...@@ -538,13 +604,13 @@ int n;
chktree(t -> rchild, n-1); chktree(t -> rchild, n-1);
} }
# ifdef SOLARIS_THREADS # if defined(SOLARIS_THREADS) && !defined(_SOLARIS_PTHREADS)
thread_key_t fl_key; thread_key_t fl_key;
void * alloc8bytes() void * alloc8bytes()
{ {
# ifdef SMALL_CONFIG # if defined(SMALL_CONFIG) || defined(GC_DEBUG)
return(GC_malloc(8)); return(GC_MALLOC(8));
# else # else
void ** my_free_list_ptr; void ** my_free_list_ptr;
void * my_free_list; void * my_free_list;
...@@ -575,7 +641,44 @@ void * alloc8bytes() ...@@ -575,7 +641,44 @@ void * alloc8bytes()
} }
#else #else
# define alloc8bytes() GC_MALLOC_ATOMIC(8)
# if defined(_SOLARIS_PTHREADS) || defined(IRIX_THREADS) \
|| defined(LINUX_THREADS) || defined(HPUX_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 #endif
void alloc_small(n) void alloc_small(n)
...@@ -753,6 +856,7 @@ void run_one_test() ...@@ -753,6 +856,7 @@ void run_one_test()
(void)GC_printf0("GC_malloc_uncollectable(0) failed\n"); (void)GC_printf0("GC_malloc_uncollectable(0) failed\n");
FAIL; FAIL;
} }
GC_FREE(0);
GC_is_valid_displacement_print_proc = fail_proc1; GC_is_valid_displacement_print_proc = fail_proc1;
GC_is_visible_print_proc = fail_proc1; GC_is_visible_print_proc = fail_proc1;
x = GC_malloc(16); x = GC_malloc(16);
...@@ -775,7 +879,7 @@ void run_one_test() ...@@ -775,7 +879,7 @@ void run_one_test()
FAIL; FAIL;
} }
if (!TEST_FAIL_COUNT(1)) { if (!TEST_FAIL_COUNT(1)) {
# if!(defined(RS6000) || defined(POWERPC)) # if!(defined(RS6000) || defined(POWERPC) || defined(IA64))
/* ON RS6000s function pointers point to a descriptor in the */ /* ON RS6000s function pointers point to a descriptor in the */
/* data segment, so there should have been no failures. */ /* data segment, so there should have been no failures. */
(void)GC_printf0("GC_is_visible produced wrong failure indication\n"); (void)GC_printf0("GC_is_visible produced wrong failure indication\n");
...@@ -826,7 +930,7 @@ void check_heap_stats() ...@@ -826,7 +930,7 @@ void check_heap_stats()
int late_finalize_count = 0; int late_finalize_count = 0;
if (sizeof(char *) > 4) { if (sizeof(char *) > 4) {
max_heap_sz = 13000000; max_heap_sz = 15000000;
} else { } else {
max_heap_sz = 11000000; max_heap_sz = 11000000;
} }
...@@ -926,7 +1030,8 @@ void SetMinimumStack(long minSize) ...@@ -926,7 +1030,8 @@ void SetMinimumStack(long minSize)
#if !defined(PCR) && !defined(SOLARIS_THREADS) && !defined(WIN32_THREADS) \ #if !defined(PCR) && !defined(SOLARIS_THREADS) && !defined(WIN32_THREADS) \
&& !defined(IRIX_THREADS) && !defined(LINUX_THREADS) || defined(LINT) && !defined(IRIX_THREADS) && !defined(LINUX_THREADS) \
&& !defined(HPUX_THREADS) || defined(LINT)
#ifdef MSWIN32 #ifdef MSWIN32
int APIENTRY WinMain(HINSTANCE instance, HINSTANCE prev, LPSTR cmd, int n) int APIENTRY WinMain(HINSTANCE instance, HINSTANCE prev, LPSTR cmd, int n)
#else #else
...@@ -980,6 +1085,9 @@ void SetMinimumStack(long minSize) ...@@ -980,6 +1085,9 @@ void SetMinimumStack(long minSize)
GC_set_max_heap_size, GC_get_bytes_since_gc, GC_set_max_heap_size, GC_get_bytes_since_gc,
GC_pre_incr, GC_post_incr); GC_pre_incr, GC_post_incr);
# endif # endif
# ifdef MSWIN32
GC_win32_free_heap();
# endif
return(0); return(0);
} }
# endif # endif
...@@ -1054,7 +1162,8 @@ test() ...@@ -1054,7 +1162,8 @@ test()
} }
#endif #endif
#if defined(SOLARIS_THREADS) || defined(IRIX_THREADS) || defined(LINUX_THREADS) #if defined(SOLARIS_THREADS) || defined(IRIX_THREADS) \
|| defined(HPUX_THREADS) || defined(LINUX_THREADS)
void * thr_run_one_test(void * arg) void * thr_run_one_test(void * arg)
{ {
run_one_test(); run_one_test();
...@@ -1115,7 +1224,7 @@ main() ...@@ -1115,7 +1224,7 @@ main()
*((volatile char *)&code - 1024*1024) = 0; /* Require 1 Mb */ *((volatile char *)&code - 1024*1024) = 0; /* Require 1 Mb */
# endif /* IRIX_THREADS */ # endif /* IRIX_THREADS */
pthread_attr_init(&attr); pthread_attr_init(&attr);
# ifdef IRIX_THREADS # if defined(IRIX_THREADS) || defined(HPUX_THREADS)
pthread_attr_setstacksize(&attr, 1000000); pthread_attr_setstacksize(&attr, 1000000);
# endif # endif
n_tests = 0; n_tests = 0;
...@@ -1125,6 +1234,10 @@ main() ...@@ -1125,6 +1234,10 @@ main()
(void) GC_printf0("Emulating dirty bits with mprotect/signals\n"); (void) GC_printf0("Emulating dirty bits with mprotect/signals\n");
# endif # endif
(void) GC_set_warn_proc(warn_proc); (void) GC_set_warn_proc(warn_proc);
if ((code = 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) { if ((code = pthread_create(&th1, &attr, thr_run_one_test, 0)) != 0) {
(void)GC_printf1("Thread 1 creation failed %lu\n", (unsigned long)code); (void)GC_printf1("Thread 1 creation failed %lu\n", (unsigned long)code);
FAIL; FAIL;
...@@ -1149,4 +1262,4 @@ main() ...@@ -1149,4 +1262,4 @@ main()
return(0); return(0);
} }
#endif /* pthreads */ #endif /* pthreads */
#endif /* SOLARIS_THREADS || IRIX_THREADS || LINUX_THREADS */ #endif /* SOLARIS_THREADS || IRIX_THREADS || LINUX_THREADS || HPUX_THREADS */
# include "config.h" # include "gcconfig.h"
# include <stdio.h> # include <stdio.h>
int main() int main()
...@@ -6,6 +6,9 @@ int main() ...@@ -6,6 +6,9 @@ int main()
# if defined(IRIX_THREADS) || defined(LINUX_THREADS) # if defined(IRIX_THREADS) || defined(LINUX_THREADS)
printf("-lpthread\n"); printf("-lpthread\n");
# endif # endif
# if defined(HPUX_THREADS)
printf("-lpthread -lrt\n");
# endif
# ifdef SOLARIS_THREADS # ifdef SOLARIS_THREADS
printf("-lthread -ldl\n"); printf("-lthread -ldl\n");
# endif # endif
......
...@@ -632,7 +632,7 @@ ptr_t GC_clear_stack(); ...@@ -632,7 +632,7 @@ ptr_t GC_clear_stack();
(GC_PTR)GC_clear_stack(GC_generic_malloc((word)lb, k)) (GC_PTR)GC_clear_stack(GC_generic_malloc((word)lb, k))
#define GENERAL_MALLOC_IOP(lb,k) \ #define GENERAL_MALLOC_IOP(lb,k) \
(GC_PTR)GC_clear_stack(GC_generic_malloc_ignore_off_page((word)lb, k)) (GC_PTR)GC_clear_stack(GC_generic_malloc_ignore_off_page(lb, k))
#if defined(__STDC__) || defined(__cplusplus) #if defined(__STDC__) || defined(__cplusplus)
void * GC_malloc_explicitly_typed(size_t lb, GC_descr d) void * GC_malloc_explicitly_typed(size_t lb, GC_descr d)
...@@ -702,7 +702,7 @@ DCL_LOCK_STATE; ...@@ -702,7 +702,7 @@ DCL_LOCK_STATE;
FASTLOCK(); FASTLOCK();
if( !FASTLOCK_SUCCEEDED() || (op = *opp) == 0 ) { if( !FASTLOCK_SUCCEEDED() || (op = *opp) == 0 ) {
FASTUNLOCK(); FASTUNLOCK();
op = (ptr_t)GENERAL_MALLOC_IOP((word)lb, GC_explicit_kind); op = (ptr_t)GENERAL_MALLOC_IOP(lb, GC_explicit_kind);
# ifdef MERGE_SIZES # ifdef MERGE_SIZES
lw = GC_size_map[lb]; /* May have been uninitialized. */ lw = GC_size_map[lb]; /* May have been uninitialized. */
# endif # endif
...@@ -712,7 +712,7 @@ DCL_LOCK_STATE; ...@@ -712,7 +712,7 @@ DCL_LOCK_STATE;
FASTUNLOCK(); FASTUNLOCK();
} }
} else { } else {
op = (ptr_t)GENERAL_MALLOC_IOP((word)lb, GC_explicit_kind); op = (ptr_t)GENERAL_MALLOC_IOP(lb, GC_explicit_kind);
if (op != NULL) if (op != NULL)
lw = BYTES_TO_WORDS(GC_size(op)); lw = BYTES_TO_WORDS(GC_size(op));
} }
......
#define GC_VERSION_MAJOR 4 #define GC_VERSION_MAJOR 5
#define GC_VERSION_MINOR 13 #define GC_VERSION_MINOR 0
#define GC_ALPHA_VERSION 2 #define GC_ALPHA_VERSION 4
# define GC_NOT_ALPHA 0xff # define GC_NOT_ALPHA 0xff
......
...@@ -8,22 +8,32 @@ ...@@ -8,22 +8,32 @@
#define MAX_THREADS 64 #define MAX_THREADS 64
struct thread_entry { struct thread_entry {
LONG in_use;
DWORD id; DWORD id;
HANDLE handle; 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; 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() void GC_stop_world()
{ {
DWORD thread_id = GetCurrentThreadId(); DWORD thread_id = GetCurrentThreadId();
int i; int i;
GC_please_stop = TRUE;
for (i = 0; i < MAX_THREADS; 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].id != thread_id) {
if (SuspendThread(thread_table[i].handle) == (DWORD)-1) if (SuspendThread(thread_table[i].handle) == (DWORD)-1)
ABORT("SuspendThread failed"); ABORT("SuspendThread failed");
thread_table[i].suspended = TRUE;
} }
} }
...@@ -32,10 +42,13 @@ void GC_start_world() ...@@ -32,10 +42,13 @@ void GC_start_world()
DWORD thread_id = GetCurrentThreadId(); DWORD thread_id = GetCurrentThreadId();
int i; int i;
for (i = 0; i < MAX_THREADS; 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) if (ResumeThread(thread_table[i].handle) == (DWORD)-1)
ABORT("ResumeThread failed"); ABORT("ResumeThread failed");
thread_table[i].suspended = FALSE;
} }
GC_please_stop = FALSE;
} }
ptr_t GC_current_stackbottom() ptr_t GC_current_stackbottom()
...@@ -78,6 +91,12 @@ void GC_push_all_stacks() ...@@ -78,6 +91,12 @@ void GC_push_all_stacks()
if (thread_table[i].context.Esp >= (DWORD)thread_table[i].stack if (thread_table[i].context.Esp >= (DWORD)thread_table[i].stack
|| thread_table[i].context.Esp < (DWORD)bottom) || thread_table[i].context.Esp < (DWORD)bottom)
ABORT("Thread stack pointer out of range"); ABORT("Thread stack pointer out of range");
GC_push_one ((word) thread_table[i].context.Edi);
GC_push_one ((word) thread_table[i].context.Esi);
GC_push_one ((word) thread_table[i].context.Ebx);
GC_push_one ((word) thread_table[i].context.Edx);
GC_push_one ((word) thread_table[i].context.Ecx);
GC_push_one ((word) thread_table[i].context.Eax);
GC_push_all_stack(thread_table[i].context.Esp, thread_table[i].stack); GC_push_all_stack(thread_table[i].context.Esp, thread_table[i].stack);
} }
} }
...@@ -117,20 +136,34 @@ BOOL WINAPI DllMain(HINSTANCE inst, ULONG reason, LPVOID reserved) ...@@ -117,20 +136,34 @@ BOOL WINAPI DllMain(HINSTANCE inst, ULONG reason, LPVOID reserved)
switch (reason) { switch (reason) {
case DLL_PROCESS_ATTACH: case DLL_PROCESS_ATTACH:
InitializeCriticalSection(&GC_allocate_ml); InitializeCriticalSection(&GC_allocate_ml);
GC_init(); /* Force initialization before thread attach. */
/* fall through */ /* fall through */
case DLL_THREAD_ATTACH: case DLL_THREAD_ATTACH:
{ {
int i; 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 */ /* The following should be a noop according to the win32 */
/* documentation. There is empirical evidence that it */ /* documentation. There is empirical evidence that it */
/* isn't. - HB */ /* isn't. - HB */
if (GC_incremental) SetUnhandledExceptionFilter(GC_write_fault_handler); # ifndef SMALL_CONFIG
for (i = 0; thread_table[i].stack != 0; i++) { 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) if (i == MAX_THREADS - 1)
ABORT("too many threads"); ABORT("too many threads");
} }
thread_table[i].stack = GC_get_stack_base();
thread_table[i].id = GetCurrentThreadId(); thread_table[i].id = GetCurrentThreadId();
if (!DuplicateHandle(GetCurrentProcess(), if (!DuplicateHandle(GetCurrentProcess(),
GetCurrentThread(), GetCurrentThread(),
...@@ -143,7 +176,11 @@ BOOL WINAPI DllMain(HINSTANCE inst, ULONG reason, LPVOID reserved) ...@@ -143,7 +176,11 @@ BOOL WINAPI DllMain(HINSTANCE inst, ULONG reason, LPVOID reserved)
GC_printf1("Last error code: %lx\n", last_error); GC_printf1("Last error code: %lx\n", last_error);
ABORT("DuplicateHandle failed"); 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; break;
case DLL_PROCESS_DETACH: case DLL_PROCESS_DETACH:
...@@ -152,10 +189,14 @@ BOOL WINAPI DllMain(HINSTANCE inst, ULONG reason, LPVOID reserved) ...@@ -152,10 +189,14 @@ BOOL WINAPI DllMain(HINSTANCE inst, ULONG reason, LPVOID reserved)
int i; int i;
DWORD thread_id = GetCurrentThreadId(); DWORD thread_id = GetCurrentThreadId();
LOCK(); 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) if (i == MAX_THREADS - 1)
ABORT("thread not found on detach"); ABORT("thread not found on detach");
}
thread_table[i].stack = 0; thread_table[i].stack = 0;
thread_table[i].in_use = FALSE;
CloseHandle(thread_table[i].handle); CloseHandle(thread_table[i].handle);
BZERO(&thread_table[i].context, sizeof(CONTEXT)); BZERO(&thread_table[i].context, sizeof(CONTEXT));
UNLOCK(); UNLOCK();
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment