gc6.2alpha6 tarball import gc6_2alpha6
authorHans Boehm <boehm@acm.org>
Thu, 5 Jun 2003 00:00:00 +0000 (00:00 +0000)
committerIvan Maidanski <ivmai@mail.ru>
Sat, 17 May 2014 14:46:39 +0000 (18:46 +0400)
39 files changed:
Makefile
Makefile.am
Makefile.direct
Makefile.dj
Makefile.in
aix_irix_threads.c [moved from irix_threads.c with 73% similarity]
configure
configure.in
darwin_stop_world.c [new file with mode: 0644]
doc/README
doc/README.MacOSX
doc/README.changes
dyn_load.c
gc_dlopen.c
include/Makefile.am
include/Makefile.in
include/gc.h
include/gc_config_macros.h
include/gc_pthread_redirects.h
include/private/darwin_semaphore.h [new file with mode: 0644]
include/private/darwin_stop_world.h [new file with mode: 0644]
include/private/gc_locks.h
include/private/gc_priv.h
include/private/gcconfig.h
include/private/pthread_stop_world.h [new file with mode: 0644]
include/private/pthread_support.h [new file with mode: 0644]
mach_dep.c
mark_rts.c
misc.c
os_dep.c
powerpc_darwin_mach_dep.s [new file with mode: 0644]
powerpc_macosx_mach_dep.s [deleted file]
pthread_stop_world.c [new file with mode: 0644]
pthread_support.c [moved from linux_threads.c with 70% similarity]
tests/test.c
tests/test_cpp.cc
threadlibs.c
version.h
win32_threads.c

index 9c2cf4c..d2742b0 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -76,6 +76,8 @@ HOSTCFLAGS=$(CFLAGS)
 # -DGC_MACOSX_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
@@ -253,7 +255,7 @@ HOSTCFLAGS=$(CFLAGS)
 #   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
@@ -277,9 +279,9 @@ AR= ar
 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
 
@@ -298,10 +300,12 @@ SRCS= $(CSRCS) mips_sgi_mach_dep.S rs6000_mach_dep.s alpha_mach_dep.S \
     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 \
@@ -334,7 +338,7 @@ OTHER_FILES= Makefile setjmp_t.c callprocs pc_excludes \
            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)
 
@@ -388,7 +392,7 @@ $(OBJS) tests/test.o dyn_load.o dyn_load_sunos53.o: \
 
 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
 
@@ -485,7 +489,7 @@ liblinuxgc.so: $(OBJS) dyn_load.o
 
 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)
@@ -494,7 +498,7 @@ mach_dep.o: $(srcdir)/mach_dep.c $(srcdir)/mips_sgi_mach_dep.S \
         | ./if_mach MIPS IRIX5 grep -v "^\#" > $(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 MACOSX $(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
index 7b851e2..649ede4 100644 (file)
@@ -25,9 +25,12 @@ SUBDIRS = doc include
 EXTRA_DIST = 
     ## more items will be succesively added below
 
-lib_LTLIBRARIES = libgc.la @addlibs@
-
-EXTRA_LTLIBRARIES = libgccpp.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 \
@@ -35,12 +38,20 @@ include/leak_detector.h include/gc_typed.h @addincludes@
 
 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:
@@ -49,7 +60,7 @@ libgc_la_DEPENDENCIES = @addobjs@
 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
 
@@ -62,8 +73,13 @@ 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
@@ -79,11 +95,7 @@ gctest_LDADD = ./libgc.la $(THREADLIBS) $(EXTRA_TEST_LIBS)
 test_cpp_SOURCES = tests/test_cpp.cc
 test_cpp_LDADD = ./libgc.la ./libgccpp.la $(THREADLIBS) $(EXTRA_TEST_LIBS)
 
-TESTS = gctest @addtests@
-
-test_cpp$(EXEEXT): test_cpp.o
-       $(LIBTOOL) --mode=link $(CXX) $(AM_CFLAGS) $(MY_CFLAGS) \
-               test_cpp.o $(test_cpp_LDADD) $(LDFLAGS) -o $@
+TESTS = gctest $(extra_checks)
 
 ## FIXME: relies on internal code generated by automake.
 all_objs = @addobjs@ $(libgc_la_OBJECTS)
index 9c2cf4c..d2742b0 100644 (file)
@@ -76,6 +76,8 @@ HOSTCFLAGS=$(CFLAGS)
 # -DGC_MACOSX_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
@@ -253,7 +255,7 @@ HOSTCFLAGS=$(CFLAGS)
 #   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
@@ -277,9 +279,9 @@ AR= ar
 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
 
@@ -298,10 +300,12 @@ SRCS= $(CSRCS) mips_sgi_mach_dep.S rs6000_mach_dep.s alpha_mach_dep.S \
     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 \
@@ -334,7 +338,7 @@ OTHER_FILES= Makefile setjmp_t.c callprocs pc_excludes \
            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)
 
@@ -388,7 +392,7 @@ $(OBJS) tests/test.o dyn_load.o dyn_load_sunos53.o: \
 
 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
 
@@ -485,7 +489,7 @@ liblinuxgc.so: $(OBJS) dyn_load.o
 
 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)
@@ -494,7 +498,7 @@ mach_dep.o: $(srcdir)/mach_dep.c $(srcdir)/mips_sgi_mach_dep.S \
         | ./if_mach MIPS IRIX5 grep -v "^\#" > $(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 MACOSX $(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
index 146c83b..6097293 100644 (file)
@@ -177,7 +177,7 @@ SRCS= $(CSRCS) mips_sgi_mach_dep.S rs6000_mach_dep.s alpha_mach_dep.S \
     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 @@ liblinuxgc.so: $(OBJS) dyn_load.o
        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 4d3ee55..6d38aaa 100644 (file)
@@ -162,9 +162,9 @@ cord/cordbscs.c cord/cordtest.c cord/de.c cord/de_win.c \
     cord/de_win.h cord/de_win.RC\
 libtool.m4
 
-lib_LTLIBRARIES = libgc.la @addlibs@
-
-EXTRA_LTLIBRARIES = libgccpp.la
+@CPLUSPLUS_TRUE@extra = libgccpp.la
+@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 \
@@ -173,12 +173,17 @@ include/leak_detector.h include/gc_typed.h @addincludes@
 
 EXTRA_HEADERS = include/gc_cpp.h include/gc_allocator.h
 
+@POWERPC_DARWIN_TRUE@asm_libgc_sources = powerpc_darwin_mach_dep.s
+@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
@@ -188,7 +193,7 @@ libgc_la_DEPENDENCIES = @addobjs@
 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
 
@@ -200,8 +205,10 @@ libgccpp_la_LDFLAGS = -version-info 1:2:0
 AM_CXXFLAGS = @GC_CFLAGS@
 AM_CFLAGS = @GC_CFLAGS@
 
-check_PROGRAMS = gctest @addtests@
-EXTRA_PROGRAMS = test_cpp
+@CPLUSPLUS_TRUE@extra_checks = test_cpp
+@CPLUSPLUS_FALSE@extra_checks = 
+
+check_PROGRAMS = gctest $(extra_checks)
 
 # gctest_OBJECTS = test.o
 gctest_SOURCES = tests/test.c
@@ -209,7 +216,7 @@ gctest_LDADD = ./libgc.la $(THREADLIBS) $(EXTRA_TEST_LIBS)
 test_cpp_SOURCES = tests/test_cpp.cc
 test_cpp_LDADD = ./libgc.la ./libgccpp.la $(THREADLIBS) $(EXTRA_TEST_LIBS)
 
-TESTS = gctest @addtests@
+TESTS = gctest $(extra_checks)
 
 all_objs = @addobjs@ $(libgc_la_OBJECTS)
 
@@ -237,19 +244,22 @@ mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs
 CONFIG_CLEAN_FILES =
 LTLIBRARIES = $(lib_LTLIBRARIES)
 
+@POWERPC_DARWIN_TRUE@am__objects_1 = powerpc_darwin_mach_dep.lo
+@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)
 libgccpp_la_DEPENDENCIES =
 am_libgccpp_la_OBJECTS = gc_cpp.lo
 libgccpp_la_OBJECTS = $(am_libgccpp_la_OBJECTS)
-EXTRA_PROGRAMS = test_cpp$(EXEEXT)
-check_PROGRAMS = gctest$(EXEEXT) @addtests@
+@CPLUSPLUS_TRUE@check_PROGRAMS = gctest$(EXEEXT) test_cpp$(EXEEXT)
+@CPLUSPLUS_FALSE@check_PROGRAMS = gctest$(EXEEXT)
 am_gctest_OBJECTS = test.$(OBJEXT)
 gctest_OBJECTS = $(am_gctest_OBJECTS)
 gctest_DEPENDENCIES = ./libgc.la
@@ -268,19 +278,22 @@ LDFLAGS = @LDFLAGS@
 LIBS = @LIBS@
 depcomp = $(SHELL) $(top_srcdir)/depcomp
 am__depfiles_maybe = depfiles
-@AMDEP_TRUE@DEP_FILES = ./$(DEPDIR)/allchblk.Plo ./$(DEPDIR)/alloc.Plo \
+@AMDEP_TRUE@DEP_FILES = ./$(DEPDIR)/aix_irix_threads.Plo \
+@AMDEP_TRUE@   ./$(DEPDIR)/allchblk.Plo ./$(DEPDIR)/alloc.Plo \
 @AMDEP_TRUE@   ./$(DEPDIR)/backgraph.Plo ./$(DEPDIR)/blacklst.Plo \
-@AMDEP_TRUE@   ./$(DEPDIR)/checksums.Plo ./$(DEPDIR)/dbg_mlc.Plo \
-@AMDEP_TRUE@   ./$(DEPDIR)/dyn_load.Plo ./$(DEPDIR)/finalize.Plo \
-@AMDEP_TRUE@   ./$(DEPDIR)/gc_cpp.Plo ./$(DEPDIR)/gc_dlopen.Plo \
-@AMDEP_TRUE@   ./$(DEPDIR)/gcj_mlc.Plo ./$(DEPDIR)/headers.Plo \
-@AMDEP_TRUE@   ./$(DEPDIR)/irix_threads.Plo \
-@AMDEP_TRUE@   ./$(DEPDIR)/linux_threads.Plo \
-@AMDEP_TRUE@   ./$(DEPDIR)/malloc.Plo ./$(DEPDIR)/mallocx.Plo \
-@AMDEP_TRUE@   ./$(DEPDIR)/mark.Plo ./$(DEPDIR)/mark_rts.Plo \
-@AMDEP_TRUE@   ./$(DEPDIR)/misc.Plo ./$(DEPDIR)/new_hblk.Plo \
-@AMDEP_TRUE@   ./$(DEPDIR)/obj_map.Plo ./$(DEPDIR)/os_dep.Plo \
+@AMDEP_TRUE@   ./$(DEPDIR)/checksums.Plo \
+@AMDEP_TRUE@   ./$(DEPDIR)/darwin_stop_world.Plo \
+@AMDEP_TRUE@   ./$(DEPDIR)/dbg_mlc.Plo ./$(DEPDIR)/dyn_load.Plo \
+@AMDEP_TRUE@   ./$(DEPDIR)/finalize.Plo ./$(DEPDIR)/gc_cpp.Plo \
+@AMDEP_TRUE@   ./$(DEPDIR)/gc_dlopen.Plo ./$(DEPDIR)/gcj_mlc.Plo \
+@AMDEP_TRUE@   ./$(DEPDIR)/headers.Plo ./$(DEPDIR)/malloc.Plo \
+@AMDEP_TRUE@   ./$(DEPDIR)/mallocx.Plo ./$(DEPDIR)/mark.Plo \
+@AMDEP_TRUE@   ./$(DEPDIR)/mark_rts.Plo ./$(DEPDIR)/misc.Plo \
+@AMDEP_TRUE@   ./$(DEPDIR)/new_hblk.Plo ./$(DEPDIR)/obj_map.Plo \
+@AMDEP_TRUE@   ./$(DEPDIR)/os_dep.Plo \
 @AMDEP_TRUE@   ./$(DEPDIR)/pcr_interface.Plo \
+@AMDEP_TRUE@   ./$(DEPDIR)/pthread_stop_world.Plo \
+@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 \
@@ -370,7 +383,7 @@ clean-libLTLIBRARIES:
 libgc.la: $(libgc_la_OBJECTS) $(libgc_la_DEPENDENCIES) 
        $(LINK) -rpath $(libdir) $(libgc_la_LDFLAGS) $(libgc_la_OBJECTS) $(libgc_la_LIBADD) $(LIBS)
 libgccpp.la: $(libgccpp_la_OBJECTS) $(libgccpp_la_DEPENDENCIES) 
-       $(CXXLINK)  $(libgccpp_la_LDFLAGS) $(libgccpp_la_OBJECTS) $(libgccpp_la_LIBADD) $(LIBS)
+       $(CXXLINK) -rpath $(libdir) $(libgccpp_la_LDFLAGS) $(libgccpp_la_OBJECTS) $(libgccpp_la_LIBADD) $(LIBS)
 
 clean-checkPROGRAMS:
        @list='$(check_PROGRAMS)'; for p in $$list; do \
@@ -383,6 +396,9 @@ gctest$(EXEEXT): $(gctest_OBJECTS) $(gctest_DEPENDENCIES)
        @rm -f gctest$(EXEEXT)
        $(LINK) $(gctest_LDFLAGS) $(gctest_OBJECTS) $(gctest_LDADD) $(LIBS)
 test_cpp.$(OBJEXT): tests/test_cpp.cc
+test_cpp$(EXEEXT): $(test_cpp_OBJECTS) $(test_cpp_DEPENDENCIES) 
+       @rm -f test_cpp$(EXEEXT)
+       $(CXXLINK) $(test_cpp_LDFLAGS) $(test_cpp_OBJECTS) $(test_cpp_LDADD) $(LIBS)
 
 mostlyclean-compile:
        -rm -f *.$(OBJEXT) core *.core
@@ -390,11 +406,13 @@ mostlyclean-compile:
 distclean-compile:
        -rm -f *.tab.c
 
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/aix_irix_threads.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/allchblk.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/alloc.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/backgraph.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/blacklst.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/checksums.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/darwin_stop_world.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dbg_mlc.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dyn_load.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/finalize.Plo@am__quote@
@@ -402,8 +420,6 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gc_dlopen.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gcj_mlc.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/headers.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/irix_threads.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/linux_threads.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/malloc.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mallocx.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mark.Plo@am__quote@
@@ -413,6 +429,8 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/obj_map.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/os_dep.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcr_interface.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pthread_stop_world.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pthread_support.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ptr_chck.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/real_malloc.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/reclaim.Plo@am__quote@
@@ -887,10 +905,6 @@ test.o:    $(srcdir)/tests/test.c
 #      Using $< in the above seems to fail with the HP/UX on Itanium make.
 test_cpp.o:    $(srcdir)/tests/test_cpp.cc
        $(COMPILE) -c $(srcdir)/tests/test_cpp.cc
-
-test_cpp$(EXEEXT): test_cpp.o
-       $(LIBTOOL) --mode=link $(CXX) $(AM_CFLAGS) $(MY_CFLAGS) \
-               test_cpp.o $(test_cpp_LDADD) $(LDFLAGS) -o $@
 $(all_objs) : include/private/gcconfig.h include/private/gc_priv.h \
 include/private/gc_hdrs.h include/gc.h include/gc_gcj.h \
 include/gc_pthread_redirects.h include/gc_config_macros.h \
similarity index 73%
rename from irix_threads.c
rename to aix_irix_threads.c
index 48173e4..4785160 100644 (file)
@@ -1,7 +1,7 @@
 /* 
  * 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.
+ * Copyright (c) 1999-2003 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.
  * modified is included with the above copyright notice.
  */
 /*
- * Support code for Irix (>=6.2) Pthreads.  This relies on properties
+ * Support code for Irix (>=6.2) Pthreads and for AIX 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 this file and
+ * (pthread_support.c, pthread_stop_world.c).  They should be merged.
+ * Pthread_support.c should be directly usable.
  *
- * 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.
+ * Please avoid adding new ports here; use the generic pthread support
+ * as a base instead.
  */
 
-# if defined(GC_IRIX_THREADS)
+# if defined(GC_IRIX_THREADS) || defined(GC_AIX_THREADS)
 
 # include "private/gc_priv.h"
 # include <pthread.h>
+# include <assert.h>
 # include <semaphore.h>
 # include <time.h>
 # include <errno.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.
+#if defined(GC_IRIX_THREADS) && !defined(MUTEX_RECURSIVE_NP)
+#define MUTEX_RECURSIVE_NP PTHREAD_MUTEX_RECURSIVE
 #endif
 
 void GC_thr_init();
@@ -104,8 +105,14 @@ 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.
  */
+#if 0 /* DOB: 6.1 */
+# if defined(GC_AIX_THREADS)
+#   define SIG_SUSPEND SIGUSR1
+# else
+#   define SIG_SUSPEND (SIGRTMIN + 6)
+# endif
+#endif
 
 pthread_mutex_t GC_suspend_lock = PTHREAD_MUTEX_INITIALIZER;
                                /* Number of threads stopped so far     */
@@ -145,6 +152,8 @@ GC_bool GC_thr_initialized = FALSE;
 
 size_t GC_min_stack_sz;
 
+size_t GC_page_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    */
@@ -173,14 +182,14 @@ ptr_t GC_stack_alloc(size_t * stack_size)
     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));
+        result = (ptr_t) GC_scratch_alloc(search_sz + 2*GC_page_sz);
+        result = (ptr_t)(((word)result + GC_page_sz) & ~(GC_page_sz - 1));
         /* Protect hottest page to detect overflow. */
 #      ifdef STACK_GROWS_UP
-          /* mprotect(result + search_sz, GC_page_size, PROT_NONE); */
+          /* mprotect(result + search_sz, GC_page_sz, PROT_NONE); */
 #      else
-          /* mprotect(result, GC_page_size, PROT_NONE); */
-          result += GC_page_size;
+          /* mprotect(result, GC_page_sz, PROT_NONE); */
+          result += GC_page_sz;
 #      endif
     }
     *stack_size = search_sz;
@@ -227,7 +236,7 @@ GC_thread GC_new_thread(pthread_t id)
        /* 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);
+                GC_generic_malloc_inner(sizeof(struct GC_Thread_Rep), NORMAL);
     }
     if (result == 0) return(0);
     result -> id = id;
@@ -294,6 +303,42 @@ GC_thread GC_lookup_thread(pthread_t id)
     return(p);
 }
 
+#if defined(GC_AIX_THREADS)
+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) {
+          pthread_suspend_np(p->id);
+        }
+      }
+    }
+    /* GC_printf1("World stopped 0x%x\n", pthread_self()); */
+}
+
+void GC_start_world()
+{
+    GC_thread p;
+    unsigned i;
+    pthread_t my_thread = pthread_self();
+
+    /* GC_printf0("World starting\n"); */
+    for (i = 0; i < THREAD_TABLE_SZ; i++) {
+      for (p = GC_threads[i]; p != 0; p = p -> next) {
+        if (p -> id != my_thread) {
+          pthread_continue_np(p->id);
+        }
+      }
+    }
+}
+
+#else /* GC_AIX_THREADS */
 
 /* Caller holds allocation lock.       */
 void GC_stop_world()
@@ -371,6 +416,8 @@ void GC_start_world()
     pthread_cond_broadcast(&GC_continue_cv);
 }
 
+#endif /* GC_AIX_THREADS */
+
 # ifdef MMAP_STACKS
 --> not really supported yet.
 int GC_is_thread_stack(ptr_t addr)
@@ -409,7 +456,41 @@ void GC_push_all_stacks()
         if (pthread_equal(p -> id, me)) {
            hot = GC_approx_sp();
        } else {
-           hot = p -> stack_ptr;
+#ifdef GC_AIX_THREADS
+          /* AIX doesn't use signals to suspend, so we need to get an accurate hot stack pointer */
+          pthread_t id = p -> id;
+          struct __pthrdsinfo pinfo;
+          int val = 255;
+          char regbuf[255];
+          int retval = pthread_getthrds_np(&id, PTHRDSINFO_QUERY_ALL, &pinfo, sizeof(pinfo), regbuf, &val);
+          if (retval != 0) { printf("ERROR: pthread_getthrds_np() failed in GC\n"); abort(); }
+          hot = (ptr_t)(unsigned long)pinfo.__pi_ustk;
+          if ((p -> stack_size != 0 && 
+               (pinfo.__pi_stackend != ((ptr_t)p -> stack) + p -> stack_size || 
+                p -> stack_ptr < p -> stack || 
+                p -> stack_ptr > ((ptr_t)p -> stack) + p -> stack_size))) {
+            printf("ERROR in GC_push_all_stacks() stack state:\n"
+                "p->stack:                 0x%08x\n"
+                "p->stack_size:            0x%08x\n"
+                "p->stack_ptr:             0x%08x\n"
+                "(p->stack+p->stack_size): 0x%08x\n"
+                "pinfo.__pi_stackaddr:     0x%08x\n"
+                "pinfo.__pi_stacksize:     0x%08x\n"
+                "pinfo.__pi_stackend:      0x%08x\n"
+                "GC_stackbottom:           0x%08x\n"
+                ,
+                (uintptr_t)p->stack, (uintptr_t)p->stack_size, 
+                (uintptr_t)p->stack_ptr, (uintptr_t)(((ptr_t)(p->stack))+p->stack_size),
+                (uintptr_t)pinfo.__pi_stackaddr, (uintptr_t)pinfo.__pi_stacksize, (uintptr_t)pinfo.__pi_stackend,
+                (uintptr_t)GC_stackbottom
+                );
+          }
+          /* push the registers too, because they won't be on stack */
+          GC_push_all_eager((ptr_t)&pinfo.__pi_context, (ptr_t)((&pinfo.__pi_context)+1));
+          GC_push_all_eager((ptr_t)regbuf, (ptr_t)&regbuf[val]);
+#else
+              hot = p -> stack_ptr;
+#endif
        }
         if (p -> stack_size != 0) {
 #        ifdef STACK_GROWS_UP
@@ -424,6 +505,7 @@ void GC_push_all_stacks()
 #      ifdef STACK_GROWS_UP
           GC_push_all_stack(cold, hot);
 #      else
+ /* printf("thread 0x%x: hot=0x%08x cold=0x%08x\n", p -> id, hot, cold); */
           GC_push_all_stack(hot, cold);
 #      endif
       }
@@ -440,6 +522,8 @@ void GC_thr_init()
     if (GC_thr_initialized) return;
     GC_thr_initialized = TRUE;
     GC_min_stack_sz = HBLKSIZE;
+    GC_page_sz = sysconf(_SC_PAGESIZE);
+#ifndef GC_AIX_THREADS
     (void) sigaction(SIG_SUSPEND, 0, &act);
     if (act.sa_handler != SIG_DFL)
        ABORT("Previously installed SIG_SUSPEND handler");
@@ -449,6 +533,7 @@ void GC_thr_init()
        (void) sigemptyset(&act.sa_mask);
         if (0 != sigaction(SIG_SUSPEND, &act, 0))
            ABORT("Failed to install SIG_SUSPEND handler");
+#endif
     /* Add the initial thread, so we can stop it.      */
       t = GC_new_thread(pthread_self());
       t -> stack_size = 0;
@@ -460,6 +545,10 @@ int GC_pthread_sigmask(int how, const sigset_t *set, sigset_t *oset)
 {
     sigset_t fudged_set;
     
+#ifdef GC_AIX_THREADS
+    return(pthread_sigmask(how, set, oset));
+#endif
+
     if (set != NULL && (how == SIG_BLOCK || how == SIG_SETMASK)) {
         fudged_set = *set;
         sigdelset(&fudged_set, SIG_SUSPEND);
@@ -474,8 +563,7 @@ struct start_info {
     word flags;
     ptr_t stack;
     size_t stack_size;
-    sem_t registered;          /* 1 ==> in our thread table, but       */
-                               /* parent hasn't yet noticed.           */
+    sem_t registered;  
 };
 
 void GC_thread_exit_proc(void *arg)
@@ -506,33 +594,10 @@ int GC_pthread_join(pthread_t thread, void **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);
+    /* Here the pthread thread id may have been recycled. */
+    GC_delete_gc_thread(thread, thread_gc_id);
     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;
 }
 
@@ -562,7 +627,12 @@ void * GC_start_routine(void * arg)
     me -> flags = si -> flags;
     me -> stack = si -> stack;
     me -> stack_size = si -> stack_size;
+#ifdef STACK_GROWS_UP
     me -> stack_ptr = (ptr_t)si -> stack + si -> stack_size - sizeof(word);
+#else
+    /* stack_ptr needs to point to the hot part of the stack (or conservatively, past it) */
+    me -> stack_ptr = (ptr_t)si -> stack;
+#endif
     UNLOCK();
     start = si -> start_routine;
     start_arg = si -> arg;
@@ -578,7 +648,43 @@ void * GC_start_routine(void * arg)
     return(result);
 }
 
-# define copy_attr(pa_ptr, source) *(pa_ptr) = *(source)
+# if defined(GC_AIX_THREADS)
+  /* pthread_attr_t is not a structure, thus a simple structure copy   */
+  /* won't work.                                                       */
+  static void copy_attr(pthread_attr_t * pa_ptr,
+                       const pthread_attr_t  * source) {
+    int tmp;
+    size_t stmp;
+    void * vtmp;
+    struct sched_param sp_tmp;
+#ifndef GC_AIX_THREADS
+    pthread_spu_t ps_tmp;
+#endif
+    (void) pthread_attr_init(pa_ptr);
+    (void) pthread_attr_getdetachstate(source, &tmp);
+    (void) pthread_attr_setdetachstate(pa_ptr, tmp);
+    (void) pthread_attr_getinheritsched(source, &tmp);
+    (void) pthread_attr_setinheritsched(pa_ptr, tmp);
+    (void) pthread_attr_getschedpolicy(source, &tmp);
+    (void) pthread_attr_setschedpolicy(pa_ptr, tmp);
+    (void) pthread_attr_getstacksize(source, &stmp);
+    (void) pthread_attr_setstacksize(pa_ptr, stmp);
+    (void) pthread_attr_getguardsize(source, &stmp);
+    (void) pthread_attr_setguardsize(pa_ptr, stmp);
+    (void) pthread_attr_getstackaddr(source, &vtmp);
+    (void) pthread_attr_setstackaddr(pa_ptr, vtmp);
+    (void) pthread_attr_getscope(source, &tmp);
+    (void) pthread_attr_setscope(pa_ptr, tmp);
+    (void) pthread_attr_getschedparam(source, &sp_tmp);
+    (void) pthread_attr_setschedparam(pa_ptr, &sp_tmp);
+#ifndef GC_AIX_THREADS
+    (void) pthread_attr_getprocessor_np(source, &ps_tmp, &tmp);
+    (void) pthread_attr_setprocessor_np(pa_ptr, ps_tmp, tmp);
+#endif
+  }
+# else
+#   define copy_attr(pa_ptr, source) *(pa_ptr) = *(source)
+# endif
 
 int
 GC_pthread_create(pthread_t *new_thread,
@@ -593,8 +699,9 @@ GC_pthread_create(pthread_t *new_thread,
     int detachstate;
     word my_flags = 0;
     struct start_info * si = GC_malloc(sizeof(struct start_info)); 
-       /* This is otherwise saved only in an area mmapped by the thread */
-       /* library, which isn't visible to the collector.                */
+
+    /* 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)) {
@@ -603,7 +710,8 @@ GC_pthread_create(pthread_t *new_thread,
     si -> start_routine = start_routine;
     si -> arg = arg;
     LOCK();
-    if (!GC_is_initialized) GC_init();
+    if (!GC_thr_initialized) GC_thr_init();
+
     if (NULL == attr) {
         stack = 0;
        (void) pthread_attr_init(&new_attr);
@@ -613,25 +721,43 @@ GC_pthread_create(pthread_t *new_thread,
     }
     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);
+#ifdef GC_AIX_THREADS
+    GC_min_stack_sz = 5*1048576;
+    if (stacksize < GC_min_stack_sz) {
+      stacksize = GC_min_stack_sz;
+    }
+    { int alignment = 16*1024; /* size must be multiple of 16KB greater than 56KB */
+      int minval = 56*1024;
+      if ((stacksize - minval) % alignment != 0) {
+        stacksize = minval + alignment * ((stacksize-minval)/alignment + 1);
+      }
+    }
+#endif
+    if (0 == stack) { 
+      stack = (void *)GC_stack_alloc(&stacksize);
+      if (0 == stack) {
+       UNLOCK();
+       return(ENOMEM);
+      }
+      pthread_attr_setstacksize(&new_attr, stacksize);
+#ifdef GC_AIX_THREADS
+      pthread_attr_setstackaddr(&new_attr, ((char *)stack)+stacksize);
+#else
+      pthread_attr_setstackaddr(&new_attr, stack);
+#endif
     } else {
-       my_flags |= CLIENT_OWNS_STACK;
+      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);
+    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  */
@@ -644,12 +770,14 @@ GC_pthread_create(pthread_t *new_thread,
          }
        }
         sem_destroy(&(si -> registered));
-    pthread_attr_destroy(&new_attr);  /* Probably unnecessary under Irix */
+    pthread_attr_destroy(&new_attr);  
+
     return(result);
 }
 
-VOLATILE GC_bool GC_collecting = 0;
-                       /* A hint that we're in the collector and       */
+/* For now we use the pthreads locking primitives on HP/UX */
+
+VOLATILE GC_bool GC_collecting = 0; /* A hint that we're in the collector and       */
                         /* holding the allocation lock for an           */
                         /* extended period.                             */
 
@@ -658,9 +786,9 @@ VOLATILE GC_bool GC_collecting = 0;
 
 #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
+volatile unsigned int 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()
 {
@@ -720,11 +848,11 @@ yield:
     }
 }
 
-# else
+# else  /* !GC_IRIX_THREADS && !GC_AIX_THREADS */
 
 #ifndef LINT
   int GC_no_Irix_threads;
 #endif
 
-# endif /* GC_IRIX_THREADS */
+# endif /* IRIX_THREADS */
 
index db84f60..845fff8 100755 (executable)
--- a/configure
+++ b/configure
@@ -1,7 +1,7 @@
 #! /bin/sh
 # From configure.in Revision: 1.2 .
 # Guess values for system-dependent variables and create Makefiles.
-# Generated by GNU Autoconf 2.53 for gc 6.2alpha5.
+# Generated by GNU Autoconf 2.53 for gc 6.2alpha6.
 #
 # Report bugs to <Hans.Boehm@hp.com>.
 #
@@ -416,8 +416,8 @@ SHELL=${CONFIG_SHELL-/bin/sh}
 # Identity of this package.
 PACKAGE_NAME='gc'
 PACKAGE_TARNAME='gc'
-PACKAGE_VERSION='6.2alpha5'
-PACKAGE_STRING='gc 6.2alpha5'
+PACKAGE_VERSION='6.2alpha6'
+PACKAGE_STRING='gc 6.2alpha6'
 PACKAGE_BUGREPORT='Hans.Boehm@hp.com'
 
 ac_unique_file="gcj_mlc.c"
@@ -930,7 +930,7 @@ if test "$ac_init_help" = "long"; then
   # Omit some internal or obsolete options to make the list less imposing.
   # This message is too long to be a string in the A/UX 3.1 sh.
   cat <<_ACEOF
-\`configure' configures gc 6.2alpha5 to adapt to many kinds of systems.
+\`configure' configures gc 6.2alpha6 to adapt to many kinds of systems.
 
 Usage: $0 [OPTION]... [VAR=VALUE]...
 
@@ -997,7 +997,7 @@ fi
 
 if test -n "$ac_init_help"; then
   case $ac_init_help in
-     short | recursive ) echo "Configuration of gc 6.2alpha5:";;
+     short | recursive ) echo "Configuration of gc 6.2alpha6:";;
    esac
   cat <<\_ACEOF
 
@@ -1106,7 +1106,7 @@ fi
 test -n "$ac_init_help" && exit 0
 if $ac_init_version; then
   cat <<\_ACEOF
-gc configure 6.2alpha5
+gc configure 6.2alpha6
 generated by GNU Autoconf 2.53
 
 Copyright 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001, 2002
@@ -1121,7 +1121,7 @@ cat >&5 <<_ACEOF
 This file contains any messages produced by compilers while
 running configure, to aid debugging if configure makes a mistake.
 
-It was created by gc $as_me 6.2alpha5, which was
+It was created by gc $as_me 6.2alpha6, which was
 generated by GNU Autoconf 2.53.  Invocation command line was
 
   $ $0 $@
@@ -1782,7 +1782,7 @@ fi
 
 # Define the identity of the package.
  PACKAGE=gc
- VERSION=6.2alpha5
+ VERSION=6.2alpha6
 
 
 cat >>confdefs.h <<_ACEOF
@@ -3555,6 +3555,16 @@ _ACEOF
 _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 @@ _ACEOF
        ;;
      *-*-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
@@ -3688,7 +3708,24 @@ echo "$as_me: error: $THREADS is an unknown thread package" >&2;}
 esac
 
 
-# I'm not too familiar with autoconf, is this the best way to do this? -Brian
+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*) ;;
   *)
@@ -3788,13 +3825,23 @@ _ACEOF
 esac
 
 if test "${enable_cplusplus}" = yes; then
-      addlibs="$addlibs libgccpp.la"
       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
+
+
+
+
 
 
 
@@ -5344,7 +5391,7 @@ test "x$enable_libtool_lock" != xno && enable_libtool_lock=yes
 case $host in
 *-*-irix6*)
   # Find out which ABI we are using.
-  echo '#line 5347 "configure"' > conftest.$ac_ext
+  echo '#line 5394 "configure"' > conftest.$ac_ext
   if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
   (eval $ac_compile) 2>&5
   ac_status=$?
@@ -5880,7 +5927,7 @@ chmod -w .
 save_CFLAGS="$CFLAGS"
 CFLAGS="$CFLAGS -o out/conftest2.$ac_objext"
 compiler_c_o=no
-if { (eval echo configure:5883: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>out/conftest.err; } && test -s out/conftest2.$ac_objext; then
+if { (eval echo configure:5930: \"$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
@@ -7673,7 +7720,7 @@ else
     lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
   lt_status=$lt_dlunknown
   cat > conftest.$ac_ext <<EOF
-#line 7676 "configure"
+#line 7723 "configure"
 #include "confdefs.h"
 
 #if HAVE_DLFCN_H
@@ -7771,7 +7818,7 @@ else
     lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
   lt_status=$lt_dlunknown
   cat > conftest.$ac_ext <<EOF
-#line 7774 "configure"
+#line 7821 "configure"
 #include "confdefs.h"
 
 #if HAVE_DLFCN_H
@@ -8944,6 +8991,20 @@ echo "$as_me: error: conditional \"MAINTAINER_MODE\" was never defined.
 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
@@ -9200,7 +9261,7 @@ _ASBOX
 } >&5
 cat >&5 <<_CSEOF
 
-This file was extended by gc $as_me 6.2alpha5, which was
+This file was extended by gc $as_me 6.2alpha6, which was
 generated by GNU Autoconf 2.53.  Invocation command line was
 
   CONFIG_FILES    = $CONFIG_FILES
@@ -9257,7 +9318,7 @@ _ACEOF
 
 cat >>$CONFIG_STATUS <<_ACEOF
 ac_cs_version="\\
-gc config.status 6.2alpha5
+gc config.status 6.2alpha6
 configured by $0, generated by GNU Autoconf 2.53,
   with options \\"`echo "$ac_configure_args" | sed 's/[\\""\`\$]/\\\\&/g'`\\"
 
@@ -9502,8 +9563,12 @@ s,@MAINTAINER_MODE_FALSE@,$MAINTAINER_MODE_FALSE,;t t
 s,@MAINT@,$MAINT,;t t
 s,@GC_CFLAGS@,$GC_CFLAGS,;t t
 s,@THREADLIBS@,$THREADLIBS,;t t
+s,@POWERPC_DARWIN_TRUE@,$POWERPC_DARWIN_TRUE,;t t
+s,@POWERPC_DARWIN_FALSE@,$POWERPC_DARWIN_FALSE,;t t
 s,@EXTRA_TEST_LIBS@,$EXTRA_TEST_LIBS,;t t
 s,@target_all@,$target_all,;t t
+s,@CPLUSPLUS_TRUE@,$CPLUSPLUS_TRUE,;t t
+s,@CPLUSPLUS_FALSE@,$CPLUSPLUS_FALSE,;t t
 s,@INCLUDES@,$INCLUDES,;t t
 s,@CXXINCLUDES@,$CXXINCLUDES,;t t
 s,@addobjs@,$addobjs,;t t
index 2e18090..cb6477d 100644 (file)
@@ -17,7 +17,7 @@ dnl Process this file with autoconf to produce configure.
 # Initialization
 # ==============
 
-AC_INIT(gc,6.2alpha5,Hans.Boehm@hp.com) 
+AC_INIT(gc,6.2alpha6,Hans.Boehm@hp.com) 
     ## version must conform to [0-9]+[.][0-9]+(alpha[0-9]+)?
 AC_CONFIG_SRCDIR(gcj_mlc.c)
 AC_CANONICAL_TARGET 
@@ -89,6 +89,10 @@ case "$THREADS" in
        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 @@ case "$THREADS" in
        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)
@@ -159,7 +167,15 @@ AC_MSG_RESULT($THREADLIBS)
 esac
 AC_SUBST(THREADLIBS)
 
-# I'm not too familiar with autoconf, is this the best way to do this? -Brian
+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*) ;;
   *) 
@@ -198,11 +214,12 @@ case "$TARGET_ECOS" in
 esac
 
 if test "${enable_cplusplus}" = yes; then
-      addlibs="$addlibs libgccpp.la"
       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)
diff --git a/darwin_stop_world.c b/darwin_stop_world.c
new file mode 100644 (file)
index 0000000..28ade58
--- /dev/null
@@ -0,0 +1,205 @@
+#include "private/pthread_support.h"
+
+# if defined(GC_DARWIN_THREADS)
+
+#define DEBUG_THREADS 0
+
+/* From "Inside Mac OS X - Mach-O Runtime Architecture" published by Apple
+   Page 49:
+   "The space beneath the stack pointer, where a new stack frame would normally
+   be allocated, is called the red zone. This area as shown in Figure 3-2 may
+   be used for any purpose as long as a new stack frame does not need to be
+   added to the stack."
+   
+   Page 50: "If a leaf procedure's red zone usage would exceed 224 bytes, then
+   it must set up a stack frame just like routines that call other routines."
+*/
+#define PPC_RED_ZONE_SIZE 224
+
+void GC_push_all_stacks() {
+    int i;
+    kern_return_t r;
+    GC_thread p;
+    pthread_t me;
+    ptr_t lo, hi;
+#      if defined(POWERPC)
+        ppc_thread_state_t state;
+#      else
+#              error FIXME for non-ppc OS X
+#      endif
+    mach_msg_type_number_t thread_state_count = MACHINE_THREAD_STATE_COUNT;
+    
+    me = pthread_self();
+    if (!GC_thr_initialized) GC_thr_init();
+    
+    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)) {
+                lo = GC_approx_sp();
+            } else {
+                /* Get the thread state (registers, etc) */
+                r = thread_get_state(
+                    p->stop_info.mach_thread,
+                    MACHINE_THREAD_STATE,
+                    (natural_t*)&state,
+                    &thread_state_count);
+                if(r != KERN_SUCCESS) ABORT("thread_get_state failed");
+    
+                #ifdef POWERPC
+                    lo = (void*)(state.r1 - PPC_RED_ZONE_SIZE);
+                    
+                    GC_push_one(state.r0); 
+                    GC_push_one(state.r2); 
+                    GC_push_one(state.r3); 
+                    GC_push_one(state.r4); 
+                    GC_push_one(state.r5); 
+                    GC_push_one(state.r6); 
+                    GC_push_one(state.r7); 
+                    GC_push_one(state.r8); 
+                    GC_push_one(state.r9); 
+                    GC_push_one(state.r10); 
+                    GC_push_one(state.r11); 
+                    GC_push_one(state.r12); 
+                    GC_push_one(state.r13); 
+                    GC_push_one(state.r14); 
+                    GC_push_one(state.r15); 
+                    GC_push_one(state.r16); 
+                    GC_push_one(state.r17); 
+                    GC_push_one(state.r18); 
+                    GC_push_one(state.r19); 
+                    GC_push_one(state.r20); 
+                    GC_push_one(state.r21); 
+                    GC_push_one(state.r22); 
+                    GC_push_one(state.r23); 
+                    GC_push_one(state.r24); 
+                    GC_push_one(state.r25); 
+                    GC_push_one(state.r26); 
+                    GC_push_one(state.r27); 
+                    GC_push_one(state.r28); 
+                    GC_push_one(state.r29); 
+                    GC_push_one(state.r30); 
+                    GC_push_one(state.r31);
+                #else
+                #      error FIXME for non-PPC darwin
+                #endif /* !POWERPC */
+            } /* p != me */
+            if(p->flags & MAIN_THREAD)
+                hi = GC_stackbottom;
+            else
+                hi = p->stack_end;
+            #if DEBUG_THREADS
+                GC_printf3("Darwin: Stack for thread 0x%lx = [%lx,%lx)\n",
+                    (unsigned long) p -> id,
+                    (unsigned long) lo,
+                    (unsigned long) hi
+                );
+            #endif
+            GC_push_all_stack(lo,hi);
+        } /* for(p=GC_threads[i]...) */
+    } /* for(i=0;i<THREAD_TABLE_SZ...) */
+}
+
+/* Caller holds allocation lock.       */
+void GC_stop_world()
+{
+    int i;
+    GC_thread p;
+    pthread_t my_thread = pthread_self();
+    kern_return_t kern_result;
+    
+    #if DEBUG_THREADS
+    GC_printf1("Stopping the world from 0x%lx\n", pthread_self());
+    #endif
+       
+    /* 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 */
+
+    for (i = 0; i < THREAD_TABLE_SZ; i++) {
+        for (p = GC_threads[i]; p != 0; p = p -> next) {
+            if (p -> id == my_thread) continue;
+            if (p -> flags & FINISHED) continue;
+            if (p -> thread_blocked) /* Will wait */ continue;
+            
+            #if DEBUG_THREADS
+            GC_printf1("Suspending thread 0x%lx\n", p -> id);
+            #endif
+            
+            /* Suspend the thread */
+            kern_result = thread_suspend(p->stop_info.mach_thread);
+            if(kern_result != KERN_SUCCESS) ABORT("thread_suspend failed");
+            
+            /* abort any mach calls */
+            kern_result = thread_abort(p->stop_info.mach_thread);
+            /* This shouldn't really be fatal, I don't think. The documentation is kind of unclear */
+            if(kern_result != KERN_SUCCESS) GC_printf1("thread_abort_safely failed (%ul)",kern_result);
+        }
+    }
+    
+#   ifdef MPROTECT_VDB
+    if(GC_incremental) {
+        extern void GC_mprotect_stop();
+        GC_mprotect_stop();
+    }
+#   endif
+    
+#   ifdef PARALLEL_MARK
+      GC_release_mark_lock();
+#   endif
+    #if DEBUG_THREADS
+      GC_printf1("World stopped from 0x%lx\n", pthread_self());
+    #endif
+}
+
+/* Caller holds allocation lock, and has held it continuously since    */
+/* the world stopped.                                                  */
+void GC_start_world()
+{
+    pthread_t my_thread = pthread_self();
+    int i;
+    GC_thread p;
+    kern_return_t kern_result;
+
+#   if DEBUG_THREADS
+      GC_printf0("World starting\n");
+#   endif
+
+#   ifdef MPROTECT_VDB
+    if(GC_incremental) {
+        extern void GC_mprotect_resume();
+        GC_mprotect_resume();
+    }
+#   endif
+
+    for (i = 0; i < THREAD_TABLE_SZ; i++) {
+        for (p = GC_threads[i]; p != 0; p = p -> next) {
+            if (p -> id == my_thread) continue;
+            if (p -> flags & FINISHED) continue;
+            if (p -> thread_blocked) continue;
+    
+            #if DEBUG_THREADS
+            GC_printf1("Resuming 0x%lx\n", p -> id);
+            #endif
+            
+            /* Resume the thread */
+            kern_result = thread_resume(p->stop_info.mach_thread);
+            if(kern_result != KERN_SUCCESS) ABORT("thread_resume failed");
+        }
+    }
+    #if DEBUG_THREADS
+      GC_printf0("World started\n");
+    #endif
+}
+
+void GC_stop_init() {
+
+}
+
+#endif
index 581d69d..593a4b5 100644 (file)
@@ -28,7 +28,7 @@ are GPL'ed, but with an exception that should cover all uses in the
 collector.  (If you are concerned about such things, I recommend you look
 at the notice in config.guess or ltmain.sh.)
 
-This is version 6.2alpha5 of a conservative garbage collector for C and C++.
+This is version 6.2alpha6 of a conservative garbage collector for C and C++.
 
 You might find a more recent version of this at
 
index a517dd6..f5333d5 100644 (file)
@@ -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@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 125f83f..781fd42 100644 (file)
@@ -1834,10 +1834,39 @@ Since 6.2alpha4:
    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 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.
     
 
 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 aacdaf6..9a530a2 100644 (file)
@@ -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.
@@ -961,7 +961,7 @@ void GC_register_dynamic_libraries()
                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);
                ldi = len ? (struct ld_info *)((char *)ldi + len) : 0;
@@ -969,63 +969,122 @@ void GC_register_dynamic_libraries()
 }
 #endif /* RS6000 */
 
-#ifdef MACOSX
+#ifdef DARWIN
 
 #include <mach-o/dyld.h>
 #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,
-                filetype == MH_EXECUTE ? FALSE : TRUE);
+        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;
+    
+    if(initialized) return;
+    
+#   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_addres failed");
+            
+#   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 existing and all future libraries
+    */
+        
+    _dyld_register_func_for_add_image(GC_dyld_image_add);
+    _dyld_register_func_for_remove_image(GC_dyld_image_remove);
+    initialized = TRUE;
 }
 
 #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 1f38907..4c690ed 100644 (file)
@@ -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 d754edb..306026b 100644 (file)
@@ -30,4 +30,6 @@ dist_noinst_HEADERS = private/gc_hdrs.h \
     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 cb650a8..9ade270 100644 (file)
@@ -134,6 +134,8 @@ dist_noinst_HEADERS = private/gc_hdrs.h \
     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 dfecfca..f3e31d9 100644 (file)
@@ -341,6 +341,10 @@ GC_API void GC_clear_roots GC_PROTO((void));
 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   */
@@ -872,9 +876,8 @@ extern void GC_thr_init();  /* 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
@@ -905,7 +908,7 @@ extern void GC_thr_init();  /* Needed for Solaris/X86       */
 #  endif
 # endif /* defined(_WIN32_WCE) */
 
-#endif /* defined(GC_WIN32_THREADS) */
+#endif /* defined(GC_WIN32_THREADS)  && !cygwin */
 
 /*
  * If you are planning on putting
@@ -924,7 +927,11 @@ extern void GC_thr_init(); /* Needed for Solaris/X86       */
      */
 #   define GC_INIT() { GC_add_roots(DATASTART, DATAEND); }
 # else
+#  if defined(__APPLE__) && defined(__MACH__)
+#   define GC_INIT() { GC_init(); }
+#  else
 #   define GC_INIT()
+#  endif
 # endif
 #endif
 
index 01de9c5..0c836d8 100644 (file)
@@ -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__)
index 47284fb..99a3e8d 100644 (file)
   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);
 
 # define pthread_create GC_pthread_create
+#ifndef GC_DARWIN_THREADS
 # define pthread_sigmask GC_pthread_sigmask
+#endif
 # define pthread_join GC_pthread_join
 # define pthread_detach GC_pthread_detach
+#ifndef GC_DARWIN_THREADS
 # define dlopen GC_dlopen
+#endif
 
 #endif /* GC_xxxxx_THREADS */
 
diff --git a/include/private/darwin_semaphore.h b/include/private/darwin_semaphore.h
new file mode 100644 (file)
index 0000000..0f43982
--- /dev/null
@@ -0,0 +1,68 @@
+#ifndef GC_DARWIN_SEMAPHORE_H
+#define GC_DARWIN_SEMAPHORE_H
+
+#if !defined(GC_DARWIN_THREADS)
+#error darwin_semaphore.h included with GC_DARWIN_THREADS not defined
+#endif
+
+/*
+   This is a very simple semaphore implementation for darwin. It
+   is implemented in terms of pthreads calls so it isn't async signal
+   safe. This isn't a problem because signals aren't used to
+   suspend threads on darwin.
+*/
+   
+typedef struct {
+    pthread_mutex_t mutex;
+    pthread_cond_t cond;
+    int value;
+} sem_t;
+
+static int sem_init(sem_t *sem, int pshared, int value) {
+    int ret;
+    if(pshared)
+        GC_abort("sem_init with pshared set");
+    sem->value = value;
+    
+    ret = pthread_mutex_init(&sem->mutex,NULL);
+    if(ret < 0) return -1;
+    ret = pthread_cond_init(&sem->cond,NULL);
+    if(ret < 0) return -1;
+    return 0;
+}
+
+static int sem_post(sem_t *sem) {
+    if(pthread_mutex_lock(&sem->mutex) < 0)
+        return -1;
+    sem->value++;
+    if(pthread_cond_signal(&sem->cond) < 0) {
+        pthread_mutex_unlock(&sem->mutex);
+        return -1;
+    }
+    if(pthread_mutex_unlock(&sem->mutex) < 0)
+        return -1;
+    return 0;
+}
+
+static int sem_wait(sem_t *sem) {
+    if(pthread_mutex_lock(&sem->mutex) < 0)
+        return -1;
+    while(sem->value == 0) {
+        pthread_cond_wait(&sem->cond,&sem->mutex);
+    }
+    sem->value--;
+    if(pthread_mutex_unlock(&sem->mutex) < 0)
+        return -1;    
+    return 0;
+}
+
+static int sem_destroy(sem_t *sem) {
+    int ret;
+    ret = pthread_cond_destroy(&sem->cond);
+    if(ret < 0) return -1;
+    ret = pthread_mutex_destroy(&sem->mutex);
+    if(ret < 0) return -1;
+    return 0;
+}
+
+#endif
diff --git a/include/private/darwin_stop_world.h b/include/private/darwin_stop_world.h
new file mode 100644 (file)
index 0000000..9924297
--- /dev/null
@@ -0,0 +1,15 @@
+#ifndef GC_DARWIN_STOP_WORLD_H
+#define GC_DARWIN_STOP_WORLD_H
+
+#if !defined(GC_DARWIN_THREADS)
+#error darwin_stop_world.h included without GC_DARWIN_THREADS defined
+#endif
+
+#include <mach/mach.h>
+#include <mach/thread_act.h>
+
+struct thread_stop_info {
+    mach_port_t mach_thread;
+};
+
+#endif
index 61397b1..2507605 100644 (file)
                "\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
 #    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 */
          __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,
                { 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 */
      /* 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 3822555..49db446 100644 (file)
@@ -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
@@ -352,7 +352,8 @@ void GC_print_callers GC_PROTO((struct callinfo info[NFRAMES]));
 #   include <string.h>
 #   define BCOPY_EXISTS
 # endif
-# if defined(MACOSX)
+# if defined(DARWIN)
+#   include <string.h>
 #   define BCOPY_EXISTS
 # endif
 
@@ -1358,6 +1359,11 @@ extern void (*GC_start_call_back) GC_PROTO((void));
 # 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 +1413,7 @@ void GC_set_fl_marks GC_PROTO((ptr_t p));
                                    /* 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 +1629,8 @@ ptr_t GC_allocobj GC_PROTO((word sz, int kind));
                                /* 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));
index 35d47fd..290055b 100644 (file)
@@ -39,7 +39,9 @@
 
 /* First a unified test for Linux: */
 # if defined(linux) || defined(__linux__)
+#  ifndef LINUX
 #    define LINUX
+#  endif
 # endif
 
 /* And one for NetBSD: */
 #    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
 # 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
                    /*             SH         ==> Hitachi SuperH        */
                    /*                  (LINUX & MSWINCE)               */
                    /*             X86_64     ==> AMD x86-64            */
+                   /*             POWERPC    ==> IBM/Apple PowerPC     */
+                   /*                  (MACOS(<=9),DARWIN(incl.MACOSX),*/
+                   /*                   LINUX, NETBSD, NOSYS variants) */
 
 
 /*
 #     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.                                        */
       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__)
 #      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
        /*      DATAEND     = _data_end__               */
        /* To get it right for both, we take the        */
        /* minumum/maximum of the two.                  */
+#     ifndef MAX
 #      define MAX(x,y) ((x) > (y) ? (x) : (y))
+#     endif
+#     ifndef MIN
 #      define MIN(x,y) ((x) < (y) ? (x) : (y))
+#     endif
 #       define DATASTART ((ptr_t) MIN(_data_start__, _bss_start__))
 #       define DATAEND  ((ptr_t) MAX(_data_end__, _bss_end__))
 #      undef STACK_GRAN
                              /* 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)
 
 # 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))
 # 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
 
 # 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
 #   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.    */
diff --git a/include/private/pthread_stop_world.h b/include/private/pthread_stop_world.h
new file mode 100644 (file)
index 0000000..054c7a0
--- /dev/null
@@ -0,0 +1,12 @@
+#ifndef GC_PTHREAD_STOP_WORLD_H
+#define GC_PTHREAD_STOP_WORLD_H
+
+struct thread_stop_info {
+    int        signal;
+    word last_stop_count;      /* GC_last_stop_count value when thread */
+                               /* last successfully handled a suspend  */
+                               /* signal.                              */
+    ptr_t stack_ptr;           /* Valid only when stopped.             */
+};
+    
+#endif
diff --git a/include/private/pthread_support.h b/include/private/pthread_support.h
new file mode 100644 (file)
index 0000000..0ef917e
--- /dev/null
@@ -0,0 +1,97 @@
+#ifndef GC_PTHREAD_SUPPORT_H
+#define GC_PTHREAD_SUPPORT_H
+
+# include "private/gc_priv.h"
+
+# if defined(GC_PTHREADS) && !defined(GC_SOLARIS_THREADS) \
+     && !defined(GC_IRIX_THREADS) && !defined(GC_WIN32_THREADS)
+     
+#if defined(GC_DARWIN_THREADS)
+# include "private/darwin_stop_world.h"
+#else
+# include "private/pthread_stop_world.h"
+#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;
+    /* Extra bookkeeping information the stopping code uses */
+    struct thread_stop_info stop_info;
+    
+    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.               */
+#   ifdef IA64
+       ptr_t backing_store_end;
+       ptr_t backing_store_ptr;
+#   endif
+    void * status;             /* The value returned from the thread.  */
+                               /* Used only to avoid premature         */
+                               /* reclamation of any data it might     */
+                               /* reference.                           */
+#   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;
+
+# define THREAD_TABLE_SZ 128   /* Must be power of 2   */
+extern volatile GC_thread GC_threads[THREAD_TABLE_SZ];
+
+extern GC_bool GC_thr_initialized;
+
+GC_thread GC_lookup_thread(pthread_t id);
+
+void GC_stop_init();
+
+#endif /* GC_PTHREADS && !GC_SOLARIS_THREADS.... etc */
+#endif /* GC_PTHREAD_SUPPORT_H */
index 4a66d5d..3dc5f0b 100644 (file)
@@ -74,7 +74,8 @@ asm static void PushMacRegisters()
 /* 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 @@ void GC_push_regs()
          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 @@ void GC_push_regs()
          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 @@ void GC_push_regs()
          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 @@ void GC_push_regs()
          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 @@ void GC_push_regs()
          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 @@ void GC_push_regs()
               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 @@ void GC_push_regs()
          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 @@ void GC_push_regs()
          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 @@ void GC_push_regs()
          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 @@ void GC_push_regs()
          __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 @@ void GC_push_regs()
          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 @@ void GC_push_regs()
          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 @@ void GC_push_regs()
            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 @@ void GC_push_regs()
          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 @@ void GC_push_regs()
          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,21 +386,19 @@ void GC_push_regs()
            extern int *__libc_stack_end;
 
            GC_push_all_stack (sp, __libc_stack_end);
+#          define HAVE_PUSH_REGS
+           /* Isn't this redundant with the code to push the stack? */
         }
 #     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)
@@ -428,8 +440,6 @@ ptr_t cold_gc_frame;
              /* 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   */
@@ -446,7 +456,7 @@ ptr_t cold_gc_frame;
 /* 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 2aae516..55eb5d5 100644 (file)
@@ -275,33 +275,72 @@ void GC_clear_roots GC_PROTO((void))
 }
 
 /* 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:                */
diff --git a/misc.c b/misc.c
index 60857f5..814fa41 100644 (file)
--- a/misc.c
+++ b/misc.c
@@ -487,6 +487,15 @@ void GC_init()
          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)
index 668cd26..e3e7e25 100644 (file)
--- a/os_dep.c
+++ b/os_dep.c
 # 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.                                                   */
@@ -272,10 +277,11 @@ char *GC_parse_map_entry(char *buf_ptr, word *start, word *end,
         return NULL;
     }
 
-    memcpy(prot_buf, buf_ptr+OFFSET_MAP_PROT, 4); // do the protections first
+    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
+    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';
@@ -864,7 +870,7 @@ ptr_t GC_get_stack_base()
          && 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 {
@@ -961,8 +967,11 @@ ptr_t GC_get_stack_base()
 
 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)
 
@@ -2007,7 +2016,6 @@ void (*GC_push_other_roots) GC_PROTO((void)) = GC_default_push_other_roots;
  *             make sure that other system calls are similarly protected
  *             or write only to the stack.
  */
 GC_bool GC_dirty_maintained = FALSE;
 
 # ifdef DEFAULT_VDB
@@ -2021,6 +2029,9 @@ GC_bool GC_dirty_maintained = FALSE;
 /* Initialize virtual dirty bit implementation.                        */
 void GC_dirty_init()
 {
+#   ifdef PRINTSTATS
+      GC_printf0("Initializing DEFAULT_VDB...\n");
+#   endif
     GC_dirty_maintained = TRUE;
 }
 
@@ -2103,7 +2114,7 @@ GC_bool is_ptrfree;
  * 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>
@@ -2122,6 +2133,23 @@ GC_bool is_ptrfree;
          
 # 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
@@ -2139,20 +2167,22 @@ GC_bool is_ptrfree;
                              &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
@@ -2166,7 +2196,8 @@ GC_bool is_ptrfree;
 
 #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
@@ -2178,7 +2209,8 @@ GC_bool is_ptrfree;
 # 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;
@@ -2212,139 +2244,14 @@ GC_bool is_ptrfree;
        return (char *)faultaddr;
     }
 #   endif /* !ALPHA */
-# endif
-
-# if defined(MACOSX) /* Should also test for PowerPC? */
-    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     */
@@ -2393,6 +2300,7 @@ SIG_PF GC_old_segv_handler;       /* Also old MSWIN32 ACCESS_VIOLATION filter */
 #endif /* !THREADS */
 
 /*ARGSUSED*/
+#if !defined(DARWIN)
 # if defined (SUNOS4) || defined(FREEBSD)
     void GC_write_fault_handler(sig, code, scp, addr)
     int sig, code;
@@ -2408,7 +2316,8 @@ SIG_PF GC_old_segv_handler;       /* Also old MSWIN32 ACCESS_VIOLATION filter */
 #     define SIG_OK (sig == SIGBUS)
 #     define CODE_OK (code == BUS_PAGE_FAULT)
 #   endif
-# endif
+# 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)
@@ -2424,7 +2333,8 @@ SIG_PF GC_old_segv_handler;       /* Also old MSWIN32 ACCESS_VIOLATION filter */
 #     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)
@@ -2444,7 +2354,8 @@ SIG_PF GC_old_segv_handler;       /* Also old MSWIN32 ACCESS_VIOLATION filter */
        /* Empirically c.trapno == 14, on IA32, but is that useful?     */
        /* 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)
@@ -2465,13 +2376,7 @@ SIG_PF GC_old_segv_handler;      /* Also old MSWIN32 ACCESS_VIOLATION filter */
 #     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)
@@ -2479,7 +2384,7 @@ SIG_PF GC_old_segv_handler;       /* Also old MSWIN32 ACCESS_VIOLATION filter */
                        STATUS_ACCESS_VIOLATION)
 #   define CODE_OK (exc_info -> ExceptionRecord -> ExceptionInformation[0] == 1)
                        /* Write fault */
-# endif
+# endif /* MSWIN32 || MSWINCE */
 {
     register unsigned i;
 #   if defined(HURD) 
@@ -2550,9 +2455,6 @@ SIG_PF GC_old_segv_handler;       /* Also old MSWIN32 ACCESS_VIOLATION filter */
 #      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]);
@@ -2616,9 +2518,6 @@ SIG_PF GC_old_segv_handler;       /* Also old MSWIN32 ACCESS_VIOLATION filter */
                    (*(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
@@ -2660,6 +2559,7 @@ SIG_PF GC_old_segv_handler;       /* Also old MSWIN32 ACCESS_VIOLATION filter */
     ABORT("Unexpected bus error or segmentation fault");
 #endif
 }
+#endif /* !DARWIN */
 
 /*
  * We hold the allocation lock.  We expect block h to be written
@@ -2692,6 +2592,7 @@ GC_bool is_ptrfree;
     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) || \
@@ -2714,13 +2615,6 @@ void GC_dirty_init()
         (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
@@ -2786,7 +2680,7 @@ void GC_dirty_init()
 #       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) {
@@ -2798,7 +2692,7 @@ void GC_dirty_init()
          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) {
@@ -2810,6 +2704,7 @@ void GC_dirty_init()
       }
 #   endif
 }
+#endif /* !DARWIN */
 
 int GC_incremental_protection_needs()
 {
@@ -3377,6 +3272,553 @@ GC_bool is_ptrfree;
 
 # 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.
+*/
+   
+/* There seem to be numerous problems with darwin's mach exception handling.
+   I'm pretty sure they are not problems in my code. Search for 
+   BROKEN_EXCEPTION_HANDLING for more information. */
+#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|
+                (GC_mprotect_state == GC_MP_DISCARDING ? MACH_RCV_TIMEOUT : 0),
+            0,
+            sizeof(msg),
+            GC_ports.exception,
+            GC_mprotect_state == GC_MP_DISCARDING ? 0 : MACH_MSG_TIMEOUT_NONE,
+            MACH_PORT_NULL);
+        
+        id = r == MACH_MSG_SUCCESS ? msg.head.msgh_id : -1;
+        
+#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,
+            code_count > 0 ? code[0] : -1,
+            code_count > 1 ? code[1] : -1); 
+        #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()
   {
@@ -3496,8 +3938,6 @@ struct callinfo info[NFRAMES];
     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
diff --git a/powerpc_darwin_mach_dep.s b/powerpc_darwin_mach_dep.s
new file mode 100644 (file)
index 0000000..92f2c93
--- /dev/null
@@ -0,0 +1,84 @@
+
+; GC_push_regs function. Under some optimization levels GCC will clobber
+; some of the non-volatile registers before we get a chance to save them
+; therefore, this can't be inline asm.
+
+.text
+       .align 2
+       .globl _GC_push_regs
+_GC_push_regs:
+    
+    ; Prolog
+       mflr r0
+       stw r0,8(r1)
+       stwu r1,-80(r1)
+
+       ; Push r13-r31
+       mr r3,r13
+       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
+
+    ; 
+    lwz r0,88(r1)
+    addi r1,r1,80
+       mtlr r0
+       
+       ; Return
+       blr
+
+; PIC stuff, generated by GCC
+
+.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
diff --git a/powerpc_macosx_mach_dep.s b/powerpc_macosx_mach_dep.s
deleted file mode 100755 (executable)
index 92f0628..0000000
+++ /dev/null
@@ -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
-       
-
-
-
diff --git a/pthread_stop_world.c b/pthread_stop_world.c
new file mode 100644 (file)
index 0000000..0a75c6c
--- /dev/null
@@ -0,0 +1,445 @@
+#include "private/pthread_support.h"
+
+#if defined(GC_PTHREADS) && !defined(GC_SOLARIS_THREADS) \
+     && !defined(GC_IRIX_THREADS) && !defined(GC_WIN32_THREADS) \
+     && !defined(GC_DARWIN_THREADS)
+
+#include <signal.h>
+#include <semaphore.h>
+#include <errno.h>
+#include <unistd.h>
+
+#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 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
+
+sem_t GC_suspend_ack_sem;
+
+void GC_suspend_handler(int sig)
+{
+    int dummy;
+    pthread_t my_thread = pthread_self();
+    GC_thread me;
+    sigset_t mask;
+#   ifdef PARALLEL_MARK
+       word my_mark_no = GC_mark_no;
+       /* Marker can't proceed until we acknowledge.  Thus this is     */
+       /* 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 -> stop_info.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 -> stop_info.stack_ptr = (ptr_t)GC_save_regs_in_stack();
+#   else
+       me -> stop_info.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.    */
+    sem_post(&GC_suspend_ack_sem);
+    me -> stop_info.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->stop_info.signal = 0;
+           sigsuspend(&mask);             /* Wait for signal */
+    } while (me->stop_info.signal != SIG_THR_RESTART);
+    /* If the RESTART signal gets lost, we can still lose.  That should be  */
+    /* less likely than losing the SUSPEND signal, since we don't do much   */
+    /* 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)
+{
+    pthread_t my_thread = pthread_self();
+    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(my_thread);
+    me->stop_info.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
+}
+
+# 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 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 -> stop_info.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
+      }
+    }
+}
+
+/* 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 -> stop_info.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:
+                    /* Not really there anymore.  Possible? */
+                    n_live_threads--;
+                    break;
+                case 0:
+                    break;
+                default:
+                    ABORT("pthread_kill failed");
+            }
+        }
+      }
+    }
+    return n_live_threads;
+}
+
+/* Caller holds allocation lock.       */
+void GC_stop_world()
+{
+    int i;
+    int n_live_threads;
+    int code;
+
+    #if DEBUG_THREADS
+    GC_printf1("Stopping the world from 0x%lx\n", pthread_self());
+    #endif
+       
+    /* 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();
+
+      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;
+         }
+      }
+    for (i = 0; i < n_live_threads; i++) {
+         if (0 != (code = sem_wait(&GC_suspend_ack_sem))) {
+             GC_err_printf1("Sem_wait returned %ld\n", (unsigned long)code);
+             ABORT("sem_wait for handler failed");
+         }
+    }
+#   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:
+                    /* Not really there anymore.  Possible? */
+                    n_live_threads--;
+                    break;
+                case 0:
+                    break;
+                default:
+                    ABORT("pthread_kill failed");
+            }
+        }
+      }
+    }
+    #if DEBUG_THREADS
+      GC_printf0("World started\n");
+    #endif
+}
+
+void GC_stop_init() {
+    struct sigaction act;
+    
+    if (sem_init(&GC_suspend_ack_sem, 0, 0) != 0)
+        ABORT("sem_init failed");
+
+    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");
+    }
+
+    /* 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
+}
+
+#endif
similarity index 70%
rename from linux_threads.c
rename to pthread_support.c
index ab5820a..a5a87ad 100644 (file)
  * + #  define GC_LOCK_TAKEN GC_allocate_lock
  */
 
-/* #define DEBUG_THREADS 1 */
+/*#define DEBUG_THREADS 1*/
+/*#define GC_ASSERTIONS*/
 
-/* ANSI C requires that a compilation unit contains something */
-
-# include "gc.h"
+# include "private/pthread_support.h"
 
 # if defined(GC_PTHREADS) && !defined(GC_SOLARIS_THREADS) \
-     && !defined(GC_IRIX_THREADS) && !defined(GC_WIN32_THREADS)
-
-# include "private/gc_priv.h"
+     && !defined(GC_IRIX_THREADS) && !defined(GC_WIN32_THREADS) \
+     && !defined(GC_AIX_THREADS)
 
 # 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)
+# if (defined(GC_DGUX386_THREADS) || defined(GC_OSF1_THREADS) || \
+      defined(GC_DARWIN_THREADS)) && !defined(USE_PTHREAD_SPECIFIC)
 #   define USE_PTHREAD_SPECIFIC
 # endif
 
 # 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)
+#if defined(GC_DARWIN_THREADS)
+# include "private/darwin_semaphore.h"
+#else
+# include <semaphore.h>
+#endif /* !GC_DARWIN_THREADS */
+
+#if defined(GC_DARWIN_THREADS)
 # include <sys/sysctl.h>
-#endif /* GC_MACOSX_THREADS */
+#endif /* GC_DARWIN_THREADS */
+
+
 
 #if defined(GC_DGUX386_THREADS)
 # include <sys/dg_sys_info.h>
 #     define REAL_FUNC(f) __d10_##f
 #   endif /* GC_DGUX386_THREADS */
 #   undef pthread_create
+#   if !defined(GC_DARWIN_THREADS)
 #   undef pthread_sigmask
+#   endif
 #   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();
@@ -366,7 +258,9 @@ GC_PTR GC_local_malloc(size_t bytes)
        int index = INDEX_FROM_BYTES(bytes);
        ptr_t * my_fl;
        ptr_t my_entry;
+#      if defined(REDIRECT_MALLOC) && !defined(USE_PTHREAD_SPECIFIC)
        GC_key_t k = GC_thread_key;
+#      endif
        void * tsd;
 
 #      if defined(REDIRECT_MALLOC) && !defined(USE_PTHREAD_SPECIFIC)
@@ -413,13 +307,14 @@ GC_PTR GC_local_malloc_atomic(size_t 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);
+        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;       */
@@ -491,40 +386,6 @@ GC_PTR GC_local_gcj_malloc(size_t bytes,
 
 # 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
@@ -539,10 +400,6 @@ 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 ...                           */
@@ -639,117 +496,6 @@ 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)
-{
-    pthread_t my_thread = pthread_self();
-    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(my_thread);
-    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     */
@@ -765,7 +511,6 @@ void GC_looping_handler(int sig)
 
 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))
@@ -920,230 +665,6 @@ void GC_remove_all_threads_but_me(void)
 }
 #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:
-                    /* Not really there anymore.  Possible? */
-                    n_live_threads--;
-                    break;
-                case 0:
-                    break;
-                default:
-                    ABORT("pthread_kill failed");
-            }
-        }
-      }
-    }
-    return n_live_threads;
-}
-
-/* Caller holds allocation lock.       */
-void GC_stop_world()
-{
-    int i;
-    int n_live_threads;
-    int code;
-
-    /* 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 for handler failed");
-#      else
-         if (0 != (code = sem_wait(&GC_suspend_ack_sem))) {
-             GC_err_printf1("Sem_wait returned %ld\n", (unsigned long)code);
-             ABORT("sem_wait for 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:
-                    /* Not really there anymore.  Possible? */
-                    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)
 {
@@ -1183,7 +704,6 @@ int GC_get_nprocs()
        /* the real one.                                                */
     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           */
@@ -1212,6 +732,7 @@ int GC_get_nprocs()
 /* 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.                                                          */
+extern GC_bool GC_collection_in_progress();
 void GC_wait_for_gc_completion(GC_bool wait_for_all)
 {
     if (GC_incremental && GC_collection_in_progress()) {
@@ -1315,45 +836,14 @@ int GC_get_nprocs()
 /* We hold the allocation lock.        */
 void GC_thr_init()
 {
-    int dummy;
+#      ifndef GC_DARWIN_THREADS
+        int dummy;
+#      endif
     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,
@@ -1361,21 +851,14 @@ void GC_thr_init()
 #   endif /* HANDLE_FORK */
     /* Add the initial thread, so we can stop it.      */
       t = GC_new_thread(pthread_self());
-      t -> stack_ptr = (ptr_t)(&dummy);
+#     ifdef GC_DARWIN_THREADS
+         t -> stop_info.mach_thread = mach_thread_self();
+#     else
+         t -> stop_info.stack_ptr = (ptr_t)(&dummy);
+#     endif
       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
+    GC_stop_init();
 
     /* Set GC_nprocs.  */
       {
@@ -1394,7 +877,7 @@ void GC_thr_init()
 #       if defined(GC_FREEBSD_THREADS)
           GC_nprocs = 1;
 #       endif
-#       if defined(GC_MACOSX_THREADS)
+#       if defined(GC_DARWIN_THREADS)
          int ncpus = 1;
          size_t len = sizeof(ncpus);
          sysctl((int[2]) {CTL_HW, HW_NCPU}, 2, &ncpus, &len, NULL, 0);
@@ -1454,7 +937,8 @@ void GC_init_parallel()
 {
     if (parallel_initialized) return;
     parallel_initialized = TRUE;
-       /* GC_init() calls us back, so set flag first.  */
+
+    /* 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
@@ -1469,6 +953,7 @@ void GC_init_parallel()
 }
 
 
+#if !defined(GC_DARWIN_THREADS)
 int WRAP_FUNC(pthread_sigmask)(int how, const sigset_t *set, sigset_t *oset)
 {
     sigset_t fudged_set;
@@ -1480,6 +965,7 @@ int WRAP_FUNC(pthread_sigmask)(int how, const sigset_t *set, sigset_t *oset)
     }
     return(REAL_FUNC(pthread_sigmask)(how, set, oset));
 }
+#endif /* !GC_DARWIN_THREADS */
 
 /* Wrappers for functions that are likely to block for an appreciable  */
 /* length of time.  Must be called in pairs, if at all.                        */
@@ -1493,25 +979,29 @@ void GC_start_blocking(void) {
     me = GC_lookup_thread(pthread_self());
     GC_ASSERT(!(me -> thread_blocked));
 #   ifdef SPARC
-       me -> stack_ptr = (ptr_t)GC_save_regs_in_stack();
+       me -> stop_info.stack_ptr = (ptr_t)GC_save_regs_in_stack();
 #   else
-       me -> stack_ptr = (ptr_t)GC_approx_sp();
+#   ifndef GC_DARWIN_THREADS
+       me -> stop_info.stack_ptr = (ptr_t)GC_approx_sp();
+#   endif
 #   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.                      */
+#   ifndef GC_DARWIN_THREADS
 #   ifdef STACK_GROWS_UP
-       me -> stack_ptr += SP_SLOP;
+       me -> stop_info.stack_ptr += SP_SLOP;
 #   else
-       me -> stack_ptr -= SP_SLOP;
+       me -> stop_info.stack_ptr -= SP_SLOP;
+#   endif
 #   endif
     me -> thread_blocked = TRUE;
     UNLOCK();
 }
 
-GC_end_blocking(void) {
+void GC_end_blocking(void) {
     GC_thread me;
     LOCK();   /* This will block if the world is stopped.      */
     me = GC_lookup_thread(pthread_self());
@@ -1539,12 +1029,8 @@ 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.                              */
@@ -1643,8 +1129,12 @@ void * GC_start_routine(void * arg)
 #   endif
     LOCK();
     me = GC_new_thread(my_pthread);
+#ifdef GC_DARWIN_THREADS
+    me -> stop_info.mach_thread = mach_thread_self();
+#else
+    me -> stop_info.stack_ptr = 0;
+#endif
     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        */
@@ -1652,12 +1142,14 @@ void * GC_start_routine(void * arg)
 #   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;
+#        ifndef GC_DARWIN_THREADS
+        me -> stop_info.stack_ptr = me -> stack_end - 0x10;
+#        endif
        /* 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;
+      me -> stop_info.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.   */
@@ -1673,11 +1165,7 @@ void * GC_start_routine(void * arg)
        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
+    sem_post(&(si -> registered));     /* Last action on si.   */
                                        /* OK to deallocate.    */
     pthread_cleanup_push(GC_thread_exit_proc, 0);
 #   if defined(THREAD_LOCAL_ALLOC) && !defined(DBG_HDRS_ALL)
@@ -1704,8 +1192,6 @@ WRAP_FUNC(pthread_create)(pthread_t *new_thread,
                   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; 
@@ -1722,11 +1208,7 @@ WRAP_FUNC(pthread_create)(pthread_t *new_thread,
     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
+    sem_init(&(si -> registered), 0, 0);
     si -> start_routine = start_routine;
     si -> arg = arg;
     LOCK();
@@ -1761,6 +1243,7 @@ WRAP_FUNC(pthread_create)(pthread_t *new_thread,
 #   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
@@ -1768,15 +1251,10 @@ WRAP_FUNC(pthread_create)(pthread_t *new_thread,
     /* 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
+    while (0 != sem_wait(&(si -> registered))) {
+        if (EINTR != errno) ABORT("sem_wait failed");
+    }
+    sem_destroy(&(si -> registered));
        LOCK();
        GC_INTERNAL_FREE(si);
        UNLOCK();
@@ -1818,7 +1296,9 @@ WRAP_FUNC(pthread_create)(pthread_t *new_thread,
 void GC_pause()
 {
     int i;
-    volatile word dummy = 0;
+#      ifndef __GNUC__
+        volatile word dummy = 0;
+#      endif
 
     for (i = 0; i < 10; ++i) { 
 #     ifdef __GNUC__
@@ -1857,6 +1337,7 @@ VOLATILE GC_bool GC_collecting = 0;
 
 void GC_generic_lock(pthread_mutex_t * lock)
 {
+#ifndef NO_PTHREAD_TRYLOCK
     unsigned pause_length = 1;
     unsigned i;
     
@@ -1874,6 +1355,7 @@ void GC_generic_lock(pthread_mutex_t * lock)
                ABORT("Unexpected error from pthread_mutex_trylock");
         }
     }
+#endif /* !NO_PTHREAD_TRYLOCK */
     pthread_mutex_lock(lock);
 }
 
@@ -1951,14 +1433,17 @@ yield:
 }
 
 #else  /* !USE_SPINLOCK */
-
 void GC_lock()
 {
+#ifndef NO_PTHREAD_TRYLOCK
     if (1 == GC_nprocs || GC_collecting) {
        pthread_mutex_lock(&GC_allocate_ml);
     } else {
         GC_generic_lock(&GC_allocate_ml);
     }
+#else  /* !NO_PTHREAD_TRYLOCK */
+    pthread_mutex_lock(&GC_allocate_ml);
+#endif /* !NO_PTHREAD_TRYLOCK */
 }
 
 #endif /* !USE_SPINLOCK */
index 43ebe8c..cfe23c0 100644 (file)
 #   include <pthread.h>
 # endif
 
-# ifdef GC_WIN32_THREADS
+# 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;
@@ -516,13 +520,6 @@ sexpr x;
     }
 }
 
-/* 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.
  */
@@ -593,6 +590,13 @@ struct {
 
 #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.
@@ -713,6 +717,8 @@ void reverse_test()
     b = c = 0;
 }
 
+#undef a
+
 /*
  * The rest of this builds balanced binary trees, checks that they don't
  * disappear, and tests finalization.
@@ -1165,6 +1171,25 @@ void fail_proc1(GC_PTR x)
     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
@@ -1278,6 +1303,21 @@ void run_one_test()
       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
@@ -1446,6 +1486,10 @@ void SetMinimumStack(long minSize)
 #   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.                              */
@@ -1459,13 +1503,18 @@ void SetMinimumStack(long minSize)
 #   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();
@@ -1745,16 +1794,30 @@ main()
           (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 daa7b07..7e50e8a 100644 (file)
@@ -192,6 +192,8 @@ int APIENTRY WinMain(
 # endif
 #endif
 
+   GC_init();
+
 #  if defined(MACOS)                        // MacOS
     char* argv_[] = {"test_cpp", "10"};     //   doesn't
     argv = argv_;                           //     have a
index 7db05f5..94ef4cd 100644 (file)
@@ -11,7 +11,7 @@ int main()
 #   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)
index 384dcbe..474efdc 100644 (file)
--- a/version.h
+++ b/version.h
@@ -3,7 +3,7 @@
 /* it to keep the old-style build process working.             */
 #define GC_TMP_VERSION_MAJOR 6
 #define GC_TMP_VERSION_MINOR 2
-#define GC_TMP_ALPHA_VERSION 5
+#define GC_TMP_ALPHA_VERSION 6
 
 #if defined(GC_VERSION_MAJOR)
 # if GC_TMP_VERSION_MAJOR != GC_VERSION_MAJOR || \
index 6e06101..a2f65a5 100755 (executable)
@@ -1,6 +1,7 @@
 #if defined(GC_WIN32_THREADS) 
 
 #include "private/gc_priv.h"
+#include <windows.h>
 
 #ifdef CYGWIN32
 # include <errno.h>
@@ -369,6 +370,8 @@ void GC_get_next_stack(char *start, char **lo, char **hi)
     if (*lo < start) *lo = start;
 }
 
+#if !defined(CYGWIN32)
+
 #if !defined(MSWINCE) && defined(GC_DLL)
 
 /* We register threads from DllMain */
@@ -511,6 +514,8 @@ static DWORD WINAPI thread_start(LPVOID arg)
 }
 #endif /* !defined(MSWINCE) && !(defined(__MINGW32__) && !defined(_DLL))  */
 
+#endif /* !CYGWIN32 */
+
 #ifdef MSWINCE
 
 typedef struct {