[m-rev.] diff: update boehm_gc to 6.3alpha2
Peter Ross
pro at missioncriticalit.com
Tue Oct 28 19:48:15 AEDT 2003
Hi,
===================================================================
Estimated hours taken: 4
Branches: main
boehm_gc/*:
Upgrade the boehm collector to gc6.3alpha2 by following the steps in
compiler/notes/upgrade_boehm_gc.html.
Index: boehm_gc/Makefile
===================================================================
RCS file: /home/staff/zs/imp/mercury/boehm_gc/Makefile,v
retrieving revision 1.56
diff -u -r1.56 Makefile
--- boehm_gc/Makefile 15 May 2003 15:15:03 -0000 1.56
+++ boehm_gc/Makefile 27 Oct 2003 21:06:16 -0000
@@ -121,9 +121,11 @@
# -DGC_OSF1_THREADS enables support for Tru64 pthreads. Untested.
# -DGC_FREEBSD_THREADS enables support for FreeBSD pthreads. Untested.
# Appeared to run into some underlying thread problems.
-# -DGC_MACOSX_THREADS enables support for Mac OS X pthreads. Untested.
+# -DGC_DARWIN_THREADS enables support for Mac OS X pthreads. Untested.
# -DGC_DGUX386_THREADS enables support for DB/UX on I386 threads.
# See README.DGUX386.
+# -DGC_WIN32_THREADS enables support for win32 threads. That makes sense
+# for this Makefile only under Cygwin.
# -DGC_THREADS should set the appropriate one of the above macros.
# It assumes pthreads for Solaris.
# -DALL_INTERIOR_POINTERS allows all pointers to the interior
@@ -301,7 +303,7 @@
# makes incremental collection easier. Was enabled by default until 6.0.
# Rarely used, to my knowledge.
# -DHANDLE_FORK attempts to make GC_malloc() work in a child process fork()ed
-# from a multithreaded parent. Currently only supported by linux_threads.c.
+# from a multithreaded parent. Currently only supported by pthread_support.c.
# (Similar code should work on Solaris or Irix, but it hasn't been tried.)
# -DTEST_WITH_SYSTEM_MALLOC causes gctest to allocate (and leak) large chunks
# of memory with the standard system malloc. This will cause the root
@@ -325,15 +327,15 @@
RANLIB= ranlib
-OBJS= alloc.o reclaim.o allchblk.o misc.o mach_dep.o os_dep.o mark_rts.o headers.o mark.o obj_map.o blacklst.o finalize.o new_hblk.o dbg_mlc.o malloc.o stubborn.o checksums.o solaris_threads.o irix_threads.o linux_threads.o typd_mlc.o ptr_chck.o mallocx.o solaris_pthreads.o gcj_mlc.o specific.o gc_dlopen.o backgraph.o
+OBJS= alloc.o reclaim.o allchblk.o misc.o mach_dep.o os_dep.o mark_rts.o headers.o mark.o obj_map.o blacklst.o finalize.o new_hblk.o dbg_mlc.o malloc.o stubborn.o checksums.o solaris_threads.o aix_irix_threads.o pthread_support.o pthread_stop_world.o darwin_stop_world.o typd_mlc.o ptr_chck.o mallocx.o solaris_pthreads.o gcj_mlc.o specific.o gc_dlopen.o backgraph.o win32_threads.o
-CSRCS= reclaim.c allchblk.c misc.c alloc.c mach_dep.c os_dep.c mark_rts.c headers.c mark.c obj_map.c pcr_interface.c blacklst.c finalize.c new_hblk.c real_malloc.c dyn_load.c dbg_mlc.c malloc.c stubborn.c checksums.c solaris_threads.c irix_threads.c linux_threads.c typd_mlc.c ptr_chck.c mallocx.c solaris_pthreads.c gcj_mlc.c specific.c gc_dlopen.c backgraph.c
+CSRCS= reclaim.c allchblk.c misc.c alloc.c mach_dep.c os_dep.c mark_rts.c headers.c mark.c obj_map.c pcr_interface.c blacklst.c finalize.c new_hblk.c real_malloc.c dyn_load.c dbg_mlc.c malloc.c stubborn.c checksums.c solaris_threads.c aix_irix_threads.c pthread_support.c pthread_stop_world.c darwin_stop_world.c typd_mlc.c ptr_chck.c mallocx.c solaris_pthreads.c gcj_mlc.c specific.c gc_dlopen.c backgraph.c win32_threads.c
CORD_SRCS= cord/cordbscs.c cord/cordxtra.c cord/cordprnt.c cord/de.c cord/cordtest.c include/cord.h include/ec.h include/private/cord_pos.h cord/de_win.c cord/de_win.h cord/de_cmds.h cord/de_win.ICO cord/de_win.RC
CORD_OBJS= cord/cordbscs.o cord/cordxtra.o cord/cordprnt.o
-SRCS= $(CSRCS) mips_sgi_mach_dep.S rs6000_mach_dep.s alpha_mach_dep.S \
+SRCS= $(CSRCS) mips_sgi_mach_dep.s rs6000_mach_dep.s alpha_mach_dep.S \
sparc_mach_dep.S include/gc.h include/gc_typed.h \
include/private/gc_hdrs.h include/private/gc_priv.h \
include/private/gcconfig.h include/private/gc_pmark.h \
@@ -346,10 +348,12 @@
include/private/solaris_threads.h include/gc_backptr.h \
hpux_test_and_clear.s include/gc_gcj.h \
include/gc_local_alloc.h include/private/dbg_mlc.h \
- include/private/specific.h powerpc_macosx_mach_dep.s \
+ include/private/specific.h powerpc_darwin_mach_dep.s \
include/leak_detector.h include/gc_amiga_redirects.h \
include/gc_pthread_redirects.h ia64_save_regs_in_stack.s \
- include/gc_config_macros.h $(CORD_SRCS)
+ include/gc_config_macros.h include/private/pthread_support.h \
+ include/private/pthread_stop_world.h include/private/darwin_semaphore.h \
+ include/private/darwin_stop_world.h $(CORD_SRCS)
DOC_FILES= README.QUICK doc/README.Mac doc/README.MacOSX doc/README.OS2 \
doc/README.amiga doc/README.cords doc/debugging.html \
@@ -360,7 +364,7 @@
doc/README.environment doc/tree.html doc/gcdescr.html \
doc/README.autoconf doc/README.macros doc/README.ews4800 \
doc/README.DGUX386 doc/README.arm.cross doc/leak.html \
- doc/scale.html doc/gcinterface.html
+ doc/scale.html doc/gcinterface.html doc/README.darwin
TESTS= tests/test.c tests/test_cpp.cc tests/trace_test.c \
tests/leak_test.c tests/thread_leak_test.c
@@ -382,7 +386,7 @@
MacProjects.sit.hqx MacOS.c \
Mac_files/datastart.c Mac_files/dataend.c \
Mac_files/MacOS_config.h Mac_files/MacOS_Test_config.h \
- add_gc_prefix.c gc_cpp.cpp win32_threads.c \
+ add_gc_prefix.c gc_cpp.cpp \
version.h AmigaOS.c \
$(TESTS) $(GNU_BUILD_FILES) $(OTHER_MAKEFILES)
@@ -436,7 +440,7 @@
mark.o typd_mlc.o finalize.o ptr_chck.o: $(srcdir)/include/gc_mark.h $(srcdir)/include/private/gc_pmark.h
-specific.o linux_threads.o: $(srcdir)/include/private/specific.h
+specific.o pthread_support.o: $(srcdir)/include/private/specific.h
solaris_threads.o solaris_pthreads.o: $(srcdir)/include/private/solaris_threads.h
@@ -551,18 +555,17 @@
# gcc -shared -Wl,-soname=libgc.so.0 -o libgc.so.0 $(LIBOBJS) dyn_load.lo
# touch liblinuxgc.so
-mach_dep.o: $(srcdir)/mach_dep.c $(srcdir)/mips_sgi_mach_dep.S \
+mach_dep.o: $(srcdir)/mach_dep.c $(srcdir)/mips_sgi_mach_dep.s \
$(srcdir)/mips_ultrix_mach_dep.s \
- $(srcdir)/rs6000_mach_dep.s $(srcdir)/powerpc_macosx_mach_dep.s \
+ $(srcdir)/rs6000_mach_dep.s $(srcdir)/powerpc_darwin_mach_dep.s \
$(srcdir)/sparc_mach_dep.S $(srcdir)/sparc_sunos4_mach_dep.s \
$(srcdir)/ia64_save_regs_in_stack.s \
$(srcdir)/sparc_netbsd_mach_dep.s $(UTILS)
rm -f mach_dep.o
- ./if_mach MIPS IRIX5 $(CC) -E $(srcdir)/mips_sgi_mach_dep.S \
- | ./if_mach MIPS IRIX5 grep -v "^\#" > $(srcdir)/mips_sgi_mach_dep.s
+ ./if_mach MIPS IRIX5 $(CC) -c -o mach_dep.o $(srcdir)/mips_sgi_mach_dep.s
./if_mach MIPS RISCOS $(AS) -o mach_dep.o $(srcdir)/mips_ultrix_mach_dep.s
./if_mach MIPS ULTRIX $(AS) -o mach_dep.o $(srcdir)/mips_ultrix_mach_dep.s
- ./if_mach POWERPC MACOSX $(AS) -o mach_dep.o $(srcdir)/powerpc_macosx_mach_dep.s
+ ./if_mach POWERPC DARWIN $(AS) -o mach_dep.o $(srcdir)/powerpc_darwin_mach_dep.s
./if_mach ALPHA LINUX $(CC) -c -o mach_dep.o $(srcdir)/alpha_mach_dep.S
./if_mach SPARC SUNOS5 $(CC) -c -o mach_dep.o $(srcdir)/sparc_mach_dep.S
./if_mach SPARC SUNOS4 $(AS) -o mach_dep.o $(srcdir)/sparc_sunos4_mach_dep.s
@@ -612,7 +615,7 @@
./if_mach SPARC DRSNX $(CC) $(CFLAGS) -o cord/de $(srcdir)/cord/de.c cord/cordbscs.o cord/cordxtra.o gc.a $(CURSES) -lucb `./threadlibs`
./if_mach HP_PA HPUX $(CC) $(CFLAGS) -o cord/de $(srcdir)/cord/de.c cord/cordbscs.o cord/cordxtra.o gc.a $(CURSES) -ldld `./threadlibs`
./if_mach RS6000 "" $(CC) $(CFLAGS) -o cord/de $(srcdir)/cord/de.c cord/cordbscs.o cord/cordxtra.o gc.a -lcurses
- ./if_mach POWERPC MACOSX $(CC) $(CFLAGS) -o cord/de $(srcdir)/cord/de.c cord/cordbscs.o cord/cordxtra.o gc.a
+ ./if_mach POWERPC DARWIN $(CC) $(CFLAGS) -o cord/de $(srcdir)/cord/de.c cord/cordbscs.o cord/cordxtra.o gc.a
./if_mach I386 LINUX $(CC) $(CFLAGS) -o cord/de $(srcdir)/cord/de.c cord/cordbscs.o cord/cordxtra.o gc.a -lcurses `./threadlibs`
./if_mach ALPHA LINUX $(CC) $(CFLAGS) -o cord/de $(srcdir)/cord/de.c cord/cordbscs.o cord/cordxtra.o gc.a -lcurses `./threadlibs`
./if_mach IA64 LINUX $(CC) $(CFLAGS) -o cord/de $(srcdir)/cord/de.c cord/cordbscs.o cord/cordxtra.o gc.a -lcurses `./threadlibs`
@@ -631,7 +634,7 @@
clean:
rm -f gc.a *.o *.exe tests/*.o gctest gctest_dyn_link test_cpp \
setjmp_test mon.out gmon.out a.out core if_not_there if_mach \
- threadlibs $(CORD_OBJS) cord/cordtest cord/de
+ threadlibs $(CORD_OBJS) cord/cordtest cord/de
-rm -f *~
gctest: tests/test.o gc.a $(UTILS)
Index: boehm_gc/Makefile.am
===================================================================
RCS file: /home/staff/zs/imp/mercury/boehm_gc/Makefile.am,v
retrieving revision 1.3
diff -u -r1.3 Makefile.am
--- boehm_gc/Makefile.am 6 May 2003 11:36:49 -0000 1.3
+++ boehm_gc/Makefile.am 27 Oct 2003 21:02:31 -0000
@@ -25,7 +25,12 @@
EXTRA_DIST =
## more items will be succesively added below
-lib_LTLIBRARIES = libgc.la
+if CPLUSPLUS
+extra = libgccpp.la
+else
+extra =
+endif
+lib_LTLIBRARIES = libgc.la $(extra)
include_HEADERS = include/gc.h include/gc_local_alloc.h \
include/gc_pthread_redirects.h include/gc_config_macros.h \
@@ -33,12 +38,20 @@
EXTRA_HEADERS = include/gc_cpp.h include/gc_allocator.h
+if POWERPC_DARWIN
+asm_libgc_sources = powerpc_darwin_mach_dep.s
+else
+asm_libgc_sources =
+endif
+
libgc_la_SOURCES = allchblk.c alloc.c blacklst.c checksums.c dbg_mlc.c \
-dyn_load.c finalize.c gc_dlopen.c gcj_mlc.c headers.c irix_threads.c \
-linux_threads.c malloc.c mallocx.c mark.c mark_rts.c misc.c new_hblk.c \
+dyn_load.c finalize.c gc_dlopen.c gcj_mlc.c headers.c aix_irix_threads.c \
+malloc.c mallocx.c mark.c mark_rts.c misc.c new_hblk.c \
obj_map.c os_dep.c pcr_interface.c ptr_chck.c real_malloc.c reclaim.c \
solaris_pthreads.c solaris_threads.c specific.c stubborn.c typd_mlc.c \
-backgraph.c win32_threads.c
+backgraph.c win32_threads.c \
+pthread_support.c pthread_stop_world.c darwin_stop_world.c \
+$(asm_libgc_sources)
# Include THREADLIBS here to ensure that the correct versions of
# linuxthread semaphore functions get linked:
@@ -47,17 +60,26 @@
libgc_la_LDFLAGS = -version-info 1:2:0
EXTRA_libgc_la_SOURCES = alpha_mach_dep.S \
- mips_sgi_mach_dep.S mips_ultrix_mach_dep.s powerpc_macosx_mach_dep.s \
+ mips_sgi_mach_dep.s mips_ultrix_mach_dep.s powerpc_darwin_mach_dep.s \
rs6000_mach_dep.s sparc_mach_dep.S sparc_netbsd_mach_dep.s \
- sparc_sunos4_mach_dep.s ia64_save_regs_in_stack.s gc_cpp.cc
+ sparc_sunos4_mach_dep.s ia64_save_regs_in_stack.s
+
+libgccpp_la_SOURCES = gc_cpp.cc
+libgccpp_la_LIBADD = $(THREADLIBS)
+libgccpp_la_LDFLAGS = -version-info 1:2:0
-EXTRA_DIST += alpha_mach_dep.S mips_sgi_mach_dep.S sparc_mach_dep.S
+EXTRA_DIST += alpha_mach_dep.S mips_sgi_mach_dep.s sparc_mach_dep.S
AM_CXXFLAGS = @GC_CFLAGS@
AM_CFLAGS = @GC_CFLAGS@
-check_PROGRAMS = gctest @addtests@
-EXTRA_PROGRAMS = test_cpp
+if CPLUSPLUS
+extra_checks = test_cpp
+else
+extra_checks =
+endif
+
+check_PROGRAMS = gctest $(extra_checks)
test.o: $(srcdir)/tests/test.c
$(COMPILE) -c $(srcdir)/tests/test.c
@@ -71,9 +93,9 @@
gctest_SOURCES = tests/test.c
gctest_LDADD = ./libgc.la $(THREADLIBS) $(EXTRA_TEST_LIBS)
test_cpp_SOURCES = tests/test_cpp.cc
-test_cpp_LDADD = ./libgc.la $(THREADLIBS) $(EXTRA_TEST_LIBS)
-TESTS_ENVIRONMENT = LD_LIBRARY_PATH=../../gcc
-TESTS = gctest @addtests@
+test_cpp_LDADD = ./libgc.la ./libgccpp.la $(THREADLIBS) $(EXTRA_TEST_LIBS)
+
+TESTS = gctest $(extra_checks)
## FIXME: relies on internal code generated by automake.
all_objs = @addobjs@ $(libgc_la_OBJECTS)
Index: boehm_gc/Makefile.direct
===================================================================
RCS file: /home/staff/zs/imp/mercury/boehm_gc/Makefile.direct,v
retrieving revision 1.5
diff -u -r1.5 Makefile.direct
--- boehm_gc/Makefile.direct 6 May 2003 11:36:49 -0000 1.5
+++ boehm_gc/Makefile.direct 27 Oct 2003 21:02:31 -0000
@@ -121,9 +121,11 @@
# -DGC_OSF1_THREADS enables support for Tru64 pthreads. Untested.
# -DGC_FREEBSD_THREADS enables support for FreeBSD pthreads. Untested.
# Appeared to run into some underlying thread problems.
-# -DGC_MACOSX_THREADS enables support for Mac OS X pthreads. Untested.
+# -DGC_DARWIN_THREADS enables support for Mac OS X pthreads. Untested.
# -DGC_DGUX386_THREADS enables support for DB/UX on I386 threads.
# See README.DGUX386.
+# -DGC_WIN32_THREADS enables support for win32 threads. That makes sense
+# for this Makefile only under Cygwin.
# -DGC_THREADS should set the appropriate one of the above macros.
# It assumes pthreads for Solaris.
# -DALL_INTERIOR_POINTERS allows all pointers to the interior
@@ -301,7 +303,7 @@
# makes incremental collection easier. Was enabled by default until 6.0.
# Rarely used, to my knowledge.
# -DHANDLE_FORK attempts to make GC_malloc() work in a child process fork()ed
-# from a multithreaded parent. Currently only supported by linux_threads.c.
+# from a multithreaded parent. Currently only supported by pthread_support.c.
# (Similar code should work on Solaris or Irix, but it hasn't been tried.)
# -DTEST_WITH_SYSTEM_MALLOC causes gctest to allocate (and leak) large chunks
# of memory with the standard system malloc. This will cause the root
@@ -325,15 +327,15 @@
RANLIB= ranlib
-OBJS= alloc.o reclaim.o allchblk.o misc.o mach_dep.o os_dep.o mark_rts.o headers.o mark.o obj_map.o blacklst.o finalize.o new_hblk.o dbg_mlc.o malloc.o stubborn.o checksums.o solaris_threads.o irix_threads.o linux_threads.o typd_mlc.o ptr_chck.o mallocx.o solaris_pthreads.o gcj_mlc.o specific.o gc_dlopen.o backgraph.o
+OBJS= alloc.o reclaim.o allchblk.o misc.o mach_dep.o os_dep.o mark_rts.o headers.o mark.o obj_map.o blacklst.o finalize.o new_hblk.o dbg_mlc.o malloc.o stubborn.o checksums.o solaris_threads.o aix_irix_threads.o pthread_support.o pthread_stop_world.o darwin_stop_world.o typd_mlc.o ptr_chck.o mallocx.o solaris_pthreads.o gcj_mlc.o specific.o gc_dlopen.o backgraph.o win32_threads.o
-CSRCS= reclaim.c allchblk.c misc.c alloc.c mach_dep.c os_dep.c mark_rts.c headers.c mark.c obj_map.c pcr_interface.c blacklst.c finalize.c new_hblk.c real_malloc.c dyn_load.c dbg_mlc.c malloc.c stubborn.c checksums.c solaris_threads.c irix_threads.c linux_threads.c typd_mlc.c ptr_chck.c mallocx.c solaris_pthreads.c gcj_mlc.c specific.c gc_dlopen.c backgraph.c
+CSRCS= reclaim.c allchblk.c misc.c alloc.c mach_dep.c os_dep.c mark_rts.c headers.c mark.c obj_map.c pcr_interface.c blacklst.c finalize.c new_hblk.c real_malloc.c dyn_load.c dbg_mlc.c malloc.c stubborn.c checksums.c solaris_threads.c aix_irix_threads.c pthread_support.c pthread_stop_world.c darwin_stop_world.c typd_mlc.c ptr_chck.c mallocx.c solaris_pthreads.c gcj_mlc.c specific.c gc_dlopen.c backgraph.c win32_threads.c
CORD_SRCS= cord/cordbscs.c cord/cordxtra.c cord/cordprnt.c cord/de.c cord/cordtest.c include/cord.h include/ec.h include/private/cord_pos.h cord/de_win.c cord/de_win.h cord/de_cmds.h cord/de_win.ICO cord/de_win.RC
CORD_OBJS= cord/cordbscs.o cord/cordxtra.o cord/cordprnt.o
-SRCS= $(CSRCS) mips_sgi_mach_dep.S rs6000_mach_dep.s alpha_mach_dep.S \
+SRCS= $(CSRCS) mips_sgi_mach_dep.s rs6000_mach_dep.s alpha_mach_dep.S \
sparc_mach_dep.S include/gc.h include/gc_typed.h \
include/private/gc_hdrs.h include/private/gc_priv.h \
include/private/gcconfig.h include/private/gc_pmark.h \
@@ -346,10 +348,12 @@
include/private/solaris_threads.h include/gc_backptr.h \
hpux_test_and_clear.s include/gc_gcj.h \
include/gc_local_alloc.h include/private/dbg_mlc.h \
- include/private/specific.h powerpc_macosx_mach_dep.s \
+ include/private/specific.h powerpc_darwin_mach_dep.s \
include/leak_detector.h include/gc_amiga_redirects.h \
include/gc_pthread_redirects.h ia64_save_regs_in_stack.s \
- include/gc_config_macros.h $(CORD_SRCS)
+ include/gc_config_macros.h include/private/pthread_support.h \
+ include/private/pthread_stop_world.h include/private/darwin_semaphore.h \
+ include/private/darwin_stop_world.h $(CORD_SRCS)
DOC_FILES= README.QUICK doc/README.Mac doc/README.MacOSX doc/README.OS2 \
doc/README.amiga doc/README.cords doc/debugging.html \
@@ -360,7 +364,7 @@
doc/README.environment doc/tree.html doc/gcdescr.html \
doc/README.autoconf doc/README.macros doc/README.ews4800 \
doc/README.DGUX386 doc/README.arm.cross doc/leak.html \
- doc/scale.html doc/gcinterface.html
+ doc/scale.html doc/gcinterface.html doc/README.darwin
TESTS= tests/test.c tests/test_cpp.cc tests/trace_test.c \
tests/leak_test.c tests/thread_leak_test.c
@@ -382,7 +386,7 @@
MacProjects.sit.hqx MacOS.c \
Mac_files/datastart.c Mac_files/dataend.c \
Mac_files/MacOS_config.h Mac_files/MacOS_Test_config.h \
- add_gc_prefix.c gc_cpp.cpp win32_threads.c \
+ add_gc_prefix.c gc_cpp.cpp \
version.h AmigaOS.c \
$(TESTS) $(GNU_BUILD_FILES) $(OTHER_MAKEFILES)
@@ -436,7 +440,7 @@
mark.o typd_mlc.o finalize.o ptr_chck.o: $(srcdir)/include/gc_mark.h $(srcdir)/include/private/gc_pmark.h
-specific.o linux_threads.o: $(srcdir)/include/private/specific.h
+specific.o pthread_support.o: $(srcdir)/include/private/specific.h
solaris_threads.o solaris_pthreads.o: $(srcdir)/include/private/solaris_threads.h
@@ -551,18 +555,17 @@
# gcc -shared -Wl,-soname=libgc.so.0 -o libgc.so.0 $(LIBOBJS) dyn_load.lo
# touch liblinuxgc.so
-mach_dep.o: $(srcdir)/mach_dep.c $(srcdir)/mips_sgi_mach_dep.S \
+mach_dep.o: $(srcdir)/mach_dep.c $(srcdir)/mips_sgi_mach_dep.s \
$(srcdir)/mips_ultrix_mach_dep.s \
- $(srcdir)/rs6000_mach_dep.s $(srcdir)/powerpc_macosx_mach_dep.s \
+ $(srcdir)/rs6000_mach_dep.s $(srcdir)/powerpc_darwin_mach_dep.s \
$(srcdir)/sparc_mach_dep.S $(srcdir)/sparc_sunos4_mach_dep.s \
$(srcdir)/ia64_save_regs_in_stack.s \
$(srcdir)/sparc_netbsd_mach_dep.s $(UTILS)
rm -f mach_dep.o
- ./if_mach MIPS IRIX5 $(CC) -E $(srcdir)/mips_sgi_mach_dep.S \
- | ./if_mach MIPS IRIX5 grep -v "^\#" > $(srcdir)/mips_sgi_mach_dep.s
+ ./if_mach MIPS IRIX5 $(CC) -c -o mach_dep.o $(srcdir)/mips_sgi_mach_dep.s
./if_mach MIPS RISCOS $(AS) -o mach_dep.o $(srcdir)/mips_ultrix_mach_dep.s
./if_mach MIPS ULTRIX $(AS) -o mach_dep.o $(srcdir)/mips_ultrix_mach_dep.s
- ./if_mach POWERPC MACOSX $(AS) -o mach_dep.o $(srcdir)/powerpc_macosx_mach_dep.s
+ ./if_mach POWERPC DARWIN $(AS) -o mach_dep.o $(srcdir)/powerpc_darwin_mach_dep.s
./if_mach ALPHA LINUX $(CC) -c -o mach_dep.o $(srcdir)/alpha_mach_dep.S
./if_mach SPARC SUNOS5 $(CC) -c -o mach_dep.o $(srcdir)/sparc_mach_dep.S
./if_mach SPARC SUNOS4 $(AS) -o mach_dep.o $(srcdir)/sparc_sunos4_mach_dep.s
@@ -612,7 +615,7 @@
./if_mach SPARC DRSNX $(CC) $(CFLAGS) -o cord/de $(srcdir)/cord/de.c cord/cordbscs.o cord/cordxtra.o gc.a $(CURSES) -lucb `./threadlibs`
./if_mach HP_PA HPUX $(CC) $(CFLAGS) -o cord/de $(srcdir)/cord/de.c cord/cordbscs.o cord/cordxtra.o gc.a $(CURSES) -ldld `./threadlibs`
./if_mach RS6000 "" $(CC) $(CFLAGS) -o cord/de $(srcdir)/cord/de.c cord/cordbscs.o cord/cordxtra.o gc.a -lcurses
- ./if_mach POWERPC MACOSX $(CC) $(CFLAGS) -o cord/de $(srcdir)/cord/de.c cord/cordbscs.o cord/cordxtra.o gc.a
+ ./if_mach POWERPC DARWIN $(CC) $(CFLAGS) -o cord/de $(srcdir)/cord/de.c cord/cordbscs.o cord/cordxtra.o gc.a
./if_mach I386 LINUX $(CC) $(CFLAGS) -o cord/de $(srcdir)/cord/de.c cord/cordbscs.o cord/cordxtra.o gc.a -lcurses `./threadlibs`
./if_mach ALPHA LINUX $(CC) $(CFLAGS) -o cord/de $(srcdir)/cord/de.c cord/cordbscs.o cord/cordxtra.o gc.a -lcurses `./threadlibs`
./if_mach IA64 LINUX $(CC) $(CFLAGS) -o cord/de $(srcdir)/cord/de.c cord/cordbscs.o cord/cordxtra.o gc.a -lcurses `./threadlibs`
@@ -631,7 +634,7 @@
clean:
rm -f gc.a *.o *.exe tests/*.o gctest gctest_dyn_link test_cpp \
setjmp_test mon.out gmon.out a.out core if_not_there if_mach \
- threadlibs $(CORD_OBJS) cord/cordtest cord/de mips_sgi_mach_dep.s
+ threadlibs $(CORD_OBJS) cord/cordtest cord/de
-rm -f *~
gctest: tests/test.o gc.a $(UTILS)
Index: boehm_gc/Makefile.dj
===================================================================
RCS file: /home/staff/zs/imp/mercury/boehm_gc/Makefile.dj,v
retrieving revision 1.2
diff -u -r1.2 Makefile.dj
--- boehm_gc/Makefile.dj 27 Oct 2003 20:50:14 -0000 1.2
+++ boehm_gc/Makefile.dj 27 Oct 2003 21:02:31 -0000
@@ -177,7 +177,7 @@
include/private/solaris_threads.h include/gc_backptr.h \
hpux_test_and_clear.s include/gc_gcj.h \
include/gc_local_alloc.h include/private/dbg_mlc.h \
- include/private/specific.h powerpc_macosx_mach_dep.s \
+ include/private/specific.h powerpc_darwin_mach_dep.s \
include/leak_detector.h $(CORD_SRCS)
OTHER_FILES= Makefile PCR-Makefile OS2_MAKEFILE NT_MAKEFILE BCC_MAKEFILE \
@@ -285,13 +285,13 @@
ln liblinuxgc.so libgc.so
mach_dep.o: $(srcdir)/mach_dep.c $(srcdir)/mips_sgi_mach_dep.S $(srcdir)/mips_ultrix_mach_dep.s \
- $(srcdir)/rs6000_mach_dep.s $(srcdir)/powerpc_macosx_mach_dep.s $(UTILS)
+ $(srcdir)/rs6000_mach_dep.s $(srcdir)/powerpc_darwin_mach_dep.s $(UTILS)
rm -f mach_dep.o
./if_mach MIPS IRIX5 $(AS) -o mach_dep.o $(srcdir)/mips_sgi_mach_dep.S
./if_mach MIPS RISCOS $(AS) -o mach_dep.o $(srcdir)/mips_ultrix_mach_dep.s
./if_mach MIPS ULTRIX $(AS) -o mach_dep.o $(srcdir)/mips_ultrix_mach_dep.s
./if_mach RS6000 "" $(AS) -o mach_dep.o $(srcdir)/rs6000_mach_dep.s
- ./if_mach POWERPC MACOSX $(AS) -o mach_dep.o $(srcdir)/powerpc_macosx_mach_dep.s
+ ./if_mach POWERPC MACOSX $(AS) -o mach_dep.o $(srcdir)/powerpc_darwin_mach_dep.s
./if_mach ALPHA "" $(AS) -o mach_dep.o $(srcdir)/alpha_mach_dep.S
./if_mach SPARC SUNOS5 $(AS) -o mach_dep.o $(srcdir)/sparc_mach_dep.S
./if_mach SPARC SUNOS4 $(AS) -o mach_dep.o $(srcdir)/sparc_sunos4_mach_dep.s
Index: boehm_gc/Makefile.in
===================================================================
RCS file: /home/staff/zs/imp/mercury/boehm_gc/Makefile.in,v
retrieving revision 1.2
diff -u -r1.2 Makefile.in
--- boehm_gc/Makefile.in 6 May 2003 11:36:49 -0000 1.2
+++ boehm_gc/Makefile.in 27 Oct 2003 21:02:31 -0000
@@ -111,6 +111,7 @@
THREADLIBS = @THREADLIBS@
VERSION = @VERSION@
addincludes = @addincludes@
+addlibs = @addlibs@
addobjs = @addobjs@
addtests = @addtests@
am__include = @am__include@
@@ -144,7 +145,7 @@
# :FIXME: why do we distribute this one???
#
-EXTRA_DIST = alpha_mach_dep.S mips_sgi_mach_dep.S sparc_mach_dep.S README.QUICK BCC_MAKEFILE NT_MAKEFILE NT_THREADS_MAKEFILE \
+EXTRA_DIST = alpha_mach_dep.S mips_sgi_mach_dep.s sparc_mach_dep.S README.QUICK BCC_MAKEFILE NT_MAKEFILE NT_THREADS_MAKEFILE \
OS2_MAKEFILE PCR-Makefile digimars.mak EMX_MAKEFILE \
Makefile.direct Makefile.dj Makefile.DLLs SMakefile.amiga \
WCC_MAKEFILE\
@@ -161,7 +162,9 @@
cord/de_win.h cord/de_win.RC\
libtool.m4
-lib_LTLIBRARIES = libgc.la
+ at CPLUSPLUS_TRUE@extra = libgccpp.la
+ at CPLUSPLUS_FALSE@extra =
+lib_LTLIBRARIES = libgc.la $(extra)
include_HEADERS = include/gc.h include/gc_local_alloc.h \
include/gc_pthread_redirects.h include/gc_config_macros.h \
@@ -170,12 +173,17 @@
EXTRA_HEADERS = include/gc_cpp.h include/gc_allocator.h
+ at POWERPC_DARWIN_TRUE@asm_libgc_sources = powerpc_darwin_mach_dep.s
+ at POWERPC_DARWIN_FALSE@asm_libgc_sources =
+
libgc_la_SOURCES = allchblk.c alloc.c blacklst.c checksums.c dbg_mlc.c \
-dyn_load.c finalize.c gc_dlopen.c gcj_mlc.c headers.c irix_threads.c \
-linux_threads.c malloc.c mallocx.c mark.c mark_rts.c misc.c new_hblk.c \
+dyn_load.c finalize.c gc_dlopen.c gcj_mlc.c headers.c aix_irix_threads.c \
+malloc.c mallocx.c mark.c mark_rts.c misc.c new_hblk.c \
obj_map.c os_dep.c pcr_interface.c ptr_chck.c real_malloc.c reclaim.c \
solaris_pthreads.c solaris_threads.c specific.c stubborn.c typd_mlc.c \
-backgraph.c win32_threads.c
+backgraph.c win32_threads.c \
+pthread_support.c pthread_stop_world.c darwin_stop_world.c \
+$(asm_libgc_sources)
# Include THREADLIBS here to ensure that the correct versions of
@@ -185,24 +193,30 @@
libgc_la_LDFLAGS = -version-info 1:2:0
EXTRA_libgc_la_SOURCES = alpha_mach_dep.S \
- mips_sgi_mach_dep.S mips_ultrix_mach_dep.s powerpc_macosx_mach_dep.s \
+ mips_sgi_mach_dep.s mips_ultrix_mach_dep.s powerpc_darwin_mach_dep.s \
rs6000_mach_dep.s sparc_mach_dep.S sparc_netbsd_mach_dep.s \
- sparc_sunos4_mach_dep.s ia64_save_regs_in_stack.s gc_cpp.cc
+ sparc_sunos4_mach_dep.s ia64_save_regs_in_stack.s
+
+libgccpp_la_SOURCES = gc_cpp.cc
+libgccpp_la_LIBADD = $(THREADLIBS)
+libgccpp_la_LDFLAGS = -version-info 1:2:0
AM_CXXFLAGS = @GC_CFLAGS@
AM_CFLAGS = @GC_CFLAGS@
-check_PROGRAMS = gctest @addtests@
-EXTRA_PROGRAMS = test_cpp
+ at CPLUSPLUS_TRUE@extra_checks = test_cpp
+ at CPLUSPLUS_FALSE@extra_checks =
+
+check_PROGRAMS = gctest $(extra_checks)
# gctest_OBJECTS = test.o
gctest_SOURCES = tests/test.c
gctest_LDADD = ./libgc.la $(THREADLIBS) $(EXTRA_TEST_LIBS)
test_cpp_SOURCES = tests/test_cpp.cc
-test_cpp_LDADD = ./libgc.la $(THREADLIBS) $(EXTRA_TEST_LIBS)
-TESTS_ENVIRONMENT = LD_LIBRARY_PATH=../../gcc
-TESTS = gctest @addtests@
+test_cpp_LDADD = ./libgc.la ./libgccpp.la $(THREADLIBS) $(EXTRA_TEST_LIBS)
+
+TESTS = gctest $(extra_checks)
all_objs = @addobjs@ $(libgc_la_OBJECTS)
@@ -230,23 +244,29 @@
CONFIG_CLEAN_FILES =
LTLIBRARIES = $(lib_LTLIBRARIES)
+ at POWERPC_DARWIN_TRUE@am__objects_1 = powerpc_darwin_mach_dep.lo
+ at POWERPC_DARWIN_FALSE@am__objects_1 =
am_libgc_la_OBJECTS = allchblk.lo alloc.lo blacklst.lo checksums.lo \
dbg_mlc.lo dyn_load.lo finalize.lo gc_dlopen.lo gcj_mlc.lo \
- headers.lo irix_threads.lo linux_threads.lo malloc.lo \
- mallocx.lo mark.lo mark_rts.lo misc.lo new_hblk.lo obj_map.lo \
- os_dep.lo pcr_interface.lo ptr_chck.lo real_malloc.lo \
- reclaim.lo solaris_pthreads.lo solaris_threads.lo specific.lo \
- stubborn.lo typd_mlc.lo backgraph.lo win32_threads.lo
+ headers.lo aix_irix_threads.lo malloc.lo mallocx.lo mark.lo \
+ mark_rts.lo misc.lo new_hblk.lo obj_map.lo os_dep.lo \
+ pcr_interface.lo ptr_chck.lo real_malloc.lo reclaim.lo \
+ solaris_pthreads.lo solaris_threads.lo specific.lo stubborn.lo \
+ typd_mlc.lo backgraph.lo win32_threads.lo pthread_support.lo \
+ pthread_stop_world.lo darwin_stop_world.lo $(am__objects_1)
libgc_la_OBJECTS = $(am_libgc_la_OBJECTS)
-EXTRA_PROGRAMS = test_cpp$(EXEEXT)
-check_PROGRAMS = gctest$(EXEEXT) @addtests@
+libgccpp_la_DEPENDENCIES =
+am_libgccpp_la_OBJECTS = gc_cpp.lo
+libgccpp_la_OBJECTS = $(am_libgccpp_la_OBJECTS)
+ at CPLUSPLUS_TRUE@check_PROGRAMS = gctest$(EXEEXT) test_cpp$(EXEEXT)
+ at CPLUSPLUS_FALSE@check_PROGRAMS = gctest$(EXEEXT)
am_gctest_OBJECTS = test.$(OBJEXT)
gctest_OBJECTS = $(am_gctest_OBJECTS)
gctest_DEPENDENCIES = ./libgc.la
gctest_LDFLAGS =
am_test_cpp_OBJECTS = test_cpp.$(OBJEXT)
test_cpp_OBJECTS = $(am_test_cpp_OBJECTS)
-test_cpp_DEPENDENCIES = ./libgc.la
+test_cpp_DEPENDENCIES = ./libgc.la ./libgccpp.la
test_cpp_LDFLAGS =
SCRIPTS = $(dist_noinst_SCRIPTS)
@@ -258,19 +278,22 @@
LIBS = @LIBS@
depcomp = $(SHELL) $(top_srcdir)/depcomp
am__depfiles_maybe = depfiles
- at AMDEP_TRUE@DEP_FILES = ./$(DEPDIR)/allchblk.Plo ./$(DEPDIR)/alloc.Plo \
+ at AMDEP_TRUE@DEP_FILES = ./$(DEPDIR)/aix_irix_threads.Plo \
+ at AMDEP_TRUE@ ./$(DEPDIR)/allchblk.Plo ./$(DEPDIR)/alloc.Plo \
@AMDEP_TRUE@ ./$(DEPDIR)/backgraph.Plo ./$(DEPDIR)/blacklst.Plo \
- at AMDEP_TRUE@ ./$(DEPDIR)/checksums.Plo ./$(DEPDIR)/dbg_mlc.Plo \
- at AMDEP_TRUE@ ./$(DEPDIR)/dyn_load.Plo ./$(DEPDIR)/finalize.Plo \
- at AMDEP_TRUE@ ./$(DEPDIR)/gc_cpp.Plo ./$(DEPDIR)/gc_dlopen.Plo \
- at AMDEP_TRUE@ ./$(DEPDIR)/gcj_mlc.Plo ./$(DEPDIR)/headers.Plo \
- at AMDEP_TRUE@ ./$(DEPDIR)/irix_threads.Plo \
- at AMDEP_TRUE@ ./$(DEPDIR)/linux_threads.Plo \
- at AMDEP_TRUE@ ./$(DEPDIR)/malloc.Plo ./$(DEPDIR)/mallocx.Plo \
- at AMDEP_TRUE@ ./$(DEPDIR)/mark.Plo ./$(DEPDIR)/mark_rts.Plo \
- at AMDEP_TRUE@ ./$(DEPDIR)/misc.Plo ./$(DEPDIR)/new_hblk.Plo \
- at AMDEP_TRUE@ ./$(DEPDIR)/obj_map.Plo ./$(DEPDIR)/os_dep.Plo \
+ at AMDEP_TRUE@ ./$(DEPDIR)/checksums.Plo \
+ at AMDEP_TRUE@ ./$(DEPDIR)/darwin_stop_world.Plo \
+ at AMDEP_TRUE@ ./$(DEPDIR)/dbg_mlc.Plo ./$(DEPDIR)/dyn_load.Plo \
+ at AMDEP_TRUE@ ./$(DEPDIR)/finalize.Plo ./$(DEPDIR)/gc_cpp.Plo \
+ at AMDEP_TRUE@ ./$(DEPDIR)/gc_dlopen.Plo ./$(DEPDIR)/gcj_mlc.Plo \
+ at AMDEP_TRUE@ ./$(DEPDIR)/headers.Plo ./$(DEPDIR)/malloc.Plo \
+ at AMDEP_TRUE@ ./$(DEPDIR)/mallocx.Plo ./$(DEPDIR)/mark.Plo \
+ at AMDEP_TRUE@ ./$(DEPDIR)/mark_rts.Plo ./$(DEPDIR)/misc.Plo \
+ at AMDEP_TRUE@ ./$(DEPDIR)/new_hblk.Plo ./$(DEPDIR)/obj_map.Plo \
+ at AMDEP_TRUE@ ./$(DEPDIR)/os_dep.Plo \
@AMDEP_TRUE@ ./$(DEPDIR)/pcr_interface.Plo \
+ at AMDEP_TRUE@ ./$(DEPDIR)/pthread_stop_world.Plo \
+ at AMDEP_TRUE@ ./$(DEPDIR)/pthread_support.Plo \
@AMDEP_TRUE@ ./$(DEPDIR)/ptr_chck.Plo \
@AMDEP_TRUE@ ./$(DEPDIR)/real_malloc.Plo ./$(DEPDIR)/reclaim.Plo \
@AMDEP_TRUE@ ./$(DEPDIR)/solaris_pthreads.Plo \
@@ -294,7 +317,7 @@
CXXLINK = $(LIBTOOL) --mode=link $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) \
$(AM_LDFLAGS) $(LDFLAGS) -o $@
DIST_SOURCES = $(libgc_la_SOURCES) $(EXTRA_libgc_la_SOURCES) \
- $(gctest_SOURCES) $(test_cpp_SOURCES)
+ $(libgccpp_la_SOURCES) $(gctest_SOURCES) $(test_cpp_SOURCES)
HEADERS = $(dist_noinst_HEADERS) $(include_HEADERS)
@@ -307,7 +330,7 @@
aclocal.m4 config.guess config.sub configure configure.in \
depcomp install-sh ltconfig ltmain.sh missing mkinstalldirs
DIST_SUBDIRS = $(SUBDIRS)
-SOURCES = $(libgc_la_SOURCES) $(EXTRA_libgc_la_SOURCES) $(gctest_SOURCES) $(test_cpp_SOURCES)
+SOURCES = $(libgc_la_SOURCES) $(EXTRA_libgc_la_SOURCES) $(libgccpp_la_SOURCES) $(gctest_SOURCES) $(test_cpp_SOURCES)
all: all-recursive
@@ -358,7 +381,9 @@
rm -f "$${dir}/so_locations"; \
done
libgc.la: $(libgc_la_OBJECTS) $(libgc_la_DEPENDENCIES)
- $(CXXLINK) -rpath $(libdir) $(libgc_la_LDFLAGS) $(libgc_la_OBJECTS) $(libgc_la_LIBADD) $(LIBS)
+ $(LINK) -rpath $(libdir) $(libgc_la_LDFLAGS) $(libgc_la_OBJECTS) $(libgc_la_LIBADD) $(LIBS)
+libgccpp.la: $(libgccpp_la_OBJECTS) $(libgccpp_la_DEPENDENCIES)
+ $(CXXLINK) -rpath $(libdir) $(libgccpp_la_LDFLAGS) $(libgccpp_la_OBJECTS) $(libgccpp_la_LIBADD) $(LIBS)
clean-checkPROGRAMS:
@list='$(check_PROGRAMS)'; for p in $$list; do \
@@ -381,11 +406,13 @@
distclean-compile:
-rm -f *.tab.c
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/aix_irix_threads.Plo at am__quote@
@AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/allchblk.Plo at am__quote@
@AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/alloc.Plo at am__quote@
@AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/backgraph.Plo at am__quote@
@AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/blacklst.Plo at am__quote@
@AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/checksums.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/darwin_stop_world.Plo at am__quote@
@AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/dbg_mlc.Plo at am__quote@
@AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/dyn_load.Plo at am__quote@
@AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/finalize.Plo at am__quote@
@@ -393,8 +420,6 @@
@AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/gc_dlopen.Plo at am__quote@
@AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/gcj_mlc.Plo at am__quote@
@AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/headers.Plo at am__quote@
- at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/irix_threads.Plo at am__quote@
- at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/linux_threads.Plo at am__quote@
@AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/malloc.Plo at am__quote@
@AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/mallocx.Plo at am__quote@
@AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/mark.Plo at am__quote@
@@ -404,6 +429,8 @@
@AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/obj_map.Plo at am__quote@
@AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/os_dep.Plo at am__quote@
@AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/pcr_interface.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/pthread_stop_world.Plo at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/pthread_support.Plo at am__quote@
@AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/ptr_chck.Plo at am__quote@
@AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/real_malloc.Plo at am__quote@
@AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/reclaim.Plo at am__quote@
Index: boehm_gc/NT_MAKEFILE
===================================================================
RCS file: /home/staff/zs/imp/mercury/boehm_gc/NT_MAKEFILE,v
retrieving revision 1.12
diff -u -r1.12 NT_MAKEFILE
--- boehm_gc/NT_MAKEFILE 25 Jul 2002 09:02:45 -0000 1.12
+++ boehm_gc/NT_MAKEFILE 27 Oct 2003 21:02:31 -0000
@@ -10,10 +10,10 @@
all: gctest.exe cord\de.exe test_cpp.exe
.c.obj:
- $(cc) $(cdebug) $(cflags) $(cvars) -Iinclude -DSILENT -DALL_INTERIOR_POINTERS -D__STDC__ -DGC_NOT_DLL $*.c /Fo$*.obj
+ $(cc) $(cdebug) $(cflags) $(cvars) -Iinclude -DSILENT -DALL_INTERIOR_POINTERS -D__STDC__ -DGC_NOT_DLL -DGC_BUILD $*.c /Fo$*.obj
.cpp.obj:
- $(cc) $(cdebug) $(cflags) $(cvars) -Iinclude -DSILENT -DALL_INTERIOR_POINTERS -DGC_NOT_DLL $*.CPP /Fo$*.obj
+ $(cc) $(cdebug) $(cflags) $(cvars) -Iinclude -DSILENT -DALL_INTERIOR_POINTERS -DGC_NOT_DLL -DGC_BUILD $*.CPP /Fo$*.obj
$(OBJS) tests\test.obj: include\private\gc_priv.h include\private\gc_hdrs.h include\gc.h include\private\gcconfig.h include\private\gc_locks.h include\private\gc_pmark.h include\gc_mark.h
Index: boehm_gc/acinclude.m4
===================================================================
RCS file: /home/staff/zs/imp/mercury/boehm_gc/acinclude.m4,v
retrieving revision 1.2
diff -u -r1.2 acinclude.m4
--- boehm_gc/acinclude.m4 6 May 2003 11:36:49 -0000 1.2
+++ boehm_gc/acinclude.m4 27 Oct 2003 21:02:31 -0000
@@ -27,7 +27,7 @@
alpha*)
GC_ALPHA_VERSION=`echo $GC_ALPHA_VERSION \
| sed 's/alpha\([[0-9]][[0-9]]*\)/\1/'` ;;
- *) GC_VERSION_MAJOR='' ;;
+ *) GC_ALPHA_MAJOR='' ;;
esac
if test :$GC_VERSION_MAJOR: = :: \
Index: boehm_gc/aclocal.m4
===================================================================
RCS file: /home/staff/zs/imp/mercury/boehm_gc/aclocal.m4,v
retrieving revision 1.2
diff -u -r1.2 aclocal.m4
--- boehm_gc/aclocal.m4 6 May 2003 11:36:49 -0000 1.2
+++ boehm_gc/aclocal.m4 27 Oct 2003 21:02:32 -0000
@@ -40,7 +40,7 @@
alpha*)
GC_ALPHA_VERSION=`echo $GC_ALPHA_VERSION \
| sed 's/alpha\([[0-9]][[0-9]]*\)/\1/'` ;;
- *) GC_VERSION_MAJOR='' ;;
+ *) GC_ALPHA_MAJOR='' ;;
esac
if test :$GC_VERSION_MAJOR: = :: \
Index: boehm_gc/alloc.c
===================================================================
RCS file: /home/staff/zs/imp/mercury/boehm_gc/alloc.c,v
retrieving revision 1.13
diff -u -r1.13 alloc.c
--- boehm_gc/alloc.c 6 May 2003 11:36:49 -0000 1.13
+++ boehm_gc/alloc.c 27 Oct 2003 21:02:32 -0000
@@ -72,6 +72,13 @@
GC_bool GC_need_full_gc = FALSE;
/* Need full GC do to heap growth. */
+#ifdef THREADS
+ GC_bool GC_world_stopped = FALSE;
+# define IF_THREADS(x) x
+#else
+# define IF_THREADS(x)
+#endif
+
word GC_used_heap_size_after_full = 0;
char * GC_copyright[] =
@@ -470,6 +477,7 @@
GC_cond_register_dynamic_libraries();
# endif
STOP_WORLD();
+ IF_THREADS(GC_world_stopped = TRUE);
# ifdef CONDPRINT
if (GC_print_stats) {
GC_printf1("--> Marking for collection %lu ",
@@ -500,6 +508,7 @@
}
# endif
GC_deficit = i; /* Give the mutator a chance. */
+ IF_THREADS(GC_world_stopped = FALSE);
START_WORLD();
return(FALSE);
}
@@ -533,6 +542,7 @@
(*GC_check_heap)();
}
+ IF_THREADS(GC_world_stopped = FALSE);
START_WORLD();
# ifdef PRINTTIMES
GET_TIME(current_time);
Index: boehm_gc/configure
===================================================================
RCS file: /home/staff/zs/imp/mercury/boehm_gc/configure,v
retrieving revision 1.2
diff -u -r1.2 configure
--- boehm_gc/configure 6 May 2003 11:36:49 -0000 1.2
+++ boehm_gc/configure 27 Oct 2003 21:02:32 -0000
@@ -1,7 +1,7 @@
#! /bin/sh
# From configure.in Revision: 1.2 .
# Guess values for system-dependent variables and create Makefiles.
-# Generated by GNU Autoconf 2.53 for gc 6.2alpha4.
+# Generated by GNU Autoconf 2.53 for gc 6.3alpha2.
#
# Report bugs to <Hans.Boehm at hp.com>.
#
@@ -416,8 +416,8 @@
# Identity of this package.
PACKAGE_NAME='gc'
PACKAGE_TARNAME='gc'
-PACKAGE_VERSION='6.2alpha4'
-PACKAGE_STRING='gc 6.2alpha4'
+PACKAGE_VERSION='6.3alpha2'
+PACKAGE_STRING='gc 6.3alpha2'
PACKAGE_BUGREPORT='Hans.Boehm at hp.com'
ac_unique_file="gcj_mlc.c"
@@ -930,7 +930,7 @@
# Omit some internal or obsolete options to make the list less imposing.
# This message is too long to be a string in the A/UX 3.1 sh.
cat <<_ACEOF
-\`configure' configures gc 6.2alpha4 to adapt to many kinds of systems.
+\`configure' configures gc 6.3alpha2 to adapt to many kinds of systems.
Usage: $0 [OPTION]... [VAR=VALUE]...
@@ -997,7 +997,7 @@
if test -n "$ac_init_help"; then
case $ac_init_help in
- short | recursive ) echo "Configuration of gc 6.2alpha4:";;
+ short | recursive ) echo "Configuration of gc 6.3alpha2:";;
esac
cat <<\_ACEOF
@@ -1010,7 +1010,7 @@
(and sometimes confusing) to the casual installer
--enable-threads=TYPE choose threading package
--enable-parallel-mark parallelize marking and free list construction
- --enable-cplusplus include C++ support in GC library and include directory
+ --enable-cplusplus install C++ support
--enable-shared=PKGS build shared libraries default=yes
--enable-static=PKGS build static libraries default=yes
--enable-fast-install=PKGS optimize for fast installation default=yes
@@ -1106,7 +1106,7 @@
test -n "$ac_init_help" && exit 0
if $ac_init_version; then
cat <<\_ACEOF
-gc configure 6.2alpha4
+gc configure 6.3alpha2
generated by GNU Autoconf 2.53
Copyright 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001, 2002
@@ -1121,7 +1121,7 @@
This file contains any messages produced by compilers while
running configure, to aid debugging if configure makes a mistake.
-It was created by gc $as_me 6.2alpha4, which was
+It was created by gc $as_me 6.3alpha2, which was
generated by GNU Autoconf 2.53. Invocation command line was
$ $0 $@
@@ -1521,7 +1521,7 @@
alpha*)
GC_ALPHA_VERSION=`echo $GC_ALPHA_VERSION \
| sed 's/alpha\([0-9][0-9]*\)/\1/'` ;;
- *) GC_VERSION_MAJOR='' ;;
+ *) GC_ALPHA_MAJOR='' ;;
esac
if test :$GC_VERSION_MAJOR: = :: \
@@ -1782,7 +1782,7 @@
# Define the identity of the package.
PACKAGE=gc
- VERSION=6.2alpha4
+ VERSION=6.3alpha2
cat >>confdefs.h <<_ACEOF
@@ -3555,6 +3555,16 @@
_ACEOF
;;
+ *-*-aix*)
+ cat >>confdefs.h <<\_ACEOF
+#define GC_AIX_THREADS 1
+_ACEOF
+
+ cat >>confdefs.h <<\_ACEOF
+#define _REENTRANT 1
+_ACEOF
+
+ ;;
*-*-hpux*)
{ echo "$as_me:$LINENO: WARNING: \"Only HP/UX 11 threads are supported.\"" >&5
echo "$as_me: WARNING: \"Only HP/UX 11 threads are supported.\"" >&2;}
@@ -3612,9 +3622,19 @@
;;
*-*-darwin*)
cat >>confdefs.h <<\_ACEOF
-#define GC_MACOSX_THREADS 1
+#define GC_DARWIN_THREADS 1
_ACEOF
+ cat >>confdefs.h <<\_ACEOF
+#define THREAD_LOCAL_ALLOC 1
+_ACEOF
+
+ if test "${enable_parallel_mark}" = yes; then
+ cat >>confdefs.h <<\_ACEOF
+#define PARALLEL_MARK 1
+_ACEOF
+
+ fi
;;
*-*-osf*)
cat >>confdefs.h <<\_ACEOF
@@ -3675,6 +3695,18 @@
# Enable _POSIX4A_DRAFT10_SOURCE with flag -pthread
INCLUDES="-pthread $INCLUDES"
;;
+ aix)
+ THREADS=posix
+ THREADLIBS=-lpthread
+ cat >>confdefs.h <<\_ACEOF
+#define GC_AIX_THREADS 1
+_ACEOF
+
+ cat >>confdefs.h <<\_ACEOF
+#define _REENTRANT 1
+_ACEOF
+
+ ;;
decosf1 | irix | mach | os2 | solaris | dce | vxworks)
{ { echo "$as_me:$LINENO: error: thread package $THREADS not yet supported" >&5
echo "$as_me: error: thread package $THREADS not yet supported" >&2;}
@@ -3688,6 +3720,27 @@
esac
+case "$host" in
+ powerpc-*-darwin*)
+ powerpc_darwin=true
+ ;;
+esac
+
+
+if test x$powerpc_darwin = xtrue; then
+ POWERPC_DARWIN_TRUE=
+ POWERPC_DARWIN_FALSE='#'
+else
+ POWERPC_DARWIN_TRUE='#'
+ POWERPC_DARWIN_FALSE=
+fi
+
+
+# We never want libdl on darwin. It is a fake libdl that just ends up making
+# dyld calls anyway
+case "$host" in
+ *-*-darwin*) ;;
+ *)
echo "$as_me:$LINENO: checking for dlopen in -ldl" >&5
echo $ECHO_N "checking for dlopen in -ldl... $ECHO_C" >&6
@@ -3748,6 +3801,9 @@
EXTRA_TEST_LIBS="$EXTRA_TEST_LIBS -ldl"
fi
+ ;;
+esac
+
target_all=libgc.la
@@ -3763,6 +3819,7 @@
fi;
addobjs=
+addlibs=
addincludes=
addtests=
CXXINCLUDES=
@@ -3780,13 +3837,23 @@
esac
if test "${enable_cplusplus}" = yes; then
- addobjs="$addobjs gc_cpp.lo"
addincludes="$addincludes include/gc_cpp.h include/gc_allocator.h"
addtests="$addtests test_cpp"
fi
+if test "${enable_cplusplus}" = yes; then
+ CPLUSPLUS_TRUE=
+ CPLUSPLUS_FALSE='#'
+else
+ CPLUSPLUS_TRUE='#'
+ CPLUSPLUS_FALSE=
+fi
+
+
+
+
@@ -3845,7 +3912,7 @@
alpha*-*-linux*)
machdep="alpha_mach_dep.lo"
;;
- i?86-*-solaris2.[89]*)
+ i?86-*-solaris2.[89] | i?86-*-solaris2.1?)
cat >>confdefs.h <<\_ACEOF
#define SOLARIS25_PROC_VDB_BUG_FIXED 1
_ACEOF
@@ -3879,7 +3946,7 @@
sparc-*-netbsd*)
machdep="sparc_netbsd_mach_dep.lo"
;;
- sparc-sun-solaris2.3*)
+ sparc-sun-solaris2.3)
machdep="sparc_mach_dep.lo"
cat >>confdefs.h <<\_ACEOF
#define SUNOS53_SHARED_LIB 1
@@ -3903,6 +3970,7 @@
+
# Check whether --enable-static or --disable-static was given.
if test "${enable_static+set}" = set; then
enableval="$enable_static"
@@ -5335,7 +5403,7 @@
case $host in
*-*-irix6*)
# Find out which ABI we are using.
- echo '#line 5338 "configure"' > conftest.$ac_ext
+ echo '#line 5406 "configure"' > conftest.$ac_ext
if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
(eval $ac_compile) 2>&5
ac_status=$?
@@ -5871,7 +5939,7 @@
save_CFLAGS="$CFLAGS"
CFLAGS="$CFLAGS -o out/conftest2.$ac_objext"
compiler_c_o=no
-if { (eval echo configure:5874: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>out/conftest.err; } && test -s out/conftest2.$ac_objext; then
+if { (eval echo configure:5942: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>out/conftest.err; } && test -s out/conftest2.$ac_objext; then
# The compiler can only warn and ignore the option if not recognized
# So say no if there are warnings
if test -s out/conftest.err; then
@@ -7664,7 +7732,7 @@
lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
lt_status=$lt_dlunknown
cat > conftest.$ac_ext <<EOF
-#line 7667 "configure"
+#line 7735 "configure"
#include "confdefs.h"
#if HAVE_DLFCN_H
@@ -7762,7 +7830,7 @@
lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
lt_status=$lt_dlunknown
cat > conftest.$ac_ext <<EOF
-#line 7765 "configure"
+#line 7833 "configure"
#include "confdefs.h"
#if HAVE_DLFCN_H
@@ -8642,7 +8710,7 @@
echo "$as_me:$LINENO: checking whether Solaris gcc optimization fix is necessary" >&5
echo $ECHO_N "checking whether Solaris gcc optimization fix is necessary... $ECHO_C" >&6
case "$host" in
- sparc-sun-solaris2*)
+ sparc-sun-solaris2*|*aix*)
if test "$GCC" = yes; then
echo "$as_me:$LINENO: result: yes" >&5
echo "${ECHO_T}yes" >&6
@@ -8935,6 +9003,20 @@
Usually this means the macro was only invoked conditionally." >&2;}
{ (exit 1); exit 1; }; }
fi
+if test -z "${POWERPC_DARWIN_TRUE}" && test -z "${POWERPC_DARWIN_FALSE}"; then
+ { { echo "$as_me:$LINENO: error: conditional \"POWERPC_DARWIN\" was never defined.
+Usually this means the macro was only invoked conditionally." >&5
+echo "$as_me: error: conditional \"POWERPC_DARWIN\" was never defined.
+Usually this means the macro was only invoked conditionally." >&2;}
+ { (exit 1); exit 1; }; }
+fi
+if test -z "${CPLUSPLUS_TRUE}" && test -z "${CPLUSPLUS_FALSE}"; then
+ { { echo "$as_me:$LINENO: error: conditional \"CPLUSPLUS\" was never defined.
+Usually this means the macro was only invoked conditionally." >&5
+echo "$as_me: error: conditional \"CPLUSPLUS\" was never defined.
+Usually this means the macro was only invoked conditionally." >&2;}
+ { (exit 1); exit 1; }; }
+fi
if test -z "${USE_LIBDIR_TRUE}" && test -z "${USE_LIBDIR_FALSE}"; then
{ { echo "$as_me:$LINENO: error: conditional \"USE_LIBDIR\" was never defined.
Usually this means the macro was only invoked conditionally." >&5
@@ -9191,7 +9273,7 @@
} >&5
cat >&5 <<_CSEOF
-This file was extended by gc $as_me 6.2alpha4, which was
+This file was extended by gc $as_me 6.3alpha2, which was
generated by GNU Autoconf 2.53. Invocation command line was
CONFIG_FILES = $CONFIG_FILES
@@ -9248,7 +9330,7 @@
cat >>$CONFIG_STATUS <<_ACEOF
ac_cs_version="\\
-gc config.status 6.2alpha4
+gc config.status 6.3alpha2
configured by $0, generated by GNU Autoconf 2.53,
with options \\"`echo "$ac_configure_args" | sed 's/[\\""\`\$]/\\\\&/g'`\\"
@@ -9493,12 +9575,17 @@
s, at MAINT@,$MAINT,;t t
s, at GC_CFLAGS@,$GC_CFLAGS,;t t
s, at THREADLIBS@,$THREADLIBS,;t t
+s, at POWERPC_DARWIN_TRUE@,$POWERPC_DARWIN_TRUE,;t t
+s, at POWERPC_DARWIN_FALSE@,$POWERPC_DARWIN_FALSE,;t t
s, at EXTRA_TEST_LIBS@,$EXTRA_TEST_LIBS,;t t
s, at target_all@,$target_all,;t t
+s, at CPLUSPLUS_TRUE@,$CPLUSPLUS_TRUE,;t t
+s, at CPLUSPLUS_FALSE@,$CPLUSPLUS_FALSE,;t t
s, at INCLUDES@,$INCLUDES,;t t
s, at CXXINCLUDES@,$CXXINCLUDES,;t t
s, at addobjs@,$addobjs,;t t
s, at addincludes@,$addincludes,;t t
+s, at addlibs@,$addlibs,;t t
s, at addtests@,$addtests,;t t
s, at LN_S@,$LN_S,;t t
s, at ECHO@,$ECHO,;t t
Index: boehm_gc/configure.host
===================================================================
RCS file: /home/staff/zs/imp/mercury/boehm_gc/configure.host,v
retrieving revision 1.2
diff -u -r1.2 configure.host
--- boehm_gc/configure.host 6 May 2003 11:36:49 -0000 1.2
+++ boehm_gc/configure.host 27 Oct 2003 21:02:32 -0000
@@ -27,8 +27,10 @@
gc_cflags="${gc_cflags} -fexceptions"
else
case "$host" in
- *-*-hpux* )
- gc_cflags="${gc_flags} +ESdbgasm"
+ hppa*-*-hpux* )
+ if test :$GCC: != :"yes": ; then
+ gc_cflags="${gc_flags} +ESdbgasm"
+ fi
# :TODO: actaully we should check using Autoconf if
# the compiler supports this option.
;;
@@ -52,7 +54,7 @@
case "${host}" in
mips-tx39-*|mipstx39-unknown-*)
- boehm_gc_cflags="${boehm_gc_cflags} -G 0"
+ gc_cflags="${gc_cflags} -G 0"
;;
*)
;;
Index: boehm_gc/configure.in
===================================================================
RCS file: /home/staff/zs/imp/mercury/boehm_gc/configure.in,v
retrieving revision 1.2
diff -u -r1.2 configure.in
--- boehm_gc/configure.in 6 May 2003 11:36:49 -0000 1.2
+++ boehm_gc/configure.in 27 Oct 2003 21:05:11 -0000
@@ -17,7 +17,7 @@
# Initialization
# ==============
-AC_INIT(gc,6.2alpha4,Hans.Boehm at hp.com)
+AC_INIT(gc,6.3alpha2,Hans.Boehm at hp.com)
## version must conform to [0-9]+[.][0-9]+(alpha[0-9]+)?
AC_CONFIG_SRCDIR(gcj_mlc.c)
AC_CANONICAL_TARGET
@@ -64,7 +64,7 @@
)
AC_ARG_ENABLE(cplusplus,
-[ --enable-cplusplus include C++ support in GC library and include directory],
+[ --enable-cplusplus install C++ support],
)
INCLUDES=-I${srcdir}/include
@@ -89,6 +89,10 @@
AC_DEFINE(GC_LINUX_THREADS)
AC_DEFINE(_REENTRANT)
;;
+ *-*-aix*)
+ AC_DEFINE(GC_AIX_THREADS)
+ AC_DEFINE(_REENTRANT)
+ ;;
*-*-hpux*)
AC_MSG_WARN("Only HP/UX 11 threads are supported.")
AC_DEFINE(GC_HPUX_THREADS)
@@ -116,7 +120,11 @@
AC_DEFINE(GC_WIN32_THREADS)
;;
*-*-darwin*)
- AC_DEFINE(GC_MACOSX_THREADS)
+ AC_DEFINE(GC_DARWIN_THREADS)
+ AC_DEFINE(THREAD_LOCAL_ALLOC)
+ if test "${enable_parallel_mark}" = yes; then
+ AC_DEFINE(PARALLEL_MARK)
+ fi
;;
*-*-osf*)
AC_DEFINE(GC_OSF1_THREADS)
@@ -150,6 +158,12 @@
# Enable _POSIX4A_DRAFT10_SOURCE with flag -pthread
INCLUDES="-pthread $INCLUDES"
;;
+ aix)
+ THREADS=posix
+ THREADLIBS=-lpthread
+ AC_DEFINE(GC_AIX_THREADS)
+ AC_DEFINE(_REENTRANT)
+ ;;
decosf1 | irix | mach | os2 | solaris | dce | vxworks)
AC_MSG_ERROR(thread package $THREADS not yet supported)
;;
@@ -159,7 +173,15 @@
esac
AC_SUBST(THREADLIBS)
+case "$host" in
+ powerpc-*-darwin*)
+ powerpc_darwin=true
+ ;;
+esac
+AM_CONDITIONAL(POWERPC_DARWIN,test x$powerpc_darwin = xtrue)
+
+# We never want libdl on darwin. It is a fake libdl that just ends up making
+# dyld calls anyway
case "$host" in
*-*-darwin*) ;;
*)
@@ -183,6 +205,7 @@
)
addobjs=
+addlibs=
addincludes=
addtests=
CXXINCLUDES=
@@ -197,11 +220,12 @@
esac
if test "${enable_cplusplus}" = yes; then
- addobjs="$addobjs gc_cpp.lo"
addincludes="$addincludes include/gc_cpp.h include/gc_allocator.h"
addtests="$addtests test_cpp"
fi
+AM_CONDITIONAL(CPLUSPLUS, test "${enable_cplusplus}" = yes)
+
AC_SUBST(CXX)
AC_SUBST(INCLUDES)
@@ -236,7 +260,7 @@
alpha*-*-linux*)
machdep="alpha_mach_dep.lo"
;;
- i?86-*-solaris2.[[89]]*)
+ i?86-*-solaris2.[[89]] | i?86-*-solaris2.1?)
AC_DEFINE(SOLARIS25_PROC_VDB_BUG_FIXED)
;;
mipstx39-*-elf*)
@@ -258,7 +282,7 @@
sparc-*-netbsd*)
machdep="sparc_netbsd_mach_dep.lo"
;;
- sparc-sun-solaris2.3*)
+ sparc-sun-solaris2.3)
machdep="sparc_mach_dep.lo"
AC_DEFINE(SUNOS53_SHARED_LIB)
;;
@@ -276,6 +300,7 @@
addobjs="$addobjs $machdep"
AC_SUBST(addobjs)
AC_SUBST(addincludes)
+AC_SUBST(addlibs)
AC_SUBST(addtests)
AC_PROG_LIBTOOL
@@ -325,7 +350,7 @@
dnl
AC_MSG_CHECKING(whether Solaris gcc optimization fix is necessary)
case "$host" in
- sparc-sun-solaris2*)
+ sparc-sun-solaris2*|*aix*)
if test "$GCC" = yes; then
AC_MSG_RESULT(yes)
new_CFLAGS=
Index: boehm_gc/dbg_mlc.c
===================================================================
RCS file: /home/staff/zs/imp/mercury/boehm_gc/dbg_mlc.c,v
retrieving revision 1.16
diff -u -r1.16 dbg_mlc.c
--- boehm_gc/dbg_mlc.c 6 May 2003 11:36:49 -0000 1.16
+++ boehm_gc/dbg_mlc.c 27 Oct 2003 21:02:33 -0000
@@ -924,9 +924,11 @@
void GC_check_heap_proc()
{
# ifndef SMALL_CONFIG
- if (sizeof(oh) & (2 * sizeof(word) - 1) != 0) {
- ABORT("Alignment problem: object header has inappropriate size\n");
- }
+# ifdef ALIGN_DOUBLE
+ GC_STATIC_ASSERT((sizeof(oh) & (2 * sizeof(word) - 1)) == 0);
+# else
+ GC_STATIC_ASSERT((sizeof(oh) & (sizeof(word) - 1)) == 0);
+# endif
# endif
GC_apply_to_all_blocks(GC_check_heap_block, (word)0);
}
Index: boehm_gc/dyn_load.c
===================================================================
RCS file: /home/staff/zs/imp/mercury/boehm_gc/dyn_load.c,v
retrieving revision 1.15
diff -u -r1.15 dyn_load.c
--- boehm_gc/dyn_load.c 6 May 2003 11:36:49 -0000 1.15
+++ boehm_gc/dyn_load.c 27 Oct 2003 21:02:33 -0000
@@ -58,7 +58,7 @@
!defined(RS6000) && !defined(SCO_ELF) && !defined(DGUX) && \
!(defined(FREEBSD) && defined(__ELF__)) && \
!(defined(NETBSD) && defined(__ELF__)) && !defined(HURD) && \
- !defined(MACOSX)
+ !defined(DARWIN)
--> We only know how to find data segments of dynamic libraries for the
--> above. Additional SVR4 variants might not be too
--> hard to add.
@@ -283,56 +283,23 @@
/* Repeatedly read until buffer is filled, or EOF is encountered */
/* Defined in os_dep.c. */
-static char *parse_map_entry(char *buf_ptr, word *start, word *end,
- char *prot_buf, unsigned int *maj_dev);
+char *GC_parse_map_entry(char *buf_ptr, word *start, word *end,
+ char *prot_buf, unsigned int *maj_dev);
+word GC_apply_to_maps(word (*fn)(char *));
+ /* From os_dep.c */
-void GC_register_dynamic_libraries()
+word GC_register_map_entries(char *maps)
{
- int f;
- int result;
char prot_buf[5];
- int maps_size;
- char maps_temp[32768];
- char *maps_buf;
- char *buf_ptr;
+ char *buf_ptr = maps;
int count;
word start, end;
- unsigned int maj_dev, min_dev;
+ unsigned int maj_dev;
word least_ha, greatest_ha;
unsigned i;
word datastart = (word)(DATASTART);
- /* Read /proc/self/maps */
- /* Note that we may not allocate, and thus can't use stdio. */
- f = open("/proc/self/maps", O_RDONLY);
- if (-1 == f) ABORT("Couldn't open /proc/self/maps");
- /* stat() doesn't work for /proc/self/maps, so we have to
- read it to find out how large it is... */
- maps_size = 0;
- do {
- result = GC_repeat_read(f, maps_temp, sizeof(maps_temp));
- if (result <= 0) ABORT("Couldn't read /proc/self/maps");
- maps_size += result;
- } while (result == sizeof(maps_temp));
-
- if (maps_size > sizeof(maps_temp)) {
- /* If larger than our buffer, close and re-read it. */
- close(f);
- f = open("/proc/self/maps", O_RDONLY);
- if (-1 == f) ABORT("Couldn't open /proc/self/maps");
- maps_buf = alloca(maps_size);
- if (NULL == maps_buf) ABORT("/proc/self/maps alloca failed");
- result = GC_repeat_read(f, maps_buf, maps_size);
- if (result <= 0) ABORT("Couldn't read /proc/self/maps");
- } else {
- /* Otherwise use the fixed size buffer */
- maps_buf = maps_temp;
- }
-
- close(f);
- maps_buf[result] = '\0';
- buf_ptr = maps_buf;
- /* Compute heap bounds. Should be done by add_to_heap? */
+ /* Compute heap bounds. FIXME: Should be done by add_to_heap? */
least_ha = (word)(-1);
greatest_ha = 0;
for (i = 0; i < GC_n_heap_sects; ++i) {
@@ -343,11 +310,10 @@
}
if (greatest_ha < (word)GC_scratch_last_end_ptr)
greatest_ha = (word)GC_scratch_last_end_ptr;
- for (;;) {
-
- buf_ptr = parse_map_entry(buf_ptr, &start, &end, prot_buf, &maj_dev);
- if (buf_ptr == NULL) return;
+ for (;;) {
+ buf_ptr = GC_parse_map_entry(buf_ptr, &start, &end, prot_buf, &maj_dev);
+ if (buf_ptr == NULL) return 1;
if (prot_buf[1] == 'w') {
/* This is a writable mapping. Add it to */
/* the root set unless it is already otherwise */
@@ -359,16 +325,7 @@
# ifdef THREADS
if (GC_segment_is_thread_stack(start, end)) continue;
# endif
- /* The rest of this assumes that there is no mapping */
- /* spanning the beginning of the data segment, or extending */
- /* beyond the entire heap at both ends. */
- /* Empirically these assumptions hold. */
-
- if (start < (word)DATAEND && end > (word)DATAEND) {
- /* Rld may use space at the end of the main data */
- /* segment. Thus we add that in. */
- start = (word)DATAEND;
- }
+ /* We no longer exclude the main data segment. */
if (start < least_ha && end > least_ha) {
end = least_ha;
}
@@ -378,7 +335,14 @@
if (start >= least_ha && end <= greatest_ha) continue;
GC_add_roots_inner((char *)start, (char *)end, TRUE);
}
- }
+ }
+ return 1;
+}
+
+void GC_register_dynamic_libraries()
+{
+ if (!GC_apply_to_maps(GC_register_map_entries))
+ ABORT("Failed to read /proc for library registration.");
}
/* We now take care of the main data segment ourselves: */
@@ -388,73 +352,6 @@
}
# define HAVE_REGISTER_MAIN_STATIC_DATA
-//
-// parse_map_entry parses an entry from /proc/self/maps so we can
-// locate all writable data segments that belong to shared libraries.
-// The format of one of these entries and the fields we care about
-// is as follows:
-// XXXXXXXX-XXXXXXXX r-xp 00000000 30:05 260537 name of mapping...\n
-// ^^^^^^^^ ^^^^^^^^ ^^^^ ^^
-// start end prot maj_dev
-// 0 9 18 32
-//
-// For 64 bit ABIs:
-// 0 17 34 56
-//
-// The parser is called with a pointer to the entry and the return value
-// is either NULL or is advanced to the next entry(the byte after the
-// trailing '\n'.)
-//
-#if CPP_WORDSZ == 32
-# define OFFSET_MAP_START 0
-# define OFFSET_MAP_END 9
-# define OFFSET_MAP_PROT 18
-# define OFFSET_MAP_MAJDEV 32
-# define ADDR_WIDTH 8
-#endif
-
-#if CPP_WORDSZ == 64
-# define OFFSET_MAP_START 0
-# define OFFSET_MAP_END 17
-# define OFFSET_MAP_PROT 34
-# define OFFSET_MAP_MAJDEV 56
-# define ADDR_WIDTH 16
-#endif
-
-static char *parse_map_entry(char *buf_ptr, word *start, word *end,
- char *prot_buf, unsigned int *maj_dev)
-{
- int i;
- char *tok;
-
- if (buf_ptr == NULL || *buf_ptr == '\0') {
- return NULL;
- }
-
- memcpy(prot_buf, buf_ptr+OFFSET_MAP_PROT, 4); // do the protections first
- prot_buf[4] = '\0';
-
- if (prot_buf[1] == 'w') { // we can skip all of this if it's not writable
-
- tok = buf_ptr;
- buf_ptr[OFFSET_MAP_START+ADDR_WIDTH] = '\0';
- *start = strtoul(tok, NULL, 16);
-
- tok = buf_ptr+OFFSET_MAP_END;
- buf_ptr[OFFSET_MAP_END+ADDR_WIDTH] = '\0';
- *end = strtoul(tok, NULL, 16);
-
- buf_ptr += OFFSET_MAP_MAJDEV;
- tok = buf_ptr;
- while (*buf_ptr != ':') buf_ptr++;
- *buf_ptr++ = '\0';
- *maj_dev = strtoul(tok, NULL, 16);
- }
-
- while (*buf_ptr && *buf_ptr++ != '\n');
-
- return buf_ptr;
-}
#endif /* USE_PROC_FOR_LIBRARIES */
@@ -549,6 +446,16 @@
#if defined(NETBSD)
# include <sys/exec_elf.h>
+/* for compatibility with 1.4.x */
+# ifndef DT_DEBUG
+# define DT_DEBUG 21
+# endif
+# ifndef PT_LOAD
+# define PT_LOAD 1
+# endif
+# ifndef PF_W
+# define PF_W 2
+# endif
#else
# include <elf.h>
#endif
@@ -820,6 +727,44 @@
# define HAVE_REGISTER_MAIN_STATIC_DATA
+ /* Should [start, start+len) be treated as a frame buffer */
+ /* and ignored? */
+ /* Unfortunately, we currently have no real way to tell */
+ /* automatically, and rely largely on user input. */
+ /* FIXME: If we had more data on this phenomenon (e.g. */
+ /* is start aligned to a MB multiple?) we should be able to */
+ /* do better. */
+ static GC_bool is_frame_buffer(ptr_t start, size_t len)
+ {
+ static GC_bool initialized = FALSE;
+ static GC_bool ignore_fb;
+# define MB (1024*1024)
+
+ switch(len) {
+ case 16*MB:
+ case 32*MB:
+ case 48*MB:
+ case 64*MB:
+ case 128*MB:
+ case 256*MB:
+ case 512*MB:
+ case 1024*MB:
+ break;
+ default:
+ return FALSE;
+ }
+ if (!initialized) {
+ ignore_fb = (0 != GETENV("GC_IGNORE_FB"));
+ if (!ignore_fb) {
+ WARN("Possible frame buffer mapping at 0x%lx: \n"
+ "\tConsider setting GC_IGNORE_FB to improve performance.\n",
+ start);
+ }
+ initialized = TRUE;
+ }
+ return ignore_fb;
+ }
+
void GC_register_dynamic_libraries()
{
MEMORY_BASIC_INFORMATION buf;
@@ -856,7 +801,8 @@
if (buf.State == MEM_COMMIT
&& (protect == PAGE_EXECUTE_READWRITE
|| protect == PAGE_READWRITE)
- && !GC_is_heap_base(buf.AllocationBase)) {
+ && !GC_is_heap_base(buf.AllocationBase)
+ && !is_frame_buffer(p, buf.RegionSize)) {
if ((char *)p != limit) {
GC_cond_add_roots(base, limit);
base = p;
@@ -1064,7 +1010,7 @@
len = ldi->ldinfo_next;
GC_add_roots_inner(
ldi->ldinfo_dataorg,
- (unsigned long)ldi->ldinfo_dataorg
+ (ptr_t)(unsigned long)ldi->ldinfo_dataorg
+ ldi->ldinfo_datasize,
TRUE);
@@ -1072,63 +1018,139 @@
}
#endif /* RS6000 */
-#ifdef MACOSX
+#ifdef DARWIN
-#include <mach-o/dyld.h>
+#ifndef __private_extern__
+# define __private_extern__ extern
+# include <mach-o/dyld.h>
+# undef __private_extern__
+#else
+# include <mach-o/dyld.h>
+#endif
#include <mach-o/getsect.h>
-/*#define MACOSX_DEBUG */
+/*#define DARWIN_DEBUG*/
-void GC_register_dynamic_libraries()
-{
- unsigned long image_count;
- const struct mach_header *mach_header;
- const struct section *sec;
- unsigned long slide;
- unsigned long filetype;
- int i,j;
- unsigned long start;
- unsigned long end;
-
- static struct {
+const static struct {
const char *seg;
const char *sect;
- } sections[] = {
+} GC_dyld_sections[] = {
{ SEG_DATA, SECT_DATA },
{ SEG_DATA, SECT_BSS },
{ SEG_DATA, SECT_COMMON }
- };
+};
- image_count = _dyld_image_count();
- for(i=0;i<image_count;i++)
- {
- mach_header = _dyld_get_image_header(i);
- slide = _dyld_get_image_vmaddr_slide(i);
- filetype = mach_header->filetype;
+#ifdef DARWIN_DEBUG
+static const char *GC_dyld_name_for_hdr(struct mach_header *hdr) {
+ unsigned long i,c;
+ c = _dyld_image_count();
+ for(i=0;i<c;i++) if(_dyld_get_image_header(i) == hdr)
+ return _dyld_get_image_name(i);
+ return NULL;
+}
+#endif
- for(j=0;j<sizeof(sections)/sizeof(sections[0]);j++) {
- sec = getsectbynamefromheader(mach_header,sections[j].seg,sections[j].sect);
+/* This should never be called by a thread holding the lock */
+static void GC_dyld_image_add(struct mach_header* hdr, unsigned long slide) {
+ unsigned long start,end,i;
+ const struct section *sec;
+ for(i=0;i<sizeof(GC_dyld_sections)/sizeof(GC_dyld_sections[0]);i++) {
+ sec = getsectbynamefromheader(
+ hdr,GC_dyld_sections[i].seg,GC_dyld_sections[i].sect);
if(sec == NULL || sec->size == 0) continue;
start = slide + sec->addr;
end = start + sec->size;
-# ifdef MACOSX_DEBUG
+# ifdef DARWIN_DEBUG
GC_printf4("Adding section at %p-%p (%lu bytes) from image %s\n",
- start,end,sec->size,_dyld_get_image_name(i));
+ start,end,sec->size,GC_dyld_name_for_hdr(hdr));
# endif
-
- GC_add_roots_inner((char*)start,(char*)end,
+ GC_add_roots((char*)start,(char*)end);
}
+# ifdef DARWIN_DEBUG
+ GC_print_static_roots();
+# endif
+}
+
+/* This should never be called by a thread holding the lock */
+static void GC_dyld_image_remove(struct mach_header* hdr, unsigned long slide) {
+ unsigned long start,end,i;
+ const struct section *sec;
+ for(i=0;i<sizeof(GC_dyld_sections)/sizeof(GC_dyld_sections[0]);i++) {
+ sec = getsectbynamefromheader(
+ hdr,GC_dyld_sections[i].seg,GC_dyld_sections[i].sect);
+ if(sec == NULL || sec->size == 0) continue;
+ start = slide + sec->addr;
+ end = start + sec->size;
+# ifdef DARWIN_DEBUG
+ GC_printf4("Removing section at %p-%p (%lu bytes) from image %s\n",
+ start,end,sec->size,GC_dyld_name_for_hdr(hdr));
+# endif
+ GC_remove_roots((char*)start,(char*)end);
+ }
+# ifdef DARWIN_DEBUG
+ GC_print_static_roots();
+# endif
+}
+
+void GC_register_dynamic_libraries() {
+ /* Currently does nothing. The callbacks are setup by GC_init_dyld()
+ The dyld library takes it from there. */
+}
+
+/* The _dyld_* functions have an internal lock so no _dyld functions
+ can be called while the world is stopped without the risk of a deadlock.
+ Because of this we MUST setup callbacks BEFORE we ever stop the world.
+ This should be called BEFORE any thread in created and WITHOUT the
+ allocation lock held. */
+
+void GC_init_dyld() {
+ static GC_bool initialized = FALSE;
+ char *bind_fully_env = NULL;
+
+ if(initialized) return;
+
+# ifdef DARWIN_DEBUG
+ GC_printf0("Registering dyld callbacks...\n");
+# endif
+
+ /* Apple's Documentation:
+ When you call _dyld_register_func_for_add_image, the dynamic linker runtime
+ calls the specified callback (func) once for each of the images that is
+ currently loaded into the program. When a new image is added to the program,
+ your callback is called again with the mach_header for the new image, and the
+ virtual memory slide amount of the new image.
+
+ This WILL properly register already linked libraries and libraries
+ linked in the future
+ */
+
+ _dyld_register_func_for_add_image(GC_dyld_image_add);
+ _dyld_register_func_for_remove_image(GC_dyld_image_remove);
+
+ /* Set this early to avoid reentrancy issues. */
+ initialized = TRUE;
+
+ bind_fully_env = getenv("DYLD_BIND_AT_LAUNCH");
+
+ if (bind_fully_env == NULL) {
+# ifdef DARWIN_DEBUG
+ GC_printf0("Forcing full bind of GC code...\n");
+# endif
+
+ if(!_dyld_bind_fully_image_containing_address((unsigned long*)GC_malloc))
+ GC_abort("_dyld_bind_fully_image_containing_address failed");
}
+
}
#define HAVE_REGISTER_MAIN_STATIC_DATA
GC_bool GC_register_main_static_data()
{
+ /* Already done through dyld callbacks */
return FALSE;
}
-#endif /* MACOSX */
+#endif /* DARWIN */
#else /* !DYNAMIC_LOADING */
Index: boehm_gc/finalize.c
===================================================================
RCS file: /home/staff/zs/imp/mercury/boehm_gc/finalize.c,v
retrieving revision 1.10
diff -u -r1.10 finalize.c
--- boehm_gc/finalize.c 6 May 2003 11:36:49 -0000 1.10
+++ boehm_gc/finalize.c 27 Oct 2003 21:02:33 -0000
@@ -764,7 +764,6 @@
struct finalizable_object * curr_fo;
int count = 0;
word mem_freed_before;
- GC_bool first_time = TRUE;
DCL_LOCK_STATE;
while (GC_finalize_now != 0) {
@@ -772,9 +771,8 @@
DISABLE_SIGNALS();
LOCK();
# endif
- if (first_time) {
+ if (count == 0) {
mem_freed_before = GC_mem_freed;
- first_time = FALSE;
}
curr_fo = GC_finalize_now;
# ifdef THREADS
@@ -797,7 +795,7 @@
GC_free((GC_PTR)curr_fo);
# endif
}
- if (mem_freed_before != GC_mem_freed) {
+ if (count != 0 && mem_freed_before != GC_mem_freed) {
LOCK();
GC_finalizer_mem_freed += (GC_mem_freed - mem_freed_before);
UNLOCK();
Index: boehm_gc/gc_dlopen.c
===================================================================
RCS file: /home/staff/zs/imp/mercury/boehm_gc/gc_dlopen.c,v
retrieving revision 1.3
diff -u -r1.3 gc_dlopen.c
--- boehm_gc/gc_dlopen.c 6 May 2003 11:36:49 -0000 1.3
+++ boehm_gc/gc_dlopen.c 27 Oct 2003 21:02:33 -0000
@@ -25,7 +25,7 @@
#include "private/gc_priv.h"
-# if (defined(GC_PTHREADS) && !defined(GC_MACOSX_THREADS)) \
+# if (defined(GC_PTHREADS) && !defined(GC_DARWIN_THREADS)) \
|| defined(GC_SOLARIS_THREADS)
# if defined(dlopen) && !defined(GC_USE_LD_WRAP)
Index: boehm_gc/irix_threads.c
===================================================================
RCS file: boehm_gc/irix_threads.c
diff -N boehm_gc/irix_threads.c
--- boehm_gc/irix_threads.c 25 Jul 2002 09:02:46 -0000 1.7
+++ /dev/null 1 Jan 1970 00:00:00 -0000
@@ -1,730 +0,0 @@
-/*
- * 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 Company. All rights reserved.
- *
- * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
- * OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
- *
- * Permission is hereby granted to use or copy this program
- * for any purpose, provided the above notices are retained on all copies.
- * Permission to modify the code and to distribute modified code is granted,
- * provided the above notices are retained, and a notice that the code was
- * modified is included with the above copyright notice.
- */
-/*
- * Support code for Irix (>=6.2) Pthreads. This relies on properties
- * not guaranteed by the Pthread standard. It may or may not be portable
- * to other implementations.
- *
- * This now also includes an initial attempt at thread support for
- * HP/UX 11.
- *
- * Note that there is a lot of code duplication between linux_threads.c
- * and irix_threads.c; any changes made here may need to be reflected
- * there too.
- */
-
-# if defined(GC_IRIX_THREADS)
-
-# include "private/gc_priv.h"
-# include <pthread.h>
-# include <semaphore.h>
-# include <time.h>
-# include <errno.h>
-# include <unistd.h>
-# include <sys/mman.h>
-# include <sys/time.h>
-
-#undef pthread_create
-#undef pthread_sigmask
-#undef pthread_join
-#undef pthread_detach
-
-#ifdef HANDLE_FORK
- --> Not yet supported. Try porting the code from linux_threads.c.
-#endif
-
-void GC_thr_init();
-
-#if 0
-void GC_print_sig_mask()
-{
- sigset_t blocked;
- int i;
-
- if (pthread_sigmask(SIG_BLOCK, NULL, &blocked) != 0)
- ABORT("pthread_sigmask");
- GC_printf0("Blocked: ");
- for (i = 1; i <= MAXSIG; i++) {
- if (sigismember(&blocked, i)) { GC_printf1("%ld ",(long) i); }
- }
- GC_printf0("\n");
-}
-#endif
-
-/* We use the allocation lock to protect thread-related data structures. */
-
-/* The set of all known threads. We intercept thread creation and */
-/* joins. We never actually create detached threads. We allocate all */
-/* new thread stacks ourselves. These allow us to maintain this */
-/* data structure. */
-/* Protected by GC_thr_lock. */
-/* Some of this should be declared volatile, but that's incosnsistent */
-/* with some library routine declarations. */
-typedef struct GC_Thread_Rep {
- struct GC_Thread_Rep * next; /* More recently allocated threads */
- /* with a given pthread id come */
- /* first. (All but the first are */
- /* guaranteed to be dead, but we may */
- /* not yet have registered the join.) */
- pthread_t id;
- word stop;
-# define NOT_STOPPED 0
-# define PLEASE_STOP 1
-# define STOPPED 2
- word flags;
-# define FINISHED 1 /* Thread has exited. */
-# define DETACHED 2 /* Thread is intended to be detached. */
-# define CLIENT_OWNS_STACK 4
- /* Stack was supplied by client. */
- ptr_t stack;
- ptr_t stack_ptr; /* Valid only when stopped. */
- /* But must be within stack region at */
- /* all times. */
- size_t stack_size; /* 0 for original thread. */
- void * status; /* Used only to avoid premature */
- /* reclamation of any data it might */
- /* reference. */
-} * GC_thread;
-
-GC_thread GC_lookup_thread(pthread_t id);
-
-/*
- * The only way to suspend threads given the pthread interface is to send
- * signals. Unfortunately, this means we have to reserve
- * a signal, and intercept client calls to change the signal mask.
- * We use SIG_SUSPEND, defined in gc_priv.h.
- */
-
-pthread_mutex_t GC_suspend_lock = PTHREAD_MUTEX_INITIALIZER;
- /* Number of threads stopped so far */
-pthread_cond_t GC_suspend_ack_cv = PTHREAD_COND_INITIALIZER;
-pthread_cond_t GC_continue_cv = PTHREAD_COND_INITIALIZER;
-
-void GC_suspend_handler(int sig)
-{
- int dummy;
- GC_thread me;
- sigset_t all_sigs;
- sigset_t old_sigs;
- int i;
-
- if (sig != SIG_SUSPEND) ABORT("Bad signal in suspend_handler");
- me = GC_lookup_thread(pthread_self());
- /* The lookup here is safe, since I'm doing this on behalf */
- /* of a thread which holds the allocation lock in order */
- /* to stop the world. Thus concurrent modification of the */
- /* data structure is impossible. */
- if (PLEASE_STOP != me -> stop) {
- /* Misdirected signal. */
- pthread_mutex_unlock(&GC_suspend_lock);
- return;
- }
- pthread_mutex_lock(&GC_suspend_lock);
- me -> stack_ptr = (ptr_t)(&dummy);
- me -> stop = STOPPED;
- pthread_cond_signal(&GC_suspend_ack_cv);
- pthread_cond_wait(&GC_continue_cv, &GC_suspend_lock);
- pthread_mutex_unlock(&GC_suspend_lock);
- /* GC_printf1("Continuing 0x%x\n", pthread_self()); */
-}
-
-
-GC_bool GC_thr_initialized = FALSE;
-
-size_t GC_min_stack_sz;
-
-# define N_FREE_LISTS 25
-ptr_t GC_stack_free_lists[N_FREE_LISTS] = { 0 };
- /* GC_stack_free_lists[i] is free list for stacks of */
- /* size GC_min_stack_sz*2**i. */
- /* Free lists are linked through first word. */
-
-/* Return a stack of size at least *stack_size. *stack_size is */
-/* replaced by the actual stack size. */
-/* Caller holds allocation lock. */
-ptr_t GC_stack_alloc(size_t * stack_size)
-{
- register size_t requested_sz = *stack_size;
- register size_t search_sz = GC_min_stack_sz;
- register int index = 0; /* = log2(search_sz/GC_min_stack_sz) */
- register ptr_t result;
-
- while (search_sz < requested_sz) {
- search_sz *= 2;
- index++;
- }
- if ((result = GC_stack_free_lists[index]) == 0
- && (result = GC_stack_free_lists[index+1]) != 0) {
- /* Try next size up. */
- search_sz *= 2; index++;
- }
- if (result != 0) {
- GC_stack_free_lists[index] = *(ptr_t *)result;
- } else {
- result = (ptr_t) GC_scratch_alloc(search_sz + 2*GC_page_size);
- result = (ptr_t)(((word)result + GC_page_size) & ~(GC_page_size - 1));
- /* Protect hottest page to detect overflow. */
-# ifdef STACK_GROWS_UP
- /* mprotect(result + search_sz, GC_page_size, PROT_NONE); */
-# else
- /* mprotect(result, GC_page_size, PROT_NONE); */
- result += GC_page_size;
-# endif
- }
- *stack_size = search_sz;
- return(result);
-}
-
-/* Caller holds allocation lock. */
-void GC_stack_free(ptr_t stack, size_t size)
-{
- register int index = 0;
- register size_t search_sz = GC_min_stack_sz;
-
- while (search_sz < size) {
- search_sz *= 2;
- index++;
- }
- if (search_sz != size) ABORT("Bad stack size");
- *(ptr_t *)stack = GC_stack_free_lists[index];
- GC_stack_free_lists[index] = stack;
-}
-
-
-
-# define THREAD_TABLE_SZ 128 /* Must be power of 2 */
-volatile GC_thread GC_threads[THREAD_TABLE_SZ];
-
-void GC_push_thread_structures GC_PROTO((void))
-{
- GC_push_all((ptr_t)(GC_threads), (ptr_t)(GC_threads)+sizeof(GC_threads));
-}
-
-/* Add a thread to GC_threads. We assume it wasn't already there. */
-/* Caller holds allocation lock. */
-GC_thread GC_new_thread(pthread_t id)
-{
- int hv = ((word)id) % THREAD_TABLE_SZ;
- GC_thread result;
- static struct GC_Thread_Rep first_thread;
- static GC_bool first_thread_used = FALSE;
-
- if (!first_thread_used) {
- result = &first_thread;
- first_thread_used = TRUE;
- /* Dont acquire allocation lock, since we may already hold it. */
- } else {
- result = (struct GC_Thread_Rep *)
- GC_INTERNAL_MALLOC(sizeof(struct GC_Thread_Rep), NORMAL);
- }
- if (result == 0) return(0);
- result -> id = id;
- result -> next = GC_threads[hv];
- GC_threads[hv] = result;
- /* result -> flags = 0; */
- /* result -> stop = 0; */
- return(result);
-}
-
-/* Delete a thread from GC_threads. We assume it is there. */
-/* (The code intentionally traps if it wasn't.) */
-/* Caller holds allocation lock. */
-void GC_delete_thread(pthread_t id)
-{
- int hv = ((word)id) % THREAD_TABLE_SZ;
- register GC_thread p = GC_threads[hv];
- register GC_thread prev = 0;
-
- while (!pthread_equal(p -> id, id)) {
- prev = p;
- p = p -> next;
- }
- if (prev == 0) {
- GC_threads[hv] = p -> next;
- } else {
- prev -> next = p -> next;
- }
-}
-
-/* If a thread has been joined, but we have not yet */
-/* been notified, then there may be more than one thread */
-/* in the table with the same pthread id. */
-/* This is OK, but we need a way to delete a specific one. */
-void GC_delete_gc_thread(pthread_t id, GC_thread gc_id)
-{
- int hv = ((word)id) % THREAD_TABLE_SZ;
- register GC_thread p = GC_threads[hv];
- register GC_thread prev = 0;
-
- while (p != gc_id) {
- prev = p;
- p = p -> next;
- }
- if (prev == 0) {
- GC_threads[hv] = p -> next;
- } else {
- prev -> next = p -> next;
- }
-}
-
-/* Return a GC_thread corresponding to a given thread_t. */
-/* Returns 0 if it's not there. */
-/* Caller holds allocation lock or otherwise inhibits */
-/* updates. */
-/* If there is more than one thread with the given id we */
-/* return the most recent one. */
-GC_thread GC_lookup_thread(pthread_t id)
-{
- int hv = ((word)id) % THREAD_TABLE_SZ;
- register GC_thread p = GC_threads[hv];
-
- while (p != 0 && !pthread_equal(p -> id, id)) p = p -> next;
- return(p);
-}
-
-
-/* Caller holds allocation lock. */
-void GC_stop_world()
-{
- pthread_t my_thread = pthread_self();
- register int i;
- register GC_thread p;
- register int result;
- struct timespec timeout;
-
- for (i = 0; i < THREAD_TABLE_SZ; i++) {
- for (p = GC_threads[i]; p != 0; p = p -> next) {
- if (p -> id != my_thread) {
- if (p -> flags & FINISHED) {
- p -> stop = STOPPED;
- continue;
- }
- p -> stop = PLEASE_STOP;
- result = pthread_kill(p -> id, SIG_SUSPEND);
- /* GC_printf1("Sent signal to 0x%x\n", p -> id); */
- switch(result) {
- case ESRCH:
- p -> stop = STOPPED;
- break;
- case 0:
- break;
- default:
- ABORT("pthread_kill failed");
- }
- }
- }
- }
- pthread_mutex_lock(&GC_suspend_lock);
- for (i = 0; i < THREAD_TABLE_SZ; i++) {
- for (p = GC_threads[i]; p != 0; p = p -> next) {
- while (p -> id != my_thread && p -> stop != STOPPED) {
- clock_gettime(CLOCK_REALTIME, &timeout);
- timeout.tv_nsec += 50000000; /* 50 msecs */
- if (timeout.tv_nsec >= 1000000000) {
- timeout.tv_nsec -= 1000000000;
- ++timeout.tv_sec;
- }
- result = pthread_cond_timedwait(&GC_suspend_ack_cv,
- &GC_suspend_lock,
- &timeout);
- if (result == ETIMEDOUT) {
- /* Signal was lost or misdirected. Try again. */
- /* Duplicate signals should be benign. */
- result = pthread_kill(p -> id, SIG_SUSPEND);
- }
- }
- }
- }
- pthread_mutex_unlock(&GC_suspend_lock);
- /* GC_printf1("World stopped 0x%x\n", pthread_self()); */
-}
-
-/* Caller holds allocation lock. */
-void GC_start_world()
-{
- GC_thread p;
- unsigned i;
-
- /* GC_printf0("World starting\n"); */
- for (i = 0; i < THREAD_TABLE_SZ; i++) {
- for (p = GC_threads[i]; p != 0; p = p -> next) {
- p -> stop = NOT_STOPPED;
- }
- }
- pthread_mutex_lock(&GC_suspend_lock);
- /* All other threads are at pthread_cond_wait in signal handler. */
- /* Otherwise we couldn't have acquired the lock. */
- pthread_mutex_unlock(&GC_suspend_lock);
- pthread_cond_broadcast(&GC_continue_cv);
-}
-
-# ifdef MMAP_STACKS
---> not really supported yet.
-int GC_is_thread_stack(ptr_t addr)
-{
- register int i;
- register GC_thread p;
-
- for (i = 0; i < THREAD_TABLE_SZ; i++) {
- for (p = GC_threads[i]; p != 0; p = p -> next) {
- if (p -> stack_size != 0) {
- if (p -> stack <= addr &&
- addr < p -> stack + p -> stack_size)
- return 1;
- }
- }
- }
- return 0;
-}
-# endif
-
-/* We hold allocation lock. Should do exactly the right thing if the */
-/* world is stopped. Should not fail if it isn't. */
-void GC_push_all_stacks()
-{
- register int i;
- register GC_thread p;
- register ptr_t sp = GC_approx_sp();
- register ptr_t hot, cold;
- pthread_t me = pthread_self();
-
- if (!GC_thr_initialized) GC_thr_init();
- /* GC_printf1("Pushing stacks from thread 0x%x\n", me); */
- for (i = 0; i < THREAD_TABLE_SZ; i++) {
- for (p = GC_threads[i]; p != 0; p = p -> next) {
- if (p -> flags & FINISHED) continue;
- if (pthread_equal(p -> id, me)) {
- hot = GC_approx_sp();
- } else {
- hot = p -> stack_ptr;
- }
- if (p -> stack_size != 0) {
-# ifdef STACK_GROWS_UP
- cold = p -> stack;
-# else
- cold = p -> stack + p -> stack_size;
-# endif
- } else {
- /* The original stack. */
- cold = GC_stackbottom;
- }
-# ifdef STACK_GROWS_UP
- GC_push_all_stack(cold, hot);
-# else
- GC_push_all_stack(hot, cold);
-# endif
- }
- }
-}
-
-
-/* We hold the allocation lock. */
-void GC_thr_init()
-{
- GC_thread t;
- struct sigaction act;
-
- if (GC_thr_initialized) return;
- GC_thr_initialized = TRUE;
- GC_min_stack_sz = HBLKSIZE;
- (void) sigaction(SIG_SUSPEND, 0, &act);
- if (act.sa_handler != SIG_DFL)
- ABORT("Previously installed SIG_SUSPEND handler");
- /* Install handler. */
- act.sa_handler = GC_suspend_handler;
- act.sa_flags = SA_RESTART;
- (void) sigemptyset(&act.sa_mask);
- if (0 != sigaction(SIG_SUSPEND, &act, 0))
- ABORT("Failed to install SIG_SUSPEND handler");
- /* Add the initial thread, so we can stop it. */
- t = GC_new_thread(pthread_self());
- t -> stack_size = 0;
- t -> stack_ptr = (ptr_t)(&t);
- t -> flags = DETACHED;
-}
-
-int GC_pthread_sigmask(int how, const sigset_t *set, sigset_t *oset)
-{
- sigset_t fudged_set;
-
- if (set != NULL && (how == SIG_BLOCK || how == SIG_SETMASK)) {
- fudged_set = *set;
- sigdelset(&fudged_set, SIG_SUSPEND);
- set = &fudged_set;
- }
- return(pthread_sigmask(how, set, oset));
-}
-
-struct start_info {
- void *(*start_routine)(void *);
- void *arg;
- word flags;
- ptr_t stack;
- size_t stack_size;
- sem_t registered; /* 1 ==> in our thread table, but */
- /* parent hasn't yet noticed. */
-};
-
-void GC_thread_exit_proc(void *arg)
-{
- GC_thread me;
-
- LOCK();
- me = GC_lookup_thread(pthread_self());
- if (me -> flags & DETACHED) {
- GC_delete_thread(pthread_self());
- } else {
- me -> flags |= FINISHED;
- }
- UNLOCK();
-}
-
-int GC_pthread_join(pthread_t thread, void **retval)
-{
- int result;
- GC_thread thread_gc_id;
-
- LOCK();
- thread_gc_id = GC_lookup_thread(thread);
- /* This is guaranteed to be the intended one, since the thread id */
- /* cant have been recycled by pthreads. */
- UNLOCK();
- result = pthread_join(thread, retval);
- /* Some versions of the Irix pthreads library can erroneously */
- /* return EINTR when the call succeeds. */
- if (EINTR == result) result = 0;
- if (result == 0) {
- LOCK();
- /* Here the pthread thread id may have been recycled. */
- GC_delete_gc_thread(thread, thread_gc_id);
- UNLOCK();
- }
- return result;
-}
-
-int GC_pthread_detach(pthread_t thread)
-{
- int result;
- GC_thread thread_gc_id;
-
- LOCK();
- thread_gc_id = GC_lookup_thread(thread);
- UNLOCK();
- result = pthread_detach(thread);
- if (result == 0) {
- LOCK();
- thread_gc_id -> flags |= DETACHED;
- /* Here the pthread thread id may have been recycled. */
- if (thread_gc_id -> flags & FINISHED) {
- GC_delete_gc_thread(thread, thread_gc_id);
- }
- UNLOCK();
- }
- return result;
-}
-
-void * GC_start_routine(void * arg)
-{
- struct start_info * si = arg;
- void * result;
- GC_thread me;
- pthread_t my_pthread;
- void *(*start)(void *);
- void *start_arg;
-
- my_pthread = pthread_self();
- /* If a GC occurs before the thread is registered, that GC will */
- /* ignore this thread. That's fine, since it will block trying to */
- /* acquire the allocation lock, and won't yet hold interesting */
- /* pointers. */
- LOCK();
- /* We register the thread here instead of in the parent, so that */
- /* we don't need to hold the allocation lock during pthread_create. */
- /* Holding the allocation lock there would make REDIRECT_MALLOC */
- /* impossible. It probably still doesn't work, but we're a little */
- /* closer ... */
- /* This unfortunately means that we have to be careful the parent */
- /* doesn't try to do a pthread_join before we're registered. */
- me = GC_new_thread(my_pthread);
- me -> flags = si -> flags;
- me -> stack = si -> stack;
- me -> stack_size = si -> stack_size;
- me -> stack_ptr = (ptr_t)si -> stack + si -> stack_size - sizeof(word);
- UNLOCK();
- start = si -> start_routine;
- start_arg = si -> arg;
- sem_post(&(si -> registered));
- pthread_cleanup_push(GC_thread_exit_proc, 0);
- result = (*start)(start_arg);
- me -> status = result;
- me -> flags |= FINISHED;
- pthread_cleanup_pop(1);
- /* This involves acquiring the lock, ensuring that we can't exit */
- /* while a collection that thinks we're alive is trying to stop */
- /* us. */
- return(result);
-}
-
-# define copy_attr(pa_ptr, source) *(pa_ptr) = *(source)
-
-int
-GC_pthread_create(pthread_t *new_thread,
- const pthread_attr_t *attr,
- void *(*start_routine)(void *), void *arg)
-{
- int result;
- GC_thread t;
- void * stack;
- size_t stacksize;
- pthread_attr_t new_attr;
- int detachstate;
- word my_flags = 0;
- struct start_info * si = GC_malloc(sizeof(struct start_info));
- /* This is otherwise saved only in an area mmapped by the thread */
- /* library, which isn't visible to the collector. */
-
- if (0 == si) return(ENOMEM);
- if (0 != sem_init(&(si -> registered), 0, 0)) {
- ABORT("sem_init failed");
- }
- si -> start_routine = start_routine;
- si -> arg = arg;
- LOCK();
- if (!GC_is_initialized) GC_init();
- if (NULL == attr) {
- stack = 0;
- (void) pthread_attr_init(&new_attr);
- } else {
- copy_attr(&new_attr, attr);
- pthread_attr_getstackaddr(&new_attr, &stack);
- }
- pthread_attr_getstacksize(&new_attr, &stacksize);
- pthread_attr_getdetachstate(&new_attr, &detachstate);
- if (stacksize < GC_min_stack_sz) ABORT("Stack too small");
- if (0 == stack) {
- stack = (void *)GC_stack_alloc(&stacksize);
- if (0 == stack) {
- UNLOCK();
- return(ENOMEM);
- }
- pthread_attr_setstackaddr(&new_attr, stack);
- } else {
- my_flags |= CLIENT_OWNS_STACK;
- }
- if (PTHREAD_CREATE_DETACHED == detachstate) my_flags |= DETACHED;
- si -> flags = my_flags;
- si -> stack = stack;
- si -> stack_size = stacksize;
- result = pthread_create(new_thread, &new_attr, GC_start_routine, si);
- if (0 == new_thread && !(my_flags & CLIENT_OWNS_STACK)) {
- GC_stack_free(stack, stacksize);
- }
- UNLOCK();
- /* Wait until child has been added to the thread table. */
- /* This also ensures that we hold onto si until the child is done */
- /* with it. Thus it doesn't matter whether it is otherwise */
- /* visible to the collector. */
- while (0 != sem_wait(&(si -> registered))) {
- if (errno != EINTR) {
- GC_printf1("Sem_wait: errno = %ld\n", (unsigned long) errno);
- ABORT("sem_wait failed");
- }
- }
- sem_destroy(&(si -> registered));
- pthread_attr_destroy(&new_attr); /* Probably unnecessary under Irix */
- return(result);
-}
-
-VOLATILE GC_bool GC_collecting = 0;
- /* A hint that we're in the collector and */
- /* holding the allocation lock for an */
- /* extended period. */
-
-/* Reasonably fast spin locks. Basically the same implementation */
-/* as STL alloc.h. */
-
-#define SLEEP_THRESHOLD 3
-
-unsigned long GC_allocate_lock = 0;
-# define GC_TRY_LOCK() !GC_test_and_set(&GC_allocate_lock)
-# define GC_LOCK_TAKEN GC_allocate_lock
-
-void GC_lock()
-{
-# define low_spin_max 30 /* spin cycles if we suspect uniprocessor */
-# define high_spin_max 1000 /* spin cycles for multiprocessor */
- static unsigned spin_max = low_spin_max;
- unsigned my_spin_max;
- static unsigned last_spins = 0;
- unsigned my_last_spins;
- volatile unsigned junk;
-# define PAUSE junk *= junk; junk *= junk; junk *= junk; junk *= junk
- int i;
-
- if (GC_TRY_LOCK()) {
- return;
- }
- junk = 0;
- my_spin_max = spin_max;
- my_last_spins = last_spins;
- for (i = 0; i < my_spin_max; i++) {
- if (GC_collecting) goto yield;
- if (i < my_last_spins/2 || GC_LOCK_TAKEN) {
- PAUSE;
- continue;
- }
- if (GC_TRY_LOCK()) {
- /*
- * got it!
- * Spinning worked. Thus we're probably not being scheduled
- * against the other process with which we were contending.
- * Thus it makes sense to spin longer the next time.
- */
- last_spins = i;
- spin_max = high_spin_max;
- return;
- }
- }
- /* We are probably being scheduled against the other process. Sleep. */
- spin_max = low_spin_max;
-yield:
- for (i = 0;; ++i) {
- if (GC_TRY_LOCK()) {
- return;
- }
- if (i < SLEEP_THRESHOLD) {
- sched_yield();
- } else {
- struct timespec ts;
-
- if (i > 26) i = 26;
- /* Don't wait for more than about 60msecs, even */
- /* under extreme contention. */
- ts.tv_sec = 0;
- ts.tv_nsec = 1 << i;
- nanosleep(&ts, 0);
- }
- }
-}
-
-# else
-
-#ifndef LINT
- int GC_no_Irix_threads;
-#endif
-
-# endif /* GC_IRIX_THREADS */
-
Index: boehm_gc/linux_threads.c
===================================================================
RCS file: boehm_gc/linux_threads.c
diff -N boehm_gc/linux_threads.c
--- boehm_gc/linux_threads.c 6 May 2003 11:36:49 -0000 1.10
+++ /dev/null 1 Jan 1970 00:00:00 -0000
@@ -1,2078 +0,0 @@
-/*
- * Copyright (c) 1994 by Xerox Corporation. All rights reserved.
- * Copyright (c) 1996 by Silicon Graphics. All rights reserved.
- * Copyright (c) 1998 by Fergus Henderson. All rights reserved.
- * Copyright (c) 2000-2001 by Hewlett-Packard Company. All rights reserved.
- *
- * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
- * OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
- *
- * Permission is hereby granted to use or copy this program
- * for any purpose, provided the above notices are retained on all copies.
- * Permission to modify the code and to distribute modified code is granted,
- * provided the above notices are retained, and a notice that the code was
- * modified is included with the above copyright notice.
- */
-/*
- * Support code for LinuxThreads, the clone()-based kernel
- * thread package for Linux which is included in libc6.
- *
- * This code relies on implementation details of LinuxThreads,
- * (i.e. properties not guaranteed by the Pthread standard),
- * though this version now does less of that than the other Pthreads
- * support code.
- *
- * Note that there is a lot of code duplication between linux_threads.c
- * and thread support for some of the other Posix platforms; any changes
- * made here may need to be reflected there too.
- */
- /* DG/UX ix86 support <takis at xfree86.org> */
-/*
- * Linux_threads.c now also includes some code to support HPUX and
- * OSF1 (Compaq Tru64 Unix, really). The OSF1 support is not yet
- * functional. The OSF1 code is based on Eric Benson's
- * patch, though that was originally against hpux_irix_threads. The code
- * here is completely untested. With 0.0000001% probability, it might
- * actually work.
- *
- * Eric also suggested an alternate basis for a lock implementation in
- * his code:
- * + #elif defined(OSF1)
- * + unsigned long GC_allocate_lock = 0;
- * + msemaphore GC_allocate_semaphore;
- * + # define GC_TRY_LOCK() \
- * + ((msem_lock(&GC_allocate_semaphore, MSEM_IF_NOWAIT) == 0) \
- * + : 0)
- * + # define GC_LOCK_TAKEN GC_allocate_lock
- */
-
-/* #define DEBUG_THREADS 1 */
-
-/* ANSI C requires that a compilation unit contains something */
-
-# include "gc.h"
-
-# if defined(GC_PTHREADS) && !defined(GC_SOLARIS_THREADS) \
- && !defined(GC_IRIX_THREADS) && !defined(GC_WIN32_THREADS)
-
-# include "private/gc_priv.h"
-
-# if defined(GC_HPUX_THREADS) && !defined(USE_PTHREAD_SPECIFIC) \
- && !defined(USE_HPUX_TLS)
-# define USE_HPUX_TLS
-# endif
-
-# if (defined(GC_DGUX386_THREADS) || defined(GC_OSF1_THREADS)) \
- && !defined(USE_PTHREAD_SPECIFIC)
-# define USE_PTHREAD_SPECIFIC
-# endif
-
-# if defined(GC_DGUX386_THREADS) && !defined(_POSIX4A_DRAFT10_SOURCE)
-# define _POSIX4A_DRAFT10_SOURCE 1
-# endif
-
-# if defined(GC_DGUX386_THREADS) && !defined(_USING_POSIX4A_DRAFT10)
-# define _USING_POSIX4A_DRAFT10 1
-# endif
-
-# ifdef THREAD_LOCAL_ALLOC
-# if !defined(USE_PTHREAD_SPECIFIC) && !defined(USE_HPUX_TLS)
-# include "private/specific.h"
-# endif
-# if defined(USE_PTHREAD_SPECIFIC)
-# define GC_getspecific pthread_getspecific
-# define GC_setspecific pthread_setspecific
-# define GC_key_create pthread_key_create
- typedef pthread_key_t GC_key_t;
-# endif
-# if defined(USE_HPUX_TLS)
-# define GC_getspecific(x) (x)
-# define GC_setspecific(key, v) ((key) = (v), 0)
-# define GC_key_create(key, d) 0
- typedef void * GC_key_t;
-# endif
-# endif
-# include <stdlib.h>
-# include <pthread.h>
-# include <sched.h>
-# include <time.h>
-# include <errno.h>
-# include <unistd.h>
-# include <sys/mman.h>
-# include <sys/time.h>
-# include <semaphore.h>
-# include <signal.h>
-# include <sys/types.h>
-# include <sys/stat.h>
-# include <fcntl.h>
-
-#if defined(GC_MACOSX_THREADS)
-# include <sys/sysctl.h>
-#endif /* GC_MACOSX_THREADS */
-
-#if defined(GC_DGUX386_THREADS)
-# include <sys/dg_sys_info.h>
-# include <sys/_int_psem.h>
- /* sem_t is an uint in DG/UX */
- typedef unsigned int sem_t;
-#endif /* GC_DGUX386_THREADS */
-
-#ifndef __GNUC__
-# define __inline__
-#endif
-
-#ifdef GC_USE_LD_WRAP
-# define WRAP_FUNC(f) __wrap_##f
-# define REAL_FUNC(f) __real_##f
-#else
-# define WRAP_FUNC(f) GC_##f
-# if !defined(GC_DGUX386_THREADS)
-# define REAL_FUNC(f) f
-# else /* GC_DGUX386_THREADS */
-# define REAL_FUNC(f) __d10_##f
-# endif /* GC_DGUX386_THREADS */
-# undef pthread_create
-# undef pthread_sigmask
-# undef pthread_join
-# undef pthread_detach
-#endif
-
-
-void GC_thr_init();
-
-#if DEBUG_THREADS
-
-#ifndef NSIG
-# if defined(MAXSIG)
-# define NSIG (MAXSIG+1)
-# elif defined(_NSIG)
-# define NSIG _NSIG
-# elif defined(__SIGRTMAX)
-# define NSIG (__SIGRTMAX+1)
-# else
- --> please fix it
-# endif
-#endif
-
-void GC_print_sig_mask()
-{
- sigset_t blocked;
- int i;
-
- if (pthread_sigmask(SIG_BLOCK, NULL, &blocked) != 0)
- ABORT("pthread_sigmask");
- GC_printf0("Blocked: ");
- for (i = 1; i < NSIG; i++) {
- if (sigismember(&blocked, i)) { GC_printf1("%ld ",(long) i); }
- }
- GC_printf0("\n");
-}
-#endif
-
-word GC_stop_count; /* Incremented at the beginning of GC_stop_world. */
-
-#ifdef GC_OSF1_THREADS
- GC_bool GC_retry_signals = TRUE;
-#else
- GC_bool GC_retry_signals = FALSE;
-#endif
-
-/* We use the allocation lock to protect thread-related data structures. */
-
-/* The set of all known threads. We intercept thread creation and */
-/* joins. */
-/* Protected by allocation/GC lock. */
-/* Some of this should be declared volatile, but that's inconsistent */
-/* with some library routine declarations. */
-typedef struct GC_Thread_Rep {
- struct GC_Thread_Rep * next; /* More recently allocated threads */
- /* with a given pthread id come */
- /* first. (All but the first are */
- /* guaranteed to be dead, but we may */
- /* not yet have registered the join.) */
- pthread_t id;
- short flags;
-# define FINISHED 1 /* Thread has exited. */
-# define DETACHED 2 /* Thread is intended to be detached. */
-# define MAIN_THREAD 4 /* True for the original thread only. */
- short thread_blocked; /* Protected by GC lock. */
- /* Treated as a boolean value. If set, */
- /* thread will acquire GC lock before */
- /* doing any pointer manipulations, and */
- /* has set its sp value. Thus it does */
- /* not need to be sent a signal to stop */
- /* it. */
- ptr_t stack_end; /* Cold end of the stack. */
- ptr_t stack_ptr; /* Valid only when stopped. */
-# ifdef IA64
- ptr_t backing_store_end;
- ptr_t backing_store_ptr;
-# endif
- int signal;
- void * status; /* The value returned from the thread. */
- /* Used only to avoid premature */
- /* reclamation of any data it might */
- /* reference. */
- word last_stop_count; /* GC_last_stop_count value when thread */
- /* last successfully handled a suspend */
- /* signal. */
-# ifdef THREAD_LOCAL_ALLOC
-# if CPP_WORDSZ == 64 && defined(ALIGN_DOUBLE)
-# define GRANULARITY 16
-# define NFREELISTS 49
-# else
-# define GRANULARITY 8
-# define NFREELISTS 65
-# endif
- /* The ith free list corresponds to size i*GRANULARITY */
-# define INDEX_FROM_BYTES(n) ((ADD_SLOP(n) + GRANULARITY - 1)/GRANULARITY)
-# define BYTES_FROM_INDEX(i) ((i) * GRANULARITY - EXTRA_BYTES)
-# define SMALL_ENOUGH(bytes) (ADD_SLOP(bytes) <= \
- (NFREELISTS-1)*GRANULARITY)
- ptr_t ptrfree_freelists[NFREELISTS];
- ptr_t normal_freelists[NFREELISTS];
-# ifdef GC_GCJ_SUPPORT
- ptr_t gcj_freelists[NFREELISTS];
-# endif
- /* Free lists contain either a pointer or a small count */
- /* reflecting the number of granules allocated at that */
- /* size. */
- /* 0 ==> thread-local allocation in use, free list */
- /* empty. */
- /* > 0, <= DIRECT_GRANULES ==> Using global allocation, */
- /* too few objects of this size have been */
- /* allocated by this thread. */
- /* >= HBLKSIZE => pointer to nonempty free list. */
- /* > DIRECT_GRANULES, < HBLKSIZE ==> transition to */
- /* local alloc, equivalent to 0. */
-# define DIRECT_GRANULES (HBLKSIZE/GRANULARITY)
- /* Don't use local free lists for up to this much */
- /* allocation. */
-# endif
-} * GC_thread;
-
-GC_thread GC_lookup_thread(pthread_t id);
-
-static GC_bool parallel_initialized = FALSE;
-
-void GC_init_parallel();
-
-# if defined(THREAD_LOCAL_ALLOC) && !defined(DBG_HDRS_ALL)
-
-/* We don't really support thread-local allocation with DBG_HDRS_ALL */
-
-#ifdef USE_HPUX_TLS
- __thread
-#endif
-GC_key_t GC_thread_key;
-
-static GC_bool keys_initialized;
-
-/* Recover the contents of the freelist array fl into the global one gfl.*/
-/* Note that the indexing scheme differs, in that gfl has finer size */
-/* resolution, even if not all entries are used. */
-/* We hold the allocator lock. */
-static void return_freelists(ptr_t *fl, ptr_t *gfl)
-{
- int i;
- ptr_t q, *qptr;
- size_t nwords;
-
- for (i = 1; i < NFREELISTS; ++i) {
- nwords = i * (GRANULARITY/sizeof(word));
- qptr = fl + i;
- q = *qptr;
- if ((word)q >= HBLKSIZE) {
- if (gfl[nwords] == 0) {
- gfl[nwords] = q;
- } else {
- /* Concatenate: */
- for (; (word)q >= HBLKSIZE; qptr = &(obj_link(q)), q = *qptr);
- GC_ASSERT(0 == q);
- *qptr = gfl[nwords];
- gfl[nwords] = fl[i];
- }
- }
- /* Clear fl[i], since the thread structure may hang around. */
- /* Do it in a way that is likely to trap if we access it. */
- fl[i] = (ptr_t)HBLKSIZE;
- }
-}
-
-/* We statically allocate a single "size 0" object. It is linked to */
-/* itself, and is thus repeatedly reused for all size 0 allocation */
-/* requests. (Size 0 gcj allocation requests are incorrect, and */
-/* we arrange for those to fault asap.) */
-static ptr_t size_zero_object = (ptr_t)(&size_zero_object);
-
-/* Each thread structure must be initialized. */
-/* This call must be made from the new thread. */
-/* Caller holds allocation lock. */
-void GC_init_thread_local(GC_thread p)
-{
- int i;
-
- if (!keys_initialized) {
- if (0 != GC_key_create(&GC_thread_key, 0)) {
- ABORT("Failed to create key for local allocator");
- }
- keys_initialized = TRUE;
- }
- if (0 != GC_setspecific(GC_thread_key, p)) {
- ABORT("Failed to set thread specific allocation pointers");
- }
- for (i = 1; i < NFREELISTS; ++i) {
- p -> ptrfree_freelists[i] = (ptr_t)1;
- p -> normal_freelists[i] = (ptr_t)1;
-# ifdef GC_GCJ_SUPPORT
- p -> gcj_freelists[i] = (ptr_t)1;
-# endif
- }
- /* Set up the size 0 free lists. */
- p -> ptrfree_freelists[0] = (ptr_t)(&size_zero_object);
- p -> normal_freelists[0] = (ptr_t)(&size_zero_object);
-# ifdef GC_GCJ_SUPPORT
- p -> gcj_freelists[0] = (ptr_t)(-1);
-# endif
-}
-
-#ifdef GC_GCJ_SUPPORT
- extern ptr_t * GC_gcjobjfreelist;
-#endif
-
-/* We hold the allocator lock. */
-void GC_destroy_thread_local(GC_thread p)
-{
- /* We currently only do this from the thread itself or from */
- /* the fork handler for a child process. */
-# ifndef HANDLE_FORK
- GC_ASSERT(GC_getspecific(GC_thread_key) == (void *)p);
-# endif
- return_freelists(p -> ptrfree_freelists, GC_aobjfreelist);
- return_freelists(p -> normal_freelists, GC_objfreelist);
-# ifdef GC_GCJ_SUPPORT
- return_freelists(p -> gcj_freelists, GC_gcjobjfreelist);
-# endif
-}
-
-extern GC_PTR GC_generic_malloc_many();
-
-GC_PTR GC_local_malloc(size_t bytes)
-{
- if (EXPECT(!SMALL_ENOUGH(bytes),0)) {
- return(GC_malloc(bytes));
- } else {
- int index = INDEX_FROM_BYTES(bytes);
- ptr_t * my_fl;
- ptr_t my_entry;
- GC_key_t k = GC_thread_key;
- void * tsd;
-
-# if defined(REDIRECT_MALLOC) && !defined(USE_PTHREAD_SPECIFIC)
- if (EXPECT(0 == k, 0)) {
- /* This can happen if we get called when the world is */
- /* being initialized. Whether we can actually complete */
- /* the initialization then is unclear. */
- GC_init_parallel();
- k = GC_thread_key;
- }
-# endif
- tsd = GC_getspecific(GC_thread_key);
-# ifdef GC_ASSERTIONS
- LOCK();
- GC_ASSERT(tsd == (void *)GC_lookup_thread(pthread_self()));
- UNLOCK();
-# endif
- my_fl = ((GC_thread)tsd) -> normal_freelists + index;
- my_entry = *my_fl;
- if (EXPECT((word)my_entry >= HBLKSIZE, 1)) {
- ptr_t next = obj_link(my_entry);
- GC_PTR result = (GC_PTR)my_entry;
- *my_fl = next;
- obj_link(my_entry) = 0;
- PREFETCH_FOR_WRITE(next);
- return result;
- } else if ((word)my_entry - 1 < DIRECT_GRANULES) {
- *my_fl = my_entry + index + 1;
- return GC_malloc(bytes);
- } else {
- GC_generic_malloc_many(BYTES_FROM_INDEX(index), NORMAL, my_fl);
- if (*my_fl == 0) return GC_oom_fn(bytes);
- return GC_local_malloc(bytes);
- }
- }
-}
-
-GC_PTR GC_local_malloc_atomic(size_t bytes)
-{
- if (EXPECT(!SMALL_ENOUGH(bytes), 0)) {
- return(GC_malloc_atomic(bytes));
- } else {
- int index = INDEX_FROM_BYTES(bytes);
- ptr_t * my_fl = ((GC_thread)GC_getspecific(GC_thread_key))
- -> ptrfree_freelists + index;
- ptr_t my_entry = *my_fl;
- if (EXPECT((word)my_entry >= HBLKSIZE, 1)) {
- GC_PTR result = (GC_PTR)my_entry;
- *my_fl = obj_link(my_entry);
- return result;
- } else if ((word)my_entry - 1 < DIRECT_GRANULES) {
- *my_fl = my_entry + index + 1;
- return GC_malloc_atomic(bytes);
- } else {
- GC_generic_malloc_many(BYTES_FROM_INDEX(index), PTRFREE, my_fl);
- /* *my_fl is updated while the collector is excluded; */
- /* the free list is always visible to the collector as */
- /* such. */
- if (*my_fl == 0) return GC_oom_fn(bytes);
- return GC_local_malloc_atomic(bytes);
- }
- }
-}
-
-#ifdef GC_GCJ_SUPPORT
-
-#include "include/gc_gcj.h"
-
-#ifdef GC_ASSERTIONS
- extern GC_bool GC_gcj_malloc_initialized;
-#endif
-
-extern int GC_gcj_kind;
-
-GC_PTR GC_local_gcj_malloc(size_t bytes,
- void * ptr_to_struct_containing_descr)
-{
- GC_ASSERT(GC_gcj_malloc_initialized);
- if (EXPECT(!SMALL_ENOUGH(bytes), 0)) {
- return GC_gcj_malloc(bytes, ptr_to_struct_containing_descr);
- } else {
- int index = INDEX_FROM_BYTES(bytes);
- ptr_t * my_fl = ((GC_thread)GC_getspecific(GC_thread_key))
- -> gcj_freelists + index;
- ptr_t my_entry = *my_fl;
- if (EXPECT((word)my_entry >= HBLKSIZE, 1)) {
- GC_PTR result = (GC_PTR)my_entry;
- GC_ASSERT(!GC_incremental);
- /* We assert that any concurrent marker will stop us. */
- /* Thus it is impossible for a mark procedure to see the */
- /* allocation of the next object, but to see this object */
- /* still containing a free list pointer. Otherwise the */
- /* marker might find a random "mark descriptor". */
- *(volatile ptr_t *)my_fl = obj_link(my_entry);
- /* We must update the freelist before we store the pointer. */
- /* Otherwise a GC at this point would see a corrupted */
- /* free list. */
- /* A memory barrier is probably never needed, since the */
- /* action of stopping this thread will cause prior writes */
- /* to complete. */
- GC_ASSERT(((void * volatile *)result)[1] == 0);
- *(void * volatile *)result = ptr_to_struct_containing_descr;
- return result;
- } else if ((word)my_entry - 1 < DIRECT_GRANULES) {
- if (!GC_incremental) *my_fl = my_entry + index + 1;
- /* In the incremental case, we always have to take this */
- /* path. Thus we leave the counter alone. */
- return GC_gcj_malloc(bytes, ptr_to_struct_containing_descr);
- } else {
- GC_generic_malloc_many(BYTES_FROM_INDEX(index), GC_gcj_kind, my_fl);
- if (*my_fl == 0) return GC_oom_fn(bytes);
- return GC_local_gcj_malloc(bytes, ptr_to_struct_containing_descr);
- }
- }
-}
-
-#endif /* GC_GCJ_SUPPORT */
-
-# else /* !THREAD_LOCAL_ALLOC && !DBG_HDRS_ALL */
-
-# define GC_destroy_thread_local(t)
-
-# endif /* !THREAD_LOCAL_ALLOC */
-
-/*
- * We use signals to stop threads during GC.
- *
- * Suspended threads wait in signal handler for SIG_THR_RESTART.
- * That's more portable than semaphores or condition variables.
- * (We do use sem_post from a signal handler, but that should be portable.)
- *
- * The thread suspension signal SIG_SUSPEND is now defined in gc_priv.h.
- * Note that we can't just stop a thread; we need it to save its stack
- * pointer(s) and acknowledge.
- */
-
-#ifndef SIG_THR_RESTART
-# if defined(GC_HPUX_THREADS) || defined(GC_OSF1_THREADS)
-# ifdef _SIGRTMIN
-# define SIG_THR_RESTART _SIGRTMIN + 5
-# else
-# define SIG_THR_RESTART SIGRTMIN + 5
-# endif
-# else
-# define SIG_THR_RESTART SIGXCPU
-# endif
-#endif
-
-#ifdef GC_MACOSX_THREADS
-# include <mach/task.h>
-# include <mach/mach_init.h>
-# include <mach/semaphore.h>
-
- semaphore_t GC_suspend_ack_sem;
-#else
- sem_t GC_suspend_ack_sem;
-#endif
-
-#if 0
-/*
-To make sure that we're using LinuxThreads and not some other thread
-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
-thread packages.
-
-We no longer do this, since this code is now portable enough that it might
-actually work for something else.
-*/
-void (*dummy_var_to_force_linux_threads)() = pthread_kill_other_threads_np;
-#endif /* 0 */
-
-#if defined(SPARC) || defined(IA64)
- extern word GC_save_regs_in_stack();
-#endif
-
-long GC_nprocs = 1; /* Number of processors. We may not have */
- /* access to all of them, but this is as good */
- /* a guess as any ... */
-
-#ifdef PARALLEL_MARK
-
-# ifndef MAX_MARKERS
-# define MAX_MARKERS 16
-# endif
-
-static ptr_t marker_sp[MAX_MARKERS] = {0};
-
-void * GC_mark_thread(void * id)
-{
- word my_mark_no = 0;
-
- marker_sp[(word)id] = GC_approx_sp();
- for (;; ++my_mark_no) {
- /* GC_mark_no is passed only to allow GC_help_marker to terminate */
- /* promptly. This is important if it were called from the signal */
- /* handler or from the GC lock acquisition code. Under Linux, it's */
- /* not safe to call it from a signal handler, since it uses mutexes */
- /* and condition variables. Since it is called only here, the */
- /* argument is unnecessary. */
- if (my_mark_no < GC_mark_no || my_mark_no > GC_mark_no + 2) {
- /* resynchronize if we get far off, e.g. because GC_mark_no */
- /* wrapped. */
- my_mark_no = GC_mark_no;
- }
-# ifdef DEBUG_THREADS
- GC_printf1("Starting mark helper for mark number %ld\n", my_mark_no);
-# endif
- GC_help_marker(my_mark_no);
- }
-}
-
-extern long GC_markers; /* Number of mark threads we would */
- /* like to have. Includes the */
- /* initiating thread. */
-
-pthread_t GC_mark_threads[MAX_MARKERS];
-
-#define PTHREAD_CREATE REAL_FUNC(pthread_create)
-
-static void start_mark_threads()
-{
- unsigned i;
- pthread_attr_t attr;
-
- if (GC_markers > MAX_MARKERS) {
- WARN("Limiting number of mark threads\n", 0);
- GC_markers = MAX_MARKERS;
- }
- if (0 != pthread_attr_init(&attr)) ABORT("pthread_attr_init failed");
-
- if (0 != pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED))
- ABORT("pthread_attr_setdetachstate failed");
-
-# if defined(HPUX) || defined(GC_DGUX386_THREADS)
- /* Default stack size is usually too small: fix it. */
- /* Otherwise marker threads or GC may run out of */
- /* space. */
-# define MIN_STACK_SIZE (8*HBLKSIZE*sizeof(word))
- {
- size_t old_size;
- int code;
-
- if (pthread_attr_getstacksize(&attr, &old_size) != 0)
- ABORT("pthread_attr_getstacksize failed\n");
- if (old_size < MIN_STACK_SIZE) {
- if (pthread_attr_setstacksize(&attr, MIN_STACK_SIZE) != 0)
- ABORT("pthread_attr_setstacksize failed\n");
- }
- }
-# endif /* HPUX || GC_DGUX386_THREADS */
-# ifdef CONDPRINT
- if (GC_print_stats) {
- GC_printf1("Starting %ld marker threads\n", GC_markers - 1);
- }
-# endif
- for (i = 0; i < GC_markers - 1; ++i) {
- if (0 != PTHREAD_CREATE(GC_mark_threads + i, &attr,
- GC_mark_thread, (void *)(word)i)) {
- WARN("Marker thread creation failed, errno = %ld.\n", errno);
- }
- }
-}
-
-#else /* !PARALLEL_MARK */
-
-static __inline__ void start_mark_threads()
-{
-}
-
-#endif /* !PARALLEL_MARK */
-
-void GC_suspend_handler(int sig)
-{
- int dummy;
- pthread_t my_thread = pthread_self();
- GC_thread me;
- sigset_t all_sigs;
- sigset_t old_sigs;
- int i;
- sigset_t mask;
-# ifdef PARALLEL_MARK
- word my_mark_no = GC_mark_no;
- /* Marker can't proceed until we acknowledge. Thus this is */
- /* guaranteed to be the mark_no correspending to our */
- /* suspension, i.e. the marker can't have incremented it yet. */
-# endif
- word my_stop_count = GC_stop_count;
-
- if (sig != SIG_SUSPEND) ABORT("Bad signal in suspend_handler");
-
-#if DEBUG_THREADS
- GC_printf1("Suspending 0x%lx\n", my_thread);
-#endif
-
- me = GC_lookup_thread(my_thread);
- /* The lookup here is safe, since I'm doing this on behalf */
- /* of a thread which holds the allocation lock in order */
- /* to stop the world. Thus concurrent modification of the */
- /* data structure is impossible. */
- if (me -> last_stop_count == my_stop_count) {
- /* Duplicate signal. OK if we are retrying. */
- if (!GC_retry_signals) {
- WARN("Duplicate suspend signal in thread %lx\n",
- pthread_self());
- }
- return;
- }
-# ifdef SPARC
- me -> stack_ptr = (ptr_t)GC_save_regs_in_stack();
-# else
- me -> stack_ptr = (ptr_t)(&dummy);
-# endif
-# ifdef IA64
- me -> backing_store_ptr = (ptr_t)GC_save_regs_in_stack();
-# endif
-
- /* Tell the thread that wants to stop the world that this */
- /* thread has been stopped. Note that sem_post() is */
- /* the only async-signal-safe primitive in LinuxThreads. */
-# ifdef GC_MACOSX_THREADS
- semaphore_signal(GC_suspend_ack_sem);
-# else
- sem_post(&GC_suspend_ack_sem);
-# endif
- me -> last_stop_count = my_stop_count;
-
- /* Wait until that thread tells us to restart by sending */
- /* this thread a SIG_THR_RESTART signal. */
- /* SIG_THR_RESTART should be masked at this point. Thus there */
- /* is no race. */
- if (sigfillset(&mask) != 0) ABORT("sigfillset() failed");
- if (sigdelset(&mask, SIG_THR_RESTART) != 0) ABORT("sigdelset() failed");
-# ifdef NO_SIGNALS
- if (sigdelset(&mask, SIGINT) != 0) ABORT("sigdelset() failed");
- if (sigdelset(&mask, SIGQUIT) != 0) ABORT("sigdelset() failed");
- if (sigdelset(&mask, SIGTERM) != 0) ABORT("sigdelset() failed");
- if (sigdelset(&mask, SIGABRT) != 0) ABORT("sigdelset() failed");
-# endif
- do {
- me->signal = 0;
- sigsuspend(&mask); /* Wait for signal */
- } while (me->signal != SIG_THR_RESTART);
- /* If the RESTART signal gets lost, we can still lose. That should be */
- /* less likely than losing the SUSPEND signal, since we don't do much */
- /* between the sem_post and sigsuspend. */
- /* We'd need more handshaking to work around that, since we don't want */
- /* to accidentally leave a RESTART signal pending, thus causing us to */
- /* continue prematurely in a future round. */
-
-#if DEBUG_THREADS
- GC_printf1("Continuing 0x%lx\n", my_thread);
-#endif
-}
-
-void GC_restart_handler(int sig)
-{
- GC_thread me;
-
- if (sig != SIG_THR_RESTART) ABORT("Bad signal in suspend_handler");
-
- /* Let the GC_suspend_handler() know that we got a SIG_THR_RESTART. */
- /* The lookup here is safe, since I'm doing this on behalf */
- /* of a thread which holds the allocation lock in order */
- /* to stop the world. Thus concurrent modification of the */
- /* data structure is impossible. */
- me = GC_lookup_thread(pthread_self());
- me->signal = SIG_THR_RESTART;
-
- /*
- ** Note: even if we didn't do anything useful here,
- ** it would still be necessary to have a signal handler,
- ** rather than ignoring the signals, otherwise
- ** the signals will not be delivered at all, and
- ** will thus not interrupt the sigsuspend() above.
- */
-
-#if DEBUG_THREADS
- GC_printf1("In GC_restart_handler for 0x%lx\n", pthread_self());
-#endif
-}
-
-/* Defining INSTALL_LOOPING_SEGV_HANDLER causes SIGSEGV and SIGBUS to */
-/* result in an infinite loop in a signal handler. This can be very */
-/* useful for debugging, since (as of RH7) gdb still seems to have */
-/* serious problems with threads. */
-#ifdef INSTALL_LOOPING_SEGV_HANDLER
-void GC_looping_handler(int sig)
-{
- GC_printf3("Signal %ld in thread %lx, pid %ld\n",
- sig, pthread_self(), getpid());
- for (;;);
-}
-#endif
-
-GC_bool GC_thr_initialized = FALSE;
-
-# define THREAD_TABLE_SZ 128 /* Must be power of 2 */
-volatile GC_thread GC_threads[THREAD_TABLE_SZ];
-
-void GC_push_thread_structures GC_PROTO((void))
-{
- GC_push_all((ptr_t)(GC_threads), (ptr_t)(GC_threads)+sizeof(GC_threads));
-# if defined(THREAD_LOCAL_ALLOC) && !defined(DBG_HDRS_ALL)
- GC_push_all((ptr_t)(&GC_thread_key),
- (ptr_t)(&GC_thread_key)+sizeof(&GC_thread_key));
-# endif
-}
-
-#ifdef THREAD_LOCAL_ALLOC
-/* We must explicitly mark ptrfree and gcj free lists, since the free */
-/* list links wouldn't otherwise be found. We also set them in the */
-/* normal free lists, since that involves touching less memory than if */
-/* we scanned them normally. */
-void GC_mark_thread_local_free_lists(void)
-{
- int i, j;
- GC_thread p;
- ptr_t q;
-
- for (i = 0; i < THREAD_TABLE_SZ; ++i) {
- for (p = GC_threads[i]; 0 != p; p = p -> next) {
- for (j = 1; j < NFREELISTS; ++j) {
- q = p -> ptrfree_freelists[j];
- if ((word)q > HBLKSIZE) GC_set_fl_marks(q);
- q = p -> normal_freelists[j];
- if ((word)q > HBLKSIZE) GC_set_fl_marks(q);
-# ifdef GC_GCJ_SUPPORT
- q = p -> gcj_freelists[j];
- if ((word)q > HBLKSIZE) GC_set_fl_marks(q);
-# endif /* GC_GCJ_SUPPORT */
- }
- }
- }
-}
-#endif /* THREAD_LOCAL_ALLOC */
-
-static struct GC_Thread_Rep first_thread;
-
-/* Add a thread to GC_threads. We assume it wasn't already there. */
-/* Caller holds allocation lock. */
-GC_thread GC_new_thread(pthread_t id)
-{
- int hv = ((word)id) % THREAD_TABLE_SZ;
- GC_thread result;
- static GC_bool first_thread_used = FALSE;
-
- if (!first_thread_used) {
- result = &first_thread;
- first_thread_used = TRUE;
- } else {
- result = (struct GC_Thread_Rep *)
- GC_INTERNAL_MALLOC(sizeof(struct GC_Thread_Rep), NORMAL);
- }
- if (result == 0) return(0);
- result -> id = id;
- result -> next = GC_threads[hv];
- GC_threads[hv] = result;
- GC_ASSERT(result -> flags == 0 && result -> thread_blocked == 0);
- return(result);
-}
-
-/* Delete a thread from GC_threads. We assume it is there. */
-/* (The code intentionally traps if it wasn't.) */
-/* Caller holds allocation lock. */
-void GC_delete_thread(pthread_t id)
-{
- int hv = ((word)id) % THREAD_TABLE_SZ;
- register GC_thread p = GC_threads[hv];
- register GC_thread prev = 0;
-
- while (!pthread_equal(p -> id, id)) {
- prev = p;
- p = p -> next;
- }
- if (prev == 0) {
- GC_threads[hv] = p -> next;
- } else {
- prev -> next = p -> next;
- }
- GC_INTERNAL_FREE(p);
-}
-
-/* If a thread has been joined, but we have not yet */
-/* been notified, then there may be more than one thread */
-/* in the table with the same pthread id. */
-/* This is OK, but we need a way to delete a specific one. */
-void GC_delete_gc_thread(pthread_t id, GC_thread gc_id)
-{
- int hv = ((word)id) % THREAD_TABLE_SZ;
- register GC_thread p = GC_threads[hv];
- register GC_thread prev = 0;
-
- while (p != gc_id) {
- prev = p;
- p = p -> next;
- }
- if (prev == 0) {
- GC_threads[hv] = p -> next;
- } else {
- prev -> next = p -> next;
- }
- GC_INTERNAL_FREE(p);
-}
-
-/* Return a GC_thread corresponding to a given thread_t. */
-/* Returns 0 if it's not there. */
-/* Caller holds allocation lock or otherwise inhibits */
-/* updates. */
-/* If there is more than one thread with the given id we */
-/* return the most recent one. */
-GC_thread GC_lookup_thread(pthread_t id)
-{
- int hv = ((word)id) % THREAD_TABLE_SZ;
- register GC_thread p = GC_threads[hv];
-
- while (p != 0 && !pthread_equal(p -> id, id)) p = p -> next;
- return(p);
-}
-
-#ifdef HANDLE_FORK
-/* Remove all entries from the GC_threads table, except the */
-/* one for the current thread. We need to do this in the child */
-/* process after a fork(), since only the current thread */
-/* survives in the child. */
-void GC_remove_all_threads_but_me(void)
-{
- pthread_t self = pthread_self();
- int hv;
- GC_thread p, next, me;
-
- for (hv = 0; hv < THREAD_TABLE_SZ; ++hv) {
- me = 0;
- for (p = GC_threads[hv]; 0 != p; p = next) {
- next = p -> next;
- if (p -> id == self) {
- me = p;
- p -> next = 0;
- } else {
-# ifdef THREAD_LOCAL_ALLOC
- if (!(p -> flags & FINISHED)) {
- GC_destroy_thread_local(p);
- }
-# endif /* THREAD_LOCAL_ALLOC */
- if (p != &first_thread) GC_INTERNAL_FREE(p);
- }
- }
- GC_threads[hv] = me;
- }
-}
-#endif /* HANDLE_FORK */
-
-/* There seems to be a very rare thread stopping problem. To help us */
-/* debug that, we save the ids of the stopping thread. */
-pthread_t GC_stopping_thread;
-int GC_stopping_pid;
-
-/* We hold the allocation lock. Suspend all threads that might */
-/* still be running. Return the number of suspend signals that */
-/* were sent. */
-int GC_suspend_all()
-{
- int n_live_threads = 0;
- int i;
- GC_thread p;
- int result;
- pthread_t my_thread = pthread_self();
-
- GC_stopping_thread = my_thread; /* debugging only. */
- GC_stopping_pid = getpid(); /* debugging only. */
- for (i = 0; i < THREAD_TABLE_SZ; i++) {
- for (p = GC_threads[i]; p != 0; p = p -> next) {
- if (p -> id != my_thread) {
- if (p -> flags & FINISHED) continue;
- if (p -> last_stop_count == GC_stop_count) continue;
- if (p -> thread_blocked) /* Will wait */ continue;
- n_live_threads++;
- #if DEBUG_THREADS
- GC_printf1("Sending suspend signal to 0x%lx\n", p -> id);
- #endif
- result = pthread_kill(p -> id, SIG_SUSPEND);
- switch(result) {
- case ESRCH:
- n_live_threads--;
- break;
- case 0:
- break;
- default:
- ABORT("pthread_kill failed");
- }
- }
- }
- }
- return n_live_threads;
-}
-
-/* Caller holds allocation lock. */
-void GC_stop_world()
-{
- register int i;
- register int n_live_threads;
-
- /* Make sure all free list construction has stopped before we start. */
- /* No new construction can start, since free list construction is */
- /* required to acquire and release the GC lock before it starts, */
- /* and we have the lock. */
-# ifdef PARALLEL_MARK
- GC_acquire_mark_lock();
- GC_ASSERT(GC_fl_builder_count == 0);
- /* We should have previously waited for it to become zero. */
-# endif /* PARALLEL_MARK */
- ++GC_stop_count;
- n_live_threads = GC_suspend_all();
- /* sem_getvalue() is not suppored on OS X, and there does not appear */
- /* to be a mach equivalent, so we disable this code. */
-# ifndef GC_MACOSX_THREADS
- if (GC_retry_signals) {
- unsigned long wait_usecs = 0; /* Total wait since retry. */
-# define WAIT_UNIT 3000
-# define RETRY_INTERVAL 100000
- for (;;) {
- int ack_count;
-
- sem_getvalue(&GC_suspend_ack_sem, &ack_count);
- if (ack_count == n_live_threads) break;
- if (wait_usecs > RETRY_INTERVAL) {
- int newly_sent = GC_suspend_all();
-
-# ifdef CONDPRINT
- if (GC_print_stats) {
- GC_printf1("Resent %ld signals after timeout\n",
- newly_sent);
- }
-# endif
- sem_getvalue(&GC_suspend_ack_sem, &ack_count);
- if (newly_sent < n_live_threads - ack_count) {
- WARN("Lost some threads during GC_stop_world?!\n",0);
- n_live_threads = ack_count + newly_sent;
- }
- wait_usecs = 0;
- }
- usleep(WAIT_UNIT);
- wait_usecs += WAIT_UNIT;
- }
- }
-# endif /* GC_MACOSX_THREADS */
- for (i = 0; i < n_live_threads; i++) {
-# ifdef GC_MACOSX_THREADS
- if (KERN_SUCCESS != semaphore_wait(GC_suspend_ack_sem))
- ABORT("semaphore_wait in handler failed");
-# else
- if (0 != sem_wait(&GC_suspend_ack_sem))
- ABORT("sem_wait in handler failed");
-# endif
- }
-# ifdef PARALLEL_MARK
- GC_release_mark_lock();
-# endif
- #if DEBUG_THREADS
- GC_printf1("World stopped from 0x%lx\n", pthread_self());
- #endif
- GC_stopping_thread = 0; /* debugging only */
-}
-
-/* Caller holds allocation lock, and has held it continuously since */
-/* the world stopped. */
-void GC_start_world()
-{
- pthread_t my_thread = pthread_self();
- register int i;
- register GC_thread p;
- register int n_live_threads = 0;
- register int result;
-
-# if DEBUG_THREADS
- GC_printf0("World starting\n");
-# endif
-
- for (i = 0; i < THREAD_TABLE_SZ; i++) {
- for (p = GC_threads[i]; p != 0; p = p -> next) {
- if (p -> id != my_thread) {
- if (p -> flags & FINISHED) continue;
- if (p -> thread_blocked) continue;
- n_live_threads++;
- #if DEBUG_THREADS
- GC_printf1("Sending restart signal to 0x%lx\n", p -> id);
- #endif
- result = pthread_kill(p -> id, SIG_THR_RESTART);
- switch(result) {
- case ESRCH:
- n_live_threads--;
- break;
- case 0:
- break;
- default:
- ABORT("pthread_kill failed");
- }
- }
- }
- }
- #if DEBUG_THREADS
- GC_printf0("World started\n");
- #endif
-}
-
-# ifdef IA64
-# define IF_IA64(x) x
-# else
-# define IF_IA64(x)
-# endif
-/* We hold allocation lock. Should do exactly the right thing if the */
-/* world is stopped. Should not fail if it isn't. */
-void GC_push_all_stacks()
-{
- int i;
- GC_thread p;
- ptr_t sp = GC_approx_sp();
- ptr_t lo, hi;
- /* On IA64, we also need to scan the register backing store. */
- IF_IA64(ptr_t bs_lo; ptr_t bs_hi;)
- pthread_t me = pthread_self();
-
- if (!GC_thr_initialized) GC_thr_init();
- #if DEBUG_THREADS
- GC_printf1("Pushing stacks from thread 0x%lx\n", (unsigned long) me);
- #endif
- for (i = 0; i < THREAD_TABLE_SZ; i++) {
- for (p = GC_threads[i]; p != 0; p = p -> next) {
- if (p -> flags & FINISHED) continue;
- if (pthread_equal(p -> id, me)) {
-# ifdef SPARC
- lo = (ptr_t)GC_save_regs_in_stack();
-# else
- lo = GC_approx_sp();
-# endif
- IF_IA64(bs_hi = (ptr_t)GC_save_regs_in_stack();)
- } else {
- lo = p -> stack_ptr;
- IF_IA64(bs_hi = p -> backing_store_ptr;)
- }
- if ((p -> flags & MAIN_THREAD) == 0) {
- hi = p -> stack_end;
- IF_IA64(bs_lo = p -> backing_store_end);
- } else {
- /* The original stack. */
- hi = GC_stackbottom;
- IF_IA64(bs_lo = BACKING_STORE_BASE;)
- }
- #if DEBUG_THREADS
- GC_printf3("Stack for thread 0x%lx = [%lx,%lx)\n",
- (unsigned long) p -> id,
- (unsigned long) lo, (unsigned long) hi);
- #endif
- if (0 == lo) ABORT("GC_push_all_stacks: sp not set!\n");
-# ifdef STACK_GROWS_UP
- /* We got them backwards! */
- GC_push_all_stack(hi, lo);
-# else
- GC_push_all_stack(lo, hi);
-# endif
-# ifdef IA64
- if (pthread_equal(p -> id, me)) {
- GC_push_all_eager(bs_lo, bs_hi);
- } else {
- GC_push_all_stack(bs_lo, bs_hi);
- }
-# endif
- }
- }
-}
-
-#ifdef USE_PROC_FOR_LIBRARIES
-int GC_segment_is_thread_stack(ptr_t lo, ptr_t hi)
-{
- int i;
- GC_thread p;
-
-# ifdef PARALLEL_MARK
- for (i = 0; i < GC_markers; ++i) {
- if (marker_sp[i] > lo & marker_sp[i] < hi) return 1;
- }
-# endif
- for (i = 0; i < THREAD_TABLE_SZ; i++) {
- for (p = GC_threads[i]; p != 0; p = p -> next) {
- if (0 != p -> stack_end) {
-# ifdef STACK_GROWS_UP
- if (p -> stack_end >= lo && p -> stack_end < hi) return 1;
-# else /* STACK_GROWS_DOWN */
- if (p -> stack_end > lo && p -> stack_end <= hi) return 1;
-# endif
- }
- }
- }
- return 0;
-}
-#endif /* USE_PROC_FOR_LIBRARIES */
-
-#ifdef GC_LINUX_THREADS
-/* Return the number of processors, or i<= 0 if it can't be determined. */
-int GC_get_nprocs()
-{
- /* Should be "return sysconf(_SC_NPROCESSORS_ONLN);" but that */
- /* appears to be buggy in many cases. */
- /* We look for lines "cpu<n>" in /proc/stat. */
-# define STAT_BUF_SIZE 4096
-# if defined(GC_USE_LD_WRAP)
-# define STAT_READ __real_read
-# else
-# define STAT_READ read
-# endif
- char stat_buf[STAT_BUF_SIZE];
- int f;
- char c;
- word result = 1;
- /* Some old kernels only have a single "cpu nnnn ..." */
- /* entry in /proc/stat. We identify those as */
- /* uniprocessors. */
- size_t i, len = 0;
-
- f = open("/proc/stat", O_RDONLY);
- if (f < 0 || (len = STAT_READ(f, stat_buf, STAT_BUF_SIZE)) < 100) {
- WARN("Couldn't read /proc/stat\n", 0);
- return -1;
- }
- for (i = 0; i < len - 100; ++i) {
- if (stat_buf[i] == '\n' && stat_buf[i+1] == 'c'
- && stat_buf[i+2] == 'p' && stat_buf[i+3] == 'u') {
- int cpu_no = atoi(stat_buf + i + 4);
- if (cpu_no >= result) result = cpu_no + 1;
- }
- }
- close(f);
- return result;
-}
-#endif /* GC_LINUX_THREADS */
-
-/* We hold the GC lock. Wait until an in-progress GC has finished. */
-/* Repeatedly RELEASES GC LOCK in order to wait. */
-/* If wait_for_all is true, then we exit with the GC lock held and no */
-/* collection in progress; otherwise we just wait for the current GC */
-/* to finish. */
-void GC_wait_for_gc_completion(GC_bool wait_for_all)
-{
- if (GC_incremental && GC_collection_in_progress()) {
- int old_gc_no = GC_gc_no;
-
- /* Make sure that no part of our stack is still on the mark stack, */
- /* since it's about to be unmapped. */
- while (GC_incremental && GC_collection_in_progress()
- && (wait_for_all || old_gc_no == GC_gc_no)) {
- ENTER_GC();
- GC_collect_a_little_inner(1);
- EXIT_GC();
- UNLOCK();
- sched_yield();
- LOCK();
- }
- }
-}
-
-#ifdef HANDLE_FORK
-/* Procedures called before and after a fork. The goal here is to make */
-/* it safe to call GC_malloc() in a forked child. It's unclear that is */
-/* attainable, since the single UNIX spec seems to imply that one */
-/* should only call async-signal-safe functions, and we probably can't */
-/* quite guarantee that. But we give it our best shot. (That same */
-/* spec also implies that it's not safe to call the system malloc */
-/* between fork() and exec(). Thus we're doing no worse than it. */
-
-/* Called before a fork() */
-void GC_fork_prepare_proc(void)
-{
- /* Acquire all relevant locks, so that after releasing the locks */
- /* the child will see a consistent state in which monitor */
- /* invariants hold. Unfortunately, we can't acquire libc locks */
- /* we might need, and there seems to be no guarantee that libc */
- /* must install a suitable fork handler. */
- /* Wait for an ongoing GC to finish, since we can't finish it in */
- /* the (one remaining thread in) the child. */
- LOCK();
-# if defined(PARALLEL_MARK) || defined(THREAD_LOCAL_ALLOC)
- GC_wait_for_reclaim();
-# endif
- GC_wait_for_gc_completion(TRUE);
-# if defined(PARALLEL_MARK) || defined(THREAD_LOCAL_ALLOC)
- GC_acquire_mark_lock();
-# endif
-}
-
-/* Called in parent after a fork() */
-void GC_fork_parent_proc(void)
-{
-# if defined(PARALLEL_MARK) || defined(THREAD_LOCAL_ALLOC)
- GC_release_mark_lock();
-# endif
- UNLOCK();
-}
-
-/* Called in child after a fork() */
-void GC_fork_child_proc(void)
-{
- /* Clean up the thread table, so that just our thread is left. */
-# if defined(PARALLEL_MARK) || defined(THREAD_LOCAL_ALLOC)
- GC_release_mark_lock();
-# endif
- GC_remove_all_threads_but_me();
-# ifdef PARALLEL_MARK
- /* Turn off parallel marking in the child, since we are probably */
- /* just going to exec, and we would have to restart mark threads. */
- GC_markers = 1;
- GC_parallel = FALSE;
-# endif /* PARALLEL_MARK */
- UNLOCK();
-}
-#endif /* HANDLE_FORK */
-
-#if defined(GC_DGUX386_THREADS)
-/* Return the number of processors, or i<= 0 if it can't be determined. */
-int GC_get_nprocs()
-{
- /* <takis at XFree86.Org> */
- int numCpus;
- struct dg_sys_info_pm_info pm_sysinfo;
- int status =0;
-
- status = dg_sys_info((long int *) &pm_sysinfo,
- DG_SYS_INFO_PM_INFO_TYPE, DG_SYS_INFO_PM_CURRENT_VERSION);
- if (status < 0)
- /* set -1 for error */
- numCpus = -1;
- else
- /* Active CPUs */
- numCpus = pm_sysinfo.idle_vp_count;
-
-# ifdef DEBUG_THREADS
- GC_printf1("Number of active CPUs in this system: %d\n", numCpus);
-# endif
- return(numCpus);
-}
-#endif /* GC_DGUX386_THREADS */
-
-/* We hold the allocation lock. */
-void GC_thr_init()
-{
- int dummy;
- GC_thread t;
- struct sigaction act;
-
- if (GC_thr_initialized) return;
- GC_thr_initialized = TRUE;
-
-# ifdef GC_MACOSX_THREADS
- if (semaphore_create(mach_task_self(), &GC_suspend_ack_sem,
- SYNC_POLICY_FIFO, 0) != KERN_SUCCESS)
- ABORT("semaphore_create failed");
-# else
- if (sem_init(&GC_suspend_ack_sem, 0, 0) != 0)
- ABORT("sem_init failed");
-# endif
-
- act.sa_flags = SA_RESTART;
- if (sigfillset(&act.sa_mask) != 0) {
- ABORT("sigfillset() failed");
- }
-# ifdef NO_SIGNALS
- if (sigdelset(&act.sa_mask, SIGINT) != 0
- || sigdelset(&act.sa_mask, SIGQUIT != 0)
- || sigdelset(&act.sa_mask, SIGABRT != 0)
- || sigdelset(&act.sa_mask, SIGTERM != 0)) {
- ABORT("sigdelset() failed");
- }
-# endif
-
- /* SIG_THR_RESTART is unmasked by the handler when necessary. */
- act.sa_handler = GC_suspend_handler;
- if (sigaction(SIG_SUSPEND, &act, NULL) != 0) {
- ABORT("Cannot set SIG_SUSPEND handler");
- }
-
- act.sa_handler = GC_restart_handler;
- if (sigaction(SIG_THR_RESTART, &act, NULL) != 0) {
- ABORT("Cannot set SIG_THR_RESTART handler");
- }
-# ifdef HANDLE_FORK
- /* Prepare for a possible fork. */
- pthread_atfork(GC_fork_prepare_proc, GC_fork_parent_proc,
- GC_fork_child_proc);
-# endif /* HANDLE_FORK */
- /* Add the initial thread, so we can stop it. */
- t = GC_new_thread(pthread_self());
- t -> stack_ptr = (ptr_t)(&dummy);
- t -> flags = DETACHED | MAIN_THREAD;
-
- /* Check for GC_RETRY_SIGNALS. */
- if (0 != GETENV("GC_RETRY_SIGNALS")) {
- GC_retry_signals = TRUE;
- }
- if (0 != GETENV("GC_NO_RETRY_SIGNALS")) {
- GC_retry_signals = FALSE;
- }
-# ifdef CONDPRINT
- if (GC_print_stats && GC_retry_signals) {
- GC_printf0("Will retry suspend signal if necessary.\n");
- }
-# endif
-
- /* Set GC_nprocs. */
- {
- char * nprocs_string = GETENV("GC_NPROCS");
- GC_nprocs = -1;
- if (nprocs_string != NULL) GC_nprocs = atoi(nprocs_string);
- }
- if (GC_nprocs <= 0) {
-# if defined(GC_HPUX_THREADS)
- GC_nprocs = pthread_num_processors_np();
-# endif
-# if defined(GC_OSF1_THREADS)
- GC_nprocs = sysconf(_SC_NPROCESSORS_ONLN);
- if (GC_nprocs <= 0) GC_nprocs = 1;
-# endif
-# if defined(GC_FREEBSD_THREADS)
- GC_nprocs = 1;
-# endif
-# if defined(GC_MACOSX_THREADS)
- int ncpus = 1;
- size_t len = sizeof(ncpus);
- sysctl((int[2]) {CTL_HW, HW_NCPU}, 2, &ncpus, &len, NULL, 0);
- GC_nprocs = ncpus;
-# endif
-# if defined(GC_LINUX_THREADS) || defined(GC_DGUX386_THREADS)
- GC_nprocs = GC_get_nprocs();
-# endif
- }
- if (GC_nprocs <= 0) {
- WARN("GC_get_nprocs() returned %ld\n", GC_nprocs);
- GC_nprocs = 2;
-# ifdef PARALLEL_MARK
- GC_markers = 1;
-# endif
- } else {
-# ifdef PARALLEL_MARK
- {
- char * markers_string = GETENV("GC_MARKERS");
- if (markers_string != NULL) {
- GC_markers = atoi(markers_string);
- } else {
- GC_markers = GC_nprocs;
- }
- }
-# endif
- }
-# ifdef PARALLEL_MARK
-# ifdef CONDPRINT
- if (GC_print_stats) {
- GC_printf2("Number of processors = %ld, "
- "number of marker threads = %ld\n", GC_nprocs, GC_markers);
- }
-# endif
- if (GC_markers == 1) {
- GC_parallel = FALSE;
-# ifdef CONDPRINT
- if (GC_print_stats) {
- GC_printf0("Single marker thread, turning off parallel marking\n");
- }
-# endif
- } else {
- GC_parallel = TRUE;
- /* Disable true incremental collection, but generational is OK. */
- GC_time_limit = GC_TIME_UNLIMITED;
- }
-# endif
-}
-
-
-/* Perform all initializations, including those that */
-/* may require allocation. */
-/* Called without allocation lock. */
-/* Must be called before a second thread is created. */
-/* Called without allocation lock. */
-void GC_init_parallel()
-{
- if (parallel_initialized) return;
- parallel_initialized = TRUE;
- /* GC_init() calls us back, so set flag first. */
- if (!GC_is_initialized) GC_init();
- /* If we are using a parallel marker, start the helper threads. */
-# ifdef PARALLEL_MARK
- if (GC_parallel) start_mark_threads();
-# endif
- /* Initialize thread local free lists if used. */
-# if defined(THREAD_LOCAL_ALLOC) && !defined(DBG_HDRS_ALL)
- LOCK();
- GC_init_thread_local(GC_lookup_thread(pthread_self()));
- UNLOCK();
-# endif
-}
-
-
-int WRAP_FUNC(pthread_sigmask)(int how, const sigset_t *set, sigset_t *oset)
-{
- sigset_t fudged_set;
-
- if (set != NULL && (how == SIG_BLOCK || how == SIG_SETMASK)) {
- fudged_set = *set;
- sigdelset(&fudged_set, SIG_SUSPEND);
- set = &fudged_set;
- }
- return(REAL_FUNC(pthread_sigmask)(how, set, oset));
-}
-
-/* Wrappers for functions that are likely to block for an appreciable */
-/* length of time. Must be called in pairs, if at all. */
-/* Nothing much beyond the system call itself should be executed */
-/* between these. */
-
-void GC_start_blocking(void) {
-# define SP_SLOP 128
- GC_thread me;
- LOCK();
- me = GC_lookup_thread(pthread_self());
- GC_ASSERT(!(me -> thread_blocked));
-# ifdef SPARC
- me -> stack_ptr = (ptr_t)GC_save_regs_in_stack();
-# else
- me -> stack_ptr = (ptr_t)GC_approx_sp();
-# endif
-# ifdef IA64
- me -> backing_store_ptr = (ptr_t)GC_save_regs_in_stack() + SP_SLOP;
-# endif
- /* Add some slop to the stack pointer, since the wrapped call may */
- /* end up pushing more callee-save registers. */
-# ifdef STACK_GROWS_UP
- me -> stack_ptr += SP_SLOP;
-# else
- me -> stack_ptr -= SP_SLOP;
-# endif
- me -> thread_blocked = TRUE;
- UNLOCK();
-}
-
-GC_end_blocking(void) {
- GC_thread me;
- LOCK(); /* This will block if the world is stopped. */
- me = GC_lookup_thread(pthread_self());
- GC_ASSERT(me -> thread_blocked);
- me -> thread_blocked = FALSE;
- UNLOCK();
-}
-
-#if defined(GC_DGUX386_THREADS)
-#define __d10_sleep sleep
-#endif /* GC_DGUX386_THREADS */
-
-/* A wrapper for the standard C sleep function */
-int WRAP_FUNC(sleep) (unsigned int seconds)
-{
- int result;
-
- GC_start_blocking();
- result = REAL_FUNC(sleep)(seconds);
- GC_end_blocking();
- return result;
-}
-
-struct start_info {
- void *(*start_routine)(void *);
- void *arg;
- word flags;
-#ifdef GC_MACOSX_THREADS
- semaphore_t registered;
-#else
- sem_t registered; /* 1 ==> in our thread table, but */
- /* parent hasn't yet noticed. */
-#endif
-};
-
-/* Called at thread exit. */
-/* Never called for main thread. That's OK, since it */
-/* results in at most a tiny one-time leak. And */
-/* linuxthreads doesn't reclaim the main threads */
-/* resources or id anyway. */
-void GC_thread_exit_proc(void *arg)
-{
- GC_thread me;
-
- LOCK();
- me = GC_lookup_thread(pthread_self());
- GC_destroy_thread_local(me);
- if (me -> flags & DETACHED) {
- GC_delete_thread(pthread_self());
- } else {
- me -> flags |= FINISHED;
- }
-# if defined(THREAD_LOCAL_ALLOC) && !defined(USE_PTHREAD_SPECIFIC) \
- && !defined(USE_HPUX_TLS) && !defined(DBG_HDRS_ALL)
- GC_remove_specific(GC_thread_key);
-# endif
- GC_wait_for_gc_completion(FALSE);
- UNLOCK();
-}
-
-int WRAP_FUNC(pthread_join)(pthread_t thread, void **retval)
-{
- int result;
- GC_thread thread_gc_id;
-
- LOCK();
- thread_gc_id = GC_lookup_thread(thread);
- /* This is guaranteed to be the intended one, since the thread id */
- /* cant have been recycled by pthreads. */
- UNLOCK();
- result = REAL_FUNC(pthread_join)(thread, retval);
-# if defined (GC_FREEBSD_THREADS)
- /* On FreeBSD, the wrapped pthread_join() sometimes returns (what
- appears to be) a spurious EINTR which caused the test and real code
- to gratuitously fail. Having looked at system pthread library source
- code, I see how this return code may be generated. In one path of
- code, pthread_join() just returns the errno setting of the thread
- being joined. This does not match the POSIX specification or the
- local man pages thus I have taken the liberty to catch this one
- spurious return value properly conditionalized on GC_FREEBSD_THREADS. */
- if (result == EINTR) result = 0;
-# endif
- if (result == 0) {
- LOCK();
- /* Here the pthread thread id may have been recycled. */
- GC_delete_gc_thread(thread, thread_gc_id);
- UNLOCK();
- }
- return result;
-}
-
-int
-WRAP_FUNC(pthread_detach)(pthread_t thread)
-{
- int result;
- GC_thread thread_gc_id;
-
- LOCK();
- thread_gc_id = GC_lookup_thread(thread);
- UNLOCK();
- result = REAL_FUNC(pthread_detach)(thread);
- if (result == 0) {
- LOCK();
- thread_gc_id -> flags |= DETACHED;
- /* Here the pthread thread id may have been recycled. */
- if (thread_gc_id -> flags & FINISHED) {
- GC_delete_gc_thread(thread, thread_gc_id);
- }
- UNLOCK();
- }
- return result;
-}
-
-void * GC_start_routine(void * arg)
-{
- int dummy;
- struct start_info * si = arg;
- void * result;
- GC_thread me;
- pthread_t my_pthread;
- void *(*start)(void *);
- void *start_arg;
-
- my_pthread = pthread_self();
-# ifdef DEBUG_THREADS
- GC_printf1("Starting thread 0x%lx\n", my_pthread);
- GC_printf1("pid = %ld\n", (long) getpid());
- GC_printf1("sp = 0x%lx\n", (long) &arg);
-# endif
- LOCK();
- me = GC_new_thread(my_pthread);
- me -> flags = si -> flags;
- me -> stack_ptr = 0;
- /* me -> stack_end = GC_linux_stack_base(); -- currently (11/99) */
- /* doesn't work because the stack base in /proc/self/stat is the */
- /* one for the main thread. There is a strong argument that that's */
- /* a kernel bug, but a pervasive one. */
-# ifdef STACK_GROWS_DOWN
- me -> stack_end = (ptr_t)(((word)(&dummy) + (GC_page_size - 1))
- & ~(GC_page_size - 1));
- me -> stack_ptr = me -> stack_end - 0x10;
- /* Needs to be plausible, since an asynchronous stack mark */
- /* should not crash. */
-# else
- me -> stack_end = (ptr_t)((word)(&dummy) & ~(GC_page_size - 1));
- me -> stack_ptr = me -> stack_end + 0x10;
-# endif
- /* This is dubious, since we may be more than a page into the stack, */
- /* and hence skip some of it, though it's not clear that matters. */
-# ifdef IA64
- me -> backing_store_end = (ptr_t)
- (GC_save_regs_in_stack() & ~(GC_page_size - 1));
- /* This is also < 100% convincing. We should also read this */
- /* from /proc, but the hook to do so isn't there yet. */
-# endif /* IA64 */
- UNLOCK();
- start = si -> start_routine;
-# ifdef DEBUG_THREADS
- GC_printf1("start_routine = 0x%lx\n", start);
-# endif
- start_arg = si -> arg;
-# ifdef GC_MACOSX_THREADS
- semaphore_signal(si->registered);
-# else
- sem_post(&(si -> registered)); /* Last action on si. */
-# endif
- /* OK to deallocate. */
- pthread_cleanup_push(GC_thread_exit_proc, 0);
-# if defined(THREAD_LOCAL_ALLOC) && !defined(DBG_HDRS_ALL)
- LOCK();
- GC_init_thread_local(me);
- UNLOCK();
-# endif
- result = (*start)(start_arg);
-#if DEBUG_THREADS
- GC_printf1("Finishing thread 0x%x\n", pthread_self());
-#endif
- me -> status = result;
- me -> flags |= FINISHED;
- pthread_cleanup_pop(1);
- /* Cleanup acquires lock, ensuring that we can't exit */
- /* while a collection that thinks we're alive is trying to stop */
- /* us. */
- return(result);
-}
-
-int
-WRAP_FUNC(pthread_create)(pthread_t *new_thread,
- const pthread_attr_t *attr,
- void *(*start_routine)(void *), void *arg)
-{
- int result;
- GC_thread t;
- pthread_t my_new_thread;
- int detachstate;
- word my_flags = 0;
- struct start_info * si;
- /* This is otherwise saved only in an area mmapped by the thread */
- /* library, which isn't visible to the collector. */
-
- /* We resist the temptation to muck with the stack size here, */
- /* even if the default is unreasonably small. That's the client's */
- /* responsibility. */
-
- LOCK();
- si = (struct start_info *)GC_INTERNAL_MALLOC(sizeof(struct start_info),
- NORMAL);
- UNLOCK();
- if (!parallel_initialized) GC_init_parallel();
- if (0 == si) return(ENOMEM);
-# ifdef GC_MACOSX_THREADS
- semaphore_create(mach_task_self(), &si->registered, SYNC_POLICY_FIFO, 0);
-# else
- sem_init(&(si -> registered), 0, 0);
-# endif
- si -> start_routine = start_routine;
- si -> arg = arg;
- LOCK();
- if (!GC_thr_initialized) GC_thr_init();
-# ifdef GC_ASSERTIONS
- {
- int stack_size;
- if (NULL == attr) {
- pthread_attr_t my_attr;
- pthread_attr_init(&my_attr);
- pthread_attr_getstacksize(&my_attr, &stack_size);
- } else {
- pthread_attr_getstacksize(attr, &stack_size);
- }
- GC_ASSERT(stack_size >= (8*HBLKSIZE*sizeof(word)));
- /* Our threads may need to do some work for the GC. */
- /* Ridiculously small threads won't work, and they */
- /* probably wouldn't work anyway. */
- }
-# endif
- if (NULL == attr) {
- detachstate = PTHREAD_CREATE_JOINABLE;
- } else {
- pthread_attr_getdetachstate(attr, &detachstate);
- }
- if (PTHREAD_CREATE_DETACHED == detachstate) my_flags |= DETACHED;
- si -> flags = my_flags;
- UNLOCK();
-# ifdef DEBUG_THREADS
- GC_printf1("About to start new thread from thread 0x%X\n",
- pthread_self());
-# endif
-
- result = REAL_FUNC(pthread_create)(new_thread, attr, GC_start_routine, si);
-# ifdef DEBUG_THREADS
- GC_printf1("Started thread 0x%X\n", *new_thread);
-# endif
- /* 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. */
-# ifdef GC_MACOSX_THREADS
- semaphore_wait(si->registered);
- semaphore_destroy(mach_task_self(), si->registered);
-# else
- while (0 != sem_wait(&(si -> registered))) {
- if (EINTR != errno) ABORT("sem_wait failed");
- }
- sem_destroy(&(si -> registered));
-# endif
- LOCK();
- GC_INTERNAL_FREE(si);
- UNLOCK();
-
- return(result);
-}
-
-#ifdef GENERIC_COMPARE_AND_SWAP
- pthread_mutex_t GC_compare_and_swap_lock = PTHREAD_MUTEX_INITIALIZER;
-
- GC_bool GC_compare_and_exchange(volatile GC_word *addr,
- GC_word old, GC_word new_val)
- {
- GC_bool result;
- pthread_mutex_lock(&GC_compare_and_swap_lock);
- if (*addr == old) {
- *addr = new_val;
- result = TRUE;
- } else {
- result = FALSE;
- }
- pthread_mutex_unlock(&GC_compare_and_swap_lock);
- return result;
- }
-
- GC_word GC_atomic_add(volatile GC_word *addr, GC_word how_much)
- {
- GC_word old;
- pthread_mutex_lock(&GC_compare_and_swap_lock);
- old = *addr;
- *addr = old + how_much;
- pthread_mutex_unlock(&GC_compare_and_swap_lock);
- return old;
- }
-
-#endif /* GENERIC_COMPARE_AND_SWAP */
-/* Spend a few cycles in a way that can't introduce contention with */
-/* othre threads. */
-void GC_pause()
-{
- int i;
- volatile word dummy = 0;
-
- for (i = 0; i < 10; ++i) {
-# ifdef __GNUC__
- __asm__ __volatile__ (" " : : : "memory");
-# else
- /* Something that's unlikely to be optimized away. */
- GC_noop(++dummy);
-# endif
- }
-}
-
-#define SPIN_MAX 1024 /* Maximum number of calls to GC_pause before */
- /* give up. */
-
-VOLATILE GC_bool GC_collecting = 0;
- /* A hint that we're in the collector and */
- /* holding the allocation lock for an */
- /* extended period. */
-
-#if !defined(USE_SPIN_LOCK) || defined(PARALLEL_MARK)
-/* If we don't want to use the below spinlock implementation, either */
-/* because we don't have a GC_test_and_set implementation, or because */
-/* we don't want to risk sleeping, we can still try spinning on */
-/* pthread_mutex_trylock for a while. This appears to be very */
-/* beneficial in many cases. */
-/* I suspect that under high contention this is nearly always better */
-/* than the spin lock. But it's a bit slower on a uniprocessor. */
-/* Hence we still default to the spin lock. */
-/* This is also used to acquire the mark lock for the parallel */
-/* marker. */
-
-/* Here we use a strict exponential backoff scheme. I don't know */
-/* whether that's better or worse than the above. We eventually */
-/* yield by calling pthread_mutex_lock(); it never makes sense to */
-/* explicitly sleep. */
-
-void GC_generic_lock(pthread_mutex_t * lock)
-{
- unsigned pause_length = 1;
- unsigned i;
-
- if (0 == pthread_mutex_trylock(lock)) return;
- for (; pause_length <= SPIN_MAX; pause_length <<= 1) {
- for (i = 0; i < pause_length; ++i) {
- GC_pause();
- }
- switch(pthread_mutex_trylock(lock)) {
- case 0:
- return;
- case EBUSY:
- break;
- default:
- ABORT("Unexpected error from pthread_mutex_trylock");
- }
- }
- pthread_mutex_lock(lock);
-}
-
-#endif /* !USE_SPIN_LOCK || PARALLEL_MARK */
-
-#if defined(USE_SPIN_LOCK)
-
-/* Reasonably fast spin locks. Basically the same implementation */
-/* as STL alloc.h. This isn't really the right way to do this. */
-/* but until the POSIX scheduling mess gets straightened out ... */
-
-volatile unsigned int GC_allocate_lock = 0;
-
-
-void GC_lock()
-{
-# define low_spin_max 30 /* spin cycles if we suspect uniprocessor */
-# define high_spin_max SPIN_MAX /* spin cycles for multiprocessor */
- static unsigned spin_max = low_spin_max;
- unsigned my_spin_max;
- static unsigned last_spins = 0;
- unsigned my_last_spins;
- int i;
-
- if (!GC_test_and_set(&GC_allocate_lock)) {
- return;
- }
- my_spin_max = spin_max;
- my_last_spins = last_spins;
- for (i = 0; i < my_spin_max; i++) {
- if (GC_collecting || GC_nprocs == 1) goto yield;
- if (i < my_last_spins/2 || GC_allocate_lock) {
- GC_pause();
- continue;
- }
- if (!GC_test_and_set(&GC_allocate_lock)) {
- /*
- * got it!
- * Spinning worked. Thus we're probably not being scheduled
- * against the other process with which we were contending.
- * Thus it makes sense to spin longer the next time.
- */
- last_spins = i;
- spin_max = high_spin_max;
- return;
- }
- }
- /* We are probably being scheduled against the other process. Sleep. */
- spin_max = low_spin_max;
-yield:
- for (i = 0;; ++i) {
- if (!GC_test_and_set(&GC_allocate_lock)) {
- return;
- }
-# define SLEEP_THRESHOLD 12
- /* Under Linux very short sleeps tend to wait until */
- /* the current time quantum expires. On old Linux */
- /* kernels nanosleep(<= 2ms) just spins under Linux. */
- /* (Under 2.4, this happens only for real-time */
- /* processes.) We want to minimize both behaviors */
- /* here. */
- if (i < SLEEP_THRESHOLD) {
- sched_yield();
- } else {
- struct timespec ts;
-
- if (i > 24) i = 24;
- /* Don't wait for more than about 15msecs, even */
- /* under extreme contention. */
- ts.tv_sec = 0;
- ts.tv_nsec = 1 << i;
- nanosleep(&ts, 0);
- }
- }
-}
-
-#else /* !USE_SPINLOCK */
-
-void GC_lock()
-{
- if (1 == GC_nprocs || GC_collecting) {
- pthread_mutex_lock(&GC_allocate_ml);
- } else {
- GC_generic_lock(&GC_allocate_ml);
- }
-}
-
-#endif /* !USE_SPINLOCK */
-
-#if defined(PARALLEL_MARK) || defined(THREAD_LOCAL_ALLOC)
-
-#ifdef GC_ASSERTIONS
- pthread_t GC_mark_lock_holder = NO_THREAD;
-#endif
-
-#if 0
- /* Ugly workaround for a linux threads bug in the final versions */
- /* of glibc2.1. Pthread_mutex_trylock sets the mutex owner */
- /* field even when it fails to acquire the mutex. This causes */
- /* pthread_cond_wait to die. Remove for glibc2.2. */
- /* According to the man page, we should use */
- /* PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP, but that isn't actually */
- /* defined. */
- static pthread_mutex_t mark_mutex =
- {0, 0, 0, PTHREAD_MUTEX_ERRORCHECK_NP, {0, 0}};
-#else
- static pthread_mutex_t mark_mutex = PTHREAD_MUTEX_INITIALIZER;
-#endif
-
-static pthread_cond_t builder_cv = PTHREAD_COND_INITIALIZER;
-
-void GC_acquire_mark_lock()
-{
-/*
- if (pthread_mutex_lock(&mark_mutex) != 0) {
- ABORT("pthread_mutex_lock failed");
- }
-*/
- GC_generic_lock(&mark_mutex);
-# ifdef GC_ASSERTIONS
- GC_mark_lock_holder = pthread_self();
-# endif
-}
-
-void GC_release_mark_lock()
-{
- GC_ASSERT(GC_mark_lock_holder == pthread_self());
-# ifdef GC_ASSERTIONS
- GC_mark_lock_holder = NO_THREAD;
-# endif
- if (pthread_mutex_unlock(&mark_mutex) != 0) {
- ABORT("pthread_mutex_unlock failed");
- }
-}
-
-/* Collector must wait for a freelist builders for 2 reasons: */
-/* 1) Mark bits may still be getting examined without lock. */
-/* 2) Partial free lists referenced only by locals may not be scanned */
-/* correctly, e.g. if they contain "pointer-free" objects, since the */
-/* free-list link may be ignored. */
-void GC_wait_builder()
-{
- GC_ASSERT(GC_mark_lock_holder == pthread_self());
-# ifdef GC_ASSERTIONS
- GC_mark_lock_holder = NO_THREAD;
-# endif
- if (pthread_cond_wait(&builder_cv, &mark_mutex) != 0) {
- ABORT("pthread_cond_wait failed");
- }
- GC_ASSERT(GC_mark_lock_holder == NO_THREAD);
-# ifdef GC_ASSERTIONS
- GC_mark_lock_holder = pthread_self();
-# endif
-}
-
-void GC_wait_for_reclaim()
-{
- GC_acquire_mark_lock();
- while (GC_fl_builder_count > 0) {
- GC_wait_builder();
- }
- GC_release_mark_lock();
-}
-
-void GC_notify_all_builder()
-{
- GC_ASSERT(GC_mark_lock_holder == pthread_self());
- if (pthread_cond_broadcast(&builder_cv) != 0) {
- ABORT("pthread_cond_broadcast failed");
- }
-}
-
-#endif /* PARALLEL_MARK || THREAD_LOCAL_ALLOC */
-
-#ifdef PARALLEL_MARK
-
-static pthread_cond_t mark_cv = PTHREAD_COND_INITIALIZER;
-
-void GC_wait_marker()
-{
- GC_ASSERT(GC_mark_lock_holder == pthread_self());
-# ifdef GC_ASSERTIONS
- GC_mark_lock_holder = NO_THREAD;
-# endif
- if (pthread_cond_wait(&mark_cv, &mark_mutex) != 0) {
- ABORT("pthread_cond_wait failed");
- }
- GC_ASSERT(GC_mark_lock_holder == NO_THREAD);
-# ifdef GC_ASSERTIONS
- GC_mark_lock_holder = pthread_self();
-# endif
-}
-
-void GC_notify_all_marker()
-{
- if (pthread_cond_broadcast(&mark_cv) != 0) {
- ABORT("pthread_cond_broadcast failed");
- }
-}
-
-#endif /* PARALLEL_MARK */
-
-# endif /* GC_LINUX_THREADS and friends */
-
Index: boehm_gc/mach_dep.c
===================================================================
RCS file: /home/staff/zs/imp/mercury/boehm_gc/mach_dep.c,v
retrieving revision 1.13
diff -u -r1.13 mach_dep.c
--- boehm_gc/mach_dep.c 25 Jul 2002 09:02:47 -0000 1.13
+++ boehm_gc/mach_dep.c 27 Oct 2003 21:02:33 -0000
@@ -74,7 +74,8 @@
/* on your architecture. Run the test_setjmp program to see whether */
/* there is any chance it will work. */
-#ifndef USE_GENERIC_PUSH_REGS
+#if !defined(USE_GENERIC_PUSH_REGS) && !defined(USE_ASM_PUSH_REGS)
+#undef HAVE_PUSH_REGS
void GC_push_regs()
{
# ifdef RT
@@ -91,6 +92,7 @@
asm("pushl r8"); asm("calls $1,_GC_push_one");
asm("pushl r7"); asm("calls $1,_GC_push_one");
asm("pushl r6"); asm("calls $1,_GC_push_one");
+# define HAVE_PUSH_REGS
# endif
# if defined(M68K) && (defined(SUNOS4) || defined(NEXT))
/* M68K SUNOS - could be replaced by generic code */
@@ -113,6 +115,7 @@
asm("movl d7,sp@"); asm("jbsr _GC_push_one");
asm("addqw #0x4,sp"); /* put stack back where it was */
+# define HAVE_PUSH_REGS
# endif
# if defined(M68K) && defined(HP)
@@ -135,6 +138,7 @@
asm("mov.l %d7,(%sp)"); asm("jsr _GC_push_one");
asm("addq.w &0x4,%sp"); /* put stack back where it was */
+# define HAVE_PUSH_REGS
# endif /* M68K HP */
# if defined(M68K) && defined(AMIGA)
@@ -158,6 +162,7 @@
asm("mov.l %d7,(%sp)"); asm("jsr _GC_push_one");
asm("addq.w &0x4,%sp"); /* put stack back where it was */
+# define HAVE_PUSH_REGS
# else /* !__GNUC__ */
GC_push_one(getreg(REG_A2));
GC_push_one(getreg(REG_A3));
@@ -174,6 +179,7 @@
GC_push_one(getreg(REG_D5));
GC_push_one(getreg(REG_D6));
GC_push_one(getreg(REG_D7));
+# define HAVE_PUSH_REGS
# endif /* !__GNUC__ */
# endif /* AMIGA */
@@ -196,10 +202,12 @@
PushMacReg(d7);
add.w #4,sp ; fix stack.
}
+# define HAVE_PUSH_REGS
# undef PushMacReg
# endif /* THINK_C */
# if defined(__MWERKS__)
PushMacRegisters();
+# define HAVE_PUSH_REGS
# endif /* __MWERKS__ */
# endif /* MACOS */
@@ -222,6 +230,7 @@
asm("pushl %esi"); asm("call _GC_push_one"); asm("addl $4,%esp");
asm("pushl %edi"); asm("call _GC_push_one"); asm("addl $4,%esp");
asm("pushl %ebx"); asm("call _GC_push_one"); asm("addl $4,%esp");
+# define HAVE_PUSH_REGS
# endif
# if ( defined(I386) && defined(LINUX) && defined(__ELF__) ) \
@@ -244,6 +253,7 @@
asm("pushl %esi; call GC_push_one; addl $4,%esp");
asm("pushl %edi; call GC_push_one; addl $4,%esp");
asm("pushl %ebx; call GC_push_one; addl $4,%esp");
+# define HAVE_PUSH_REGS
# endif
# if ( defined(I386) && defined(BEOS) && defined(__ELF__) )
@@ -255,6 +265,7 @@
asm("pushl %esi; call GC_push_one; addl $4,%esp");
asm("pushl %edi; call GC_push_one; addl $4,%esp");
asm("pushl %ebx; call GC_push_one; addl $4,%esp");
+# define HAVE_PUSH_REGS
# endif
# if defined(I386) && defined(MSWIN32) && !defined(__MINGW32__) \
@@ -281,6 +292,7 @@
__asm push edi
__asm call GC_push_one
__asm add esp,4
+# define HAVE_PUSH_REGS
# endif
# if defined(I386) && (defined(SVR4) || defined(SCO) || defined(SCO_ELF))
@@ -292,6 +304,7 @@
asm("pushl %ebp"); asm("call GC_push_one"); asm("addl $4,%esp");
asm("pushl %esi"); asm("call GC_push_one"); asm("addl $4,%esp");
asm("pushl %edi"); asm("call GC_push_one"); asm("addl $4,%esp");
+# define HAVE_PUSH_REGS
# endif
# ifdef NS32K
@@ -300,14 +313,12 @@
asm ("movd r5, tos"); asm ("bsr ?_GC_push_one"); asm ("adjspb $-4");
asm ("movd r6, tos"); asm ("bsr ?_GC_push_one"); asm ("adjspb $-4");
asm ("movd r7, tos"); asm ("bsr ?_GC_push_one"); asm ("adjspb $-4");
+# define HAVE_PUSH_REGS
# endif
# if defined(SPARC)
- {
- word GC_save_regs_in_stack();
-
- GC_save_regs_ret_val = GC_save_regs_in_stack();
- }
+ GC_save_regs_ret_val = GC_save_regs_in_stack();
+# define HAVE_PUSH_REGS
# endif
# ifdef RT
@@ -323,6 +334,7 @@
asm("cas r11, r13, r0"); GC_push_one(TMP_SP); /* through */
asm("cas r11, r14, r0"); GC_push_one(TMP_SP); /* r15 */
asm("cas r11, r15, r0"); GC_push_one(TMP_SP);
+# define HAVE_PUSH_REGS
# endif
# if defined(M68K) && defined(SYSV)
@@ -346,6 +358,7 @@
asm("movl %d7,%sp@"); asm("jbsr GC_push_one");
asm("addqw #0x4,%sp"); /* put stack back where it was */
+# define HAVE_PUSH_REGS
# else /* !__GNUC__*/
asm("subq.w &0x4,%sp"); /* allocate word on top of stack */
@@ -363,6 +376,7 @@
asm("mov.l %d7,(%sp)"); asm("jsr GC_push_one");
asm("addq.w &0x4,%sp"); /* put stack back where it was */
+# define HAVE_PUSH_REGS
# endif /* !__GNUC__ */
# endif /* M68K/SYSV */
@@ -372,27 +386,27 @@
extern int *__libc_stack_end;
GC_push_all_stack (sp, __libc_stack_end);
+# define HAVE_PUSH_REGS
}
# endif
/* other machines... */
-# if !defined(M68K) && !defined(VAX) && !defined(RT)
-# if !defined(SPARC) && !defined(I386) && !defined(NS32K)
-# if !defined(POWERPC) && !defined(UTS4)
-# if !defined(PJ) && !(defined(MIPS) && defined(LINUX))
- --> bad news <--
-# endif
-# endif
-# endif
+# if !defined(HAVE_PUSH_REGS)
+ --> We just generated an empty GC_push_regs, which
+ --> is almost certainly broken. Try defining
+ --> USE_GENERIC_PUSH_REGS instead.
# endif
}
-#endif /* !USE_GENERIC_PUSH_REGS */
+#endif /* !USE_GENERIC_PUSH_REGS && !USE_ASM_PUSH_REGS */
#if defined(USE_GENERIC_PUSH_REGS)
void GC_generic_push_regs(cold_gc_frame)
ptr_t cold_gc_frame;
{
{
+ word dummy;
+
# ifdef HAVE_BUILTIN_UNWIND_INIT
/* This was suggested by Richard Henderson as the way to */
/* force callee-save registers and register windows onto */
@@ -428,8 +442,6 @@
/* needed on IA64, since some non-windowed registers are */
/* preserved. */
{
- word GC_save_regs_in_stack();
-
GC_save_regs_ret_val = GC_save_regs_in_stack();
/* On IA64 gcc, could use __builtin_ia64_flushrs() and */
/* __builtin_ia64_flushrs(). The latter will be done */
@@ -438,6 +450,10 @@
}
# endif
GC_push_current_stack(cold_gc_frame);
+ /* Strongly discourage the compiler from treating the above */
+ /* as a tail-call, since that would pop the register */
+ /* contents before we get a chance to look at them. */
+ GC_noop1((word)(&dummy));
}
}
#endif /* USE_GENERIC_PUSH_REGS */
@@ -446,7 +462,7 @@
/* the stack. Return sp. */
# ifdef SPARC
asm(" .seg \"text\"");
-# ifdef SVR4
+# if defined(SVR4) || defined(NETBSD)
asm(" .globl GC_save_regs_in_stack");
asm("GC_save_regs_in_stack:");
asm(" .type GC_save_regs_in_stack,#function");
Index: boehm_gc/malloc.c
===================================================================
RCS file: /home/staff/zs/imp/mercury/boehm_gc/malloc.c,v
retrieving revision 1.13
diff -u -r1.13 malloc.c
--- boehm_gc/malloc.c 6 May 2003 11:36:50 -0000 1.13
+++ boehm_gc/malloc.c 27 Oct 2003 21:02:33 -0000
@@ -62,14 +62,14 @@
if (h == 0) {
result = 0;
} else {
- int total_bytes = BYTES_TO_WORDS(n_blocks * HBLKSIZE);
+ int total_bytes = n_blocks * HBLKSIZE;
if (n_blocks > 1) {
- GC_large_allocd_bytes += n_blocks * HBLKSIZE;
+ GC_large_allocd_bytes += total_bytes;
if (GC_large_allocd_bytes > GC_max_large_allocd_bytes)
GC_max_large_allocd_bytes = GC_large_allocd_bytes;
}
result = (ptr_t) (h -> hb_body);
- GC_words_wasted += total_bytes - lw;
+ GC_words_wasted += BYTES_TO_WORDS(total_bytes) - lw;
}
return result;
}
Index: boehm_gc/mark.c
===================================================================
RCS file: /home/staff/zs/imp/mercury/boehm_gc/mark.c,v
retrieving revision 1.11
diff -u -r1.11 mark.c
--- boehm_gc/mark.c 6 May 2003 11:36:50 -0000 1.11
+++ boehm_gc/mark.c 27 Oct 2003 21:02:33 -0000
@@ -19,6 +19,10 @@
# include <stdio.h>
# include "private/gc_pmark.h"
+#if defined(MSWIN32) && defined(__GNUC__)
+# include <excpt.h>
+#endif
+
/* We put this here to minimize the risk of inlining. */
/*VARARGS*/
#ifdef __WATCOMC__
@@ -261,20 +265,20 @@
/* remains valid until all marking is complete. */
/* A zero value indicates that it's OK to miss some */
/* register values. */
-GC_bool GC_mark_some(cold_gc_frame)
-ptr_t cold_gc_frame;
+/* We hold the allocation lock. In the case of */
+/* incremental collection, the world may not be stopped.*/
+#ifdef MSWIN32
+ /* For win32, this is called after we establish a structured */
+ /* exception handler, in case Windows unmaps one of our root */
+ /* segments. See below. In either case, we acquire the */
+ /* allocator lock long before we get here. */
+ GC_bool GC_mark_some_inner(cold_gc_frame)
+ ptr_t cold_gc_frame;
+#else
+ GC_bool GC_mark_some(cold_gc_frame)
+ ptr_t cold_gc_frame;
+#endif
{
-#if defined(MSWIN32) && !defined(__GNUC__)
- /* Windows 98 appears to asynchronously create and remove writable */
- /* memory mappings, for reasons we haven't yet understood. Since */
- /* we look for writable regions to determine the root set, we may */
- /* try to mark from an address range that disappeared since we */
- /* started the collection. Thus we have to recover from faults here. */
- /* This code does not appear to be necessary for Windows 95/NT/2000. */
- /* Note that this code should never generate an incremental GC write */
- /* fault. */
- __try {
-#endif /* defined(MSWIN32) && !defined(__GNUC__) */
switch(GC_mark_state) {
case MS_NONE:
return(FALSE);
@@ -395,23 +399,130 @@
ABORT("GC_mark_some: bad state");
return(FALSE);
}
-#if defined(MSWIN32) && !defined(__GNUC__)
- } __except (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ?
- EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) {
-# ifdef CONDPRINT
- if (GC_print_stats) {
- GC_printf0("Caught ACCESS_VIOLATION in marker. "
- "Memory mapping disappeared.\n");
+}
+
+
+#ifdef MSWIN32
+
+# ifdef __GNUC__
+
+ typedef struct {
+ EXCEPTION_REGISTRATION ex_reg;
+ void *alt_path;
+ } ext_ex_regn;
+
+
+ static EXCEPTION_DISPOSITION mark_ex_handler(
+ struct _EXCEPTION_RECORD *ex_rec,
+ void *est_frame,
+ struct _CONTEXT *context,
+ void *disp_ctxt)
+ {
+ if (ex_rec->ExceptionCode == STATUS_ACCESS_VIOLATION) {
+ ext_ex_regn *xer = (ext_ex_regn *)est_frame;
+
+ /* Unwind from the inner function assuming the standard */
+ /* function prologue. */
+ /* Assumes code has not been compiled with */
+ /* -fomit-frame-pointer. */
+ context->Esp = context->Ebp;
+ context->Ebp = *((DWORD *)context->Esp);
+ context->Esp = context->Esp - 8;
+
+ /* Resume execution at the "real" handler within the */
+ /* wrapper function. */
+ context->Eip = (DWORD )(xer->alt_path);
+
+ return ExceptionContinueExecution;
+
+ } else {
+ return ExceptionContinueSearch;
+ }
+ }
+# endif /* __GNUC__ */
+
+
+ GC_bool GC_mark_some(cold_gc_frame)
+ ptr_t cold_gc_frame;
+ {
+ GC_bool ret_val;
+
+# ifndef __GNUC__
+ /* Windows 98 appears to asynchronously create and remove */
+ /* writable memory mappings, for reasons we haven't yet */
+ /* understood. Since we look for writable regions to */
+ /* determine the root set, we may try to mark from an */
+ /* address range that disappeared since we started the */
+ /* collection. Thus we have to recover from faults here. */
+ /* This code does not appear to be necessary for Windows */
+ /* 95/NT/2000. Note that this code should never generate */
+ /* an incremental GC write fault. */
+
+ __try {
+
+# else /* __GNUC__ */
+
+ /* Manually install an exception handler since GCC does */
+ /* not yet support Structured Exception Handling (SEH) on */
+ /* Win32. */
+
+ ext_ex_regn er;
+
+ er.alt_path = &&handle_ex;
+ er.ex_reg.handler = mark_ex_handler;
+ asm volatile ("movl %%fs:0, %0" : "=r" (er.ex_reg.prev));
+ asm volatile ("movl %0, %%fs:0" : : "r" (&er));
+
+# endif /* __GNUC__ */
+
+ ret_val = GC_mark_some_inner(cold_gc_frame);
+
+# ifndef __GNUC__
+
+ } __except (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ?
+ EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) {
+
+# else /* __GNUC__ */
+
+ /* Prevent GCC from considering the following code unreachable */
+ /* and thus eliminating it. */
+ if (er.alt_path != 0)
+ goto rm_handler;
+
+handle_ex:
+ /* Execution resumes from here on an access violation. */
+
+# endif /* __GNUC__ */
+
+# ifdef CONDPRINT
+ if (GC_print_stats) {
+ GC_printf0("Caught ACCESS_VIOLATION in marker. "
+ "Memory mapping disappeared.\n");
+ }
+# endif /* CONDPRINT */
+
+ /* We have bad roots on the stack. Discard mark stack. */
+ /* Rescan from marked objects. Redetermine roots. */
+ GC_invalidate_mark_state();
+ scan_ptr = 0;
+
+ ret_val = FALSE;
+
+# ifndef __GNUC__
+
}
-# endif /* CONDPRINT */
- /* We have bad roots on the stack. Discard mark stack. */
- /* Rescan from marked objects. Redetermine roots. */
- GC_invalidate_mark_state();
- scan_ptr = 0;
- return FALSE;
+
+# else /* __GNUC__ */
+
+rm_handler:
+ /* Uninstall the exception handler */
+ asm volatile ("mov %0, %%fs:0" : : "r" (er.ex_reg.prev));
+
+# endif /* __GNUC__ */
+
+ return ret_val;
}
-#endif /* defined(MSWIN32) && !defined(__GNUC__) */
-}
+#endif /* MSWIN32 */
GC_bool GC_mark_stack_empty()
@@ -447,8 +558,8 @@
current = current - HBLKSIZE*(word)hhdr;
hhdr = HDR(current);
} while(IS_FORWARDING_ADDR_OR_NIL(hhdr));
- /* current points to the start of the large object */
- if (hhdr -> hb_flags & IGNORE_OFF_PAGE) return(0);
+ /* current points to near the start of the large object */
+ if (hhdr -> hb_flags & IGNORE_OFF_PAGE) return(orig);
if ((word *)orig - (word *)current
>= (ptrdiff_t)(hhdr->hb_sz)) {
/* Pointer past the end of the block */
Index: boehm_gc/mark_rts.c
===================================================================
RCS file: /home/staff/zs/imp/mercury/boehm_gc/mark_rts.c,v
retrieving revision 1.12
diff -u -r1.12 mark_rts.c
--- boehm_gc/mark_rts.c 6 May 2003 11:36:50 -0000 1.12
+++ boehm_gc/mark_rts.c 27 Oct 2003 21:02:33 -0000
@@ -275,33 +275,72 @@
}
/* Internal use only; lock held. */
+static void GC_remove_root_at_pos(i)
+int i;
+{
+ GC_root_size -= (GC_static_roots[i].r_end - GC_static_roots[i].r_start);
+ GC_static_roots[i].r_start = GC_static_roots[n_root_sets-1].r_start;
+ GC_static_roots[i].r_end = GC_static_roots[n_root_sets-1].r_end;
+ GC_static_roots[i].r_tmp = GC_static_roots[n_root_sets-1].r_tmp;
+ n_root_sets--;
+}
+
+#if !defined(MSWIN32) && !defined(MSWINCE)
+static void GC_rebuild_root_index()
+{
+ register int i;
+
+ for (i = 0; i < RT_SIZE; i++) GC_root_index[i] = 0;
+ for (i = 0; i < n_root_sets; i++)
+ add_roots_to_index(GC_static_roots + i);
+}
+#endif
+
+/* Internal use only; lock held. */
void GC_remove_tmp_roots()
{
register int i;
for (i = 0; i < n_root_sets; ) {
if (GC_static_roots[i].r_tmp) {
- GC_root_size -=
- (GC_static_roots[i].r_end - GC_static_roots[i].r_start);
- GC_static_roots[i].r_start = GC_static_roots[n_root_sets-1].r_start;
- GC_static_roots[i].r_end = GC_static_roots[n_root_sets-1].r_end;
- GC_static_roots[i].r_tmp = GC_static_roots[n_root_sets-1].r_tmp;
- n_root_sets--;
+ GC_remove_root_at_pos(i);
} else {
i++;
- }
}
-# if !defined(MSWIN32) && !defined(MSWINCE)
- {
- register int i;
-
- for (i = 0; i < RT_SIZE; i++) GC_root_index[i] = 0;
- for (i = 0; i < n_root_sets; i++)
- add_roots_to_index(GC_static_roots + i);
}
-# endif
+ #if !defined(MSWIN32) && !defined(MSWINCE)
+ GC_rebuild_root_index();
+ #endif
+}
+
+#if !defined(MSWIN32) && !defined(MSWINCE)
+void GC_remove_roots(b, e)
+char * b; char * e;
+{
+ DCL_LOCK_STATE;
+ DISABLE_SIGNALS();
+ LOCK();
+ GC_remove_roots_inner(b, e);
+ UNLOCK();
+ ENABLE_SIGNALS();
+}
+
+/* Should only be called when the lock is held */
+void GC_remove_roots_inner(b,e)
+char * b; char * e;
+{
+ int i;
+ for (i = 0; i < n_root_sets; ) {
+ if (GC_static_roots[i].r_start >= (ptr_t)b && GC_static_roots[i].r_end <= (ptr_t)e) {
+ GC_remove_root_at_pos(i);
+ } else {
+ i++;
+ }
+ }
+ GC_rebuild_root_index();
}
+#endif /* !defined(MSWIN32) && !defined(MSWINCE) */
#if defined(MSWIN32) || defined(_WIN32_WCE_EMULATION)
/* Workaround for the OS mapping and unmapping behind our back: */
@@ -573,8 +612,11 @@
/* Mark thread local free lists, even if their mark */
/* descriptor excludes the link field. */
+ /* If the world is not stopped, this is unsafe. It is */
+ /* also unnecessary, since we will do this again with the */
+ /* world stopped. */
# ifdef THREAD_LOCAL_ALLOC
- GC_mark_thread_local_free_lists();
+ if (GC_world_stopped) GC_mark_thread_local_free_lists();
# endif
/*
Index: boehm_gc/mips_sgi_mach_dep.S
===================================================================
RCS file: boehm_gc/mips_sgi_mach_dep.S
diff -N boehm_gc/mips_sgi_mach_dep.S
--- boehm_gc/mips_sgi_mach_dep.S 24 Oct 2003 11:51:20 -0000 1.3
+++ /dev/null 1 Jan 1970 00:00:00 -0000
@@ -1,41 +0,0 @@
-#include <sys/regdef.h>
-#include <sys/asm.h>
-
-# define call_push(x) move $4,x; jal GC_push_one
-
- .option pic2
- .text
-/* Mark from machine registers that are saved by C compiler */
-# define FRAMESZ 32
-# define RAOFF FRAMESZ-SZREG
-# define GPOFF FRAMESZ-(2*SZREG)
- NESTED(GC_push_regs, FRAMESZ, ra)
- .mask 0x80000000,-SZREG # inform debugger of saved ra loc
- move t0,gp
- SETUP_GPX(t8)
- PTR_SUBU sp,FRAMESZ
-# ifdef SETUP_GP64
- SETUP_GP64(GPOFF, GC_push_regs)
-# endif
- SAVE_GP(GPOFF)
- REG_S ra,RAOFF(sp)
-# if (_MIPS_SIM == _MIPS_SIM_ABI32)
- call_push($2)
- call_push($3)
-# endif
- call_push($16)
- call_push($17)
- call_push($18)
- call_push($19)
- call_push($20)
- call_push($21)
- call_push($22)
- call_push($23)
- call_push($30)
- REG_L ra,RAOFF(sp)
-# ifdef RESTORE_GP64
- RESTORE_GP64
-# endif
- PTR_ADDU sp,FRAMESZ
- j ra
- .end GC_push_regs
Index: boehm_gc/mips_sgi_mach_dep.s
===================================================================
RCS file: boehm_gc/mips_sgi_mach_dep.s
diff -N boehm_gc/mips_sgi_mach_dep.s
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ boehm_gc/mips_sgi_mach_dep.s 25 Jul 2002 12:49:45 -0000
@@ -0,0 +1,46 @@
+#include <sys/regdef.h>
+#include <sys/asm.h>
+/* This file must be preprocessed. But the SGI assembler always does */
+/* that. Furthermore, a generic preprocessor won't do, since some of */
+/* the SGI-supplied include files rely on behavior of the MIPS */
+/* assembler. Hence we treat and name this file as though it required */
+/* no preprocessing. */
+
+# define call_push(x) move $4,x; jal GC_push_one
+
+ .option pic2
+ .text
+/* Mark from machine registers that are saved by C compiler */
+# define FRAMESZ 32
+# define RAOFF FRAMESZ-SZREG
+# define GPOFF FRAMESZ-(2*SZREG)
+ NESTED(GC_push_regs, FRAMESZ, ra)
+ .mask 0x80000000,-SZREG # inform debugger of saved ra loc
+ move t0,gp
+ SETUP_GPX(t8)
+ PTR_SUBU sp,FRAMESZ
+# ifdef SETUP_GP64
+ SETUP_GP64(GPOFF, GC_push_regs)
+# endif
+ SAVE_GP(GPOFF)
+ REG_S ra,RAOFF(sp)
+# if (_MIPS_SIM == _MIPS_SIM_ABI32)
+ call_push($2)
+ call_push($3)
+# endif
+ call_push($16)
+ call_push($17)
+ call_push($18)
+ call_push($19)
+ call_push($20)
+ call_push($21)
+ call_push($22)
+ call_push($23)
+ call_push($30)
+ REG_L ra,RAOFF(sp)
+# ifdef RESTORE_GP64
+ RESTORE_GP64
+# endif
+ PTR_ADDU sp,FRAMESZ
+ j ra
+ .end GC_push_regs
Index: boehm_gc/misc.c
===================================================================
RCS file: /home/staff/zs/imp/mercury/boehm_gc/misc.c,v
retrieving revision 1.15
diff -u -r1.15 misc.c
--- boehm_gc/misc.c 6 May 2003 11:36:50 -0000 1.15
+++ boehm_gc/misc.c 27 Oct 2003 21:02:33 -0000
@@ -59,7 +59,7 @@
# if defined(GC_WIN32_THREADS)
# if defined(GC_PTHREADS)
pthread_mutex_t GC_allocate_ml = PTHREAD_MUTEX_INITIALIZER;
-# elif !defined(GC_NOT_DLL) && (defined(_DLL) || defined(GC_DLL))
+# elif defined(GC_DLL)
__declspec(dllexport) CRITICAL_SECTION GC_allocate_ml;
# else
CRITICAL_SECTION GC_allocate_ml;
@@ -483,7 +483,13 @@
DISABLE_SIGNALS();
#if defined(GC_WIN32_THREADS) && !defined(GC_PTHREADS)
- if (!GC_is_initialized) InitializeCriticalSection(&GC_allocate_ml);
+ if (!GC_is_initialized) {
+# if (_WIN32_WINNT >= 0x0403)
+ InitializeCriticalSectionAndSpinCount (&GC_allocate_ml, 4000)
+# else
+ InitializeCriticalSection (&GC_allocate_ml);
+# endif
+ }
#endif /* MSWIN32 */
LOCK();
@@ -500,6 +506,15 @@
GC_init_parallel();
}
# endif /* PARALLEL_MARK || THREAD_LOCAL_ALLOC */
+
+# if defined(DYNAMIC_LOADING) && defined(DARWIN)
+ {
+ /* This must be called WITHOUT the allocation lock held
+ and before any threads are created */
+ extern void GC_init_dyld();
+ GC_init_dyld();
+ }
+# endif
}
#if defined(MSWIN32) || defined(MSWINCE)
@@ -512,6 +527,22 @@
extern void GC_setpagesize();
+
+#ifdef MSWIN32
+extern GC_bool GC_no_win32_dlls;
+#else
+# define GC_no_win32_dlls FALSE
+#endif
+
+void GC_exit_check GC_PROTO((void))
+{
+ GC_gcollect();
+}
+
+#ifdef SEARCH_FOR_DATA_START
+ extern void GC_init_linux_data_start GC_PROTO((void));
+#endif
+
#ifdef UNIX_LIKE
extern void GC_set_and_save_fault_handler GC_PROTO((void (*handler)(int)));
@@ -522,21 +553,23 @@
GC_err_printf1("Caught signal %d: looping in handler\n", sig);
for(;;);
}
-#endif
-#ifdef MSWIN32
-extern GC_bool GC_no_win32_dlls;
-#else
-# define GC_no_win32_dlls FALSE
-#endif
+static GC_bool installed_looping_handler = FALSE;
-void GC_exit_check GC_PROTO((void))
+void maybe_install_looping_handler()
{
- GC_gcollect();
+ /* Install looping handler before the write fault handler, so we */
+ /* handle write faults correctly. */
+ if (!installed_looping_handler && 0 != GETENV("GC_LOOP_ON_ABORT")) {
+ GC_set_and_save_fault_handler(looping_handler);
+ installed_looping_handler = TRUE;
+ }
}
-#ifdef SEARCH_FOR_DATA_START
- extern void GC_init_linux_data_start GC_PROTO((void));
+#else /* !UNIX_LIKE */
+
+# define maybe_install_looping_handler()
+
#endif
void GC_init_inner()
@@ -603,11 +636,7 @@
}
}
}
-# ifdef UNIX_LIKE
- if (0 != GETENV("GC_LOOP_ON_ABORT")) {
- GC_set_and_save_fault_handler(looping_handler);
- }
-# endif
+ maybe_install_looping_handler();
/* Adjust normal object descriptor for extra allocation. */
if (ALIGNMENT > GC_DS_TAGS && EXTRA_BYTES != 0) {
GC_obj_kinds[NORMAL].ok_descriptor = ((word)(-ALIGNMENT) | GC_DS_LENGTH);
@@ -628,7 +657,8 @@
# if (defined(NETBSD) || defined(OPENBSD)) && defined(__ELF__)
GC_init_netbsd_elf();
# endif
-# if defined(GC_PTHREADS) || defined(GC_SOLARIS_THREADS)
+# if defined(GC_PTHREADS) || defined(GC_SOLARIS_THREADS) \
+ || defined(GC_WIN32_THREADS)
GC_thr_init();
# endif
# ifdef GC_SOLARIS_THREADS
@@ -639,14 +669,14 @@
|| defined(GC_SOLARIS_THREADS)
if (GC_stackbottom == 0) {
GC_stackbottom = GC_get_stack_base();
-# if defined(LINUX) && defined(IA64)
+# if (defined(LINUX) || defined(HPUX)) && defined(IA64)
GC_register_stackbottom = GC_get_register_stack_base();
# endif
} else {
-# if defined(LINUX) && defined(IA64)
+# if (defined(LINUX) || defined(HPUX)) && defined(IA64)
if (GC_register_stackbottom == 0) {
WARN("GC_register_stackbottom should be set with GC_stackbottom", 0);
- /* The following is likely to fail, since we rely on */
+ /* The following may fail, since we may rely on */
/* alignment properties that may not hold with a user set */
/* GC_stackbottom. */
GC_register_stackbottom = GC_get_register_stack_base();
@@ -654,9 +684,9 @@
# endif
}
# endif
- GC_ASSERT(sizeof (ptr_t) == sizeof(word));
- GC_ASSERT(sizeof (signed_word) == sizeof(word));
- GC_ASSERT(sizeof (struct hblk) == HBLKSIZE);
+ GC_STATIC_ASSERT(sizeof (ptr_t) == sizeof(word));
+ GC_STATIC_ASSERT(sizeof (signed_word) == sizeof(word));
+ GC_STATIC_ASSERT(sizeof (struct hblk) == HBLKSIZE);
# ifndef THREADS
# if defined(STACK_GROWS_UP) && defined(STACK_GROWS_DOWN)
ABORT(
@@ -778,8 +808,9 @@
if (GC_incremental) goto out;
GC_setpagesize();
if (GC_no_win32_dlls) goto out;
-# ifndef GC_SOLARIS_THREADS
- GC_dirty_init();
+# ifndef GC_SOLARIS_THREADS
+ maybe_install_looping_handler(); /* Before write fault handler! */
+ GC_dirty_init();
# endif
if (!GC_is_initialized) {
GC_init_inner();
@@ -991,6 +1022,9 @@
{
GC_warn_proc result;
+# ifdef GC_WIN32_THREADS
+ GC_ASSERT(GC_is_initialized);
+# endif
LOCK();
result = GC_current_warn_proc;
GC_current_warn_proc = p;
Index: boehm_gc/os_dep.c
===================================================================
RCS file: /home/staff/zs/imp/mercury/boehm_gc/os_dep.c,v
retrieving revision 1.28
diff -u -r1.28 os_dep.c
--- boehm_gc/os_dep.c 6 May 2003 11:36:50 -0000 1.28
+++ boehm_gc/os_dep.c 27 Oct 2003 21:02:33 -0000
@@ -134,6 +134,11 @@
# define jmp_buf sigjmp_buf
#endif
+#ifdef DARWIN
+/* for get_etext and friends */
+#include <mach-o/getsect.h>
+#endif
+
#ifdef DJGPP
/* Apparently necessary for djgpp 2.01. May cause problems with */
/* other versions. */
@@ -152,6 +157,156 @@
# define OPT_PROT_EXEC 0
#endif
+#if defined(LINUX) && \
+ (defined(USE_PROC_FOR_LIBRARIES) || defined(IA64) || !defined(SMALL_CONFIG))
+
+/* We need to parse /proc/self/maps, either to find dynamic libraries, */
+/* and/or to find the register backing store base (IA64). Do it once */
+/* here. */
+
+#define READ read
+
+/* Repeatedly perform a read call until the buffer is filled or */
+/* we encounter EOF. */
+ssize_t GC_repeat_read(int fd, char *buf, size_t count)
+{
+ ssize_t num_read = 0;
+ ssize_t result;
+
+ while (num_read < count) {
+ result = READ(fd, buf + num_read, count - num_read);
+ if (result < 0) return result;
+ if (result == 0) break;
+ num_read += result;
+ }
+ return num_read;
+}
+
+/*
+ * Apply fn to a buffer containing the contents of /proc/self/maps.
+ * Return the result of fn or, if we failed, 0.
+ */
+
+word GC_apply_to_maps(word (*fn)(char *))
+{
+ int f;
+ int result;
+ int maps_size;
+ char maps_temp[32768];
+ char *maps_buf;
+
+ /* Read /proc/self/maps */
+ /* Note that we may not allocate, and thus can't use stdio. */
+ f = open("/proc/self/maps", O_RDONLY);
+ if (-1 == f) return 0;
+ /* stat() doesn't work for /proc/self/maps, so we have to
+ read it to find out how large it is... */
+ maps_size = 0;
+ do {
+ result = GC_repeat_read(f, maps_temp, sizeof(maps_temp));
+ if (result <= 0) return 0;
+ maps_size += result;
+ } while (result == sizeof(maps_temp));
+
+ if (maps_size > sizeof(maps_temp)) {
+ /* If larger than our buffer, close and re-read it. */
+ close(f);
+ f = open("/proc/self/maps", O_RDONLY);
+ if (-1 == f) return 0;
+ maps_buf = alloca(maps_size);
+ if (NULL == maps_buf) return 0;
+ result = GC_repeat_read(f, maps_buf, maps_size);
+ if (result <= 0) return 0;
+ } else {
+ /* Otherwise use the fixed size buffer */
+ maps_buf = maps_temp;
+ }
+
+ close(f);
+ maps_buf[result] = '\0';
+
+ /* Apply fn to result. */
+ return fn(maps_buf);
+}
+
+#endif /* Need GC_apply_to_maps */
+
+#if defined(LINUX) && (defined(USE_PROC_FOR_LIBRARIES) || defined(IA64))
+//
+// GC_parse_map_entry parses an entry from /proc/self/maps so we can
+// locate all writable data segments that belong to shared libraries.
+// The format of one of these entries and the fields we care about
+// is as follows:
+// XXXXXXXX-XXXXXXXX r-xp 00000000 30:05 260537 name of mapping...\n
+// ^^^^^^^^ ^^^^^^^^ ^^^^ ^^
+// start end prot maj_dev
+// 0 9 18 32
+//
+// For 64 bit ABIs:
+// 0 17 34 56
+//
+// The parser is called with a pointer to the entry and the return value
+// is either NULL or is advanced to the next entry(the byte after the
+// trailing '\n'.)
+//
+#if CPP_WORDSZ == 32
+# define OFFSET_MAP_START 0
+# define OFFSET_MAP_END 9
+# define OFFSET_MAP_PROT 18
+# define OFFSET_MAP_MAJDEV 32
+# define ADDR_WIDTH 8
+#endif
+
+#if CPP_WORDSZ == 64
+# define OFFSET_MAP_START 0
+# define OFFSET_MAP_END 17
+# define OFFSET_MAP_PROT 34
+# define OFFSET_MAP_MAJDEV 56
+# define ADDR_WIDTH 16
+#endif
+
+/*
+ * Assign various fields of the first line in buf_ptr to *start, *end,
+ * *prot_buf and *maj_dev. Only *prot_buf may be set for unwritable maps.
+ */
+char *GC_parse_map_entry(char *buf_ptr, word *start, word *end,
+ char *prot_buf, unsigned int *maj_dev)
+{
+ int i;
+ char *tok;
+
+ if (buf_ptr == NULL || *buf_ptr == '\0') {
+ return NULL;
+ }
+
+ memcpy(prot_buf, buf_ptr+OFFSET_MAP_PROT, 4);
+ /* do the protections first. */
+ prot_buf[4] = '\0';
+
+ if (prot_buf[1] == 'w') {/* we can skip all of this if it's not writable. */
+
+ tok = buf_ptr;
+ buf_ptr[OFFSET_MAP_START+ADDR_WIDTH] = '\0';
+ *start = strtoul(tok, NULL, 16);
+
+ tok = buf_ptr+OFFSET_MAP_END;
+ buf_ptr[OFFSET_MAP_END+ADDR_WIDTH] = '\0';
+ *end = strtoul(tok, NULL, 16);
+
+ buf_ptr += OFFSET_MAP_MAJDEV;
+ tok = buf_ptr;
+ while (*buf_ptr != ':') buf_ptr++;
+ *buf_ptr++ = '\0';
+ *maj_dev = strtoul(tok, NULL, 16);
+ }
+
+ while (*buf_ptr && *buf_ptr++ != '\n');
+
+ return buf_ptr;
+}
+
+#endif /* Need to parse /proc/self/maps. */
+
#if defined(SEARCH_FOR_DATA_START)
/* The I386 case can be handled without a search. The Alpha case */
/* used to be handled differently as well, but the rules changed */
@@ -673,6 +828,29 @@
}
#endif
+#ifdef HPUX_STACKBOTTOM
+
+#include <sys/param.h>
+#include <sys/pstat.h>
+
+ ptr_t GC_get_register_stack_base(void)
+ {
+ struct pst_vm_status vm_status;
+
+ int i = 0;
+ while (pstat_getprocvm(&vm_status, sizeof(vm_status), 0, i++) == 1) {
+ if (vm_status.pst_type == PS_RSESTACK) {
+ return (ptr_t) vm_status.pst_vaddr;
+ }
+ }
+
+ /* old way to get the register stackbottom */
+ return (ptr_t)(((word)GC_stackbottom - BACKING_STORE_DISPLACEMENT - 1)
+ & ~(BACKING_STORE_ALIGNMENT - 1));
+ }
+
+#endif /* HPUX_STACK_BOTTOM */
+
#ifdef LINUX_STACKBOTTOM
#include <sys/types.h>
@@ -686,6 +864,33 @@
extern ptr_t __libc_stack_end;
# ifdef IA64
+ /* Try to read the backing store base from /proc/self/maps. */
+ /* We look for the writable mapping with a 0 major device, */
+ /* which is as close to our frame as possible, but below it.*/
+ static word backing_store_base_from_maps(char *maps)
+ {
+ char prot_buf[5];
+ char *buf_ptr = maps;
+ word start, end;
+ unsigned int maj_dev;
+ word current_best = 0;
+ word dummy;
+
+ for (;;) {
+ buf_ptr = GC_parse_map_entry(buf_ptr, &start, &end, prot_buf, &maj_dev);
+ if (buf_ptr == NULL) return current_best;
+ if (prot_buf[1] == 'w' && maj_dev == 0) {
+ if (end < (word)(&dummy) && start > current_best) current_best = start;
+ }
+ }
+ return current_best;
+ }
+
+ static word backing_store_base_from_proc(void)
+ {
+ return GC_apply_to_maps(backing_store_base_from_maps);
+ }
+
# pragma weak __libc_ia64_register_backing_store_base
extern ptr_t __libc_ia64_register_backing_store_base;
@@ -695,13 +900,19 @@
&& 0 != __libc_ia64_register_backing_store_base) {
/* Glibc 2.2.4 has a bug such that for dynamically linked */
/* executables __libc_ia64_register_backing_store_base is */
- /* defined but ininitialized during constructor calls. */
+ /* defined but uninitialized during constructor calls. */
/* Hence we check for both nonzero address and value. */
return __libc_ia64_register_backing_store_base;
} else {
- word result = (word)GC_stackbottom - BACKING_STORE_DISPLACEMENT;
- result += BACKING_STORE_ALIGNMENT - 1;
- result &= ~(BACKING_STORE_ALIGNMENT - 1);
+ word result = backing_store_base_from_proc();
+ if (0 == result) {
+ /* Use dumb heuristics. Works only for default configuration. */
+ result = (word)GC_stackbottom - BACKING_STORE_DISPLACEMENT;
+ result += BACKING_STORE_ALIGNMENT - 1;
+ result &= ~(BACKING_STORE_ALIGNMENT - 1);
+ /* Verify that it's at least readable. If not, we goofed. */
+ GC_noop1(*(word *)result);
+ }
return (ptr_t)result;
}
}
@@ -713,11 +924,8 @@
/* using direct I/O system calls in order to avoid calling malloc */
/* in case REDIRECT_MALLOC is defined. */
# define STAT_BUF_SIZE 4096
-# if defined(GC_USE_LD_WRAP)
-# define STAT_READ __real_read
-# else
-# define STAT_READ read
-# endif
+# define STAT_READ read
+ /* Should probably call the real read, if read is wrapped. */
char stat_buf[STAT_BUF_SIZE];
int f;
char c;
@@ -785,12 +993,15 @@
#endif /* FREEBSD_STACKBOTTOM */
#if !defined(BEOS) && !defined(AMIGA) && !defined(MSWIN32) \
- && !defined(MSWINCE) && !defined(OS2)
+ && !defined(MSWINCE) && !defined(OS2) && !defined(NOSYS) && !defined(ECOS)
ptr_t GC_get_stack_base()
{
+# if defined(HEURISTIC1) || defined(HEURISTIC2) || \
+ defined(LINUX_STACKBOTTOM) || defined(FREEBSD_STACKBOTTOM)
word dummy;
ptr_t result;
+# endif
# define STACKBOTTOM_ALIGNMENT_M1 ((word)STACK_GRAN - 1)
@@ -840,7 +1051,7 @@
# endif /* STACKBOTTOM */
}
-# endif /* ! AMIGA, !OS 2, ! MS Windows, !BEOS */
+# endif /* ! AMIGA, !OS 2, ! MS Windows, !BEOS, !NOSYS, !ECOS */
/*
* Register static data segment(s) as roots.
@@ -952,12 +1163,10 @@
/* all real work is done by GC_register_dynamic_libraries. Under */
/* win32s, we cannot find the data segments associated with dll's. */
/* We register the main data segment here. */
-# ifdef __GCC__
- GC_bool GC_no_win32_dlls = TRUE;
- /* GCC can't do SEH, so we can't use VirtualQuery */
-# else
GC_bool GC_no_win32_dlls = FALSE;
-# endif
+ /* This used to be set for gcc, to avoid dealing with */
+ /* the structured exception handling issues. But we now have */
+ /* assembly code to do that right. */
void GC_init_win32()
{
@@ -1837,7 +2046,6 @@
* make sure that other system calls are similarly protected
* or write only to the stack.
*/
-
GC_bool GC_dirty_maintained = FALSE;
# ifdef DEFAULT_VDB
@@ -1851,6 +2059,9 @@
/* Initialize virtual dirty bit implementation. */
void GC_dirty_init()
{
+# ifdef PRINTSTATS
+ GC_printf0("Initializing DEFAULT_VDB...\n");
+# endif
GC_dirty_maintained = TRUE;
}
@@ -1933,7 +2144,7 @@
* objects only if they are the same.
*/
-# if !defined(MSWIN32) && !defined(MSWINCE)
+# if !defined(MSWIN32) && !defined(MSWINCE) && !defined(DARWIN)
# include <sys/mman.h>
# include <signal.h>
@@ -1952,6 +2163,23 @@
# else
+# ifdef DARWIN
+ /* Using vm_protect (mach syscall) over mprotect (BSD syscall) seems to
+ decrease the likelihood of some of the problems described below. */
+ #include <mach/vm_map.h>
+ extern mach_port_t GC_task_self;
+ #define PROTECT(addr,len) \
+ if(vm_protect(GC_task_self,(vm_address_t)(addr),(vm_size_t)(len), \
+ FALSE,VM_PROT_READ) != KERN_SUCCESS) { \
+ ABORT("vm_portect failed"); \
+ }
+ #define UNPROTECT(addr,len) \
+ if(vm_protect(GC_task_self,(vm_address_t)(addr),(vm_size_t)(len), \
+ FALSE,VM_PROT_READ|VM_PROT_WRITE) != KERN_SUCCESS) { \
+ ABORT("vm_portect failed"); \
+ }
+# else
+
# ifndef MSWINCE
# include <signal.h>
# endif
@@ -1969,20 +2197,22 @@
&protect_junk)) { \
ABORT("un-VirtualProtect failed"); \
}
-
-# endif
+# endif /* !DARWIN */
+# endif /* MSWIN32 || MSWINCE || DARWIN */
#if defined(SUNOS4) || defined(FREEBSD)
typedef void (* SIG_PF)();
-#endif
+#endif /* SUNOS4 || FREEBSD */
+
#if defined(SUNOS5SIGS) || defined(OSF1) || defined(LINUX) \
- || defined(MACOSX) || defined(HURD)
+ || defined(HURD)
# ifdef __STDC__
typedef void (* SIG_PF)(int);
# else
typedef void (* SIG_PF)();
# endif
-#endif
+#endif /* SUNOS5SIGS || OSF1 || LINUX || HURD */
+
#if defined(MSWIN32)
typedef LPTOP_LEVEL_EXCEPTION_FILTER SIG_PF;
# undef SIG_DFL
@@ -1996,7 +2226,8 @@
#if defined(IRIX5) || defined(OSF1) || defined(HURD)
typedef void (* REAL_SIG_PF)(int, int, struct sigcontext *);
-#endif
+#endif /* IRIX5 || OSF1 || HURD */
+
#if defined(SUNOS5SIGS)
# ifdef HPUX
# define SIGINFO __siginfo
@@ -2008,7 +2239,8 @@
# else
typedef void (* REAL_SIG_PF)();
# endif
-#endif
+#endif /* SUNOS5SIGS */
+
#if defined(LINUX)
# if __GLIBC__ > 2 || __GLIBC__ == 2 && __GLIBC_MINOR__ >= 2
typedef struct sigcontext s_c;
@@ -2042,139 +2274,14 @@
return (char *)faultaddr;
}
# endif /* !ALPHA */
-# endif
-
- typedef void (* REAL_SIG_PF)(int, int, struct sigcontext *);
-
-/* Decodes the machine instruction which was responsible for the sending of the
- SIGBUS signal. Sadly this is the only way to find the faulting address because
- the signal handler doesn't get it directly from the kernel (although it is
- available on the Mach level, but droppped by the BSD personality before it
- calls our signal handler...)
- This code should be able to deal correctly with all PPCs starting from the
- 601 up to and including the G4s (including Velocity Engine). */
-#define EXTRACT_OP1(iw) (((iw) & 0xFC000000) >> 26)
-#define EXTRACT_OP2(iw) (((iw) & 0x000007FE) >> 1)
-#define EXTRACT_REGA(iw) (((iw) & 0x001F0000) >> 16)
-#define EXTRACT_REGB(iw) (((iw) & 0x03E00000) >> 21)
-#define EXTRACT_REGC(iw) (((iw) & 0x0000F800) >> 11)
-#define EXTRACT_DISP(iw) ((short *) &(iw))[1]
-
-static char *get_fault_addr(struct sigcontext *scp)
-{
- unsigned int instr = *((unsigned int *) scp->sc_ir);
- unsigned int * regs = &((unsigned int *) scp->sc_regs)[2];
- int disp = 0, tmp;
- unsigned int baseA = 0, baseB = 0;
- unsigned int addr, alignmask = 0xFFFFFFFF;
-
-#ifdef GC_DEBUG_DECODER
- GC_err_printf1("Instruction: 0x%lx\n", instr);
- GC_err_printf1("Opcode 1: d\n", (int)EXTRACT_OP1(instr));
-#endif
- switch(EXTRACT_OP1(instr)) {
- case 38: /* stb */
- case 39: /* stbu */
- case 54: /* stfd */
- case 55: /* stfdu */
- case 52: /* stfs */
- case 53: /* stfsu */
- case 44: /* sth */
- case 45: /* sthu */
- case 47: /* stmw */
- case 36: /* stw */
- case 37: /* stwu */
- tmp = EXTRACT_REGA(instr);
- if(tmp > 0)
- baseA = regs[tmp];
- disp = EXTRACT_DISP(instr);
- break;
- case 31:
-#ifdef GC_DEBUG_DECODER
- GC_err_printf1("Opcode 2: %d\n", (int)EXTRACT_OP2(instr));
-#endif
- switch(EXTRACT_OP2(instr)) {
- case 86: /* dcbf */
- case 54: /* dcbst */
- case 1014: /* dcbz */
- case 247: /* stbux */
- case 215: /* stbx */
- case 759: /* stfdux */
- case 727: /* stfdx */
- case 983: /* stfiwx */
- case 695: /* stfsux */
- case 663: /* stfsx */
- case 918: /* sthbrx */
- case 439: /* sthux */
- case 407: /* sthx */
- case 661: /* stswx */
- case 662: /* stwbrx */
- case 150: /* stwcx. */
- case 183: /* stwux */
- case 151: /* stwx */
- case 135: /* stvebx */
- case 167: /* stvehx */
- case 199: /* stvewx */
- case 231: /* stvx */
- case 487: /* stvxl */
- tmp = EXTRACT_REGA(instr);
- if(tmp > 0)
- baseA = regs[tmp];
- baseB = regs[EXTRACT_REGC(instr)];
- /* determine Altivec alignment mask */
- switch(EXTRACT_OP2(instr)) {
- case 167: /* stvehx */
- alignmask = 0xFFFFFFFE;
- break;
- case 199: /* stvewx */
- alignmask = 0xFFFFFFFC;
- break;
- case 231: /* stvx */
- alignmask = 0xFFFFFFF0;
- break;
- case 487: /* stvxl */
- alignmask = 0xFFFFFFF0;
- break;
- }
- break;
- case 725: /* stswi */
- tmp = EXTRACT_REGA(instr);
- if(tmp > 0)
- baseA = regs[tmp];
- break;
- default: /* ignore instruction */
-#ifdef GC_DEBUG_DECODER
- GC_err_printf("Ignored by inner handler\n");
-#endif
- return NULL;
- break;
- }
- break;
- default: /* ignore instruction */
-#ifdef GC_DEBUG_DECODER
- GC_err_printf("Ignored by main handler\n");
-#endif
- return NULL;
- break;
- }
-
- addr = (baseA + baseB) + disp;
- addr &= alignmask;
-#ifdef GC_DEBUG_DECODER
- GC_err_printf1("BaseA: %d\n", baseA);
- GC_err_printf1("BaseB: %d\n", baseB);
- GC_err_printf1("Disp: %d\n", disp);
- GC_err_printf1("Address: %d\n", addr);
-#endif
- return (char *)addr;
-}
-#endif /* MACOSX */
+# endif /* LINUX */
+#ifndef DARWIN
SIG_PF GC_old_bus_handler;
SIG_PF GC_old_segv_handler; /* Also old MSWIN32 ACCESS_VIOLATION filter */
+#endif /* !DARWIN */
-#ifdef THREADS
+#if defined(THREADS)
/* We need to lock around the bitmap update in the write fault handler */
/* in order to avoid the risk of losing a bit. We do this with a */
/* test-and-set spin lock if we know how to do that. Otherwise we */
@@ -2223,6 +2330,7 @@
#endif /* !THREADS */
/*ARGSUSED*/
+#if !defined(DARWIN)
# if defined (SUNOS4) || defined(FREEBSD)
void GC_write_fault_handler(sig, code, scp, addr)
int sig, code;
@@ -2238,7 +2346,8 @@
# define SIG_OK (sig == SIGBUS)
# define CODE_OK (code == BUS_PAGE_FAULT)
# endif
-# endif
+# endif /* SUNOS4 || FREEBSD */
+
# if defined(IRIX5) || defined(OSF1) || defined(HURD)
# include <errno.h>
void GC_write_fault_handler(int sig, int code, struct sigcontext *scp)
@@ -2254,7 +2363,8 @@
# define SIG_OK (sig == SIGBUS || sig == SIGSEGV)
# define CODE_OK TRUE
# endif
-# endif
+# endif /* IRIX5 || OSF1 || HURD */
+
# if defined(LINUX)
# if defined(ALPHA) || defined(M68K)
void GC_write_fault_handler(int sig, int code, s_c * sc)
@@ -2274,7 +2384,8 @@
/* Should probably consider alignment issues on other */
/* architectures. */
-# endif
+# endif /* LINUX */
+
# if defined(SUNOS5SIGS)
# ifdef __STDC__
void GC_write_fault_handler(int sig, struct SIGINFO *scp, void * context)
@@ -2295,13 +2406,7 @@
# define SIG_OK (sig == SIGSEGV)
# define CODE_OK (scp -> si_code == SEGV_ACCERR)
# endif
-# endif
-
-# if defined(MACOSX)
- void GC_write_fault_handler(int sig, int code, struct sigcontext *scp)
-# define SIG_OK (sig == SIGBUS)
-# define CODE_OK (code == 0 /* experimentally determined */)
-# endif
+# endif /* SUNOS5SIGS */
# if defined(MSWIN32) || defined(MSWINCE)
LONG WINAPI GC_write_fault_handler(struct _EXCEPTION_POINTERS *exc_info)
@@ -2309,7 +2414,7 @@
STATUS_ACCESS_VIOLATION)
# define CODE_OK (exc_info -> ExceptionRecord -> ExceptionInformation[0] == 1)
/* Write fault */
-# endif
+# endif /* MSWIN32 || MSWINCE */
{
register unsigned i;
# if defined(HURD)
@@ -2380,9 +2485,6 @@
# endif
# endif
# endif
-# if defined(MACOSX)
- char * addr = get_fault_addr(scp);
-# endif
# if defined(MSWIN32) || defined(MSWINCE)
char * addr = (char *) (exc_info -> ExceptionRecord
-> ExceptionInformation[1]);
@@ -2446,9 +2548,6 @@
(*(REAL_SIG_PF)old_handler) (sig, code, scp);
return;
# endif
-# ifdef MACOSX
- (*(REAL_SIG_PF)old_handler) (sig, code, scp);
-# endif
# ifdef MSWIN32
return((*old_handler)(exc_info));
# endif
@@ -2490,6 +2589,7 @@
ABORT("Unexpected bus error or segmentation fault");
#endif
}
+#endif /* !DARWIN */
/*
* We hold the allocation lock. We expect block h to be written
@@ -2522,6 +2622,7 @@
UNPROTECT(h_trunc, (ptr_t)h_end - (ptr_t)h_trunc);
}
+#if !defined(DARWIN)
void GC_dirty_init()
{
# if defined(SUNOS5SIGS) || defined(IRIX5) || defined(LINUX) || \
@@ -2544,13 +2645,6 @@
(void)sigaddset(&act.sa_mask, SIG_SUSPEND);
# endif /* SIG_SUSPEND */
# endif
-# if defined(MACOSX)
- struct sigaction act, oldact;
-
- act.sa_flags = SA_RESTART;
- act.sa_handler = GC_write_fault_handler;
- sigemptyset(&act.sa_mask);
-# endif
# ifdef PRINTSTATS
GC_printf0("Inititalizing mprotect virtual dirty bit implementation\n");
# endif
@@ -2590,7 +2684,10 @@
sigaction(SIGSEGV, 0, &oldact);
sigaction(SIGSEGV, &act, 0);
# else
- sigaction(SIGSEGV, &act, &oldact);
+ {
+ int res = sigaction(SIGSEGV, &act, &oldact);
+ if (res != 0) ABORT("Sigaction failed");
+ }
# endif
# if defined(_sigargs) || defined(HURD) || !defined(SA_SIGINFO)
/* This is Irix 5.x, not 6.x. Irix 5.x does not have */
@@ -2613,7 +2710,7 @@
# endif
}
# endif
-# if defined(MACOSX) || defined(HPUX) || defined(LINUX) || defined(HURD)
+# if defined(HPUX) || defined(LINUX) || defined(HURD)
sigaction(SIGBUS, &act, &oldact);
GC_old_bus_handler = oldact.sa_handler;
if (GC_old_bus_handler == SIG_IGN) {
@@ -2625,7 +2722,7 @@
GC_err_printf0("Replaced other SIGBUS handler\n");
# endif
}
-# endif /* MACOS || HPUX || LINUX */
+# endif /* HPUX || LINUX || HURD */
# if defined(MSWIN32)
GC_old_segv_handler = SetUnhandledExceptionFilter(GC_write_fault_handler);
if (GC_old_segv_handler != NULL) {
@@ -2637,6 +2734,7 @@
}
# endif
}
+#endif /* !DARWIN */
int GC_incremental_protection_needs()
{
@@ -2886,13 +2984,6 @@
{
}
-# else /* !MPROTECT_VDB */
-
-# ifdef GC_USE_LD_WRAP
- ssize_t __wrap_read(int fd, void *buf, size_t nbyte)
- { return __real_read(fd, buf, nbyte); }
-# endif
-
# endif /* MPROTECT_VDB */
# ifdef PROC_VDB
@@ -3211,6 +3302,552 @@
# endif /* PCR_VDB */
+#if defined(MPROTECT_VDB) && defined(DARWIN)
+/* The following sources were used as a *reference* for this exception handling
+ code:
+ 1. Apple's mach/xnu documentation
+ 2. Timothy J. Wood's "Mach Exception Handlers 101" post to the
+ omnigroup's macosx-dev list.
+ www.omnigroup.com/mailman/archive/macosx-dev/2000-June/002030.html
+ 3. macosx-nat.c from Apple's GDB source code.
+*/
+
+/* The bug that caused all this trouble should now be fixed. This should
+ eventually be removed if all goes well. */
+/* define BROKEN_EXCEPTION_HANDLING */
+
+#include <mach/mach.h>
+#include <mach/mach_error.h>
+#include <mach/thread_status.h>
+#include <mach/exception.h>
+#include <mach/task.h>
+#include <pthread.h>
+
+/* These are not defined in any header, although they are documented */
+extern boolean_t exc_server(mach_msg_header_t *,mach_msg_header_t *);
+extern kern_return_t exception_raise(
+ mach_port_t,mach_port_t,mach_port_t,
+ exception_type_t,exception_data_t,mach_msg_type_number_t);
+extern kern_return_t exception_raise_state(
+ mach_port_t,mach_port_t,mach_port_t,
+ exception_type_t,exception_data_t,mach_msg_type_number_t,
+ thread_state_flavor_t*,thread_state_t,mach_msg_type_number_t,
+ thread_state_t,mach_msg_type_number_t*);
+extern kern_return_t exception_raise_state_identity(
+ mach_port_t,mach_port_t,mach_port_t,
+ exception_type_t,exception_data_t,mach_msg_type_number_t,
+ thread_state_flavor_t*,thread_state_t,mach_msg_type_number_t,
+ thread_state_t,mach_msg_type_number_t*);
+
+
+#define MAX_EXCEPTION_PORTS 16
+
+static mach_port_t GC_task_self;
+
+static struct {
+ mach_msg_type_number_t count;
+ exception_mask_t masks[MAX_EXCEPTION_PORTS];
+ exception_handler_t ports[MAX_EXCEPTION_PORTS];
+ exception_behavior_t behaviors[MAX_EXCEPTION_PORTS];
+ thread_state_flavor_t flavors[MAX_EXCEPTION_PORTS];
+} GC_old_exc_ports;
+
+static struct {
+ mach_port_t exception;
+#if defined(THREADS)
+ mach_port_t reply;
+#endif
+} GC_ports;
+
+typedef struct {
+ mach_msg_header_t head;
+} GC_msg_t;
+
+typedef enum {
+ GC_MP_NORMAL, GC_MP_DISCARDING, GC_MP_STOPPED
+} GC_mprotect_state_t;
+
+/* FIXME: 1 and 2 seem to be safe to use in the msgh_id field,
+ but it isn't documented. Use the source and see if they
+ should be ok. */
+#define ID_STOP 1
+#define ID_RESUME 2
+
+/* These values are only used on the reply port */
+#define ID_ACK 3
+
+#if defined(THREADS)
+
+GC_mprotect_state_t GC_mprotect_state;
+
+/* The following should ONLY be called when the world is stopped */
+static void GC_mprotect_thread_notify(mach_msg_id_t id) {
+ struct {
+ GC_msg_t msg;
+ mach_msg_trailer_t trailer;
+ } buf;
+ mach_msg_return_t r;
+ /* remote, local */
+ buf.msg.head.msgh_bits =
+ MACH_MSGH_BITS(MACH_MSG_TYPE_MAKE_SEND,0);
+ buf.msg.head.msgh_size = sizeof(buf.msg);
+ buf.msg.head.msgh_remote_port = GC_ports.exception;
+ buf.msg.head.msgh_local_port = MACH_PORT_NULL;
+ buf.msg.head.msgh_id = id;
+
+ r = mach_msg(
+ &buf.msg.head,
+ MACH_SEND_MSG|MACH_RCV_MSG|MACH_RCV_LARGE,
+ sizeof(buf.msg),
+ sizeof(buf),
+ GC_ports.reply,
+ MACH_MSG_TIMEOUT_NONE,
+ MACH_PORT_NULL);
+ if(r != MACH_MSG_SUCCESS)
+ ABORT("mach_msg failed in GC_mprotect_thread_notify");
+ if(buf.msg.head.msgh_id != ID_ACK)
+ ABORT("invalid ack in GC_mprotect_thread_notify");
+}
+
+/* Should only be called by the mprotect thread */
+static void GC_mprotect_thread_reply() {
+ GC_msg_t msg;
+ mach_msg_return_t r;
+ /* remote, local */
+ msg.head.msgh_bits =
+ MACH_MSGH_BITS(MACH_MSG_TYPE_MAKE_SEND,0);
+ msg.head.msgh_size = sizeof(msg);
+ msg.head.msgh_remote_port = GC_ports.reply;
+ msg.head.msgh_local_port = MACH_PORT_NULL;
+ msg.head.msgh_id = ID_ACK;
+
+ r = mach_msg(
+ &msg.head,
+ MACH_SEND_MSG,
+ sizeof(msg),
+ 0,
+ MACH_PORT_NULL,
+ MACH_MSG_TIMEOUT_NONE,
+ MACH_PORT_NULL);
+ if(r != MACH_MSG_SUCCESS)
+ ABORT("mach_msg failed in GC_mprotect_thread_reply");
+}
+
+void GC_mprotect_stop() {
+ GC_mprotect_thread_notify(ID_STOP);
+}
+void GC_mprotect_resume() {
+ GC_mprotect_thread_notify(ID_RESUME);
+}
+
+#else /* !THREADS */
+/* The compiler should optimize away any GC_mprotect_state computations */
+#define GC_mprotect_state GC_MP_NORMAL
+#endif
+
+static void *GC_mprotect_thread(void *arg) {
+ mach_msg_return_t r;
+ /* These two structures contain some private kernel data. We don't need to
+ access any of it so we don't bother defining a proper struct. The
+ correct definitions are in the xnu source code. */
+ struct {
+ mach_msg_header_t head;
+ char data[256];
+ } reply;
+ struct {
+ mach_msg_header_t head;
+ mach_msg_body_t msgh_body;
+ char data[1024];
+ } msg;
+
+ mach_msg_id_t id;
+
+ for(;;) {
+ r = mach_msg(
+ &msg.head,
+ MACH_RCV_MSG|MACH_RCV_LARGE|
+ 0,
+ sizeof(msg),
+ GC_ports.exception,
+ MACH_PORT_NULL);
+
+
+#if defined(THREADS)
+ if(GC_mprotect_state == GC_MP_DISCARDING) {
+ if(r == MACH_RCV_TIMED_OUT) {
+ GC_mprotect_state = GC_MP_STOPPED;
+ GC_mprotect_thread_reply();
+ continue;
+ }
+ if(r == MACH_MSG_SUCCESS && (id == ID_STOP || id == ID_RESUME))
+ ABORT("out of order mprotect thread request");
+ }
+#endif
+
+ if(r != MACH_MSG_SUCCESS) {
+ GC_err_printf2("mach_msg failed with %d %s\n",
+ (int)r,mach_error_string(r));
+ ABORT("mach_msg failed");
+ }
+
+ switch(id) {
+#if defined(THREADS)
+ case ID_STOP:
+ if(GC_mprotect_state != GC_MP_NORMAL)
+ ABORT("Called mprotect_stop when state wasn't normal");
+ GC_mprotect_state = GC_MP_DISCARDING;
+ break;
+ case ID_RESUME:
+ if(GC_mprotect_state != GC_MP_STOPPED)
+ ABORT("Called mprotect_resume when state wasn't stopped");
+ GC_mprotect_state = GC_MP_NORMAL;
+ GC_mprotect_thread_reply();
+ break;
+#endif /* THREADS */
+ default:
+ /* Handle the message (calls catch_exception_raise) */
+ if(!exc_server(&msg.head,&reply.head))
+ ABORT("exc_server failed");
+ /* Send the reply */
+ r = mach_msg(
+ &reply.head,
+ MACH_SEND_MSG,
+ reply.head.msgh_size,
+ 0,
+ MACH_PORT_NULL,
+ MACH_MSG_TIMEOUT_NONE,
+ MACH_PORT_NULL);
+ if(r != MACH_MSG_SUCCESS) {
+ /* This will fail if the thread dies, but the thread shouldn't
+ die... */
+ #ifdef BROKEN_EXCEPTION_HANDLING
+ GC_err_printf2(
+ "mach_msg failed with %d %s while sending exc reply\n",
+ (int)r,mach_error_string(r));
+ #else
+ ABORT("mach_msg failed while sending exception reply");
+ #endif
+ }
+ } /* switch */
+ } /* for(;;) */
+ /* NOT REACHED */
+ return NULL;
+}
+
+/* All this SIGBUS code shouldn't be necessary. All protection faults should
+ be going throught the mach exception handler. However, it seems a SIGBUS is
+ occasionally sent for some unknown reason. Even more odd, it seems to be
+ meaningless and safe to ignore. */
+#ifdef BROKEN_EXCEPTION_HANDLING
+
+typedef void (* SIG_PF)();
+static SIG_PF GC_old_bus_handler;
+
+/* Updates to this aren't atomic, but the SIGBUSs seem pretty rare.
+ Even if this doesn't get updated property, it isn't really a problem */
+static int GC_sigbus_count;
+
+static void GC_darwin_sigbus(int num,siginfo_t *sip,void *context) {
+ if(num != SIGBUS) ABORT("Got a non-sigbus signal in the sigbus handler");
+
+ /* Ugh... some seem safe to ignore, but too many in a row probably means
+ trouble. GC_sigbus_count is reset for each mach exception that is
+ handled */
+ if(GC_sigbus_count >= 8) {
+ ABORT("Got more than 8 SIGBUSs in a row!");
+ } else {
+ GC_sigbus_count++;
+ GC_err_printf0("GC: WARNING: Ignoring SIGBUS.\n");
+ }
+}
+#endif /* BROKEN_EXCEPTION_HANDLING */
+
+void GC_dirty_init() {
+ kern_return_t r;
+ mach_port_t me;
+ pthread_t thread;
+ pthread_attr_t attr;
+ exception_mask_t mask;
+
+# ifdef PRINTSTATS
+ GC_printf0("Inititalizing mach/darwin mprotect virtual dirty bit "
+ "implementation\n");
+# endif
+# ifdef BROKEN_EXCEPTION_HANDLING
+ GC_err_printf0("GC: WARNING: Enabling workarounds for various darwin "
+ "exception handling bugs.\n");
+# endif
+ GC_dirty_maintained = TRUE;
+ if (GC_page_size % HBLKSIZE != 0) {
+ GC_err_printf0("Page size not multiple of HBLKSIZE\n");
+ ABORT("Page size not multiple of HBLKSIZE");
+ }
+
+ GC_task_self = me = mach_task_self();
+
+ r = mach_port_allocate(me,MACH_PORT_RIGHT_RECEIVE,&GC_ports.exception);
+ if(r != KERN_SUCCESS) ABORT("mach_port_allocate failed (exception port)");
+
+ r = mach_port_insert_right(me,GC_ports.exception,GC_ports.exception,
+ MACH_MSG_TYPE_MAKE_SEND);
+ if(r != KERN_SUCCESS)
+ ABORT("mach_port_insert_right failed (exception port)");
+
+ #if defined(THREADS)
+ r = mach_port_allocate(me,MACH_PORT_RIGHT_RECEIVE,&GC_ports.reply);
+ if(r != KERN_SUCCESS) ABORT("mach_port_allocate failed (reply port)");
+ #endif
+
+ /* The exceptions we want to catch */
+ mask = EXC_MASK_BAD_ACCESS;
+
+ r = task_get_exception_ports(
+ me,
+ mask,
+ GC_old_exc_ports.masks,
+ &GC_old_exc_ports.count,
+ GC_old_exc_ports.ports,
+ GC_old_exc_ports.behaviors,
+ GC_old_exc_ports.flavors
+ );
+ if(r != KERN_SUCCESS) ABORT("task_get_exception_ports failed");
+
+ r = task_set_exception_ports(
+ me,
+ mask,
+ GC_ports.exception,
+ EXCEPTION_DEFAULT,
+ MACHINE_THREAD_STATE
+ );
+ if(r != KERN_SUCCESS) ABORT("task_set_exception_ports failed");
+
+ if(pthread_attr_init(&attr) != 0) ABORT("pthread_attr_init failed");
+ if(pthread_attr_setdetachstate(&attr,PTHREAD_CREATE_DETACHED) != 0)
+ ABORT("pthread_attr_setdetachedstate failed");
+
+# undef pthread_create
+ /* This will call the real pthread function, not our wrapper */
+ if(pthread_create(&thread,&attr,GC_mprotect_thread,NULL) != 0)
+ ABORT("pthread_create failed");
+ pthread_attr_destroy(&attr);
+
+ /* Setup the sigbus handler for ignoring the meaningless SIGBUSs */
+ #ifdef BROKEN_EXCEPTION_HANDLING
+ {
+ struct sigaction sa, oldsa;
+ sa.sa_handler = (SIG_PF)GC_darwin_sigbus;
+ sigemptyset(&sa.sa_mask);
+ sa.sa_flags = SA_RESTART|SA_SIGINFO;
+ if(sigaction(SIGBUS,&sa,&oldsa) < 0) ABORT("sigaction");
+ GC_old_bus_handler = (SIG_PF)oldsa.sa_handler;
+ if (GC_old_bus_handler != SIG_DFL) {
+# ifdef PRINTSTATS
+ GC_err_printf0("Replaced other SIGBUS handler\n");
+# endif
+ }
+ }
+ #endif /* BROKEN_EXCEPTION_HANDLING */
+}
+
+/* The source code for Apple's GDB was used as a reference for the exception
+ forwarding code. This code is similar to be GDB code only because there is
+ only one way to do it. */
+static kern_return_t GC_forward_exception(
+ mach_port_t thread,
+ mach_port_t task,
+ exception_type_t exception,
+ exception_data_t data,
+ mach_msg_type_number_t data_count
+) {
+ int i;
+ kern_return_t r;
+ mach_port_t port;
+ exception_behavior_t behavior;
+ thread_state_flavor_t flavor;
+
+ thread_state_data_t thread_state;
+ mach_msg_type_number_t thread_state_count = THREAD_STATE_MAX;
+
+ for(i=0;i<GC_old_exc_ports.count;i++)
+ if(GC_old_exc_ports.masks[i] & (1 << exception))
+ break;
+ if(i==GC_old_exc_ports.count) ABORT("No handler for exception!");
+
+ port = GC_old_exc_ports.ports[i];
+ behavior = GC_old_exc_ports.behaviors[i];
+ flavor = GC_old_exc_ports.flavors[i];
+
+ if(behavior != EXCEPTION_DEFAULT) {
+ r = thread_get_state(thread,flavor,thread_state,&thread_state_count);
+ if(r != KERN_SUCCESS)
+ ABORT("thread_get_state failed in forward_exception");
+ }
+
+ switch(behavior) {
+ case EXCEPTION_DEFAULT:
+ r = exception_raise(port,thread,task,exception,data,data_count);
+ break;
+ case EXCEPTION_STATE:
+ r = exception_raise_state(port,thread,task,exception,data,
+ data_count,&flavor,thread_state,thread_state_count,
+ thread_state,&thread_state_count);
+ break;
+ case EXCEPTION_STATE_IDENTITY:
+ r = exception_raise_state_identity(port,thread,task,exception,data,
+ data_count,&flavor,thread_state,thread_state_count,
+ thread_state,&thread_state_count);
+ break;
+ default:
+ r = KERN_FAILURE; /* make gcc happy */
+ ABORT("forward_exception: unknown behavior");
+ break;
+ }
+
+ if(behavior != EXCEPTION_DEFAULT) {
+ r = thread_set_state(thread,flavor,thread_state,thread_state_count);
+ if(r != KERN_SUCCESS)
+ ABORT("thread_set_state failed in forward_exception");
+ }
+
+ return r;
+}
+
+#define FWD() GC_forward_exception(thread,task,exception,code,code_count)
+
+/* This violates the namespace rules but there isn't anything that can be done
+ about it. The exception handling stuff is hard coded to call this */
+kern_return_t
+catch_exception_raise(
+ mach_port_t exception_port,mach_port_t thread,mach_port_t task,
+ exception_type_t exception,exception_data_t code,
+ mach_msg_type_number_t code_count
+) {
+ kern_return_t r;
+ char *addr;
+ struct hblk *h;
+ int i;
+#ifdef POWERPC
+ thread_state_flavor_t flavor = PPC_EXCEPTION_STATE;
+ mach_msg_type_number_t exc_state_count = PPC_EXCEPTION_STATE_COUNT;
+ ppc_exception_state_t exc_state;
+#else
+# error FIXME for non-ppc darwin
+#endif
+
+
+ if(exception != EXC_BAD_ACCESS || code[0] != KERN_PROTECTION_FAILURE) {
+ #ifdef DEBUG_EXCEPTION_HANDLING
+ /* We aren't interested, pass it on to the old handler */
+ GC_printf3("Exception: 0x%x Code: 0x%x 0x%x in catch....\n",
+ exception,
+ #endif
+ return FWD();
+ }
+
+ r = thread_get_state(thread,flavor,
+ (natural_t*)&exc_state,&exc_state_count);
+ if(r != KERN_SUCCESS) {
+ /* The thread is supposed to be suspended while the exception handler
+ is called. This shouldn't fail. */
+ #ifdef BROKEN_EXCEPTION_HANDLING
+ GC_err_printf0("thread_get_state failed in "
+ "catch_exception_raise\n");
+ return KERN_SUCCESS;
+ #else
+ ABORT("thread_get_state failed in catch_exception_raise");
+ #endif
+ }
+
+ /* This is the address that caused the fault */
+ addr = (char*) exc_state.dar;
+
+ if((HDR(addr)) == 0) {
+ /* Ugh... just like the SIGBUS problem above, it seems we get a bogus
+ KERN_PROTECTION_FAILURE every once and a while. We wait till we get
+ a bunch in a row before doing anything about it. If a "real" fault
+ ever occurres it'll just keep faulting over and over and we'll hit
+ the limit pretty quickly. */
+ #ifdef BROKEN_EXCEPTION_HANDLING
+ static char *last_fault;
+ static int last_fault_count;
+
+ if(addr != last_fault) {
+ last_fault = addr;
+ last_fault_count = 0;
+ }
+ if(++last_fault_count < 32) {
+ if(last_fault_count == 1)
+ GC_err_printf1(
+ "GC: WARNING: Ignoring KERN_PROTECTION_FAILURE at %p\n",
+ addr);
+ return KERN_SUCCESS;
+ }
+
+ GC_err_printf1("Unexpected KERN_PROTECTION_FAILURE at %p\n",addr);
+ /* Can't pass it along to the signal handler because that is
+ ignoring SIGBUS signals. We also shouldn't call ABORT here as
+ signals don't always work too well from the exception handler. */
+ GC_err_printf0("Aborting\n");
+ exit(EXIT_FAILURE);
+ #else /* BROKEN_EXCEPTION_HANDLING */
+ /* Pass it along to the next exception handler
+ (which should call SIGBUS/SIGSEGV) */
+ return FWD();
+ #endif /* !BROKEN_EXCEPTION_HANDLING */
+ }
+
+ #ifdef BROKEN_EXCEPTION_HANDLING
+ /* Reset the number of consecutive SIGBUSs */
+ GC_sigbus_count = 0;
+ #endif
+
+ if(GC_mprotect_state == GC_MP_NORMAL) { /* common case */
+ h = (struct hblk*)((word)addr & ~(GC_page_size-1));
+ UNPROTECT(h, GC_page_size);
+ for (i = 0; i < divHBLKSZ(GC_page_size); i++) {
+ register int index = PHT_HASH(h+i);
+ async_set_pht_entry_from_index(GC_dirty_pages, index);
+ }
+ } else if(GC_mprotect_state == GC_MP_DISCARDING) {
+ /* Lie to the thread for now. No sense UNPROTECT()ing the memory
+ when we're just going to PROTECT() it again later. The thread
+ will just fault again once it resumes */
+ } else {
+ /* Shouldn't happen, i don't think */
+ GC_printf0("KERN_PROTECTION_FAILURE while world is stopped\n");
+ return FWD();
+ }
+ return KERN_SUCCESS;
+}
+#undef FWD
+
+/* These should never be called, but just in case... */
+kern_return_t catch_exception_raise_state(mach_port_name_t exception_port,
+ int exception, exception_data_t code, mach_msg_type_number_t codeCnt,
+ int flavor, thread_state_t old_state, int old_stateCnt,
+ thread_state_t new_state, int new_stateCnt)
+{
+ ABORT("catch_exception_raise_state");
+ return(KERN_INVALID_ARGUMENT);
+}
+kern_return_t catch_exception_raise_state_identity(
+ mach_port_name_t exception_port, mach_port_t thread, mach_port_t task,
+ int exception, exception_data_t code, mach_msg_type_number_t codeCnt,
+ int flavor, thread_state_t old_state, int old_stateCnt,
+ thread_state_t new_state, int new_stateCnt)
+{
+ ABORT("catch_exception_raise_state_identity");
+ return(KERN_INVALID_ARGUMENT);
+}
+
+
+#endif /* DARWIN && MPROTECT_VDB */
+
# ifndef HAVE_INCREMENTAL_PROTECTION_NEEDS
int GC_incremental_protection_needs()
{
@@ -3330,8 +3967,6 @@
asm("movl %%ebp,%0" : "=r"(frame));
fp = frame;
# else
- word GC_save_regs_in_stack();
-
frame = (struct frame *) GC_save_regs_in_stack ();
fp = (struct frame *)((long) frame -> FR_SAVFP + BIAS);
#endif
@@ -3472,7 +4107,7 @@
}
name = result_buf;
pclose(pipe);
- out:
+ out:;
}
# endif /* LINUX */
GC_err_printf1("\t\t%s\n", name);
@@ -3488,31 +4123,6 @@
#endif /* NEED_CALLINFO */
-#if defined(LINUX) && defined(__ELF__) && \
- (!defined(SMALL_CONFIG) || defined(USE_PROC_FOR_LIBRARIES))
-#ifdef GC_USE_LD_WRAP
-# define READ __real_read
-#else
-# define READ read
-#endif
-
-
-/* Repeatedly perform a read call until the buffer is filled or */
-/* we encounter EOF. */
-ssize_t GC_repeat_read(int fd, char *buf, size_t count)
-{
- ssize_t num_read = 0;
- ssize_t result;
-
- while (num_read < count) {
- result = READ(fd, buf + num_read, count - num_read);
- if (result < 0) return result;
- if (result == 0) break;
- num_read += result;
- }
- return num_read;
-}
-#endif /* LINUX && ... */
#if defined(LINUX) && defined(__ELF__) && !defined(SMALL_CONFIG)
@@ -3520,20 +4130,16 @@
/* Dump /proc/self/maps to GC_stderr, to enable looking up names for
addresses in FIND_LEAK output. */
+static word dump_maps(char *maps)
+{
+ GC_err_write(maps, strlen(maps));
+ return 1;
+}
+
void GC_print_address_map()
{
- int f;
- int result;
- char maps_temp[32768];
GC_err_printf0("---------- Begin address map ----------\n");
- f = open("/proc/self/maps", O_RDONLY);
- if (-1 == f) ABORT("Couldn't open /proc/self/maps");
- do {
- result = GC_repeat_read(f, maps_temp, sizeof(maps_temp));
- if (result <= 0) ABORT("Couldn't read /proc/self/maps");
- GC_err_write(maps_temp, result);
- } while (result == sizeof(maps_temp));
- close(f);
+ GC_apply_to_maps(dump_maps);
GC_err_printf0("---------- End address map ----------\n");
}
Index: boehm_gc/powerpc_macosx_mach_dep.s
===================================================================
RCS file: boehm_gc/powerpc_macosx_mach_dep.s
diff -N boehm_gc/powerpc_macosx_mach_dep.s
--- boehm_gc/powerpc_macosx_mach_dep.s 25 Jul 2002 09:02:48 -0000 1.2
+++ /dev/null 1 Jan 1970 00:00:00 -0000
@@ -1,95 +0,0 @@
-
-.text
-
- .set linkageArea,24
- .set params,4
- .set alignment,4
-
- .set spaceToSave,linkageArea+params+alignment
- .set spaceToSave8,spaceToSave+8
-
-; Mark from machine registers that are saved by C compiler
- .globl _GC_push_regs
-_GC_push_regs:
- ; PROLOG
- mflr r0 ; get return address
- stw r0,8(r1) ; save return address
- stwu r1,-spaceToSave(r1) ; skip over caller save area
- ;
- mr r3,r2 ; mark from r2. Well Im not really sure
- ; that this is necessary or even the right
- ; thing to do - at least it doesnt harm...
- ; According to Apples docs it points to
- ; the direct data area, whatever that is...
- bl L_GC_push_one$stub
- mr r3,r13 ; mark from r13-r31
- bl L_GC_push_one$stub
- mr r3,r14
- bl L_GC_push_one$stub
- mr r3,r15
- bl L_GC_push_one$stub
- mr r3,r16
- bl L_GC_push_one$stub
- mr r3,r17
- bl L_GC_push_one$stub
- mr r3,r18
- bl L_GC_push_one$stub
- mr r3,r19
- bl L_GC_push_one$stub
- mr r3,r20
- bl L_GC_push_one$stub
- mr r3,r21
- bl L_GC_push_one$stub
- mr r3,r22
- bl L_GC_push_one$stub
- mr r3,r23
- bl L_GC_push_one$stub
- mr r3,r24
- bl L_GC_push_one$stub
- mr r3,r25
- bl L_GC_push_one$stub
- mr r3,r26
- bl L_GC_push_one$stub
- mr r3,r27
- bl L_GC_push_one$stub
- mr r3,r28
- bl L_GC_push_one$stub
- mr r3,r29
- bl L_GC_push_one$stub
- mr r3,r30
- bl L_GC_push_one$stub
- mr r3,r31
- bl L_GC_push_one$stub
- ; EPILOG
- lwz r0,spaceToSave8(r1) ; get return address back
- mtlr r0 ; reset link register
- addic r1,r1,spaceToSave ; restore stack pointer
- blr
-
-.data
-.picsymbol_stub
-L_GC_push_one$stub:
- .indirect_symbol _GC_push_one
- mflr r0
- bcl 20,31,L0$_GC_push_one
-L0$_GC_push_one:
- mflr r11
- addis r11,r11,ha16(L_GC_push_one$lazy_ptr-L0$_GC_push_one)
- mtlr r0
- lwz r12,lo16(L_GC_push_one$lazy_ptr-L0$_GC_push_one)(r11)
- mtctr r12
- addi r11,r11,lo16(L_GC_push_one$lazy_ptr-L0$_GC_push_one)
- bctr
-.data
-.lazy_symbol_pointer
-L_GC_push_one$lazy_ptr:
- .indirect_symbol _GC_push_one
- .long dyld_stub_binding_helper
-.non_lazy_symbol_pointer
-L_GC_push_one$non_lazy_ptr:
- .indirect_symbol _GC_push_one
- .long 0
-
-
-
-
Index: boehm_gc/ptr_chck.c
===================================================================
RCS file: /home/staff/zs/imp/mercury/boehm_gc/ptr_chck.c,v
retrieving revision 1.2
diff -u -r1.2 ptr_chck.c
--- boehm_gc/ptr_chck.c 27 Oct 2003 20:50:15 -0000 1.2
+++ boehm_gc/ptr_chck.c 27 Oct 2003 21:02:34 -0000
@@ -79,7 +79,7 @@
return(p);
}
sz = WORDS_TO_BYTES(hhdr -> hb_sz);
- if (sz > WORDS_TO_BYTES(MAXOBJSZ)) {
+ if (sz > MAXOBJBYTES) {
base = (ptr_t)HBLKPTR(p);
limit = base + sz;
if ((ptr_t)p >= limit) {
@@ -165,7 +165,7 @@
pdispl = HBLKDISPL(p);
map_entry = MAP_ENTRY((hhdr -> hb_map), pdispl);
if (map_entry == OBJ_INVALID
- || sz > MAXOBJSZ && (ptr_t)p >= (ptr_t)h + sz) {
+ || sz > MAXOBJBYTES && (ptr_t)p >= (ptr_t)h + sz) {
goto fail;
}
return(p);
Index: boehm_gc/reclaim.c
===================================================================
RCS file: /home/staff/zs/imp/mercury/boehm_gc/reclaim.c,v
retrieving revision 1.12
diff -u -r1.12 reclaim.c
--- boehm_gc/reclaim.c 6 May 2003 11:36:50 -0000 1.12
+++ boehm_gc/reclaim.c 27 Oct 2003 21:02:34 -0000
@@ -904,7 +904,7 @@
* Clear *flp.
* This must be done before dropping a list of free gcj-style objects,
* since may otherwise end up with dangling "descriptor" pointers.
- * It may help for other pointer-containg objects.
+ * It may help for other pointer-containing objects.
*/
void GC_clear_fl_links(flp)
ptr_t *flp;
Index: boehm_gc/threadlibs.c
===================================================================
RCS file: /home/staff/zs/imp/mercury/boehm_gc/threadlibs.c,v
retrieving revision 1.7
diff -u -r1.7 threadlibs.c
--- boehm_gc/threadlibs.c 6 May 2003 11:36:50 -0000 1.7
+++ boehm_gc/threadlibs.c 27 Oct 2003 21:02:34 -0000
@@ -4,14 +4,14 @@
int main()
{
# if defined(GC_USE_LD_WRAP)
- printf("-Wl,--wrap -Wl,read -Wl,--wrap -Wl,dlopen "
+ printf("-Wl,--wrap -Wl,dlopen "
"-Wl,--wrap -Wl,pthread_create -Wl,--wrap -Wl,pthread_join "
"-Wl,--wrap -Wl,pthread_detach "
"-Wl,--wrap -Wl,pthread_sigmask -Wl,--wrap -Wl,sleep\n");
# endif
# if defined(GC_LINUX_THREADS) || defined(GC_IRIX_THREADS) \
|| defined(GC_FREEBSD_THREADS) || defined(GC_SOLARIS_PTHREADS) \
- || defined(GC_MACOSX_THREADS)
+ || defined(GC_DARWIN_THREADS) || defined(GC_AIX_THREADS)
printf("-lpthread\n");
# endif
# if defined(GC_HPUX_THREADS) || defined(GC_OSF1_THREADS)
@@ -24,7 +24,7 @@
printf("-lpthread\n");
# endif
# if defined(GC_OSF1_THREADS)
- printf("-lpthread -lrt");
+ printf("-pthread -lrt"); /* DOB: must be -pthread, not -lpthread */
# endif
/* You need GCC 3.0.3 to build this one! */
/* DG/UX native gcc doesnt know what "-pthread" is */
Index: boehm_gc/version.h
===================================================================
RCS file: /home/staff/zs/imp/mercury/boehm_gc/version.h,v
retrieving revision 1.8
diff -u -r1.8 version.h
--- boehm_gc/version.h 6 May 2003 11:36:50 -0000 1.8
+++ boehm_gc/version.h 27 Oct 2003 21:02:34 -0000
@@ -2,13 +2,18 @@
/* Eventually this one may become unnecessary. For now we need */
/* it to keep the old-style build process working. */
#define GC_TMP_VERSION_MAJOR 6
-#define GC_TMP_VERSION_MINOR 2
-#define GC_TMP_ALPHA_VERSION 4
+#define GC_TMP_VERSION_MINOR 3
+#define GC_TMP_ALPHA_VERSION 2
+
+#ifndef GC_NOT_ALPHA
+# define GC_NOT_ALPHA 0xff
+#endif
#if defined(GC_VERSION_MAJOR)
# if GC_TMP_VERSION_MAJOR != GC_VERSION_MAJOR || \
GC_TMP_VERSION_MINOR != GC_VERSION_MINOR || \
- GC_TMP_ALPHA_VERSION != GC_ALPHA_VERSION
+ defined(GC_ALPHA_VERSION) != (GC_TMP_ALPHA_VERSION != GC_NOT_ALPHA) || \
+ defined(GC_ALPHA_VERSION) && GC_TMP_ALPHA_VERSION != GC_ALPHA_VERSION
# error Inconsistent version info. Check version.h and configure.in.
# endif
#else
@@ -17,12 +22,9 @@
# define GC_ALPHA_VERSION GC_TMP_ALPHA_VERSION
#endif
-#ifndef GC_NOT_ALPHA
-# define GC_NOT_ALPHA 0xff
-#endif
#ifndef GC_NO_VERSION_VAR
-unsigned GC_version = ((GC_VERSION_MAJOR << 16) | (GC_VERSION_MINOR << 8) | GC_ALPHA_VERSION);
+unsigned GC_version = ((GC_VERSION_MAJOR << 16) | (GC_VERSION_MINOR << 8) | GC_TMP_ALPHA_VERSION);
#endif /* GC_NO_VERSION_VAR */
Index: boehm_gc/win32_threads.c
===================================================================
RCS file: /home/staff/zs/imp/mercury/boehm_gc/win32_threads.c,v
retrieving revision 1.3
diff -u -r1.3 win32_threads.c
--- boehm_gc/win32_threads.c 6 May 2003 11:36:50 -0000 1.3
+++ boehm_gc/win32_threads.c 27 Oct 2003 21:02:34 -0000
@@ -1,6 +1,7 @@
#if defined(GC_WIN32_THREADS)
#include "private/gc_priv.h"
+#include <windows.h>
#ifdef CYGWIN32
# include <errno.h>
@@ -13,40 +14,205 @@
# define DEBUG_CYGWIN_THREADS 0
- GC_bool GC_thr_initialized = FALSE;
void * GC_start_routine(void * arg);
void GC_thread_exit_proc(void *arg);
#endif
-
-#if 0
-#define STRICT
-#include <windows.h>
+/* The type of the first argument to InterlockedExchange. */
+/* Documented to be LONG volatile *, but at least gcc likes */
+/* this better. */
+typedef LONG * IE_t;
+
+#ifndef MAX_THREADS
+# define MAX_THREADS 256
+ /* FIXME: */
+ /* Things may get quite slow for large numbers of threads, */
+ /* since we look them up with sequential search. */
#endif
-#define MAX_THREADS 64
+GC_bool GC_thr_initialized = FALSE;
+
+DWORD GC_main_thread = 0;
-struct thread_entry {
- LONG in_use;
+struct GC_thread_Rep {
+ LONG in_use; /* Updated without lock. */
+ /* We assert that unused */
+ /* entries have invalid ids of */
+ /* zero and zero stack fields. */
DWORD id;
HANDLE handle;
- void *stack; /* The cold end of the stack. */
+ ptr_t stack_base; /* The cold end of the stack. */
/* 0 ==> entry not valid. */
- /* !in_use ==> stack == 0 */
- CONTEXT context;
+ /* !in_use ==> stack_base == 0 */
GC_bool suspended;
# ifdef CYGWIN32
void *status; /* hold exit value until join in case it's a pointer */
pthread_t pthread_id;
+ short flags; /* Protected by GC lock. */
+# define FINISHED 1 /* Thread has exited. */
+# define DETACHED 2 /* Thread is intended to be detached. */
# endif
-
};
+typedef volatile struct GC_thread_Rep * GC_thread;
+
+/*
+ * We generally assume that volatile ==> memory ordering, at least among
+ * volatiles.
+ */
+
volatile GC_bool GC_please_stop = FALSE;
-volatile struct thread_entry thread_table[MAX_THREADS];
+volatile struct GC_thread_Rep thread_table[MAX_THREADS];
+
+volatile LONG GC_max_thread_index = 0; /* Largest index in thread_table */
+ /* that was ever used. */
+
+extern LONG WINAPI GC_write_fault_handler(struct _EXCEPTION_POINTERS *exc_info);
+
+/*
+ * This may be called from DllMain, and hence operates under unusual
+ * constraints.
+ */
+static GC_thread GC_new_thread(void) {
+ int i;
+ /* 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 */
+ /* initialization tasks".) */
+ /* Hence we make do with nonblocking synchronization. */
+
+ /* The following should be a noop according to the win32 */
+ /* documentation. There is empirical evidence that it */
+ /* isn't. - HB */
+# if defined(MPROTECT_VDB)
+ if (GC_incremental) SetUnhandledExceptionFilter(GC_write_fault_handler);
+# endif
+ /* cast away volatile qualifier */
+ for (i = 0; InterlockedExchange((IE_t)&thread_table[i].in_use,1) != 0; i++) {
+ /* Compare-and-swap would make this cleaner, but that's not */
+ /* supported before Windows 98 and NT 4.0. In Windows 2000, */
+ /* InterlockedExchange is supposed to be replaced by */
+ /* InterlockedExchangePointer, but that's not really what I */
+ /* want here. */
+ if (i == MAX_THREADS - 1)
+ ABORT("too many threads");
+ }
+ /* Update GC_max_thread_index if necessary. The following is safe, */
+ /* and unlike CompareExchange-based solutions seems to work on all */
+ /* Windows95 and later platforms. */
+ /* Unfortunately, GC_max_thread_index may be temporarily out of */
+ /* bounds, so readers have to compensate. */
+ while (i > GC_max_thread_index) {
+ InterlockedIncrement((IE_t)&GC_max_thread_index);
+ }
+ if (GC_max_thread_index >= MAX_THREADS) {
+ /* We overshot due to simultaneous increments. */
+ /* Setting it to MAX_THREADS-1 is always safe. */
+ GC_max_thread_index = MAX_THREADS - 1;
+ }
+
+# ifdef CYGWIN32
+ thread_table[i].pthread_id = pthread_self();
+# endif
+ if (!DuplicateHandle(GetCurrentProcess(),
+ GetCurrentThread(),
+ GetCurrentProcess(),
+ (HANDLE*)&thread_table[i].handle,
+ 0,
+ 0,
+ DUPLICATE_SAME_ACCESS)) {
+ DWORD last_error = GetLastError();
+ GC_printf1("Last error code: %lx\n", last_error);
+ ABORT("DuplicateHandle failed");
+ }
+ thread_table[i].stack_base = GC_get_stack_base();
+ /* Up until this point, GC_psuh_all_stacks considers this thread */
+ /* invalid. */
+ if (thread_table[i].stack_base == NULL)
+ ABORT("Failed to find stack base in GC_new_thread");
+ /* Up until this point, this entry is viewed as reserved but invalid */
+ /* by GC_delete_thread. */
+ thread_table[i].id = GetCurrentThreadId();
+ /* 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);
+ return thread_table + i;
+}
+
+/*
+ * GC_max_thread_index may temporarily be larger than MAX_THREADS.
+ * To avoid subscript errors, we check on access.
+ */
+#ifdef __GNUC__
+__inline__
+#endif
+LONG GC_get_max_thread_index()
+{
+ LONG my_max = GC_max_thread_index;
+
+ if (my_max >= MAX_THREADS) return MAX_THREADS-1;
+ return my_max;
+}
+
+/* This is intended to be lock-free, though that */
+/* assumes that the CloseHandle becomes visible before the */
+/* in_use assignment. */
+static void GC_delete_gc_thread(GC_thread thr)
+{
+ CloseHandle(thr->handle);
+ /* cast away volatile qualifier */
+ thr->stack_base = 0;
+ thr->id = 0;
+# ifdef CYGWIN32
+ thr->pthread_id = 0;
+# endif /* CYGWIN32 */
+ thr->in_use = FALSE;
+}
+
+static void GC_delete_thread(DWORD thread_id) {
+ int i;
+ LONG my_max = GC_get_max_thread_index();
+
+ for (i = 0;
+ i <= my_max &&
+ (!thread_table[i].in_use || thread_table[i].id != thread_id);
+ /* Must still be in_use, since nobody else can store our thread_id. */
+ i++) {}
+ if (i > my_max) {
+ WARN("Removing nonexisiting thread %ld\n", (GC_word)thread_id);
+ } else {
+ GC_delete_gc_thread(thread_table+i);
+ }
+}
+
+
+#ifdef CYGWIN32
+
+/* Return a GC_thread corresponding to a given pthread_t. */
+/* Returns 0 if it's not there. */
+/* We assume that this is only called for pthread ids that */
+/* have not yet terminated or are still joinable. */
+static GC_thread GC_lookup_thread(pthread_t id)
+{
+ int i;
+ LONG my_max = GC_get_max_thread_index();
+
+ for (i = 0;
+ i <= my_max &&
+ (!thread_table[i].in_use || thread_table[i].pthread_id != id
+ || !thread_table[i].in_use);
+ /* Must still be in_use, since nobody else can store our thread_id. */
+ i++);
+ if (i > my_max) return 0;
+ return thread_table + i;
+}
+
+#endif /* CYGWIN32 */
void GC_push_thread_structures GC_PROTO((void))
{
@@ -55,8 +221,12 @@
/* no private structures we need to preserve. */
# ifdef CYGWIN32
{ int i; /* pthreads may keep a pointer in the thread exit value */
- for (i = 0; i < MAX_THREADS; i++)
- if (thread_table[i].in_use) GC_push_all((ptr_t)&(thread_table[i].status),(ptr_t)(&(thread_table[i].status)+1));
+ LONG my_max = GC_get_max_thread_index();
+
+ for (i = 0; i <= my_max; i++)
+ if (thread_table[i].in_use)
+ GC_push_all((ptr_t)&(thread_table[i].status),
+ (ptr_t)(&(thread_table[i].status)+1));
}
# endif
}
@@ -66,13 +236,11 @@
DWORD thread_id = GetCurrentThreadId();
int i;
-#ifdef CYGWIN32
if (!GC_thr_initialized) ABORT("GC_stop_world() called before GC_thr_init()");
-#endif
GC_please_stop = TRUE;
- for (i = 0; i < MAX_THREADS; i++)
- if (thread_table[i].stack != 0
+ for (i = 0; i <= GC_get_max_thread_index(); i++)
+ if (thread_table[i].stack_base != 0
&& thread_table[i].id != thread_id) {
# ifdef MSWINCE
/* SuspendThread will fail if thread is running kernel code */
@@ -87,13 +255,12 @@
DWORD exitCode;
if (GetExitCodeThread(thread_table[i].handle,&exitCode) &&
exitCode != STILL_ACTIVE) {
- thread_table[i].stack = 0; /* prevent stack from being pushed */
+ thread_table[i].stack_base = 0; /* prevent stack from being pushed */
# ifndef CYGWIN32
/* this breaks pthread_join on Cygwin, which is guaranteed to */
/* only see user pthreads */
thread_table[i].in_use = FALSE;
CloseHandle(thread_table[i].handle);
- BZERO((void *)(&thread_table[i].context), sizeof(CONTEXT));
# endif
continue;
}
@@ -108,8 +275,10 @@
{
DWORD thread_id = GetCurrentThreadId();
int i;
- for (i = 0; i < MAX_THREADS; i++)
- if (thread_table[i].stack != 0 && thread_table[i].suspended
+ LONG my_max = GC_get_max_thread_index();
+
+ for (i = 0; i <= my_max; i++)
+ if (thread_table[i].stack_base != 0 && thread_table[i].suspended
&& thread_table[i].id != thread_id) {
if (ResumeThread(thread_table[i].handle) == (DWORD)-1)
ABORT("ResumeThread failed");
@@ -125,9 +294,11 @@
{
DWORD thread_id = GetCurrentThreadId();
int i;
- for (i = 0; i < MAX_THREADS; i++)
- if (thread_table[i].stack && thread_table[i].id == thread_id)
- return thread_table[i].stack;
+ LONG my_max = GC_get_max_thread_index();
+
+ for (i = 0; i <= my_max; i++)
+ if (thread_table[i].stack_base && thread_table[i].id == thread_id)
+ return thread_table[i].stack_base;
ABORT("no thread table entry for current thread");
}
# ifdef _MSC_VER
@@ -138,10 +309,10 @@
/* The VirtualQuery calls below won't work properly on WinCE, but */
/* since each stack is restricted to an aligned 64K region of */
/* virtual memory we can just take the next lowest multiple of 64K. */
-# define GC_get_lo_stack_addr(s) \
+# define GC_get_stack_min(s) \
((ptr_t)(((DWORD)(s) - 1) & 0xFFFF0000))
# else
- static ptr_t GC_get_lo_stack_addr(ptr_t s)
+ static ptr_t GC_get_stack_min(ptr_t s)
{
ptr_t bottom;
MEMORY_BASIC_INFORMATION info;
@@ -158,197 +329,76 @@
void GC_push_all_stacks()
{
DWORD thread_id = GetCurrentThreadId();
+ GC_bool found_me = FALSE;
int i;
- for (i = 0; i < MAX_THREADS; i++)
- if (thread_table[i].stack) {
- ptr_t bottom = GC_get_lo_stack_addr(thread_table[i].stack);
- if (thread_table[i].id == thread_id)
- GC_push_all_stack((ptr_t)&i, thread_table[i].stack);
- else {
- thread_table[i].context.ContextFlags
- = (CONTEXT_INTEGER|CONTEXT_CONTROL);
- if (!GetThreadContext(thread_table[i].handle,
- /* cast away volatile qualifier */
- (LPCONTEXT)&thread_table[i].context))
+ int dummy;
+ ptr_t sp, stack_min;
+ GC_thread thread;
+ LONG my_max = GC_get_max_thread_index();
+
+ for (i = 0; i <= my_max; i++) {
+ thread = thread_table + i;
+ if (thread -> in_use && thread -> stack_base) {
+ if (thread -> id == thread_id) {
+ sp = (ptr_t) &dummy;
+ found_me = TRUE;
+ } else {
+ CONTEXT context;
+ context.ContextFlags = CONTEXT_INTEGER|CONTEXT_CONTROL;
+ if (!GetThreadContext(thread_table[i].handle, &context))
ABORT("GetThreadContext failed");
-# ifdef I386
- 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.Ebp);
- 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);
- if (thread_table[i].context.Esp >= (DWORD)thread_table[i].stack
- || thread_table[i].context.Esp < (DWORD)bottom) {
- WARN("Thread stack pointer 0x%lx out of range, pushing everything",
- thread_table[i].context.Esp);
- GC_push_all_stack((char *) bottom, thread_table[i].stack);
- } else {
- GC_push_all_stack((char *) thread_table[i].context.Esp,
- thread_table[i].stack);
- }
-# else
-# ifdef ARM32
- if (thread_table[i].context.Sp >= (DWORD)thread_table[i].stack
- || thread_table[i].context.Sp < (DWORD)bottom)
- ABORT("Thread stack pointer out of range");
- GC_push_one ((word) thread_table[i].context.R0);
- GC_push_one ((word) thread_table[i].context.R1);
- GC_push_one ((word) thread_table[i].context.R2);
- GC_push_one ((word) thread_table[i].context.R3);
- GC_push_one ((word) thread_table[i].context.R4);
- GC_push_one ((word) thread_table[i].context.R5);
- GC_push_one ((word) thread_table[i].context.R6);
- GC_push_one ((word) thread_table[i].context.R7);
- GC_push_one ((word) thread_table[i].context.R8);
- GC_push_one ((word) thread_table[i].context.R9);
- GC_push_one ((word) thread_table[i].context.R10);
- GC_push_one ((word) thread_table[i].context.R11);
- GC_push_one ((word) thread_table[i].context.R12);
- GC_push_all_stack((char *) thread_table[i].context.Sp,
- thread_table[i].stack);
-# else
-# ifdef SHx
- if (thread_table[i].context.R15 >= (DWORD)thread_table[i].stack
- || thread_table[i].context.R15 < (DWORD)bottom)
- ABORT("Thread stack pointer out of range");
- GC_push_one ((word) thread_table[i].context.R0);
- GC_push_one ((word) thread_table[i].context.R1);
- GC_push_one ((word) thread_table[i].context.R2);
- GC_push_one ((word) thread_table[i].context.R3);
- GC_push_one ((word) thread_table[i].context.R4);
- GC_push_one ((word) thread_table[i].context.R5);
- GC_push_one ((word) thread_table[i].context.R6);
- GC_push_one ((word) thread_table[i].context.R7);
- GC_push_one ((word) thread_table[i].context.R8);
- GC_push_one ((word) thread_table[i].context.R9);
- GC_push_one ((word) thread_table[i].context.R10);
- GC_push_one ((word) thread_table[i].context.R11);
- GC_push_one ((word) thread_table[i].context.R12);
- GC_push_one ((word) thread_table[i].context.R13);
- GC_push_one ((word) thread_table[i].context.R14);
- GC_push_all_stack((char *) thread_table[i].context.R15,
- thread_table[i].stack);
+
+ /* Push all registers that might point into the heap. Frame */
+ /* pointer registers are included in case client code was */
+ /* compiled with the 'omit frame pointer' optimisation. */
+# define PUSH1(reg) GC_push_one((word)context.reg)
+# define PUSH2(r1,r2) PUSH1(r1), PUSH1(r2)
+# define PUSH4(r1,r2,r3,r4) PUSH2(r1,r2), PUSH2(r3,r4)
+# if defined(I386)
+ PUSH4(Edi,Esi,Ebx,Edx), PUSH2(Ecx,Eax), PUSH1(Ebp);
+ sp = (ptr_t)context.Esp;
+# elif defined(ARM32)
+ PUSH4(R0,R1,R2,R3),PUSH4(R4,R5,R6,R7),PUSH4(R8,R9,R10,R11),PUSH1(R12);
+ sp = (ptr_t)context.Sp;
+# elif defined(SHx)
+ PUSH4(R0,R1,R2,R3), PUSH4(R4,R5,R6,R7), PUSH4(R8,R9,R10,R11);
+ PUSH2(R12,R13), PUSH1(R14);
+ sp = (ptr_t)context.R15;
+# elif defined(MIPS)
+ PUSH4(IntAt,IntV0,IntV1,IntA0), PUSH4(IntA1,IntA2,IntA3,IntT0);
+ PUSH4(IntT1,IntT2,IntT3,IntT4), PUSH4(IntT5,IntT6,IntT7,IntS0);
+ PUSH4(IntS1,IntS2,IntS3,IntS4), PUSH4(IntS5,IntS6,IntS7,IntT8);
+ PUSH4(IntT9,IntK0,IntK1,IntS8);
+ sp = (ptr_t)context.IntSp;
+# elif defined(PPC)
+ PUSH4(Gpr0, Gpr3, Gpr4, Gpr5), PUSH4(Gpr6, Gpr7, Gpr8, Gpr9);
+ PUSH4(Gpr10,Gpr11,Gpr12,Gpr14), PUSH4(Gpr15,Gpr16,Gpr17,Gpr18);
+ PUSH4(Gpr19,Gpr20,Gpr21,Gpr22), PUSH4(Gpr23,Gpr24,Gpr25,Gpr26);
+ PUSH4(Gpr27,Gpr28,Gpr29,Gpr30), PUSH1(Gpr31);
+ sp = (ptr_t)context.Gpr1;
+# elif defined(ALPHA)
+ PUSH4(IntV0,IntT0,IntT1,IntT2), PUSH4(IntT3,IntT4,IntT5,IntT6);
+ PUSH4(IntT7,IntS0,IntS1,IntS2), PUSH4(IntS3,IntS4,IntS5,IntFp);
+ PUSH4(IntA0,IntA1,IntA2,IntA3), PUSH4(IntA4,IntA5,IntT8,IntT9);
+ PUSH4(IntT10,IntT11,IntT12,IntAt);
+ sp = (ptr_t)context.IntSp;
# else
-# ifdef MIPS
- if (thread_table[i].context.IntSp >= (DWORD)thread_table[i].stack
- || thread_table[i].context.IntSp < (DWORD)bottom)
- ABORT("Thread stack pointer out of range");
- GC_push_one ((word) thread_table[i].context.IntAt);
- GC_push_one ((word) thread_table[i].context.IntV0);
- GC_push_one ((word) thread_table[i].context.IntV1);
- GC_push_one ((word) thread_table[i].context.IntA0);
- GC_push_one ((word) thread_table[i].context.IntA1);
- GC_push_one ((word) thread_table[i].context.IntA2);
- GC_push_one ((word) thread_table[i].context.IntA3);
- GC_push_one ((word) thread_table[i].context.IntT0);
- GC_push_one ((word) thread_table[i].context.IntT1);
- GC_push_one ((word) thread_table[i].context.IntT2);
- GC_push_one ((word) thread_table[i].context.IntT3);
- GC_push_one ((word) thread_table[i].context.IntT4);
- GC_push_one ((word) thread_table[i].context.IntT5);
- GC_push_one ((word) thread_table[i].context.IntT6);
- GC_push_one ((word) thread_table[i].context.IntT7);
- GC_push_one ((word) thread_table[i].context.IntS0);
- GC_push_one ((word) thread_table[i].context.IntS1);
- GC_push_one ((word) thread_table[i].context.IntS2);
- GC_push_one ((word) thread_table[i].context.IntS3);
- GC_push_one ((word) thread_table[i].context.IntS4);
- GC_push_one ((word) thread_table[i].context.IntS5);
- GC_push_one ((word) thread_table[i].context.IntS6);
- GC_push_one ((word) thread_table[i].context.IntS7);
- GC_push_one ((word) thread_table[i].context.IntT8);
- GC_push_one ((word) thread_table[i].context.IntT9);
- GC_push_one ((word) thread_table[i].context.IntK0);
- GC_push_one ((word) thread_table[i].context.IntK1);
- GC_push_one ((word) thread_table[i].context.IntS8);
- GC_push_all_stack((char *) thread_table[i].context.IntSp,
- thread_table[i].stack);
-# else
-# ifdef PPC
- if (thread_table[i].context.Gpr1 >= (DWORD)thread_table[i].stack
- || thread_table[i].context.Gpr1 < (DWORD)bottom)
- ABORT("Thread stack pointer out of range");
- GC_push_one ((word) thread_table[i].context.Gpr0);
- /* Gpr1 is stack pointer */
- /* Gpr2 is global pointer */
- GC_push_one ((word) thread_table[i].context.Gpr3);
- GC_push_one ((word) thread_table[i].context.Gpr4);
- GC_push_one ((word) thread_table[i].context.Gpr5);
- GC_push_one ((word) thread_table[i].context.Gpr6);
- GC_push_one ((word) thread_table[i].context.Gpr7);
- GC_push_one ((word) thread_table[i].context.Gpr8);
- GC_push_one ((word) thread_table[i].context.Gpr9);
- GC_push_one ((word) thread_table[i].context.Gpr10);
- GC_push_one ((word) thread_table[i].context.Gpr11);
- GC_push_one ((word) thread_table[i].context.Gpr12);
- /* Gpr13 is reserved for the kernel */
- GC_push_one ((word) thread_table[i].context.Gpr14);
- GC_push_one ((word) thread_table[i].context.Gpr15);
- GC_push_one ((word) thread_table[i].context.Gpr16);
- GC_push_one ((word) thread_table[i].context.Gpr17);
- GC_push_one ((word) thread_table[i].context.Gpr18);
- GC_push_one ((word) thread_table[i].context.Gpr19);
- GC_push_one ((word) thread_table[i].context.Gpr20);
- GC_push_one ((word) thread_table[i].context.Gpr21);
- GC_push_one ((word) thread_table[i].context.Gpr22);
- GC_push_one ((word) thread_table[i].context.Gpr23);
- GC_push_one ((word) thread_table[i].context.Gpr24);
- GC_push_one ((word) thread_table[i].context.Gpr25);
- GC_push_one ((word) thread_table[i].context.Gpr26);
- GC_push_one ((word) thread_table[i].context.Gpr27);
- GC_push_one ((word) thread_table[i].context.Gpr28);
- GC_push_one ((word) thread_table[i].context.Gpr29);
- GC_push_one ((word) thread_table[i].context.Gpr30);
- GC_push_one ((word) thread_table[i].context.Gpr31);
- GC_push_all_stack((char *) thread_table[i].context.Gpr1,
- thread_table[i].stack);
-# else
-# ifdef ALPHA
- if (thread_table[i].context.IntSp >= (DWORD)thread_table[i].stack
- || thread_table[i].context.IntSp < (DWORD)bottom)
- ABORT("Thread stack pointer out of range");
- GC_push_one ((word) thread_table[i].context.IntV0);
- GC_push_one ((word) thread_table[i].context.IntT0);
- GC_push_one ((word) thread_table[i].context.IntT1);
- GC_push_one ((word) thread_table[i].context.IntT2);
- GC_push_one ((word) thread_table[i].context.IntT3);
- GC_push_one ((word) thread_table[i].context.IntT4);
- GC_push_one ((word) thread_table[i].context.IntT5);
- GC_push_one ((word) thread_table[i].context.IntT6);
- GC_push_one ((word) thread_table[i].context.IntT7);
- GC_push_one ((word) thread_table[i].context.IntS0);
- GC_push_one ((word) thread_table[i].context.IntS1);
- GC_push_one ((word) thread_table[i].context.IntS2);
- GC_push_one ((word) thread_table[i].context.IntS3);
- GC_push_one ((word) thread_table[i].context.IntS4);
- GC_push_one ((word) thread_table[i].context.IntS5);
- GC_push_one ((word) thread_table[i].context.IntFp);
- GC_push_one ((word) thread_table[i].context.IntA0);
- GC_push_one ((word) thread_table[i].context.IntA1);
- GC_push_one ((word) thread_table[i].context.IntA2);
- GC_push_one ((word) thread_table[i].context.IntA3);
- GC_push_one ((word) thread_table[i].context.IntA4);
- GC_push_one ((word) thread_table[i].context.IntA5);
- GC_push_one ((word) thread_table[i].context.IntT8);
- GC_push_one ((word) thread_table[i].context.IntT9);
- GC_push_one ((word) thread_table[i].context.IntT10);
- GC_push_one ((word) thread_table[i].context.IntT11);
- GC_push_one ((word) thread_table[i].context.IntT12);
- GC_push_one ((word) thread_table[i].context.IntAt);
- GC_push_all_stack((char *) thread_table[i].context.IntSp,
- thread_table[i].stack);
-# else
- --> architecture not supported
-# endif /* !ALPHA */
-# endif /* !PPC */
-# endif /* !MIPS */
-# endif /* !SHx */
-# endif /* !ARM32 */
-# endif /* !I386 */
+# error "architecture is not supported"
+# endif
+ }
+
+ stack_min = GC_get_stack_min(thread->stack_base);
+
+ if (sp >= stack_min && sp < thread->stack_base)
+ GC_push_all_stack(sp, thread->stack_base);
+ else {
+ WARN("Thread stack pointer 0x%lx out of range, pushing everything\n",
+ (unsigned long)sp);
+ GC_push_all_stack(stack_min, thread->stack_base);
}
}
+ }
+ if (!found_me) ABORT("Collecting from unknown thread.");
}
void GC_get_next_stack(char *start, char **lo, char **hi)
@@ -356,9 +406,10 @@
int i;
# define ADDR_LIMIT (char *)(-1L)
char * current_min = ADDR_LIMIT;
-
- for (i = 0; i < MAX_THREADS; i++) {
- char * s = (char *)thread_table[i].stack;
+ LONG my_max = GC_get_max_thread_index();
+
+ for (i = 0; i <= my_max; i++) {
+ char * s = (char *)thread_table[i].stack_base;
if (0 != s && s > start && s < current_min) {
current_min = s;
@@ -369,13 +420,17 @@
*lo = ADDR_LIMIT;
return;
}
- *lo = GC_get_lo_stack_addr(current_min);
+ *lo = GC_get_stack_min(current_min);
if (*lo < start) *lo = start;
}
-#if !defined(MSWINCE) && !(defined(__MINGW32__) && !defined(_DLL))
+#if !defined(CYGWIN32)
+
+#if !defined(MSWINCE) && defined(GC_DLL)
-HANDLE WINAPI GC_CreateThread(
+/* We register threads from DllMain */
+
+GC_API HANDLE WINAPI GC_CreateThread(
LPSECURITY_ATTRIBUTES lpThreadAttributes,
DWORD dwStackSize, LPTHREAD_START_ROUTINE lpStartAddress,
LPVOID lpParameter, DWORD dwCreationFlags, LPDWORD lpThreadId )
@@ -384,87 +439,45 @@
lpParameter, dwCreationFlags, lpThreadId);
}
-#else /* !defined(MSWINCE) && !(defined(__MINGW32__) && !defined(_DLL)) */
+#else /* defined(MSWINCE) || !defined(GC_DLL)) */
+
+/* We have no DllMain to take care of new threads. Thus we */
+/* must properly intercept thread creation. */
typedef struct {
- HANDLE child_ready_h, parent_ready_h;
- volatile struct thread_entry * entry;
LPTHREAD_START_ROUTINE start;
LPVOID param;
} thread_args;
-DWORD WINAPI thread_start(LPVOID arg);
+static DWORD WINAPI thread_start(LPVOID arg);
-HANDLE WINAPI GC_CreateThread(
+GC_API HANDLE WINAPI GC_CreateThread(
LPSECURITY_ATTRIBUTES lpThreadAttributes,
DWORD dwStackSize, LPTHREAD_START_ROUTINE lpStartAddress,
LPVOID lpParameter, DWORD dwCreationFlags, LPDWORD lpThreadId )
{
HANDLE thread_h = NULL;
- HANDLE child_ready_h, parent_ready_h;
- int i;
- thread_args args;
+ thread_args *args;
- /* allocate thread slot */
- LOCK();
- for (i = 0; i != MAX_THREADS && thread_table[i].in_use; i++)
- ;
- if (i != MAX_THREADS) {
- thread_table[i].in_use = TRUE;
+ if (!GC_is_initialized) GC_init();
+ /* make sure GC is initialized (i.e. main thread is attached) */
+
+ args = GC_malloc_uncollectable(sizeof(thread_args));
+ /* Handed off to and deallocated by child thread. */
+ if (0 == args) {
+ SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+ return NULL;
}
- UNLOCK();
-
- if (i != MAX_THREADS) {
-
- /* create unnamed unsignalled events */
- if (child_ready_h = CreateEvent(NULL, FALSE, FALSE, NULL)) {
- if (parent_ready_h = CreateEvent(NULL, FALSE, FALSE, NULL)) {
-
- /* set up thread arguments */
- args.child_ready_h = child_ready_h;
- args.parent_ready_h = parent_ready_h;
- args.entry = &thread_table[i];
- args.start = lpStartAddress;
- args.param = lpParameter;
-
- thread_h = CreateThread(lpThreadAttributes,
- dwStackSize, thread_start,
- &args,
- dwCreationFlags & ~CREATE_SUSPENDED,
- lpThreadId);
-
- if (thread_h) {
-
- /* fill in ID and handle; tell child this is done */
- thread_table[i].id = *lpThreadId;
- thread_table[i].handle = thread_h;
- SetEvent (parent_ready_h);
-
- /* wait for child to fill in stack and copy args */
- WaitForSingleObject (child_ready_h, INFINITE);
-
- /* suspend the child if requested */
- if (dwCreationFlags & CREATE_SUSPENDED)
- SuspendThread (thread_h);
-
- /* let child call given function now (or when resumed) */
- SetEvent (parent_ready_h);
-
- } else {
- CloseHandle (parent_ready_h);
- }
- }
- }
-
- CloseHandle (child_ready_h);
-
- if (thread_h == NULL)
- thread_table[i].in_use = FALSE;
- } else { /* no thread slot found */
- SetLastError (ERROR_TOO_MANY_TCBS);
- }
+ /* set up thread arguments */
+ args -> start = lpStartAddress;
+ args -> param = lpParameter;
+
+ thread_h = CreateThread(lpThreadAttributes,
+ dwStackSize, thread_start,
+ args, dwCreationFlags,
+ lpThreadId);
return thread_h;
}
@@ -472,19 +485,9 @@
static DWORD WINAPI thread_start(LPVOID arg)
{
DWORD ret = 0;
- thread_args args = *(thread_args *)arg;
+ thread_args *args = (thread_args *)arg;
- /* wait for parent to fill in ID and handle */
- WaitForSingleObject (args.parent_ready_h, INFINITE);
- ResetEvent (args.parent_ready_h);
-
- /* fill in stack; tell parent this is done */
- args.entry->stack = GC_get_stack_base();
- SetEvent (args.child_ready_h);
-
- /* wait for parent to tell us to go (in case it needs to suspend us) */
- WaitForSingleObject (args.parent_ready_h, INFINITE);
- CloseHandle (args.parent_ready_h);
+ GC_new_thread();
/* Clear the thread entry even if we exit with an exception. */
/* This is probably pointless, since an uncaught exception is */
@@ -492,16 +495,12 @@
#ifndef __GNUC__
__try {
#endif /* __GNUC__ */
- ret = args.start (args.param);
+ ret = args->start (args->param);
#ifndef __GNUC__
} __finally {
#endif /* __GNUC__ */
- LOCK();
- args.entry->stack = 0;
- args.entry->in_use = FALSE;
- /* cast away volatile qualifier */
- BZERO((void *) &args.entry->context, sizeof(CONTEXT));
- UNLOCK();
+ GC_free(args);
+ GC_delete_thread(GetCurrentThreadId());
#ifndef __GNUC__
}
#endif /* __GNUC__ */
@@ -510,6 +509,8 @@
}
#endif /* !defined(MSWINCE) && !(defined(__MINGW32__) && !defined(_DLL)) */
+#endif /* !CYGWIN32 */
+
#ifdef MSWINCE
typedef struct {
@@ -533,7 +534,6 @@
DWORD thread_id;
/* initialize everything */
- InitializeCriticalSection(&GC_allocate_ml);
GC_init();
/* start the main thread */
@@ -563,126 +563,44 @@
# else /* !MSWINCE */
-LONG WINAPI GC_write_fault_handler(struct _EXCEPTION_POINTERS *exc_info);
-
-/* threadAttach/threadDetach routines used by both CYGWIN and DLL implementation,
- since both recieve explicit notification on thread creation/destruction
- */
-void threadAttach() {
- int i;
- /* It appears to be unsafe to acquire a lock here, since this */
- /* code is apparently not preeemptible on some systems. */
- /* (This is based on complaints, not on Microsoft's official */
- /* documentation, which says this should perform "only simple */
- /* inititalization tasks".) */
- /* Hence we make do with nonblocking synchronization. */
-
- /* The following should be a noop according to the win32 */
- /* documentation. There is empirical evidence that it */
- /* isn't. - HB */
-# if defined(MPROTECT_VDB)
- if (GC_incremental) SetUnhandledExceptionFilter(GC_write_fault_handler);
-# endif
- /* cast away volatile qualifier */
- for (i = 0; InterlockedExchange((LONG*)&thread_table[i].in_use,1) != 0; i++) {
- /* Compare-and-swap would make this cleaner, but that's not */
- /* supported before Windows 98 and NT 4.0. In Windows 2000, */
- /* InterlockedExchange is supposed to be replaced by */
- /* InterlockedExchangePointer, but that's not really what I */
- /* want here. */
- if (i == MAX_THREADS - 1)
- ABORT("too many threads");
- }
- thread_table[i].id = GetCurrentThreadId();
-# ifdef CYGWIN32
- thread_table[i].pthread_id = pthread_self();
-# endif
- if (!DuplicateHandle(GetCurrentProcess(),
- GetCurrentThread(),
- GetCurrentProcess(),
- (HANDLE*)&thread_table[i].handle,
- 0,
- 0,
- DUPLICATE_SAME_ACCESS)) {
- DWORD last_error = GetLastError();
- GC_printf1("Last error code: %lx\n", last_error);
- ABORT("DuplicateHandle failed");
- }
- thread_table[i].stack = GC_get_stack_base();
- if (thread_table[i].stack == NULL)
- ABORT("Failed to find stack base in threadAttach");
- /* 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);
-}
-
-void threadDetach(DWORD thread_id) {
- int i;
-
- LOCK();
- for (i = 0;
- i < MAX_THREADS &&
- !thread_table[i].in_use || thread_table[i].id != thread_id;
- i++) {}
- if (i >= MAX_THREADS ) {
- WARN("thread %ld not found on detach", (GC_word)thread_id);
- }
- else {
- thread_table[i].stack = 0;
- thread_table[i].in_use = FALSE;
- CloseHandle(thread_table[i].handle);
- /* cast away volatile qualifier */
- BZERO((void *)&thread_table[i].context, sizeof(CONTEXT));
- }
- UNLOCK();
-}
-
-#ifdef CYGWIN32
-
/* Called by GC_init() - we hold the allocation lock. */
void GC_thr_init() {
if (GC_thr_initialized) return;
+ GC_main_thread = GetCurrentThreadId();
GC_thr_initialized = TRUE;
-#if 0
- /* this might already be handled in GC_init... */
- InitializeCriticalSection(&GC_allocate_ml);
-#endif
-
/* Add the initial thread, so we can stop it. */
- threadAttach();
+ GC_new_thread();
}
+#ifdef CYGWIN32
+
struct start_info {
void *(*start_routine)(void *);
void *arg;
+ GC_bool detached;
};
int GC_pthread_join(pthread_t pthread_id, void **retval) {
int result;
int i;
+ GC_thread me;
# if DEBUG_CYGWIN_THREADS
- GC_printf3("thread 0x%x(0x%x) is joining thread 0x%x.\n",(int)pthread_self(),
- GetCurrentThreadId(), (int)pthread_id);
+ GC_printf3("thread 0x%x(0x%x) is joining thread 0x%x.\n",
+ (int)pthread_self(), GetCurrentThreadId(), (int)pthread_id);
# endif
- /* Can't do any table lookups here, because thread being joined
- might not have registered itself yet */
+ /* Thread being joined might not have registered itself yet. */
+ /* After the join,thread id may have been recycled. */
+ /* FIXME: It would be better if this worked more like */
+ /* pthread_support.c. */
+
+ while ((me = GC_lookup_thread(pthread_id)) == 0) Sleep(10);
result = pthread_join(pthread_id, retval);
- LOCK();
- for (i = 0; !thread_table[i].in_use || thread_table[i].pthread_id != pthread_id;
- i++) {
- if (i == MAX_THREADS - 1) {
- GC_printf1("Failed to find thread 0x%x in pthread_join()\n", pthread_id);
- ABORT("thread not found on detach");
- }
- }
- UNLOCK();
- threadDetach(thread_table[i].id);
+ GC_delete_gc_thread(me);
# if DEBUG_CYGWIN_THREADS
GC_printf3("thread 0x%x(0x%x) completed join with thread 0x%x.\n",
@@ -713,10 +631,15 @@
si -> start_routine = start_routine;
si -> arg = arg;
+ if (attr != 0 &&
+ pthread_attr_getdetachstate(attr, &si->detached)
+ == PTHREAD_CREATE_DETACHED) {
+ si->detached = TRUE;
+ }
# if DEBUG_CYGWIN_THREADS
- GC_printf2("About to create a thread from 0x%x(0x%x)\n",(int)pthread_self(),
- GetCurrentThreadId);
+ GC_printf2("About to create a thread from 0x%x(0x%x)\n",
+ (int)pthread_self(), GetCurrentThreadId);
# endif
result = pthread_create(new_thread, attr, GC_start_routine, si);
@@ -734,6 +657,8 @@
void *(*start)(void *);
void *start_arg;
pthread_t pthread_id;
+ GC_thread me;
+ GC_bool detached;
int i;
# if DEBUG_CYGWIN_THREADS
@@ -748,17 +673,19 @@
LOCK();
/* We register the thread here instead of in the parent, so that */
/* we don't need to hold the allocation lock during pthread_create. */
- threadAttach();
+ me = GC_new_thread();
UNLOCK();
start = si -> start_routine;
start_arg = si -> arg;
- pthread_id = pthread_self();
+ if (si-> detached) me -> flags |= DETACHED;
+ me -> pthread_id = pthread_id = pthread_self();
GC_free(si); /* was allocated uncollectable */
- pthread_cleanup_push(GC_thread_exit_proc, pthread_id);
+ pthread_cleanup_push(GC_thread_exit_proc, (void *)me);
result = (*start)(start_arg);
+ me -> status = result;
pthread_cleanup_pop(0);
# if DEBUG_CYGWIN_THREADS
@@ -766,65 +693,77 @@
(int)pthread_self(),GetCurrentThreadId());
# endif
- LOCK();
- for (i = 0; thread_table[i].pthread_id != pthread_id; i++) {
- if (i == MAX_THREADS - 1)
- ABORT("thread not found on exit");
- }
- thread_table[i].status = result;
- UNLOCK();
-
return(result);
}
void GC_thread_exit_proc(void *arg)
{
- pthread_t pthread_id = (pthread_t)arg;
+ GC_thread me = (GC_thread)arg;
int i;
# if DEBUG_CYGWIN_THREADS
- GC_printf2("thread 0x%x(0x%x) called pthread_exit().\n",(int)pthread_self(),GetCurrentThreadId());
+ GC_printf2("thread 0x%x(0x%x) called pthread_exit().\n",
+ (int)pthread_self(),GetCurrentThreadId());
# endif
LOCK();
- for (i = 0; thread_table[i].pthread_id != pthread_id; i++) {
- if (i == MAX_THREADS - 1)
- ABORT("thread not found on exit");
+ if (me -> flags & DETACHED) {
+ GC_delete_thread(GetCurrentThreadId());
+ } else {
+ /* deallocate it as part of join */
+ me -> flags |= FINISHED;
}
UNLOCK();
-
-#if 0
- /* TODO: we need a way to get the exit value after a pthread_exit so we can stash it safely away */
- thread_table[i].status = ???
-#endif
}
/* nothing required here... */
int GC_pthread_sigmask(int how, const sigset_t *set, sigset_t *oset) {
return pthread_sigmask(how, set, oset);
}
-int GC_pthread_detach(pthread_t thread) {
- return pthread_detach(thread);
+
+int GC_pthread_detach(pthread_t thread)
+{
+ int result;
+ GC_thread thread_gc_id;
+
+ LOCK();
+ thread_gc_id = GC_lookup_thread(thread);
+ UNLOCK();
+ result = pthread_detach(thread);
+ if (result == 0) {
+ LOCK();
+ thread_gc_id -> flags |= DETACHED;
+ /* Here the pthread thread id may have been recycled. */
+ if (thread_gc_id -> flags & FINISHED) {
+ GC_delete_gc_thread(thread_gc_id);
+ }
+ UNLOCK();
+ }
+ return result;
}
-#else
+
+#else /* !CYGWIN32 */
/*
* We avoid acquiring locks here, since this doesn't seem to be preemptable.
* Pontus Rydin suggests wrapping the thread start routine instead.
*/
+#ifdef GC_DLL
BOOL WINAPI DllMain(HINSTANCE inst, ULONG reason, LPVOID reserved)
{
switch (reason) {
case DLL_PROCESS_ATTACH:
- InitializeCriticalSection(&GC_allocate_ml);
GC_init(); /* Force initialization before thread attach. */
/* fall through */
case DLL_THREAD_ATTACH:
- threadAttach();
+ GC_ASSERT(GC_thr_initialized);
+ if (GC_main_thread != GetCurrentThreadId()) {
+ GC_new_thread();
+ } /* o.w. we already did it during GC_thr_init(), called by GC_init() */
break;
case DLL_THREAD_DETACH:
- threadDetach(GetCurrentThreadId());
+ GC_delete_thread(GetCurrentThreadId());
break;
case DLL_PROCESS_DETACH:
@@ -832,15 +771,10 @@
int i;
LOCK();
- for (i = 0; i < MAX_THREADS; ++i)
+ for (i = 0; i <= GC_get_max_thread_index(); ++i)
{
if (thread_table[i].in_use)
- {
- thread_table[i].stack = 0;
- thread_table[i].in_use = FALSE;
- CloseHandle(thread_table[i].handle);
- BZERO((void *) &thread_table[i].context, sizeof(CONTEXT));
- }
+ GC_delete_gc_thread(thread_table + i);
}
UNLOCK();
@@ -852,7 +786,8 @@
}
return TRUE;
}
-#endif /* CYGWIN32 */
+#endif /* GC_DLL */
+#endif /* !CYGWIN32 */
# endif /* !MSWINCE */
Index: boehm_gc/cord/cordbscs.c
===================================================================
RCS file: /home/staff/zs/imp/mercury/boehm_gc/cord/cordbscs.c,v
retrieving revision 1.5
diff -u -r1.5 cordbscs.c
--- boehm_gc/cord/cordbscs.c 16 Sep 1999 20:05:16 -0000 1.5
+++ boehm_gc/cord/cordbscs.c 27 Oct 2003 21:02:34 -0000
@@ -219,7 +219,7 @@
result->len = result_len;
result->left = x;
result->right = y;
- if (depth > MAX_DEPTH) {
+ if (depth >= MAX_DEPTH) {
return(CORD_balance((CORD)result));
} else {
return((CORD) result);
@@ -260,7 +260,11 @@
result->len = result_len;
result->left = x;
result->right = y;
- return((CORD) result);
+ if (depth >= MAX_DEPTH) {
+ return(CORD_balance((CORD)result));
+ } else {
+ return((CORD) result);
+ }
}
}
Index: boehm_gc/cord/cordxtra.c
===================================================================
RCS file: /home/staff/zs/imp/mercury/boehm_gc/cord/cordxtra.c,v
retrieving revision 1.7
diff -u -r1.7 cordxtra.c
--- boehm_gc/cord/cordxtra.c 16 Sep 1999 20:05:16 -0000 1.7
+++ boehm_gc/cord/cordxtra.c 27 Oct 2003 21:02:34 -0000
@@ -385,7 +385,7 @@
mask <<= 8;
mask |= 0xff;
s_buf <<= 8;
- s_buf |= s_start[i];
+ s_buf |= (unsigned char)s_start[i];
x_buf <<= 8;
x_buf |= CORD_pos_fetch(xpos);
CORD_next(xpos);
Index: boehm_gc/doc/README
===================================================================
RCS file: /home/staff/zs/imp/mercury/boehm_gc/doc/README,v
retrieving revision 1.3
diff -u -r1.3 README
--- boehm_gc/doc/README 6 May 2003 11:36:51 -0000 1.3
+++ boehm_gc/doc/README 27 Oct 2003 21:02:34 -0000
@@ -1,7 +1,7 @@
Copyright (c) 1988, 1989 Hans-J. Boehm, Alan J. Demers
Copyright (c) 1991-1996 by Xerox Corporation. All rights reserved.
Copyright (c) 1996-1999 by Silicon Graphics. All rights reserved.
-Copyright (c) 1999-2001 by Hewlett-Packard Company. All rights reserved.
+Copyright (c) 1999-2003 by Hewlett-Packard Company. All rights reserved.
The file linux_threads.c is also
Copyright (c) 1998 by Fergus Henderson. All rights reserved.
@@ -28,7 +28,7 @@
collector. (If you are concerned about such things, I recommend you look
at the notice in config.guess or ltmain.sh.)
-This is version 6.2alpha3 of a conservative garbage collector for C and C++.
+This is version 6.3alpha2 of a conservative garbage collector for C and C++.
You might find a more recent version of this at
Index: boehm_gc/doc/README.MacOSX
===================================================================
RCS file: /home/staff/zs/imp/mercury/boehm_gc/doc/README.MacOSX,v
retrieving revision 1.3
diff -u -r1.3 README.MacOSX
--- boehm_gc/doc/README.MacOSX 6 May 2003 11:36:51 -0000 1.3
+++ boehm_gc/doc/README.MacOSX 27 Oct 2003 21:02:34 -0000
@@ -1,40 +1 @@
-While the GC should work on MacOS X Server, MacOS X and Darwin, I only tested
-it on MacOS X Server.
-I've added a PPC assembly version of GC_push_regs(), thus the setjmp() hack is
-no longer necessary. Incremental collection is supported via mprotect/signal.
-The current solution isn't really optimal because the signal handler must decode
-the faulting PPC machine instruction in order to find the correct heap address.
-Further, it must poke around in the register state which the kernel saved away
-in some obscure register state structure before it calls the signal handler -
-needless to say the layout of this structure is no where documented.
-Threads and dynamic libraries are not yet supported (adding dynamic library
-support via the low-level dyld API shouldn't be that hard).
-
-The original MacOS X port was brought to you by Andrew Stone.
-
-
-June, 1 2000
-
-Dietmar Planitzer
-dave.pl at ping.at
-
-Note from Andrew Begel:
-
-One more fix to enable gc.a to link successfully into a shared library for
-MacOS X. You have to add -fno-common to the CFLAGS in the Makefile. MacOSX
-disallows common symbols in anything that eventually finds its way into a
-shared library. (I don't completely understand why, but -fno-common seems to
-work and doesn't mess up the garbage collector's functionality).
-
-Feb 26, 2003
-
-Jeff Sturm and Jesse Rosenstock provided a patch that adds thread support.
-GC_MACOSX_THREADS should be defined in the build and in clients. Real
-dynamic library support is still missing, i.e. dynamic library data segments
-are still not scanned. Code that stores pointers to the garbage collected
-heap in statically allocated variables should not reside in a dynamic
-library. This still doesn't appear to be 100% reliable.
-
-Mar 10, 2003
-Brian Alliet contributed dynamic library support for MacOSX. It could also
-use more testing.
+See README.darwin for the latest Darwin/MacOSX information.
Index: boehm_gc/doc/README.changes
===================================================================
RCS file: /home/staff/zs/imp/mercury/boehm_gc/doc/README.changes,v
retrieving revision 1.3
diff -u -r1.3 README.changes
--- boehm_gc/doc/README.changes 6 May 2003 11:36:51 -0000 1.3
+++ boehm_gc/doc/README.changes 27 Oct 2003 21:02:34 -0000
@@ -1780,8 +1780,177 @@
when it should have called the lower case version, since it was
explicitly computing a base pointer.
+Since 6.2alpha4:
+ - GC_invoke_finalizers could, under rare conditions, set
+ GC_finalizer_mem_freed to an essentially random value. This could
+ possibly cause unbounded heap growth for long-running applications
+ under some conditions. (The bug was introduced in 6.1alpha5, and
+ is not in gcc3.3. Thanks to Ben Hutchings for finding it.)
+ - Attempted to sanitize the various DLL macros. GC_USE_DLL disappeared.
+ GC_DLL is used instead. All internal tests are now on GC_DLL.
+ README.macros is now more precise about the intended meaning.
+ - Include DllMain in the multithreaded win32 version only if the
+ collector is actually built as a dll. (Thanks to Mohan Embar for
+ a version of the patch.)
+ - Hide the cygwin threadAttach/Detach functions. They were violating our
+ namespace rules.
+ - Fixed an assertion in GC_check_heap_proc. Added GC_STATIC_ASSERT.
+ (Thanks again to Ben Hutchings.)
+ - Removed some obsolete definitions for Linux/PowerPC in gcconfig.h.
+ - CORD_cat was not rebalancing unbalanced trees in some cases, violating
+ a CORD invariant. Also tweaked the rebalancing rule for
+ CORD_cat_char_star. (Thanks to Alexandr Petrosian for the bug report
+ and patch.)
+ - Added hand-coded structured exception handling support to mark.c.
+ This should enable support of dynamic libraries under win32 with
+ gcc-compiled code. (Thanks to Ranjit Mathew for the patch.)
+ Turned on dynamic library scanning for win32/gcc.
+ - Removed some remnants of read wrapping. (Thanks to Kenneth Schalk.)
+ GC_USE_LD_WRAP ws probably broken in recent versions.
+ - The build could fail on some platforms since gcconfig.h could include
+ declarations mentioning ptr_t, which was not defined, e.g. when if_mach
+ was built. (Thanks to Yann Dirson for pointing this out.) Also
+ cleaned up tests for GC_PRIVATE_H in gcconfig.h a bit.
+ - The GC_LOOP_ON_ABORT environment variable interfered with incremental
+ collection, since the write fault handler was erroneously overridden.
+ Handlers are now set up in the correct order.
+ - It used to be possible to call GC_mark_thread_local_free_lists() while
+ the world was not stopped during an incremental GC. This was not safe.
+ Fortunately, it was also unnecessary. Added GC_world_stopped flag
+ to avoid it. (This caused occasional crashes in GC_set_fl_marks
+ with thread local allocation and incremental GC. This probably happened
+ primarily on old, slow multiprocessors.)
+ - Allowed overriding of MAX_THREADS in win32_threads.c from the build
+ command line. (Patch from Yannis Bres.)
+ - Taught the IA64/linux code to determine the register backing store base from
+ /proc/self/maps after checking the __libc symbol, but before guessing.
+ (__libc symbols are on the endangered list, and the guess is likely to not
+ always be right for 2.6 kernels.) Restructured the code to read and parse
+ /proc/self/maps so it only exists in one place (all platforms).
+ - The -DUSE_PROC_FOR_LIBRARIES code was broken on Linux. It claimed that it
+ also registered the main data segment, but didn't actually do so. (I don't
+ think anyone actually uses this configuration, but ...)
+ - Made another attempt to get --enablecplusplus to do the right thing.
+ Since there are unavoidable problems with C programs linking against a
+ dynamic library that includes C++ code, I separated out the c++ code into
+ libgccpp.
+
+Since 6.2alpha5:
+ - There was an extra underscore in the name of GC_save_registers_in_stack
+ for NetBSD/SPARC. (Thanks to Jaap Boender for the patch.)
+ - Integrated Brian Alliet's patch for Darwin. This restructured the
+ linuxthreads/pthreads support to separate generic pthreads support
+ from more the system-dependent thread-stopping code. I believe this
+ should make it easier to eliminate the code duplication between
+ pthreads platforms in the future. The patch included some other
+ code cleanups.
+ - Integrated Dan Bonachea's patch to support AIX threads. This required
+ substantial manual integration, mostly due to conflicts with other
+ recent threads changes. It may take another iteration to
+ get it to work.
+ - Removed HPUX/PA-RISC support from aix_irix_threads.c. It wasn't used
+ anyway and it cluttered up the code. And anything we can do to migrate
+ towards generic pthreads support is a good thing.
+ - Added a more explicit test for tracing of function arguments to test.c.
+ (Thanks to Dan Grayson.)
+ - Added Akira Tagoh's PowerPC64 patch.
+ - Fixed some bit rot in the Cygwin port. (Thanks to Dan Bonachea for
+ pointing it out.) Gc.h now includes just windows.h, not winbase.h.
+ - Declared GC_save_regs_in_stack() in gc_priv.h. Remove other declarations.
+ - Changed --enable-cplusplus to use automake consitionals. The old way
+ confused libtool. "Make install" didn't work correctly for the old version.
+ Previously --enable-cplusplus was broken on cygwin.
+ - Changed the C version of GC_push_regs to fail at compile time if it is
+ generated with an empty body. This seems to have been the cause of one
+ or two subtle failures on unusual platforms. Those failures should
+ now occur at build time and be easily fixable.
+
+Since 6.2alpha6:
+ - Integrated a second round of Irix/AIX patches from Dan Bonachea.
+ Renamed mips_sgi_mach_dep.S back to mips_sgi_mach_dep.s, since it requires
+ the Irix assembler to do the C preprocessing; gcc -E doesn't work.
+ - Fixed Makefile.direct for DARWIN. (Thanks to Manuel Serrano.)
+ - There was a race between GC_pthread_detach and thread exit that could
+ result in a thread structure being deallocated by GC_pthread_detach
+ eventhough it was still needed by the thread exit code. (Thanks to
+ Dick Porter for the small test case that allowed this to be debugged.)
+ - Fixed version parsing for non-alpha versions in acinclude.m4 and
+ version checking in version.h.
+
+Since 6.2:
+ - Integrated some NetBSD patches forwarded to me by Marc Recht. These
+ were already in the NetBSD package.
+ - GC_pthread_create waited for the semaphore even if pthread_create failed.
+ Thanks to Dick Porter for the pthread_support.c patch. Applied the
+ analogous fix for aix_irix_threads.c.
+ - Added Rainer Orth's Tru64 fixes.
+ - The check for exceeding the thread table size in win32 threadDetach
+ was incorrect. (Thanks to Alexandr Petrosian for the patch.)
+ - Applied Andrew Begel's patch to correct some reentrancy issues
+ with dynamic loading on Darwin.
+ - GC_CreateThread() was neglecting to duplicate the thread handle in
+ the table. (Thanks to Tum Nguyen for the patch.)
+ - Pass +ESdbgasm only on PA-RISC machines with vendor compiler.
+ (Thanks to Roger Sayle for the patch.)
+ - Applied more AIX threads patches from Scott Ananian.
+
+Since 6.3alpha1:
+ - Reenabled I_HOLD_LOCK assertion in aix_irix_threads.h.
+ - Put back the WINABI qualifier for GC_CreateThread. (Thanks to
+ Danny Smith for the patch. 6.3alpha1 had the qualifier in one place
+ but not elsewhere, which was clearly wrong.)
+ - Sometimes explicitly define __private_extern__ before DARWIN dyld.h
+ include. (Thanks to Andreas Tobker for postting the patch.)
+ - Included signal.h from pthread_support.c. Removed GC_looping_handler,
+ which was dead code.
+ - GC_find_start was misdeclared by gc_pmark.h if PRINT_BLACK_LIST was
+ defined. (Thanks to Glauco Masotti for testing and reporting this.)
+ Changed GC_find_start to never just return 0. According to its
+ comment it doesn't, and it's unclear that's correct.
+ - GC_alloc_large had several largely compensating bugs in the
+ computation of GC_words_wasted. (It was confused about bytes vs.
+ words in two places.)
+ - Integrated Slava Sysoltev's patch to support more recent versions of
+ the Intel compiler on IA64/Linux.
+ - Changed win32 spinlock initialization to conditionally set a spin count.
+ (Emmanual Stumpf pointed out that enabling this makes a large performance
+ difference on win32 multiprocessors.) Also cleaned up the win32 spinlock
+ initialization code a bit.
+ - Fixed thread support for HP/UX/IA64. The register backing store base for
+ the main thread was sometimes not set correctly. (Thanks to Laurent
+ Morichetti.)
+ - Added -DEMPTY_GETENV_RESULTS flag to work around Wine problem.
+ - Declare GC_stack_alloc and GC_stack_free in solaris_threads.h to
+ avoid 64-bit size mismatches. (Thanks to Bernie Solomon.)
+ - Fixed GC_generic_push_regs to avoid a potential and very unfortunate
+ tail call optimization. This could lead to prematurely reclaimed
+ objects on configurations that used the generic routine and the new
+ build infrastructure (which potentially optimizes mach_dep.c).
+ This was a serious bug, but it's unclear whether it has resulted in
+ any real failures.
+ - Fixed CORD_str to deal with signed characters. (Thanks to Alexandr
+ Petrosian for noticing the problem and supplying the patch.)
+ - Merged a couple of NOSYS/ECOS tests into os_dep.c from gcj. (Thanks
+ to Anthony Green.)
+ - Partially merged a win32 patch from Ben Hutchings, and substantially
+ revised other parts of win32_threads.c. It had several problems.
+ Under MinGW with a statically linked library, the main thread was
+ not registered. Cygwin detached threads leaked thread descriptors.
+ There were several race conditions. For now, unfortunately the
+ static threads limit remains, though we increased it, and made table
+ traversal cost depend on the actual thread count.
+ There is also still some code duplication with pthread_support.c.
+ (Thread descriptors did become much smaller, since Ben Hutchings
+ removed the thread context from them.)
+ - Integrated a Solaris configure.in patch from Rainer Orth.
+ - Added GC_IGNORE_FB and associated warning to very partially address
+ the issue of the collector treating a mapped frame buffer as part
+ of the root set. (Thanks to David Peroutka for providing some
+ insight. More would be helpful. Is there anything that can be used
+ to at least partially identify such memory segments?)
+
+
To do:
- - MacOSX thread support still appears to be a bit unreliable.
- A dynamic libgc.so references dlopen unconditionally, but doesn't link
against libdl.
- GC_proc_fd for Solaris is not correctly updated in response to a
Index: boehm_gc/doc/README.environment
===================================================================
RCS file: /home/staff/zs/imp/mercury/boehm_gc/doc/README.environment,v
retrieving revision 1.3
diff -u -r1.3 README.environment
--- boehm_gc/doc/README.environment 6 May 2003 11:36:52 -0000 1.3
+++ boehm_gc/doc/README.environment 27 Oct 2003 21:02:35 -0000
@@ -86,6 +86,13 @@
was turned into a runtime flag to enable last-minute
work-arounds.
+GC_IGNORE_FB - (Currently win32 only.) Try to avoid treating a mapped
+ frame buffer as part of the root set. Certain (higher end?)
+ graphics cards seems to result in the frame buffer mapped
+ into the user address space as writable memory.
+ Unfortunately, there seems to be no systematic way to
+ identify such memory.
+
The following turn on runtime flags that are also program settable. Checked
only during initialization. We expect that they will usually be set through
other means, but this may help with debugging and testing:
Index: boehm_gc/doc/README.macros
===================================================================
RCS file: /home/staff/zs/imp/mercury/boehm_gc/doc/README.macros,v
retrieving revision 1.1
diff -u -r1.1 README.macros
--- boehm_gc/doc/README.macros 25 Jul 2002 05:27:52 -0000 1.1
+++ boehm_gc/doc/README.macros 27 Oct 2003 21:02:35 -0000
@@ -51,7 +51,18 @@
__declspec(dllexport) needs to be added to declarations
to support the case in which the collector is in a dll.
-GC_DLL User-settable macro that forces the effect of _DLL.
+GC_DLL User-settable macro that forces the effect of _DLL. Set
+ by gc.h if _DLL is defined and GC_NOT_DLL is undefined.
+ This is the macro that is tested internally to determine
+ whether the GC is in its own dynamic library. May need
+ to be set by clients before including gc.h. Note that
+ inside the GC implementation it indicates that the
+ collector is in its own dynamic library, should export
+ its symbols, etc. But in clients it indicates that the
+ GC resides in a different DLL, its entry points should
+ be referenced accordingly, and precautions may need to
+ be taken to properly deal with statically allocated
+ variables in the main program. Used only for MS Windows.
GC_NOT_DLL User-settable macro that overrides _DLL, e.g. if dynamic
libraries are used, but the collector is in a static library.
Index: boehm_gc/doc/README.win32
===================================================================
RCS file: /home/staff/zs/imp/mercury/boehm_gc/doc/README.win32,v
retrieving revision 1.3
diff -u -r1.3 README.win32
--- boehm_gc/doc/README.win32 6 May 2003 11:36:52 -0000 1.3
+++ boehm_gc/doc/README.win32 27 Oct 2003 21:02:35 -0000
@@ -1,34 +1,11 @@
-The collector has at various times been compiled under Windows 95 & NT,
-with the original Microsoft SDK, with Visual C++ 2.0, 4.0, and 6, with
-the GNU win32 environment, with Borland 4.5, with Watcom C, and recently
+The collector has at various times been compiled under Windows 95 & later, NT,
+and XP, with the original Microsoft SDK, with Visual C++ 2.0, 4.0, and 6, with
+the GNU win32 tools, with Borland 4.5, with Watcom C, and recently
with the Digital Mars compiler. It is likely that some of these have been
broken in the meantime. Patches are appreciated.
-It runs under both win32s and win32, but with different semantics.
-Under win32, all writable pages outside of the heaps and stack are
-scanned for roots. Thus the collector sees pointers in DLL data
-segments. Under win32s, only the main data segment is scanned.
-(The main data segment should always be scanned. Under some
-versions of win32s, other regions may also be scanned.)
-Thus all accessible objects should be accessible from local variables
-or variables in the main data segment. Alternatively, other data
-segments (e.g. in DLLs) may be registered with the collector by
-calling GC_init() and then GC_register_root_section(a), where
-a is the address of some variable inside the data segment. (Duplicate
-registrations are ignored, but not terribly quickly.)
-
-(There are two reasons for this. We didn't want to see many 16:16
-pointers. And the VirtualQuery call has different semantics under
-the two systems, and under different versions of win32s.)
-
-Win32 applications compiled with some flavor of gcc currently behave
-like win32s applications, in that dynamic library data segments are
-not scanned. (Gcc does not directly support Microsoft's "structured
-exception handling". It turns out that use of this feature is
-unavoidable if you scan arbitrary memory segments obtained from
-VirtualQuery.)
-
-The collector test program "gctest" is linked as a GUI application,
+For historical reasons,
+the collector test program "gctest" is linked as a GUI application,
but does not open any windows. Its output appears in the file
"gc.log". It may be started from the file manager. The hour glass
cursor may appear as long as it's running. If it is started from the
@@ -60,11 +37,23 @@
Clark for tracking this down. There's some chance this may be fixed
in 6.1alpha4, since we now separate heap sections with an unused page.)
+Microsoft Tools
+---------------
For Microsoft development tools, rename NT_MAKEFILE as
MAKEFILE. (Make sure that the CPU environment variable is defined
to be i386.) In order to use the gc_cpp.h C++ interface, all
client code should include gc_cpp.h.
+For historical reasons,
+the collector test program "gctest" is linked as a GUI application,
+but does not open any windows. Its output appears in the file
+"gc.log". It may be started from the file manager. The hour glass
+cursor may 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.
+
If you would prefer a VC++.NET project file, ask boehm at acm.org. One has
been contributed, but it seems to contain some absolute paths etc., so
it can presumably only be a starting point, and is not in the standard
@@ -75,13 +64,22 @@
collector was built as a static library (as it normally is in the
absence of thread support).
+GNU Tools
+---------
For GNU-win32, use the regular makefile, possibly after uncommenting
the line "include Makefile.DLLs". The latter should be necessary only
-if you want to package the collector as a DLL. The GNU-win32 port is
+if you want to package the collector as a DLL.
believed to work only for b18, not b19, probably due to linker changes
in b19. This is probably fixable with a different definition of
DATASTART and DATAEND in gcconfig.h.
+The collector should also be buildable under Cygwin with either the
+old standard Makefile, or with the "configure;make" machinery.
+
+Borland Tools
+-------------
+[Rarely tested.]
For Borland tools, use BCC_MAKEFILE. Note that
Borland's compiler defaults to 1 byte alignment in structures (-a1),
whereas Visual C++ appears to default to 8 byte alignment (/Zp8).
@@ -97,6 +95,8 @@
require the assembler. If you do have the assembler, I recommend
removing the -DUSE_GENERIC.
+Incremental Collection
+----------------------
There is some support for incremental collection. This is
currently pretty simple-minded. Pages are protected. Protection
faults are caught by a handler installed at the bottom of the handler
@@ -112,6 +112,8 @@
Note that incremental collection is disabled with -DSMALL_CONFIG.
+Threads
+-------
James Clark has contributed the necessary code to support win32 threads.
Use NT_THREADS_MAKEFILE (a.k.a gc.mak) instead of NT_MAKEFILE
to build this version. Note that this requires some files whose names
@@ -126,6 +128,10 @@
This version relies on the collector residing in a dll.
+On a multiprocessor, performance may be greatly improved if _WIN32_WINNT
+is defined to be >= 0x0403, though this may prevent correct operation
+on some old versions of Windows NT and Windows 95.
+
This version currently supports incremental collection only if it is
enabled before any additional threads are created.
Version 4.13 attempts to fix some of the earlier problems, but there
@@ -133,7 +139,19 @@
might check with Geodesic Systems. Their collector must be licensed,
but they have invested far more time in win32-specific issues.
-Hans
+Since 6.3alpha2, threads are also better supported in static library builds
+with Microsoft tools (use NT_STATIC_THREADS_MAKEFILE) and with the GNU
+tools. In all cases,the collector must be built with GC_WIN32_THREADS
+defined, even if the Cygwin pthreads interface is used.
+(NT_STATIC_THREADS_MAKEFILE does this implicitly. Under Cygwin,
+./configure --enable-threads=posix defines GC_WIN32_THREADS.) Threads must be
+created with GC_CreateThread. This can be accomplished by
+including gc.h and then calling CreateThread, which is redefined
+by gc.h.
+
+
+Watcom compiler
+---------------
Ivan V. Demakov's README for the Watcom port:
@@ -161,10 +179,32 @@
All programs using gc should be compiled with 4-byte alignment.
For further explanations on this see comments about Borland.
-If gc compiled as dll, the macro ``GC_DLL'' should be defined before
+If the gc is compiled as dll, the macro ``GC_DLL'' should be defined before
including "gc.h" (for example, with -DGC_DLL compiler option). It's
important, otherwise resulting programs will not run.
Ivan Demakov (email: ivan at tgrad.nsk.su)
+Win32S
+------
+
+[The following is probably obsolete. The win32s support is still in the
+collector, but I doubt anyone cares, or has tested it recently.]
+
+The collector runs under both win32s and win32, but with different semantics.
+Under win32, all writable pages outside of the heaps and stack are
+scanned for roots. Thus the collector sees pointers in DLL data
+segments. Under win32s, only the main data segment is scanned.
+(The main data segment should always be scanned. Under some
+versions of win32s, other regions may also be scanned.)
+Thus all accessible objects should be accessible from local variables
+or variables in the main data segment. Alternatively, other data
+segments (e.g. in DLLs) may be registered with the collector by
+calling GC_init() and then GC_register_root_section(a), where
+a is the address of some variable inside the data segment. (Duplicate
+registrations are ignored, but not terribly quickly.)
+
+(There are two reasons for this. We didn't want to see many 16:16
+pointers. And the VirtualQuery call has different semantics under
+the two systems, and under different versions of win32s.)
Index: boehm_gc/doc/debugging.html
===================================================================
RCS file: /home/staff/zs/imp/mercury/boehm_gc/doc/debugging.html,v
retrieving revision 1.2
diff -u -r1.2 debugging.html
--- boehm_gc/doc/debugging.html 6 May 2003 11:36:52 -0000 1.2
+++ boehm_gc/doc/debugging.html 27 Oct 2003 21:02:35 -0000
@@ -47,6 +47,10 @@
<PRE>
Needed to allocate blacklisted block at 0x...
</pre>
+or
+<PRE>
+Repeated allocation of very large block ...
+</pre>
when it needs to allocate a block at a location that it knows to be
referenced by a false pointer. These false pointers can be either permanent
(<I>e.g.</i> a static integer variable that never changes) or temporary.
@@ -123,7 +127,8 @@
but were not cleared, or by caches growing without bounds.
<LI> Pointer misidentification. The garbage collector is interpreting
integers or other data as pointers and retaining the "referenced"
-objects.
+objects. A common symptom is that GC_dump() shows much of the heap
+as black-listed.
<LI> Heap fragmentation. This should never result in unbounded growth,
but it may account for larger heaps. This is most commonly caused
by allocation of large objects. On some platforms it can be reduced
@@ -180,6 +185,12 @@
<LI> Consider using <TT>GC_malloc_ignore_off_page()</tt>
to allocate large objects. (See <TT>gc.h</tt> and above for details.
Large means > 100K in most environments.)
+<LI> If your heap size is larger than 100MB or so, build the collector with
+-DLARGE_CONFIG. This allows the collector to keep more precise black-list
+information.
+<LI> If you are using heaps close to, or larger than, a gigabyte on a 32-bit
+machine, you may want to consider moving to a platform with 64-bit pointers.
+This is very likely to resolve any false pointer issues.
</ol>
<H2>Prematurely Reclaimed Objects</h2>
The usual symptom of this is a segmentation fault, or an obviously overwritten
Index: boehm_gc/doc/gc.man
===================================================================
RCS file: /home/staff/zs/imp/mercury/boehm_gc/doc/gc.man,v
retrieving revision 1.1
diff -u -r1.1 gc.man
--- boehm_gc/doc/gc.man 10 Apr 2001 01:01:12 -0000 1.1
+++ boehm_gc/doc/gc.man 27 Oct 2003 21:02:35 -0000
@@ -1,12 +1,14 @@
-.TH GC_MALLOC 1L "12 February 1996"
+.TH GC_MALLOC 1L "2 October 2003"
.SH NAME
GC_malloc, GC_malloc_atomic, GC_free, GC_realloc, GC_enable_incremental, GC_register_finalizer, GC_malloc_ignore_off_page, GC_malloc_atomic_ignore_off_page, GC_set_warn_proc \- Garbage collecting malloc replacement
.SH SYNOPSIS
#include "gc.h"
.br
-# define malloc(n) GC_malloc(n)
+void * GC_malloc(size_t size);
.br
-... malloc(...) ...
+void GC_free(void *ptr);
+.br
+void * GC_realloc(void *ptr, size_t size);
.br
.sp
cc ... gc.a
@@ -23,6 +25,11 @@
GC_malloc
or friends.
.LP
+In most cases it is preferable to call the macros GC_MALLOC, GC_FREE, etc.
+instead of calling GC_malloc and friends directly. This allows debugging
+versions of the routines to be substituted by defining GC_DEBUG before
+including gc.h.
+.LP
See the documentation in the include file gc_cpp.h for an alternate, C++ specific interface to the garbage collector.
.LP
Unlike the standard implementations of malloc,
@@ -77,4 +84,5 @@
The malloc(3) man page.
.LP
.SH AUTHOR
-Hans-J. Boehm (boehm at parc.xerox.com). Some of the code was written by others, most notably Alan Demers.
+Hans-J. Boehm (Hans.Boehm at hp.com).
+Some of the code was written by others, most notably Alan Demers.
Index: boehm_gc/include/Makefile.am
===================================================================
RCS file: /home/staff/zs/imp/mercury/boehm_gc/include/Makefile.am,v
retrieving revision 1.2
diff -u -r1.2 Makefile.am
--- boehm_gc/include/Makefile.am 27 Oct 2003 20:50:15 -0000 1.2
+++ boehm_gc/include/Makefile.am 27 Oct 2003 21:02:35 -0000
@@ -30,4 +30,6 @@
private/gc_pmark.h private/gc_locks.h \
private/solaris_threads.h private/dbg_mlc.h \
private/specific.h private/cord_pos.h \
+ private/pthread_support.h private/pthread_stop_world.h \
+ private/darwin_semaphore.h private/darwin_stop_world.h \
cord.h ec.h javaxfc.h
Index: boehm_gc/include/Makefile.in
===================================================================
RCS file: /home/staff/zs/imp/mercury/boehm_gc/include/Makefile.in,v
retrieving revision 1.2
diff -u -r1.2 Makefile.in
--- boehm_gc/include/Makefile.in 27 Oct 2003 20:50:15 -0000 1.2
+++ boehm_gc/include/Makefile.in 27 Oct 2003 21:02:35 -0000
@@ -108,6 +108,7 @@
THREADLIBS = @THREADLIBS@
VERSION = @VERSION@
addincludes = @addincludes@
+addlibs = @addlibs@
addobjs = @addobjs@
addtests = @addtests@
am__include = @am__include@
@@ -133,6 +134,8 @@
private/gc_pmark.h private/gc_locks.h \
private/solaris_threads.h private/dbg_mlc.h \
private/specific.h private/cord_pos.h \
+ private/pthread_support.h private/pthread_stop_world.h \
+ private/darwin_semaphore.h private/darwin_stop_world.h \
cord.h ec.h javaxfc.h
subdir = include
Index: boehm_gc/include/gc.h
===================================================================
RCS file: /home/staff/zs/imp/mercury/boehm_gc/include/gc.h,v
retrieving revision 1.13
diff -u -r1.13 gc.h
--- boehm_gc/include/gc.h 6 May 2003 11:36:52 -0000 1.13
+++ boehm_gc/include/gc.h 27 Oct 2003 21:02:35 -0000
@@ -136,7 +136,7 @@
/* thread, which will call GC_invoke_finalizers */
/* in response. */
-GC_API int GC_dont_gc; /* != 0 ==> Dont collect. In versions 7.2a1+, */
+GC_API int GC_dont_gc; /* != 0 ==> Dont collect. In versions 6.2a1+, */
/* this overrides explicit GC_gcollect() calls. */
/* Used as a counter, so that nested enabling */
/* and disabling work correctly. Should */
@@ -243,6 +243,7 @@
* allocation, since unlike the regular allocation routines, GC_local_malloc
* is not self-initializing. If you use GC_local_malloc you should arrange
* to call this somehow (e.g. from a constructor) before doing any allocation.
+ * For win32 threads, it needs to be called explicitly.
*/
GC_API void GC_init GC_PROTO((void));
@@ -346,17 +347,21 @@
GC_API void GC_add_roots GC_PROTO((char * low_address,
char * high_address_plus_1));
+/* Remove a root segment. Wizards only. */
+GC_API void GC_remove_roots GC_PROTO((char * low_address,
+ char * high_address_plus_1));
+
/* Add a displacement to the set of those considered valid by the */
/* collector. GC_register_displacement(n) means that if p was returned */
/* by GC_malloc, then (char *)p + n will be considered to be a valid */
-/* pointer to n. N must be small and less than the size of p. */
+/* pointer to p. N must be small and less than the size of p. */
/* (All pointers to the interior of objects from the stack are */
/* considered valid in any case. This applies to heap objects and */
/* static data.) */
/* Preferably, this should be called before any other GC procedures. */
/* Calling it later adds to the probability of excess memory */
/* retention. */
-/* This is a no-op if the collector was compiled with recognition of */
+/* This is a no-op if the collector has recognition of */
/* arbitrary interior pointers enabled, which is now the default. */
GC_API void GC_register_displacement GC_PROTO((GC_word n));
@@ -398,7 +403,7 @@
/* ineffective. */
GC_API void GC_disable GC_PROTO((void));
-/* Reenable garbage collection. GC_diable() and GC_enable() calls */
+/* Reenable garbage collection. GC_disable() and GC_enable() calls */
/* nest. Garbage collection is enabled if the number of calls to both */
/* both functions is equal. */
GC_API void GC_enable GC_PROTO((void));
@@ -876,9 +881,8 @@
extern void GC_thr_init(void); /* Needed for Solaris/X86 */
#endif /* THREADS && !SRC_M3 */
-#if defined(GC_WIN32_THREADS)
+#if defined(GC_WIN32_THREADS) && !defined(__CYGWIN32__) && !defined(__CYGWIN__)
# include <windows.h>
-# include <winbase.h>
/*
* All threads must be created using GC_CreateThread, so that they will be
@@ -887,7 +891,7 @@
* and does then use DllMain to keep track of thread creations. But new code
* should be built to call GC_CreateThread.
*/
- HANDLE WINAPI GC_CreateThread(
+ GC_API HANDLE WINAPI GC_CreateThread(
LPSECURITY_ATTRIBUTES lpThreadAttributes,
DWORD dwStackSize, LPTHREAD_START_ROUTINE lpStartAddress,
LPVOID lpParameter, DWORD dwCreationFlags, LPDWORD lpThreadId );
@@ -909,7 +913,7 @@
# endif
# endif /* defined(_WIN32_WCE) */
-#endif /* defined(GC_WIN32_THREADS) */
+#endif /* defined(GC_WIN32_THREADS) && !cygwin */
/*
* If you are planning on putting
@@ -922,7 +926,7 @@
extern void GC_noop(void *, void *); \
GC_noop(&end, &etext); }
#else
-# if defined(__CYGWIN32__) && defined(GC_USE_DLL) || defined (_AIX)
+# if defined(__CYGWIN32__) && defined(GC_DLL) || defined (_AIX)
/*
* Similarly gnu-win32 DLLs need explicit initialization, as does AIX.
* (We can't use DATASTART and DATAEND here, because gc_private.h
@@ -935,7 +939,11 @@
GC_add_roots((void *)&_bss_start__, (void *)&_data_end__); \
}
# else
+# if defined(__APPLE__) && defined(__MACH__) || defined(GC_WIN32_THREADS)
+# define GC_INIT() { GC_init(); }
+# else
# define GC_INIT()
+# endif
# endif
#endif
Index: boehm_gc/include/gc_config_macros.h
===================================================================
RCS file: /home/staff/zs/imp/mercury/boehm_gc/include/gc_config_macros.h,v
retrieving revision 1.2
diff -u -r1.2 gc_config_macros.h
--- boehm_gc/include/gc_config_macros.h 27 Oct 2003 20:50:15 -0000 1.2
+++ boehm_gc/include/gc_config_macros.h 27 Oct 2003 21:02:35 -0000
@@ -19,6 +19,9 @@
# define GC_DGUX386_THREADS
# endif
#endif
+#if defined(AIX_THREADS)
+# define GC_AIX_THREADS
+#endif
#if defined(HPUX_THREADS)
# define GC_HPUX_THREADS
#endif
@@ -38,6 +41,7 @@
#if !defined(_REENTRANT) && (defined(GC_SOLARIS_THREADS) \
|| defined(GC_SOLARIS_PTHREADS) \
|| defined(GC_HPUX_THREADS) \
+ || defined(GC_AIX_THREADS) \
|| defined(GC_LINUX_THREADS))
# define _REENTRANT
/* Better late than never. This fails if system headers that */
@@ -51,7 +55,8 @@
# if defined(GC_SOLARIS_PTHREADS) || defined(GC_FREEBSD_THREADS) || \
defined(GC_IRIX_THREADS) || defined(GC_LINUX_THREADS) || \
defined(GC_HPUX_THREADS) || defined(GC_OSF1_THREADS) || \
- defined(GC_DGUX386_THREADS) || defined(GC_MACOSX_THREADS) || \
+ defined(GC_DGUX386_THREADS) || defined(GC_DARWIN_THREADS) || \
+ defined(GC_AIX_THREADS) || \
(defined(GC_WIN32_THREADS) && defined(__CYGWIN32__))
# define GC_PTHREADS
# endif
@@ -79,7 +84,7 @@
# define GC_PTHREADS
# endif
# if defined(__APPLE__) && defined(__MACH__) && defined(__ppc__)
-# define GC_MACOSX_THREADS
+# define GC_DARWIN_THREADS
# define GC_PTHREADS
# endif
# if !defined(GC_PTHREADS) && defined(__FreeBSD__)
@@ -108,7 +113,11 @@
typedef long ptrdiff_t; /* ptrdiff_t is not defined */
# endif
-#if defined(__MINGW32__) && defined(_DLL) && !defined(GC_NOT_DLL)
+#if defined(_DLL) && !defined(GC_NOT_DLL) && !defined(GC_DLL)
+# define GC_DLL
+#endif
+
+#if defined(__MINGW32__) && defined(GC_DLL)
# ifdef GC_BUILD
# define GC_API __declspec(dllexport)
# else
@@ -116,9 +125,7 @@
# endif
#endif
-#if (defined(__DMC__) || defined(_MSC_VER)) \
- && (defined(_DLL) && !defined(GC_NOT_DLL) \
- || defined(GC_DLL))
+#if (defined(__DMC__) || defined(_MSC_VER)) && defined(GC_DLL)
# ifdef GC_BUILD
# define GC_API extern __declspec(dllexport)
# else
Index: boehm_gc/include/gc_pthread_redirects.h
===================================================================
RCS file: /home/staff/zs/imp/mercury/boehm_gc/include/gc_pthread_redirects.h,v
retrieving revision 1.2
diff -u -r1.2 gc_pthread_redirects.h
--- boehm_gc/include/gc_pthread_redirects.h 25 Jul 2002 09:03:14 -0000 1.2
+++ boehm_gc/include/gc_pthread_redirects.h 27 Oct 2003 21:02:35 -0000
@@ -52,15 +52,30 @@
int GC_pthread_create(pthread_t *new_thread,
const pthread_attr_t *attr,
void *(*start_routine)(void *), void *arg);
+#ifndef GC_DARWIN_THREADS
int GC_pthread_sigmask(int how, const sigset_t *set, sigset_t *oset);
+#endif
int GC_pthread_join(pthread_t thread, void **retval);
int GC_pthread_detach(pthread_t thread);
+#if defined(GC_OSF1_THREADS) \
+ && defined(_PTHREAD_USE_MANGLED_NAMES_) && !defined(_PTHREAD_USE_PTDNAM_)
+/* Unless the compiler supports #pragma extern_prefix, the Tru64 UNIX
+ <pthread.h> redefines some POSIX thread functions to use mangled names.
+ If so, undef them before redefining. */
+# undef pthread_create
+# undef pthread_join
+# undef pthread_detach
+#endif
+
# define pthread_create GC_pthread_create
-# define pthread_sigmask GC_pthread_sigmask
# define pthread_join GC_pthread_join
# define pthread_detach GC_pthread_detach
+
+#ifndef GC_DARWIN_THREADS
+# define pthread_sigmask GC_pthread_sigmask
# define dlopen GC_dlopen
+#endif
#endif /* GC_xxxxx_THREADS */
Index: boehm_gc/include/gc_typed.h
===================================================================
RCS file: /home/staff/zs/imp/mercury/boehm_gc/include/gc_typed.h,v
retrieving revision 1.6
diff -u -r1.6 gc_typed.h
--- boehm_gc/include/gc_typed.h 6 May 2003 11:36:53 -0000 1.6
+++ boehm_gc/include/gc_typed.h 27 Oct 2003 21:02:35 -0000
@@ -67,7 +67,7 @@
/* It is possible to generate a descriptor for a C type T with */
/* word aligned pointer fields f1, f2, ... as follows: */
/* */
-/* GC_descr T_descr;
+/* GC_descr T_descr; */
/* GC_word T_bitmap[GC_BITMAP_SIZE(T)] = {0}; */
/* GC_set_bit(T_bitmap, GC_WORD_OFFSET(T,f1)); */
/* GC_set_bit(T_bitmap, GC_WORD_OFFSET(T,f2)); */
Index: boehm_gc/include/private/gc_locks.h
===================================================================
RCS file: /home/staff/zs/imp/mercury/boehm_gc/include/private/gc_locks.h,v
retrieving revision 1.3
diff -u -r1.3 gc_locks.h
--- boehm_gc/include/private/gc_locks.h 6 May 2003 11:36:53 -0000 1.3
+++ boehm_gc/include/private/gc_locks.h 27 Oct 2003 21:02:35 -0000
@@ -100,17 +100,29 @@
# define GC_TEST_AND_SET_DEFINED
# endif
# if defined(IA64)
+# if defined(__INTEL_COMPILER)
+# include <ia64intrin.h>
+# endif
inline static int GC_test_and_set(volatile unsigned int *addr) {
long oldval, n = 1;
+# ifndef __INTEL_COMPILER
__asm__ __volatile__("xchg4 %0=%1,%2"
: "=r"(oldval), "=m"(*addr)
: "r"(n), "1"(*addr) : "memory");
+# else
+ oldval = _InterlockedExchange(addr, n);
+# endif
return oldval;
}
# define GC_TEST_AND_SET_DEFINED
inline static void GC_clear(volatile unsigned int *addr) {
+# ifndef __INTEL_COMPILER
__asm__ __volatile__("st4.rel %0=r0" : "=m" (*addr) : : "memory");
+# else
+ // there is no st4 but I can use xchg I hope
+ _InterlockedExchange(addr, 0);
+# endif
}
# define GC_CLEAR_DEFINED
# endif
@@ -153,10 +165,11 @@
"\tbne 2f\n" /* non-zero, return already set */
"\tstwcx. %2,0,%1\n" /* else store conditional */
"\tbne- 1b\n" /* retry if lost reservation */
+ "\tsync\n" /* import barrier */
"2:\t\n" /* oldval is zero if we set */
: "=&r"(oldval), "=p"(addr)
: "r"(temp), "1"(addr)
- : "memory");
+ : "cr0","memory");
return oldval;
}
# define GC_TEST_AND_SET_DEFINED
@@ -178,12 +191,18 @@
" bne %2,2f\n"
" xor %0,%3,%0\n"
" stl_c %0,%1\n"
+# ifdef __ELF__
" beq %0,3f\n"
+# else
+ " beq %0,1b\n"
+# endif
" mb\n"
"2:\n"
+# ifdef __ELF__
".section .text2,\"ax\"\n"
"3: br 1b\n"
".previous"
+# endif
:"=&r" (temp), "=m" (*addr), "=&r" (oldvalue)
:"Ir" (1), "m" (*addr)
:"memory");
@@ -250,17 +269,50 @@
# elif __mips < 3 || !(defined (_ABIN32) || defined(_ABI64)) \
|| !defined(_COMPILER_VERSION) || _COMPILER_VERSION < 700
# ifdef __GNUC__
-# define GC_test_and_set(addr) _test_and_set(addr,1)
+# define GC_test_and_set(addr) _test_and_set((void *)addr,1)
# else
-# define GC_test_and_set(addr) test_and_set(addr,1)
+# define GC_test_and_set(addr) test_and_set((void *)addr,1)
# endif
# else
-# define GC_test_and_set(addr) __test_and_set(addr,1)
+# define GC_test_and_set(addr) __test_and_set32((void *)addr,1)
# define GC_clear(addr) __lock_release(addr);
# define GC_CLEAR_DEFINED
# endif
# define GC_TEST_AND_SET_DEFINED
# endif /* MIPS */
+# if defined(_AIX)
+# include <sys/atomic_op.h>
+# if (defined(_POWER) || defined(_POWERPC))
+# if defined(__GNUC__)
+ inline static void GC_memsync() {
+ __asm__ __volatile__ ("sync" : : : "memory");
+ }
+# else
+# ifndef inline
+# define inline __inline
+# endif
+# pragma mc_func GC_memsync { \
+ "7c0004ac" /* sync (same opcode used for dcs)*/ \
+ }
+# endif
+# else
+# error dont know how to memsync
+# endif
+ inline static int GC_test_and_set(volatile unsigned int * addr) {
+ int oldvalue = 0;
+ if (compare_and_swap((void *)addr, &oldvalue, 1)) {
+ GC_memsync();
+ return 0;
+ } else return 1;
+ }
+# define GC_TEST_AND_SET_DEFINED
+ inline static void GC_clear(volatile unsigned int *addr) {
+ GC_memsync();
+ *(addr) = 0;
+ }
+# define GC_CLEAR_DEFINED
+
+# endif
# if 0 /* defined(HP_PA) */
/* The official recommendation seems to be to not use ldcw from */
/* user mode. Since multithreaded incremental collection doesn't */
@@ -325,8 +377,8 @@
{
char result;
__asm__ __volatile__("lock; cmpxchgl %2, %0; setz %1"
- : "=m"(*(addr)), "=r"(result)
- : "r" (new_val), "0"(*(addr)), "a"(old) : "memory");
+ : "+m"(*(addr)), "=r"(result)
+ : "r" (new_val), "a"(old) : "memory");
return (GC_bool) result;
}
# endif /* !GENERIC_COMPARE_AND_SWAP */
@@ -338,6 +390,37 @@
__asm__ __volatile__("" : : : "memory");
}
# endif /* I386 */
+
+# if defined(POWERPC)
+# if !defined(GENERIC_COMPARE_AND_SWAP)
+ /* Returns TRUE if the comparison succeeded. */
+ inline static GC_bool GC_compare_and_exchange(volatile GC_word *addr,
+ GC_word old, GC_word new_val)
+ {
+ int result, dummy;
+ __asm__ __volatile__(
+ "1:\tlwarx %0,0,%5\n"
+ "\tcmpw %0,%4\n"
+ "\tbne 2f\n"
+ "\tstwcx. %3,0,%2\n"
+ "\tbne- 1b\n"
+ "\tsync\n"
+ "\tli %1, 1\n"
+ "\tb 3f\n"
+ "2:\tli %1, 0\n"
+ "3:\t\n"
+ : "=&r" (dummy), "=r" (result), "=p" (addr)
+ : "r" (new_val), "r" (old), "2"(addr)
+ : "cr0","memory");
+ return (GC_bool) result;
+ }
+# endif /* !GENERIC_COMPARE_AND_SWAP */
+ inline static void GC_memory_barrier()
+ {
+ __asm__ __volatile__("sync" : : : "memory");
+ }
+# endif /* POWERPC */
+
# if defined(IA64)
# if !defined(GENERIC_COMPARE_AND_SWAP)
inline static GC_bool GC_compare_and_exchange(volatile GC_word *addr,
@@ -489,8 +572,12 @@
{ GC_ASSERT(I_HOLD_LOCK()); UNSET_LOCK_HOLDER(); \
pthread_mutex_unlock(&GC_allocate_ml); }
# else /* !GC_ASSERTIONS */
+# if defined(NO_PTHREAD_TRYLOCK)
+# define LOCK() GC_lock();
+# else /* !defined(NO_PTHREAD_TRYLOCK) */
# define LOCK() \
{ if (0 != pthread_mutex_trylock(&GC_allocate_ml)) GC_lock(); }
+# endif
# define UNLOCK() pthread_mutex_unlock(&GC_allocate_ml)
# endif /* !GC_ASSERTIONS */
# endif /* USE_PTHREAD_LOCKS */
@@ -512,7 +599,7 @@
/* on Irix anymore. */
# include <mutex.h>
- extern unsigned long GC_allocate_lock;
+ extern volatile unsigned int GC_allocate_lock;
/* This is not a mutex because mutexes that obey the (optional) */
/* POSIX scheduling rules are subject to convoys in high contention */
/* applications. This is basically a spin lock. */
Index: boehm_gc/include/private/gc_pmark.h
===================================================================
RCS file: /home/staff/zs/imp/mercury/boehm_gc/include/private/gc_pmark.h,v
retrieving revision 1.2
diff -u -r1.2 gc_pmark.h
--- boehm_gc/include/private/gc_pmark.h 6 May 2003 11:36:54 -0000 1.2
+++ boehm_gc/include/private/gc_pmark.h 27 Oct 2003 21:02:35 -0000
@@ -135,12 +135,7 @@
/* Return a pointer to within 1st page of object. */
/* Set *new_hdr_p to corr. hdr. */
#ifdef __STDC__
-# ifdef PRINT_BLACK_LIST
- ptr_t GC_find_start(ptr_t current, hdr *hhdr, hdr **new_hdr_p,
- word source);
-# else
- ptr_t GC_find_start(ptr_t current, hdr *hhdr, hdr **new_hdr_p);
-# endif
+ ptr_t GC_find_start(ptr_t current, hdr *hhdr, hdr **new_hdr_p);
#else
ptr_t GC_find_start();
#endif
Index: boehm_gc/include/private/gc_priv.h
===================================================================
RCS file: /home/staff/zs/imp/mercury/boehm_gc/include/private/gc_priv.h,v
retrieving revision 1.3
diff -u -r1.3 gc_priv.h
--- boehm_gc/include/private/gc_priv.h 6 May 2003 11:36:54 -0000 1.3
+++ boehm_gc/include/private/gc_priv.h 27 Oct 2003 21:02:35 -0000
@@ -42,8 +42,8 @@
# include <sys/resource.h>
#endif /* BSD_TIME */
-# ifndef GC_H
-# include "gc.h"
+# ifndef _GC_H
+# include "../gc.h"
# endif
# ifndef GC_MARK_H
@@ -356,7 +356,8 @@
# include <string.h>
# define BCOPY_EXISTS
# endif
-# if defined(MACOSX)
+# if defined(DARWIN)
+# include <string.h>
# define BCOPY_EXISTS
# endif
@@ -451,7 +452,19 @@
/* Get environment entry */
#if !defined(NO_GETENV)
-# define GETENV(name) getenv(name)
+# if defined(EMPTY_GETENV_RESULTS)
+ /* Workaround for a reputed Wine bug. */
+ static inline char * fixed_getenv(const char *name)
+ {
+ char * tmp = getenv(name);
+ if (tmp == 0 || strlen(tmp) == 0)
+ return 0;
+ return tmp;
+ }
+# define GETENV(name) fixed_getenv(name)
+# else
+# define GETENV(name) getenv(name)
+# endif
#else
# define GETENV(name) 0
#endif
@@ -909,7 +922,7 @@
/* OFFSET_TOO_BIG if the value j would be too */
/* large to fit in the entry. (Note that the */
/* size of these entries matters, both for */
- /* space consumption and for cache utilization. */
+ /* space consumption and for cache utilization.) */
# define OFFSET_TOO_BIG 0xfe
# define OBJ_INVALID 0xff
# define MAP_ENTRY(map, bytes) (map)[bytes]
@@ -1184,6 +1197,10 @@
extern long GC_large_alloc_warn_suppressed;
/* Number of warnings suppressed so far. */
+#ifdef THREADS
+ extern GC_bool GC_world_stopped;
+#endif
+
/* Operations */
# ifndef abs
@@ -1358,6 +1375,11 @@
# else
void GC_push_regs GC_PROTO((void));
# endif
+# if defined(SPARC) || defined(IA64)
+ /* Cause all stacked registers to be saved in memory. Return a */
+ /* pointer to the top of the corresponding memory stack. */
+ word GC_save_regs_in_stack GC_PROTO((void));
+# endif
/* Push register contents onto mark stack. */
/* If NURSERY is defined, the default push */
/* action can be overridden with GC_push_proc */
@@ -1407,6 +1429,7 @@
/* Set all mark bits associated with */
/* a free list. */
void GC_add_roots_inner GC_PROTO((char * b, char * e, GC_bool tmp));
+void GC_remove_roots_inner GC_PROTO((char * b, char * e));
GC_bool GC_is_static_root GC_PROTO((ptr_t p));
/* Is the address p in one of the registered static */
/* root sections? */
@@ -1622,6 +1645,8 @@
/* Make the indicated */
/* free list nonempty, and return its */
/* head. */
+
+void GC_free_inner(GC_PTR p);
void GC_init_headers GC_PROTO((void));
struct hblkhdr * GC_install_header GC_PROTO((struct hblk *h));
@@ -1849,6 +1874,16 @@
# else
# define GC_ASSERT(expr)
# endif
+
+/* Check a compile time assertion at compile time. The error */
+/* message for failure is a bit baroque, but ... */
+#if defined(mips) && !defined(__GNUC__)
+/* DOB: MIPSPro C gets an internal error taking the sizeof an array type.
+ This code works correctly (ugliness is to avoid "unused var" warnings) */
+#else
+#endif
# if defined(PARALLEL_MARK) || defined(THREAD_LOCAL_ALLOC)
/* We need additional synchronization facilities from the thread */
Index: boehm_gc/include/private/gcconfig.h
===================================================================
RCS file: /home/staff/zs/imp/mercury/boehm_gc/include/private/gcconfig.h,v
retrieving revision 1.8
diff -u -r1.8 gcconfig.h
--- boehm_gc/include/private/gcconfig.h 6 May 2003 11:36:54 -0000 1.8
+++ boehm_gc/include/private/gcconfig.h 27 Oct 2003 21:22:13 -0000
@@ -26,6 +26,13 @@
# define GCCONFIG_H
+# ifndef GC_PRIVATE_H
+ /* Fake ptr_t declaration, just to avoid compilation errors. */
+ /* This avoids many instances if "ifndef GC_PRIVATE_H" below. */
+# define GC_ptr_t_defined
+ typedef struct GC_undefined_struct * ptr_t;
+# endif
+
/* Machine dependent parameters. Some tuning parameters can be found */
/* near the top of gc_private.h. */
@@ -33,7 +40,9 @@
/* First a unified test for Linux: */
# if defined(linux) || defined(__linux__)
+# ifndef LINUX
# define LINUX
+# endif
# endif
/* And one for NetBSD: */
@@ -77,7 +86,7 @@
# define SPARC
# define mach_type_known
# endif
-# if defined(NETBSD) && defined(m68k)
+# if defined(NETBSD) && (defined(m68k) || defined(__m68k__))
# define M68K
# define mach_type_known
# endif
@@ -85,7 +94,7 @@
# define POWERPC
# define mach_type_known
# endif
-# if defined(NETBSD) && defined(__arm32__)
+# if defined(NETBSD) && (defined(__arm32__) || defined(__arm__))
# define ARM32
# define mach_type_known
# endif
@@ -98,6 +107,10 @@
# endif
# define mach_type_known
# endif
+# if defined(__NetBSD__) && defined(__vax__)
+# define VAX
+# define mach_type_known
+# endif
# if defined(mips) || defined(__mips) || defined(_mips)
# define MIPS
# if defined(nec_ews) || defined(_nec_ews)
@@ -220,7 +233,7 @@
# define ARM32
# define mach_type_known
# endif
-# if defined(LINUX) && (defined(powerpc) || defined(__powerpc__))
+# if defined(LINUX) && (defined(powerpc) || defined(__powerpc__) || defined(powerpc64) || defined(__powerpc64__))
# define POWERPC
# define mach_type_known
# endif
@@ -266,12 +279,12 @@
# endif
# if defined(macosx) || \
defined(__APPLE__) && defined(__MACH__) && defined(__ppc__)
-# define MACOSX
+# define DARWIN
# define POWERPC
# define mach_type_known
# endif
# if defined(__APPLE__) && defined(__MACH__) && defined(__i386__)
-# define MACOSX
+# define DARWIN
# define I386
--> Not really supported, but at least we recognize it.
# endif
@@ -450,6 +463,9 @@
/* SH ==> Hitachi SuperH */
/* (LINUX & MSWINCE) */
/* X86_64 ==> AMD x86-64 */
+ /* POWERPC ==> IBM/Apple PowerPC */
+ /* (MACOS(<=9),DARWIN(incl.MACOSX),*/
+ /* LINUX, NETBSD, NOSYS variants) */
/* ptr_t: A generic pointer to which we can add byte displacements. */
@@ -598,12 +614,19 @@
# ifdef NETBSD
# define OS_TYPE "NETBSD"
# define HEURISTIC2
- extern char etext[];
-# define DATASTART ((ptr_t)(etext))
+# ifdef __ELF__
+# define DATASTART GC_data_start
+# define DYNAMIC_LOADING
+# else
+ extern char etext[];
+# define DATASTART ((ptr_t)(etext))
+# endif
# endif
# ifdef LINUX
# define OS_TYPE "LINUX"
# define STACKBOTTOM ((ptr_t)0xf0000000)
+# define USE_GENERIC_PUSH_REGS
+ /* We never got around to the assembly version. */
/* # define MPROTECT_VDB - Reported to not work 9/17/01 */
# ifdef __ELF__
# define DYNAMIC_LOADING
@@ -704,38 +727,37 @@
# define DATAEND /* not needed */
# endif
# ifdef LINUX
-# define ALIGNMENT 4 /* Guess. Can someone verify? */
+# if (defined (powerpc64) || defined(__powerpc64__))
+# define ALIGNMENT 8
+# define CPP_WORDSZ 64
+# else
+# define ALIGNMENT 4 /* Guess. Can someone verify? */
/* This was 2, but that didn't sound right. */
+# endif
# define OS_TYPE "LINUX"
/* HEURISTIC1 has been reliably reported to fail for a 32-bit */
/* executable on a 64 bit kernel. */
# define LINUX_STACKBOTTOM
# define DYNAMIC_LOADING
-# undef STACK_GRAN
-# define STACK_GRAN 0x10000000
- /* Stack usually starts at 0x80000000 */
# define SEARCH_FOR_DATA_START
extern int _end[];
# define DATAEND (_end)
# endif
-# ifdef MACOSX
- /* There are reasons to suspect this may not be reliable. */
+# ifdef DARWIN
# define ALIGNMENT 4
-# define OS_TYPE "MACOSX"
-# ifdef GC_MACOSX_THREADS
-# define SIG_SUSPEND SIGXCPU
-# define SIG_THR_RESTART SIGXFSZ
-# endif
+# define OS_TYPE "DARWIN"
# define DYNAMIC_LOADING
- /* XXX: see get_end(3), get_etext() and get_end() should not be used */
+ /* XXX: see get_end(3), get_etext() and get_end() should not be used.
+ These aren't used when dyld support is enabled (it is by default) */
# define DATASTART ((ptr_t) get_etext())
-# define STACKBOTTOM ((ptr_t) 0xc0000000)
# define DATAEND ((ptr_t) get_end())
+# define STACKBOTTOM ((ptr_t) 0xc0000000)
# define USE_MMAP
# define USE_MMAP_ANON
-/* # define MPROTECT_VDB -- There is some evidence that this breaks
- * on some minor versions of MACOSX, i.e. 10.2.3. In theory,
- * it should be OK */
+# define USE_ASM_PUSH_REGS
+ /* This is potentially buggy. It needs more testing. See the comments in
+ os_dep.c */
+# define MPROTECT_VDB
# include <unistd.h>
# define GETPAGESIZE() getpagesize()
# if defined(USE_PPC_PREFETCH) && defined(__GNUC__)
@@ -745,6 +767,9 @@
# define PREFETCH_FOR_WRITE(x) \
__asm__ __volatile__ ("dcbtst 0,%0" : : "r" ((const void *) (x)))
# endif
+ /* There seems to be some issues with trylock hanging on darwin. This
+ should be looked into some more */
+# define NO_PTHREAD_TRYLOCK
# endif
# ifdef NETBSD
# define ALIGNMENT 4
@@ -1026,7 +1051,7 @@
/* possibly because Linux threads is itself a malloc client */
/* and can't deal with the signals. */
# endif
-# define HEAP_START 0x1000
+# define HEAP_START (ptr_t)0x1000
/* This encourages mmap to give us low addresses, */
/* thus allowing the heap to grow to ~3GB */
# ifdef __ELF__
@@ -1091,8 +1116,12 @@
/* DATAEND = _data_end__ */
/* To get it right for both, we take the */
/* minumum/maximum of the two. */
+# ifndef MAX
+# endif
+# ifndef MIN
+# endif
# define DATASTART ((ptr_t) MIN(_data_start__, _bss_start__))
# define DATAEND ((ptr_t) MAX(_data_end__, _bss_end__))
# undef STACK_GRAN
@@ -1285,7 +1314,8 @@
/* heap sections so they're not */
/* considered as roots. */
# define OS_TYPE "IRIX5"
-# define MPROTECT_VDB
+/*# define MPROTECT_VDB DOB: this should work, but there is evidence */
+/* of recent breakage. */
# ifdef _MIPS_SZPTR
# define CPP_WORDSZ _MIPS_SZPTR
# define ALIGNMENT (_MIPS_SZPTR/8)
@@ -1324,15 +1354,28 @@
# ifdef RS6000
# define MACH_TYPE "RS6000"
+# ifdef ALIGNMENT
+# undef ALIGNMENT
+# endif
+# ifdef IA64
+# undef IA64 /* DOB: some AIX installs stupidly define IA64 in /usr/include/sys/systemcfg.h */
+# endif
# ifdef __64BIT__
# define ALIGNMENT 8
# define CPP_WORDSZ 64
-# define STACKBOTTOM 0x1000000000000000
+# define STACKBOTTOM ((ptr_t)0x1000000000000000)
# else
# define ALIGNMENT 4
# define CPP_WORDSZ 32
# define STACKBOTTOM ((ptr_t)((ulong)&errno))
# endif
+ /* From AIX linker man page:
+ _text Specifies the first location of the program.
+ _etext Specifies the first location after the program.
+ _data Specifies the first location of the data.
+ _edata Specifies the first location after the initialized data
+ _end or end Specifies the first location after all data.
+ */
extern int _data[], _end[];
# define DATASTART ((ptr_t)((ulong)_data))
# define DATAEND ((ptr_t)((ulong)_end))
@@ -1530,6 +1573,7 @@
/* first putenv call. */
extern char ** environ;
# define STACKBOTTOM ((ptr_t)environ)
+# define HPUX_STACKBOTTOM
# define DYNAMIC_LOADING
# include <unistd.h>
# define GETPAGESIZE() sysconf(_SC_PAGE_SIZE)
@@ -1539,9 +1583,9 @@
/* address minus one page. */
# define BACKING_STORE_DISPLACEMENT 0x1000000
# define BACKING_STORE_ALIGNMENT 0x1000
-# define BACKING_STORE_BASE \
- (ptr_t)(((word)GC_stackbottom - BACKING_STORE_DISPLACEMENT - 1) \
- & ~(BACKING_STORE_ALIGNMENT - 1))
+ extern ptr_t GC_register_stackbottom;
+# define BACKING_STORE_BASE GC_register_stackbottom
+ /* Known to be wrong for recent HP/UX versions!!! */
# endif
# ifdef LINUX
# define CPP_WORDSZ 64
@@ -1559,8 +1603,8 @@
/* constants: */
# define BACKING_STORE_ALIGNMENT 0x100000
# define BACKING_STORE_DISPLACEMENT 0x80000000
- extern char * GC_register_stackbottom;
-# define BACKING_STORE_BASE ((ptr_t)GC_register_stackbottom)
+ extern ptr_t GC_register_stackbottom;
+# define BACKING_STORE_BASE GC_register_stackbottom
# define SEARCH_FOR_DATA_START
# ifdef __GNUC__
# define DYNAMIC_LOADING
@@ -1574,12 +1618,22 @@
extern int _end[];
# define DATAEND (_end)
# ifdef __GNUC__
-# define PREFETCH(x) \
- __asm__ (" lfetch [%0]": : "r"((void *)(x)))
-# define PREFETCH_FOR_WRITE(x) \
- __asm__ (" lfetch.excl [%0]": : "r"((void *)(x)))
-# define CLEAR_DOUBLE(x) \
- __asm__ (" stf.spill [%0]=f0": : "r"((void *)(x)))
+# ifndef __INTEL_COMPILER
+# define PREFETCH(x) \
+ __asm__ (" lfetch [%0]": : "r"((void *)(x)))
+# define PREFETCH_FOR_WRITE(x) \
+ __asm__ (" lfetch.excl [%0]": : "r"((void *)(x)))
+# define CLEAR_DOUBLE(x) \
+ __asm__ (" stf.spill [%0]=f0": : "r"((void *)(x)))
+# else
+# include <ia64intrin.h>
+# define PREFETCH(x) \
+ __lfetch(__lfhint_none, (void*)(x))
+# define PREFETCH_FOR_WRITE(x) \
+ __lfetch(__lfhint_nta, (void*)(x))
+# define CLEAR_DOUBLE(x) \
+ __stf_spill((void *)(x), 0)
+# endif // __INTEL_COMPILER
# endif
# endif
# endif
@@ -1826,8 +1880,9 @@
# endif
# if defined(SVR4) || defined(LINUX) || defined(IRIX) || defined(HPUX) \
- || defined(OPENBSD) || defined(NETBSD) || defined(FREEBSD) || defined(DGUX) \
- || defined(BSD) || defined(AIX) || defined(MACOSX) || defined(OSF1)
+ || defined(OPENBSD) || defined(NETBSD) || defined(FREEBSD) \
+ || defined(DGUX) || defined(BSD) \
+ || defined(_AIX) || defined(DARWIN) || defined(OSF1)
# define UNIX_LIKE /* Basic Unix-like system calls work. */
# endif
@@ -1892,7 +1947,7 @@
/* platforms as well, though it should be avoided in win32. */
# endif /* LINUX */
-# if defined(SEARCH_FOR_DATA_START) && defined(GC_PRIVATE_H)
+# if defined(SEARCH_FOR_DATA_START)
extern ptr_t GC_data_start;
# define DATASTART GC_data_start
# endif
@@ -1920,6 +1975,9 @@
# if defined(GC_HPUX_THREADS) && !defined(HPUX)
--> inconsistent configuration
# endif
+# if defined(GC_AIX_THREADS) && !defined(_AIX)
+ --> inconsistent configuration
+# endif
# if defined(GC_WIN32_THREADS) && !defined(MSWIN32) && !defined(CYGWIN32)
--> inconsistent configuration
# endif
@@ -1930,7 +1988,7 @@
# define THREADS
# endif
-# if defined(HP_PA) || defined(M88K) || defined(POWERPC) && !defined(MACOSX) \
+# if defined(HP_PA) || defined(M88K) || defined(POWERPC) && !defined(DARWIN) \
|| defined(LINT) || defined(MSWINCE) || defined(ARM32) \
|| (defined(I386) && defined(__LCC__))
/* Use setjmp based hack to mark from callee-save registers. */
@@ -2047,9 +2105,7 @@
+ GC_page_size-1)
# else
# ifdef MSWIN32
-# ifdef GC_PRIVATE_H
- extern ptr_t GC_win32_get_mem();
-# endif
+ extern ptr_t GC_win32_get_mem();
# define GET_MEM(bytes) (struct hblk *)GC_win32_get_mem(bytes)
# else
# ifdef MACOS
@@ -2065,9 +2121,7 @@
# endif
# else
# ifdef MSWINCE
-# ifdef GC_PRIVATE_H
- extern ptr_t GC_wince_get_mem();
-# endif
+ extern ptr_t GC_wince_get_mem();
# define GET_MEM(bytes) (struct hblk *)GC_wince_get_mem(bytes)
# else
# if defined(AMIGA) && defined(GC_AMIGA_FASTALLOC)
@@ -2076,9 +2130,7 @@
GC_amiga_get_mem((size_t)bytes + GC_page_size) \
+ GC_page_size-1)
# else
-# ifdef GC_PRIVATE_H
- extern ptr_t GC_unix_get_mem();
-# endif
+ extern ptr_t GC_unix_get_mem();
# define GET_MEM(bytes) (struct hblk *)GC_unix_get_mem(bytes)
# endif
# endif
Index: boehm_gc/include/private/solaris_threads.h
===================================================================
RCS file: /home/staff/zs/imp/mercury/boehm_gc/include/private/solaris_threads.h,v
retrieving revision 1.2
diff -u -r1.2 solaris_threads.h
--- boehm_gc/include/private/solaris_threads.h 25 Jul 2002 09:03:20 -0000 1.2
+++ boehm_gc/include/private/solaris_threads.h 27 Oct 2003 21:02:36 -0000
@@ -30,6 +30,8 @@
extern size_t GC_min_stack_sz;
extern size_t GC_page_sz;
extern void GC_thr_init(void);
+ extern ptr_t GC_stack_alloc(size_t * stack_size);
+ extern void GC_stack_free(ptr_t stack, size_t size);
# endif /* GC_SOLARIS_THREADS */
Index: boehm_gc/tests/test.c
===================================================================
RCS file: /home/staff/zs/imp/mercury/boehm_gc/tests/test.c,v
retrieving revision 1.3
diff -u -r1.3 test.c
--- boehm_gc/tests/test.c 6 May 2003 11:36:55 -0000 1.3
+++ boehm_gc/tests/test.c 27 Oct 2003 21:02:36 -0000
@@ -68,15 +68,14 @@
# include <pthread.h>
# endif
-# ifdef GC_WIN32_THREADS
-# ifndef MSWINCE
-# include <process.h>
-# define GC_CreateThread(a,b,c,d,e,f) ((HANDLE) _beginthreadex(a,b,c,d,e,f))
-# endif
+# if defined(GC_WIN32_THREADS) && !defined(GC_PTHREADS)
static CRITICAL_SECTION incr_cs;
# endif
+#ifdef __STDC__
+# include <stdarg.h>
+#endif
+
/* Allocation Statistics */
int stubborn_count = 0;
@@ -521,20 +520,13 @@
}
}
-/* Try to force a to be strangely aligned */
-struct {
- char dummy;
- sexpr aa;
-} A;
-#define a A.aa
-
/*
* A tiny list reversal test to check thread creation.
*/
#ifdef THREADS
# if defined(GC_WIN32_THREADS) && !defined(CYGWIN32)
- unsigned __stdcall tiny_reverse_test(void * arg)
+ DWORD __stdcall tiny_reverse_test(void * arg)
# else
void * tiny_reverse_test(void * arg)
# endif
@@ -569,7 +561,7 @@
# elif defined(GC_WIN32_THREADS)
void fork_a_thread()
{
- unsigned thread_id;
+ DWORD thread_id;
HANDLE h;
h = GC_CreateThread(NULL, 0, tiny_reverse_test, 0, 0, &thread_id);
if (h == (HANDLE)NULL) {
@@ -598,6 +590,13 @@
#endif
+/* Try to force a to be strangely aligned */
+struct {
+ char dummy;
+ sexpr aa;
+} A;
+#define a A.aa
+
/*
* Repeatedly reverse lists built out of very different sized cons cells.
* Check that we didn't lose anything.
@@ -718,6 +717,8 @@
b = c = 0;
}
+#undef a
+
/*
* The rest of this builds balanced binary trees, checks that they don't
* disappear, and tests finalization.
@@ -762,6 +763,7 @@
FAIL;
}
finalized_count++;
+ t -> level = -1; /* detect duplicate finalization immediately */
# ifdef PCR
PCR_ThCrSec_ExitSys();
# endif
@@ -1169,6 +1171,25 @@
fail_count++;
}
+static void uniq(void *p, ...) {
+ va_list a;
+ void *q[100];
+ int n = 0, i, j;
+ q[n++] = p;
+ va_start(a,p);
+ for (;(q[n] = va_arg(a,void *));n++) ;
+ va_end(a);
+ for (i=0; i<n; i++)
+ for (j=0; j<i; j++)
+ if (q[i] == q[j]) {
+ GC_printf0(
+ "Apparently failed to mark form some function arguments.\n"
+ "Perhaps GC_push_regs was configured incorrectly?\n"
+ );
+ FAIL;
+ }
+}
+
#endif /* __STDC__ */
#ifdef THREADS
@@ -1282,6 +1303,21 @@
GC_REGISTER_DISPLACEMENT(sizeof(struct fake_vtable *));
GC_init_gcj_malloc(0, (void *)fake_gcj_mark_proc);
# endif
+ /* Make sure that fn arguments are visible to the collector. */
+# ifdef __STDC__
+ uniq(
+ GC_malloc(12), GC_malloc(12), GC_malloc(12),
+ (GC_gcollect(),GC_malloc(12)),
+ GC_malloc(12), GC_malloc(12), GC_malloc(12),
+ (GC_gcollect(),GC_malloc(12)),
+ GC_malloc(12), GC_malloc(12), GC_malloc(12),
+ (GC_gcollect(),GC_malloc(12)),
+ GC_malloc(12), GC_malloc(12), GC_malloc(12),
+ (GC_gcollect(),GC_malloc(12)),
+ GC_malloc(12), GC_malloc(12), GC_malloc(12),
+ (GC_gcollect(),GC_malloc(12)),
+ (void *)0);
+# endif
/* Repeated list reversal test. */
reverse_test();
# ifdef PRINTSTATS
@@ -1450,6 +1486,10 @@
# endif
n_tests = 0;
+#if defined(__APPLE__) && defined(__MACH__)
+ GC_INIT();
+#endif
+
# if defined(DJGPP)
/* No good way to determine stack base from library; do it */
/* manually on this platform. */
@@ -1463,13 +1503,18 @@
# endif
GC_INIT(); /* Only needed if gc is dynamic library. */
(void) GC_set_warn_proc(warn_proc);
-# if (defined(MPROTECT_VDB) || defined(PROC_VDB)) && !defined(MAKE_BACK_GRAPH)
+# if (defined(MPROTECT_VDB) || defined(PROC_VDB)) \
+ && !defined(MAKE_BACK_GRAPH)
GC_enable_incremental();
(void) GC_printf0("Switched to incremental mode\n");
# if defined(MPROTECT_VDB)
(void)GC_printf0("Emulating dirty bits with mprotect/signals\n");
# else
+# ifdef PROC_VDB
(void)GC_printf0("Reading dirty bits from /proc\n");
+# else
+ (void)GC_printf0("Using DEFAULT_VDB dirty bit implementation\n");
+# endif
# endif
# endif
run_one_test();
@@ -1503,7 +1548,7 @@
#if defined(GC_WIN32_THREADS) && !defined(CYGWIN32)
-unsigned __stdcall thr_run_one_test(void *arg)
+DWORD __stdcall thr_run_one_test(void *arg)
{
run_one_test();
return 0;
@@ -1535,7 +1580,7 @@
return ret;
}
-unsigned __stdcall thr_window(void *arg)
+DWORD __stdcall thr_window(void *arg)
{
WNDCLASS win_class = {
CS_NOCLOSE,
@@ -1597,10 +1642,11 @@
# ifdef MSWINCE
HANDLE win_thr_h;
# endif
- unsigned thread_id;
+ DWORD thread_id;
# if 0
GC_enable_incremental();
# endif
+ GC_init();
InitializeCriticalSection(&incr_cs);
(void) GC_set_warn_proc(warn_proc);
# ifdef MSWINCE
@@ -1748,16 +1794,30 @@
(void)GC_printf0("pthread_default_stacksize_np failed.\n");
}
# endif /* GC_HPUX_THREADS */
+# if defined(__APPLE__) && defined(__MACH__)
+ GC_INIT();
+# endif
+
pthread_attr_init(&attr);
# if defined(GC_IRIX_THREADS) || defined(GC_FREEBSD_THREADS) \
- || defined(GC_MACOSX_THREADS)
+ || defined(GC_DARWIN_THREADS) || defined(GC_AIX_THREADS)
pthread_attr_setstacksize(&attr, 1000000);
# endif
n_tests = 0;
-# if defined(MPROTECT_VDB) && !defined(PARALLEL_MARK) &&!defined(REDIRECT_MALLOC) && !defined(MAKE_BACK_GRAPH)
+# if (defined(MPROTECT_VDB)) \
+ && !defined(PARALLEL_MARK) &&!defined(REDIRECT_MALLOC) \
+ && !defined(MAKE_BACK_GRAPH)
GC_enable_incremental();
(void) GC_printf0("Switched to incremental mode\n");
- (void) GC_printf0("Emulating dirty bits with mprotect/signals\n");
+# if defined(MPROTECT_VDB)
+ (void)GC_printf0("Emulating dirty bits with mprotect/signals\n");
+# else
+# ifdef PROC_VDB
+ (void)GC_printf0("Reading dirty bits from /proc\n");
+# else
+ (void)GC_printf0("Using DEFAULT_VDB dirty bit implementation\n");
+# endif
+# endif
# endif
(void) GC_set_warn_proc(warn_proc);
if ((code = pthread_key_create(&fl_key, 0)) != 0) {
Index: boehm_gc/tests/test_cpp.cc
===================================================================
RCS file: /home/staff/zs/imp/mercury/boehm_gc/tests/test_cpp.cc,v
retrieving revision 1.3
diff -u -r1.3 test_cpp.cc
--- boehm_gc/tests/test_cpp.cc 6 May 2003 11:36:55 -0000 1.3
+++ boehm_gc/tests/test_cpp.cc 27 Oct 2003 21:02:36 -0000
@@ -192,6 +192,8 @@
# endif
#endif
+ GC_init();
+
# if defined(MACOS) // MacOS
char* argv_[] = {"test_cpp", "10"}; // doesn't
argv = argv_; // have a
Index: boehm_gc/tests/trace_test.c
===================================================================
RCS file: /home/staff/zs/imp/mercury/boehm_gc/tests/trace_test.c,v
retrieving revision 1.1
diff -u -r1.1 trace_test.c
--- boehm_gc/tests/trace_test.c 10 Apr 2001 01:01:13 -0000 1.1
+++ boehm_gc/tests/trace_test.c 27 Oct 2003 21:02:36 -0000
@@ -10,6 +10,7 @@
struct treenode * mktree(int i) {
struct treenode * r = GC_MALLOC(sizeof(struct treenode));
if (0 == i) return 0;
+ if (1 == i) r = GC_MALLOC_ATOMIC(sizeof(struct treenode));
r -> x = mktree(i-1);
r -> y = mktree(i-1);
return r;
----
Peter Ross
PhD Student University of Melbourne
http://www.cs.mu.oz.au/~petdr/
--------------------------------------------------------------------------
mercury-reviews mailing list
post: mercury-reviews at cs.mu.oz.au
administrative address: owner-mercury-reviews at cs.mu.oz.au
unsubscribe: Address: mercury-reviews-request at cs.mu.oz.au Message: unsubscribe
subscribe: Address: mercury-reviews-request at cs.mu.oz.au Message: subscribe
--------------------------------------------------------------------------
More information about the reviews
mailing list