mirror of git://gcc.gnu.org/git/gcc.git
parent
ac42ec79e0
commit
54f28c21ee
|
@ -1,3 +1,7 @@
|
||||||
|
2006-01-24 Bryce McKinlay <mckinlay@redhat.com>
|
||||||
|
|
||||||
|
Import Boehm GC version 6.6.
|
||||||
|
|
||||||
2006-01-24 David Ayers <d.ayers@inode.at>
|
2006-01-24 David Ayers <d.ayers@inode.at>
|
||||||
|
|
||||||
PR libobjc/13946
|
PR libobjc/13946
|
||||||
|
|
|
@ -17,28 +17,27 @@ else
|
||||||
asm_libgc_sources =
|
asm_libgc_sources =
|
||||||
endif
|
endif
|
||||||
|
|
||||||
GC_SOURCES = allchblk.c alloc.c blacklst.c checksums.c dbg_mlc.c \
|
libgcjgc_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 aix_irix_threads.c \
|
dyn_load.c finalize.c gc_dlopen.c gcj_mlc.c headers.c \
|
||||||
malloc.c mallocx.c mark.c mark_rts.c misc.c new_hblk.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 \
|
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 \
|
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 \
|
pthread_support.c pthread_stop_world.c darwin_stop_world.c \
|
||||||
$(asm_libgc_sources)
|
$(asm_libgcjgc_sources)
|
||||||
|
|
||||||
|
libgcjgc_convenience_la_SOURCES = $(libgcjgc_la_SOURCES)
|
||||||
|
|
||||||
EXTRA_DIST = alpha_mach_dep.S \
|
EXTRA_DIST = alpha_mach_dep.S \
|
||||||
mips_sgi_mach_dep.s mips_ultrix_mach_dep.s powerpc_darwin_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 \
|
rs6000_mach_dep.s sparc_mach_dep.S sparc_netbsd_mach_dep.s \
|
||||||
sparc_sunos4_mach_dep.s ia64_save_regs_in_stack.s
|
sparc_sunos4_mach_dep.s ia64_save_regs_in_stack.s
|
||||||
|
|
||||||
libgcjgc_la_SOURCES = $(GC_SOURCES)
|
|
||||||
libgcjgc_convenience_la_SOURCES = $(GC_SOURCES)
|
|
||||||
|
|
||||||
# Include THREADLIBS here to ensure that the correct versions of
|
# Include THREADLIBS here to ensure that the correct versions of
|
||||||
# linuxthread semaphore functions get linked:
|
# linuxthread semaphore functions get linked:
|
||||||
libgcjgc_la_LIBADD = @addobjs@ $(THREADLIBS)
|
libgcjgc_la_LIBADD = @addobjs@ $(THREADLIBS) $(UNWINDLIBS)
|
||||||
libgcjgc_la_DEPENDENCIES = @addobjs@
|
libgcjgc_la_DEPENDENCIES = @addobjs@
|
||||||
libgcjgc_la_LDFLAGS = -version-info 1:1:0 -rpath $(toolexeclibdir)
|
libgcjgc_la_LDFLAGS = -version-info 1:2:0 -rpath $(toolexeclibdir)
|
||||||
|
|
||||||
libgcjgc_convenience_la_LIBADD = @addobjs@
|
libgcjgc_convenience_la_LIBADD = @addobjs@
|
||||||
libgcjgc_convenience_la_DEPENDENCIES = @addobjs@
|
libgcjgc_convenience_la_DEPENDENCIES = @addobjs@
|
||||||
|
@ -48,7 +47,7 @@ AM_CFLAGS = @GC_CFLAGS@
|
||||||
|
|
||||||
check_PROGRAMS = gctest
|
check_PROGRAMS = gctest
|
||||||
gctest_SOURCES = tests/test.c
|
gctest_SOURCES = tests/test.c
|
||||||
gctest_LDADD = ./libgcjgc.la $(THREADLIBS) $(EXTRA_TEST_LIBS)
|
gctest_LDADD = ./libgcjgc.la $(THREADDLLIBS) $(UNWINDLIBS) $(EXTRA_TEST_LIBS)
|
||||||
gctest_LDFLAGS = -shared-libgcc
|
gctest_LDFLAGS = -shared-libgcc
|
||||||
TESTS_ENVIRONMENT = LD_LIBRARY_PATH=../../$(MULTIBUILDTOP)gcc
|
TESTS_ENVIRONMENT = LD_LIBRARY_PATH=../../$(MULTIBUILDTOP)gcc
|
||||||
TESTS = gctest
|
TESTS = gctest
|
||||||
|
|
|
@ -36,7 +36,7 @@ CFLAGS= -O -I$(srcdir)/include -DATOMIC_UNCOLLECTABLE -DNO_SIGNALS -DNO_EXECUTE_
|
||||||
# -DGC_LINUX_THREADS -DPARALLEL_MARK -DTHREAD_LOCAL_ALLOC
|
# -DGC_LINUX_THREADS -DPARALLEL_MARK -DTHREAD_LOCAL_ALLOC
|
||||||
# To build the parallel collector in a static library on HP/UX,
|
# To build the parallel collector in a static library on HP/UX,
|
||||||
# add to the above:
|
# add to the above:
|
||||||
# -DGC_HPUX_THREADS -DPARALLEL_MARK -DTHREAD_LOCAL_ALLOC -D_POSIX_C_SOURCE=199506L
|
# -DGC_HPUX_THREADS -DPARALLEL_MARK -DTHREAD_LOCAL_ALLOC -D_POSIX_C_SOURCE=199506L -mt
|
||||||
# To build the thread-safe collector on Tru64, add to the above:
|
# To build the thread-safe collector on Tru64, add to the above:
|
||||||
# -pthread -DGC_OSF1_THREADS
|
# -pthread -DGC_OSF1_THREADS
|
||||||
|
|
||||||
|
@ -70,10 +70,11 @@ HOSTCFLAGS=$(CFLAGS)
|
||||||
# Also requires -D_REENTRANT or -D_POSIX_C_SOURCE=199506L. See README.hp.
|
# Also requires -D_REENTRANT or -D_POSIX_C_SOURCE=199506L. See README.hp.
|
||||||
# -DGC_LINUX_THREADS enables support for Xavier Leroy's Linux threads.
|
# -DGC_LINUX_THREADS enables support for Xavier Leroy's Linux threads.
|
||||||
# see README.linux. -D_REENTRANT may also be required.
|
# see README.linux. -D_REENTRANT may also be required.
|
||||||
# -DGC_OSF1_THREADS enables support for Tru64 pthreads. Untested.
|
# -DGC_OSF1_THREADS enables support for Tru64 pthreads.
|
||||||
# -DGC_FREEBSD_THREADS enables support for FreeBSD pthreads. Untested.
|
# -DGC_FREEBSD_THREADS enables support for FreeBSD pthreads.
|
||||||
# Appeared to run into some underlying thread problems.
|
# Appeared to run into some underlying thread problems.
|
||||||
# -DGC_DARWIN_THREADS enables support for Mac OS X pthreads. Untested.
|
# -DGC_DARWIN_THREADS enables support for Mac OS X pthreads.
|
||||||
|
# -DGC_AIX_THREADS enables support for IBM AIX threads.
|
||||||
# -DGC_DGUX386_THREADS enables support for DB/UX on I386 threads.
|
# -DGC_DGUX386_THREADS enables support for DB/UX on I386 threads.
|
||||||
# See README.DGUX386.
|
# See README.DGUX386.
|
||||||
# -DGC_WIN32_THREADS enables support for win32 threads. That makes sense
|
# -DGC_WIN32_THREADS enables support for win32 threads. That makes sense
|
||||||
|
@ -233,8 +234,8 @@ HOSTCFLAGS=$(CFLAGS)
|
||||||
# -DTHREAD_LOCAL_ALLOC defines GC_local_malloc(), GC_local_malloc_atomic()
|
# -DTHREAD_LOCAL_ALLOC defines GC_local_malloc(), GC_local_malloc_atomic()
|
||||||
# and GC_local_gcj_malloc(). Needed for gc_gcj.h interface. These allocate
|
# and GC_local_gcj_malloc(). Needed for gc_gcj.h interface. These allocate
|
||||||
# in a way that usually does not involve acquisition of a global lock.
|
# in a way that usually does not involve acquisition of a global lock.
|
||||||
# Currently requires -DGC_LINUX_THREADS, but should be easy to port to
|
# Currently works only on platforms such as Linux which use pthread_support.c.
|
||||||
# other pthreads environments. Recommended for multiprocessors.
|
# Recommended for multiprocessors.
|
||||||
# -DUSE_COMPILER_TLS causes thread local allocation to use compiler-supported
|
# -DUSE_COMPILER_TLS causes thread local allocation to use compiler-supported
|
||||||
# "__thread" thread-local variables. This is the default in HP/UX. It
|
# "__thread" thread-local variables. This is the default in HP/UX. It
|
||||||
# may help performance on recent Linux installations. (It failed for
|
# may help performance on recent Linux installations. (It failed for
|
||||||
|
@ -276,6 +277,10 @@ HOSTCFLAGS=$(CFLAGS)
|
||||||
# -DPOINTER_SHIFT=n causes the collector to left shift candidate pointers
|
# -DPOINTER_SHIFT=n causes the collector to left shift candidate pointers
|
||||||
# by the indicated amount before trying to interpret them. Applied
|
# by the indicated amount before trying to interpret them. Applied
|
||||||
# after POINTER_MASK. EXPERIMENTAL. See also the preceding macro.
|
# after POINTER_MASK. EXPERIMENTAL. See also the preceding macro.
|
||||||
|
# -DDARWIN_DONT_PARSE_STACK Causes the Darwin port to discover thread
|
||||||
|
# stack bounds in the same way as other pthread ports, without trying to
|
||||||
|
# walk the frames onthe stack. This is recommended only as a fallback
|
||||||
|
# for applications that don't support proper stack unwinding.
|
||||||
#
|
#
|
||||||
|
|
||||||
CXXFLAGS= $(CFLAGS)
|
CXXFLAGS= $(CFLAGS)
|
||||||
|
@ -283,9 +288,9 @@ AR= ar
|
||||||
RANLIB= ranlib
|
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 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
|
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 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 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
|
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 pthread_support.c pthread_stop_world.c darwin_stop_world.c typd_mlc.c ptr_chck.c mallocx.c solaris_pthreads.c gcj_mlc.c specific.c gc_dlopen.c backgraph.c win32_threads.c
|
||||||
|
|
||||||
CORD_SRCS= cord/cordbscs.c cord/cordxtra.c cord/cordprnt.c cord/de.c cord/cordtest.c include/cord.h include/ec.h include/private/cord_pos.h cord/de_win.c cord/de_win.h cord/de_cmds.h cord/de_win.ICO cord/de_win.RC
|
CORD_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
|
||||||
|
|
||||||
|
|
|
@ -65,12 +65,13 @@ DIST_COMMON = $(srcdir)/../config.guess $(srcdir)/../config.sub \
|
||||||
$(srcdir)/../compile $(srcdir)/../compile $(srcdir)/../compile \
|
$(srcdir)/../compile $(srcdir)/../compile $(srcdir)/../compile \
|
||||||
$(srcdir)/../compile $(srcdir)/../compile $(srcdir)/../compile \
|
$(srcdir)/../compile $(srcdir)/../compile $(srcdir)/../compile \
|
||||||
$(srcdir)/../compile $(srcdir)/../compile $(srcdir)/../compile \
|
$(srcdir)/../compile $(srcdir)/../compile $(srcdir)/../compile \
|
||||||
$(srcdir)/../compile $(srcdir)/../compile $(srcdir)/../compile \
|
$(srcdir)/../compile $(srcdir)/../ltmain.sh \
|
||||||
$(srcdir)/../ltmain.sh $(srcdir)/../config.guess \
|
$(srcdir)/../config.guess $(srcdir)/../config.sub
|
||||||
$(srcdir)/../config.sub
|
|
||||||
subdir = .
|
subdir = .
|
||||||
ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
|
ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
|
||||||
am__aclocal_m4_deps = $(top_srcdir)/../config/acx.m4 \
|
am__aclocal_m4_deps = $(top_srcdir)/../config/acx.m4 \
|
||||||
|
$(top_srcdir)/../config/depstand.m4 \
|
||||||
|
$(top_srcdir)/../config/lead-dot.m4 \
|
||||||
$(top_srcdir)/../config/no-executables.m4 \
|
$(top_srcdir)/../config/no-executables.m4 \
|
||||||
$(top_srcdir)/../libtool.m4 $(top_srcdir)/configure.ac
|
$(top_srcdir)/../libtool.m4 $(top_srcdir)/configure.ac
|
||||||
am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
|
am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
|
||||||
|
@ -82,34 +83,36 @@ CONFIG_HEADER = $(top_builddir)/include/gc_config.h \
|
||||||
CONFIG_CLEAN_FILES =
|
CONFIG_CLEAN_FILES =
|
||||||
LTLIBRARIES = $(noinst_LTLIBRARIES)
|
LTLIBRARIES = $(noinst_LTLIBRARIES)
|
||||||
am__DEPENDENCIES_1 =
|
am__DEPENDENCIES_1 =
|
||||||
@POWERPC_DARWIN_TRUE@am__objects_1 = powerpc_darwin_mach_dep.lo
|
am_libgcjgc_la_OBJECTS = allchblk.lo alloc.lo blacklst.lo checksums.lo \
|
||||||
am__objects_2 = allchblk.lo alloc.lo blacklst.lo checksums.lo \
|
|
||||||
dbg_mlc.lo dyn_load.lo finalize.lo gc_dlopen.lo gcj_mlc.lo \
|
dbg_mlc.lo dyn_load.lo finalize.lo gc_dlopen.lo gcj_mlc.lo \
|
||||||
headers.lo aix_irix_threads.lo malloc.lo mallocx.lo mark.lo \
|
headers.lo malloc.lo mallocx.lo mark.lo mark_rts.lo misc.lo \
|
||||||
mark_rts.lo misc.lo new_hblk.lo obj_map.lo os_dep.lo \
|
new_hblk.lo obj_map.lo os_dep.lo pcr_interface.lo ptr_chck.lo \
|
||||||
pcr_interface.lo ptr_chck.lo real_malloc.lo reclaim.lo \
|
real_malloc.lo reclaim.lo solaris_pthreads.lo \
|
||||||
solaris_pthreads.lo solaris_threads.lo specific.lo stubborn.lo \
|
solaris_threads.lo specific.lo stubborn.lo typd_mlc.lo \
|
||||||
typd_mlc.lo backgraph.lo win32_threads.lo pthread_support.lo \
|
backgraph.lo win32_threads.lo pthread_support.lo \
|
||||||
pthread_stop_world.lo darwin_stop_world.lo $(am__objects_1)
|
pthread_stop_world.lo darwin_stop_world.lo
|
||||||
am_libgcjgc_la_OBJECTS = $(am__objects_2)
|
|
||||||
libgcjgc_la_OBJECTS = $(am_libgcjgc_la_OBJECTS)
|
libgcjgc_la_OBJECTS = $(am_libgcjgc_la_OBJECTS)
|
||||||
am_libgcjgc_convenience_la_OBJECTS = $(am__objects_2)
|
am__objects_1 = allchblk.lo alloc.lo blacklst.lo checksums.lo \
|
||||||
|
dbg_mlc.lo dyn_load.lo finalize.lo gc_dlopen.lo gcj_mlc.lo \
|
||||||
|
headers.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_libgcjgc_convenience_la_OBJECTS = $(am__objects_1)
|
||||||
libgcjgc_convenience_la_OBJECTS = \
|
libgcjgc_convenience_la_OBJECTS = \
|
||||||
$(am_libgcjgc_convenience_la_OBJECTS)
|
$(am_libgcjgc_convenience_la_OBJECTS)
|
||||||
am__dirstamp = $(am__leading_dot)dirstamp
|
am__dirstamp = $(am__leading_dot)dirstamp
|
||||||
am_gctest_OBJECTS = tests/test.$(OBJEXT)
|
am_gctest_OBJECTS = tests/test.$(OBJEXT)
|
||||||
gctest_OBJECTS = $(am_gctest_OBJECTS)
|
gctest_OBJECTS = $(am_gctest_OBJECTS)
|
||||||
gctest_DEPENDENCIES = ./libgcjgc.la $(am__DEPENDENCIES_1) \
|
gctest_DEPENDENCIES = ./libgcjgc.la $(am__DEPENDENCIES_1)
|
||||||
$(am__DEPENDENCIES_1)
|
|
||||||
DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir)/include -I$(top_builddir)/include
|
DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir)/include -I$(top_builddir)/include
|
||||||
depcomp =
|
depcomp =
|
||||||
am__depfiles_maybe =
|
am__depfiles_maybe =
|
||||||
COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
|
COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
|
||||||
$(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
|
$(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
|
||||||
CCLD = $(CC)
|
CCLD = $(CC)
|
||||||
CCASCOMPILE = $(CCAS) $(AM_CCASFLAGS) $(CCASFLAGS)
|
|
||||||
LTCCASCOMPILE = $(LIBTOOL) --mode=compile $(CCAS) $(AM_CCASFLAGS) \
|
|
||||||
$(CCASFLAGS)
|
|
||||||
SOURCES = $(libgcjgc_la_SOURCES) $(libgcjgc_convenience_la_SOURCES) \
|
SOURCES = $(libgcjgc_la_SOURCES) $(libgcjgc_convenience_la_SOURCES) \
|
||||||
$(gctest_SOURCES)
|
$(gctest_SOURCES)
|
||||||
MULTISRCTOP =
|
MULTISRCTOP =
|
||||||
|
@ -254,34 +257,33 @@ SUBDIRS = include
|
||||||
noinst_LTLIBRARIES = libgcjgc.la libgcjgc_convenience.la
|
noinst_LTLIBRARIES = libgcjgc.la libgcjgc_convenience.la
|
||||||
@POWERPC_DARWIN_FALSE@asm_libgc_sources =
|
@POWERPC_DARWIN_FALSE@asm_libgc_sources =
|
||||||
@POWERPC_DARWIN_TRUE@asm_libgc_sources = powerpc_darwin_mach_dep.s
|
@POWERPC_DARWIN_TRUE@asm_libgc_sources = powerpc_darwin_mach_dep.s
|
||||||
GC_SOURCES = allchblk.c alloc.c blacklst.c checksums.c dbg_mlc.c \
|
libgcjgc_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 aix_irix_threads.c \
|
dyn_load.c finalize.c gc_dlopen.c gcj_mlc.c headers.c \
|
||||||
malloc.c mallocx.c mark.c mark_rts.c misc.c new_hblk.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 \
|
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 \
|
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 \
|
pthread_support.c pthread_stop_world.c darwin_stop_world.c \
|
||||||
$(asm_libgc_sources)
|
$(asm_libgcjgc_sources)
|
||||||
|
|
||||||
|
libgcjgc_convenience_la_SOURCES = $(libgcjgc_la_SOURCES)
|
||||||
EXTRA_DIST = alpha_mach_dep.S \
|
EXTRA_DIST = alpha_mach_dep.S \
|
||||||
mips_sgi_mach_dep.s mips_ultrix_mach_dep.s powerpc_darwin_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 \
|
rs6000_mach_dep.s sparc_mach_dep.S sparc_netbsd_mach_dep.s \
|
||||||
sparc_sunos4_mach_dep.s ia64_save_regs_in_stack.s
|
sparc_sunos4_mach_dep.s ia64_save_regs_in_stack.s
|
||||||
|
|
||||||
libgcjgc_la_SOURCES = $(GC_SOURCES)
|
|
||||||
libgcjgc_convenience_la_SOURCES = $(GC_SOURCES)
|
|
||||||
|
|
||||||
# Include THREADLIBS here to ensure that the correct versions of
|
# Include THREADLIBS here to ensure that the correct versions of
|
||||||
# linuxthread semaphore functions get linked:
|
# linuxthread semaphore functions get linked:
|
||||||
libgcjgc_la_LIBADD = @addobjs@ $(THREADLIBS)
|
libgcjgc_la_LIBADD = @addobjs@ $(THREADLIBS) $(UNWINDLIBS)
|
||||||
libgcjgc_la_DEPENDENCIES = @addobjs@
|
libgcjgc_la_DEPENDENCIES = @addobjs@
|
||||||
libgcjgc_la_LDFLAGS = -version-info 1:1:0 -rpath $(toolexeclibdir)
|
libgcjgc_la_LDFLAGS = -version-info 1:2:0 -rpath $(toolexeclibdir)
|
||||||
libgcjgc_convenience_la_LIBADD = @addobjs@
|
libgcjgc_convenience_la_LIBADD = @addobjs@
|
||||||
libgcjgc_convenience_la_DEPENDENCIES = @addobjs@
|
libgcjgc_convenience_la_DEPENDENCIES = @addobjs@
|
||||||
AM_CXXFLAGS = @GC_CFLAGS@
|
AM_CXXFLAGS = @GC_CFLAGS@
|
||||||
AM_CFLAGS = @GC_CFLAGS@
|
AM_CFLAGS = @GC_CFLAGS@
|
||||||
gctest_SOURCES = tests/test.c
|
gctest_SOURCES = tests/test.c
|
||||||
gctest_LDADD = ./libgcjgc.la $(THREADLIBS) $(EXTRA_TEST_LIBS)
|
gctest_LDADD = ./libgcjgc.la $(THREADDLLIBS) $(UNWINDLIBS) $(EXTRA_TEST_LIBS)
|
||||||
gctest_LDFLAGS = -shared-libgcc
|
gctest_LDFLAGS = -shared-libgcc
|
||||||
TESTS_ENVIRONMENT = LD_LIBRARY_PATH=../../$(MULTIBUILDTOP)gcc
|
TESTS_ENVIRONMENT = LD_LIBRARY_PATH=../../$(MULTIBUILDTOP)gcc
|
||||||
TESTS = gctest
|
TESTS = gctest
|
||||||
|
@ -414,12 +416,6 @@ distclean-compile:
|
||||||
.c.lo:
|
.c.lo:
|
||||||
$(LTCOMPILE) -c -o $@ $<
|
$(LTCOMPILE) -c -o $@ $<
|
||||||
|
|
||||||
.s.o:
|
|
||||||
$(CCASCOMPILE) -c $<
|
|
||||||
|
|
||||||
.s.obj:
|
|
||||||
$(CCASCOMPILE) -c `$(CYGPATH_W) '$<'`
|
|
||||||
|
|
||||||
mostlyclean-libtool:
|
mostlyclean-libtool:
|
||||||
-rm -f *.lo
|
-rm -f *.lo
|
||||||
|
|
||||||
|
|
|
@ -547,39 +547,6 @@ AC_DEFUN([AM_PROG_INSTALL_SH],
|
||||||
install_sh=${install_sh-"$am_aux_dir/install-sh"}
|
install_sh=${install_sh-"$am_aux_dir/install-sh"}
|
||||||
AC_SUBST(install_sh)])
|
AC_SUBST(install_sh)])
|
||||||
|
|
||||||
# -*- Autoconf -*-
|
|
||||||
# Copyright (C) 2003 Free Software Foundation, Inc.
|
|
||||||
|
|
||||||
# This program is free software; you can redistribute it and/or modify
|
|
||||||
# it under the terms of the GNU General Public License as published by
|
|
||||||
# the Free Software Foundation; either version 2, or (at your option)
|
|
||||||
# any later version.
|
|
||||||
|
|
||||||
# This program is distributed in the hope that it will be useful,
|
|
||||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
# GNU General Public License for more details.
|
|
||||||
|
|
||||||
# You should have received a copy of the GNU General Public License
|
|
||||||
# along with this program; if not, write to the Free Software
|
|
||||||
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
|
||||||
# 02111-1307, USA.
|
|
||||||
|
|
||||||
# serial 1
|
|
||||||
|
|
||||||
# Check whether the underlying file-system supports filenames
|
|
||||||
# with a leading dot. For instance MS-DOS doesn't.
|
|
||||||
AC_DEFUN([AM_SET_LEADING_DOT],
|
|
||||||
[rm -rf .tst 2>/dev/null
|
|
||||||
mkdir .tst 2>/dev/null
|
|
||||||
if test -d .tst; then
|
|
||||||
am__leading_dot=.
|
|
||||||
else
|
|
||||||
am__leading_dot=_
|
|
||||||
fi
|
|
||||||
rmdir .tst 2>/dev/null
|
|
||||||
AC_SUBST([am__leading_dot])])
|
|
||||||
|
|
||||||
# Add --enable-maintainer-mode option to configure.
|
# Add --enable-maintainer-mode option to configure.
|
||||||
# From Jim Meyering
|
# From Jim Meyering
|
||||||
|
|
||||||
|
@ -1168,5 +1135,7 @@ AC_SUBST([am__untar])
|
||||||
]) # _AM_PROG_TAR
|
]) # _AM_PROG_TAR
|
||||||
|
|
||||||
m4_include([../config/acx.m4])
|
m4_include([../config/acx.m4])
|
||||||
|
m4_include([../config/depstand.m4])
|
||||||
|
m4_include([../config/lead-dot.m4])
|
||||||
m4_include([../config/no-executables.m4])
|
m4_include([../config/no-executables.m4])
|
||||||
m4_include([../libtool.m4])
|
m4_include([../libtool.m4])
|
||||||
|
|
|
@ -1,689 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 1991-1995 by Xerox Corporation. All rights reserved.
|
|
||||||
* Copyright (c) 1996-1999 by Silicon Graphics. All rights reserved.
|
|
||||||
* Copyright (c) 1999-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.
|
|
||||||
*
|
|
||||||
* Permission is hereby granted to use or copy this program
|
|
||||||
* for any purpose, provided the above notices are retained on all copies.
|
|
||||||
* Permission to modify the code and to distribute modified code is granted,
|
|
||||||
* provided the above notices are retained, and a notice that the code was
|
|
||||||
* modified is included with the above copyright notice.
|
|
||||||
*/
|
|
||||||
/*
|
|
||||||
* Support code for Irix (>=6.2) Pthreads and for AIX pthreads.
|
|
||||||
* This relies on properties
|
|
||||||
* not guaranteed by the Pthread standard. It may or may not be portable
|
|
||||||
* to other implementations.
|
|
||||||
*
|
|
||||||
* 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.
|
|
||||||
*
|
|
||||||
* Please avoid adding new ports here; use the generic pthread support
|
|
||||||
* as a base instead.
|
|
||||||
*/
|
|
||||||
|
|
||||||
# include "private/gc_priv.h"
|
|
||||||
|
|
||||||
# if defined(GC_IRIX_THREADS) || defined(GC_AIX_THREADS)
|
|
||||||
|
|
||||||
# include <pthread.h>
|
|
||||||
# include <assert.h>
|
|
||||||
# include <semaphore.h>
|
|
||||||
# include <time.h>
|
|
||||||
# include <errno.h>
|
|
||||||
# include <unistd.h>
|
|
||||||
# include <sys/mman.h>
|
|
||||||
# include <sys/time.h>
|
|
||||||
|
|
||||||
#undef pthread_create
|
|
||||||
#undef pthread_sigmask
|
|
||||||
#undef pthread_join
|
|
||||||
|
|
||||||
#if defined(GC_IRIX_THREADS) && !defined(MUTEX_RECURSIVE_NP)
|
|
||||||
#define MUTEX_RECURSIVE_NP PTHREAD_MUTEX_RECURSIVE
|
|
||||||
#endif
|
|
||||||
|
|
||||||
void GC_thr_init();
|
|
||||||
|
|
||||||
#if 0
|
|
||||||
void GC_print_sig_mask()
|
|
||||||
{
|
|
||||||
sigset_t blocked;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
if (pthread_sigmask(SIG_BLOCK, NULL, &blocked) != 0)
|
|
||||||
ABORT("pthread_sigmask");
|
|
||||||
GC_printf0("Blocked: ");
|
|
||||||
for (i = 1; i <= MAXSIG; i++) {
|
|
||||||
if (sigismember(&blocked, i)) { GC_printf1("%ld ",(long) i); }
|
|
||||||
}
|
|
||||||
GC_printf0("\n");
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* We use the allocation lock to protect thread-related data structures. */
|
|
||||||
|
|
||||||
/* The set of all known threads. We intercept thread creation and */
|
|
||||||
/* joins. We never actually create detached threads. We allocate all */
|
|
||||||
/* new thread stacks ourselves. These allow us to maintain this */
|
|
||||||
/* data structure. */
|
|
||||||
/* Protected by GC_thr_lock. */
|
|
||||||
/* Some of this should be declared volatile, but that's incosnsistent */
|
|
||||||
/* with some library routine declarations. */
|
|
||||||
typedef struct GC_Thread_Rep {
|
|
||||||
struct GC_Thread_Rep * next; /* More recently allocated threads */
|
|
||||||
/* with a given pthread id come */
|
|
||||||
/* first. (All but the first are */
|
|
||||||
/* guaranteed to be dead, but we may */
|
|
||||||
/* not yet have registered the join.) */
|
|
||||||
pthread_t id;
|
|
||||||
word stop;
|
|
||||||
# define NOT_STOPPED 0
|
|
||||||
# define PLEASE_STOP 1
|
|
||||||
# define STOPPED 2
|
|
||||||
word flags;
|
|
||||||
# define FINISHED 1 /* Thread has exited. */
|
|
||||||
# define DETACHED 2 /* Thread is intended to be detached. */
|
|
||||||
ptr_t stack_cold; /* cold end of the stack */
|
|
||||||
ptr_t stack_hot; /* Valid only when stopped. */
|
|
||||||
/* But must be within stack region at */
|
|
||||||
/* all times. */
|
|
||||||
void * status; /* Used only to avoid premature */
|
|
||||||
/* reclamation of any data it might */
|
|
||||||
/* reference. */
|
|
||||||
} * GC_thread;
|
|
||||||
|
|
||||||
GC_thread GC_lookup_thread(pthread_t id);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* The only way to suspend threads given the pthread interface is to send
|
|
||||||
* signals. Unfortunately, this means we have to reserve
|
|
||||||
* a signal, and intercept client calls to change the signal mask.
|
|
||||||
*/
|
|
||||||
#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 */
|
|
||||||
pthread_cond_t GC_suspend_ack_cv = PTHREAD_COND_INITIALIZER;
|
|
||||||
pthread_cond_t GC_continue_cv = PTHREAD_COND_INITIALIZER;
|
|
||||||
|
|
||||||
void GC_suspend_handler(int sig)
|
|
||||||
{
|
|
||||||
int dummy;
|
|
||||||
GC_thread me;
|
|
||||||
sigset_t all_sigs;
|
|
||||||
sigset_t old_sigs;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
if (sig != SIG_SUSPEND) ABORT("Bad signal in suspend_handler");
|
|
||||||
me = GC_lookup_thread(pthread_self());
|
|
||||||
/* The lookup here is safe, since I'm doing this on behalf */
|
|
||||||
/* of a thread which holds the allocation lock in order */
|
|
||||||
/* to stop the world. Thus concurrent modification of the */
|
|
||||||
/* data structure is impossible. */
|
|
||||||
if (PLEASE_STOP != me -> stop) {
|
|
||||||
/* Misdirected signal. */
|
|
||||||
pthread_mutex_unlock(&GC_suspend_lock);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
pthread_mutex_lock(&GC_suspend_lock);
|
|
||||||
me -> stack_hot = (ptr_t)(&dummy);
|
|
||||||
me -> stop = STOPPED;
|
|
||||||
pthread_cond_signal(&GC_suspend_ack_cv);
|
|
||||||
pthread_cond_wait(&GC_continue_cv, &GC_suspend_lock);
|
|
||||||
pthread_mutex_unlock(&GC_suspend_lock);
|
|
||||||
/* GC_printf1("Continuing 0x%x\n", pthread_self()); */
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
GC_bool GC_thr_initialized = FALSE;
|
|
||||||
|
|
||||||
|
|
||||||
# define THREAD_TABLE_SZ 128 /* Must be power of 2 */
|
|
||||||
volatile GC_thread GC_threads[THREAD_TABLE_SZ];
|
|
||||||
|
|
||||||
void GC_push_thread_structures GC_PROTO((void))
|
|
||||||
{
|
|
||||||
GC_push_all((ptr_t)(GC_threads), (ptr_t)(GC_threads)+sizeof(GC_threads));
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Add a thread to GC_threads. We assume it wasn't already there. */
|
|
||||||
/* Caller holds allocation lock. */
|
|
||||||
GC_thread GC_new_thread(pthread_t id)
|
|
||||||
{
|
|
||||||
int hv = ((word)id) % THREAD_TABLE_SZ;
|
|
||||||
GC_thread result;
|
|
||||||
static struct GC_Thread_Rep first_thread;
|
|
||||||
static GC_bool first_thread_used = FALSE;
|
|
||||||
|
|
||||||
GC_ASSERT(I_HOLD_LOCK());
|
|
||||||
if (!first_thread_used) {
|
|
||||||
result = &first_thread;
|
|
||||||
first_thread_used = TRUE;
|
|
||||||
/* Dont acquire allocation lock, since we may already hold it. */
|
|
||||||
} else {
|
|
||||||
result = (struct GC_Thread_Rep *)
|
|
||||||
GC_generic_malloc_inner(sizeof(struct GC_Thread_Rep), NORMAL);
|
|
||||||
}
|
|
||||||
if (result == 0) return(0);
|
|
||||||
result -> id = id;
|
|
||||||
result -> next = GC_threads[hv];
|
|
||||||
GC_threads[hv] = result;
|
|
||||||
/* result -> flags = 0; */
|
|
||||||
/* result -> stop = 0; */
|
|
||||||
return(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Delete a thread from GC_threads. We assume it is there. */
|
|
||||||
/* (The code intentionally traps if it wasn't.) */
|
|
||||||
/* Caller holds allocation lock. */
|
|
||||||
/* We explicitly pass in the GC_thread we're looking for, since */
|
|
||||||
/* if a thread has been joined, but we have not yet */
|
|
||||||
/* been notified, then there may be more than one thread */
|
|
||||||
/* in the table with the same pthread id. */
|
|
||||||
/* This is OK, but we need a way to delete a specific one. */
|
|
||||||
void GC_delete_gc_thread(pthread_t id, GC_thread gc_id)
|
|
||||||
{
|
|
||||||
int hv = ((word)id) % THREAD_TABLE_SZ;
|
|
||||||
register GC_thread p = GC_threads[hv];
|
|
||||||
register GC_thread prev = 0;
|
|
||||||
|
|
||||||
GC_ASSERT(I_HOLD_LOCK());
|
|
||||||
while (p != gc_id) {
|
|
||||||
prev = p;
|
|
||||||
p = p -> next;
|
|
||||||
}
|
|
||||||
if (prev == 0) {
|
|
||||||
GC_threads[hv] = p -> next;
|
|
||||||
} else {
|
|
||||||
prev -> next = p -> next;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Return a GC_thread corresponding to a given thread_t. */
|
|
||||||
/* Returns 0 if it's not there. */
|
|
||||||
/* Caller holds allocation lock or otherwise inhibits */
|
|
||||||
/* updates. */
|
|
||||||
/* If there is more than one thread with the given id we */
|
|
||||||
/* return the most recent one. */
|
|
||||||
GC_thread GC_lookup_thread(pthread_t id)
|
|
||||||
{
|
|
||||||
int hv = ((word)id) % THREAD_TABLE_SZ;
|
|
||||||
register GC_thread p = GC_threads[hv];
|
|
||||||
|
|
||||||
/* I either hold the lock, or i'm being called from the stop-the-world
|
|
||||||
* handler. */
|
|
||||||
#if defined(GC_AIX_THREADS)
|
|
||||||
GC_ASSERT(I_HOLD_LOCK()); /* no stop-the-world handler needed on AIX */
|
|
||||||
#endif
|
|
||||||
while (p != 0 && !pthread_equal(p -> id, id)) p = p -> next;
|
|
||||||
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;
|
|
||||||
|
|
||||||
GC_ASSERT(I_HOLD_LOCK());
|
|
||||||
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"); */
|
|
||||||
GC_ASSERT(I_HOLD_LOCK());
|
|
||||||
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()
|
|
||||||
{
|
|
||||||
pthread_t my_thread = pthread_self();
|
|
||||||
register int i;
|
|
||||||
register GC_thread p;
|
|
||||||
register int result;
|
|
||||||
struct timespec timeout;
|
|
||||||
|
|
||||||
GC_ASSERT(I_HOLD_LOCK());
|
|
||||||
for (i = 0; i < THREAD_TABLE_SZ; i++) {
|
|
||||||
for (p = GC_threads[i]; p != 0; p = p -> next) {
|
|
||||||
if (p -> id != my_thread) {
|
|
||||||
if (p -> flags & FINISHED) {
|
|
||||||
p -> stop = STOPPED;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
p -> stop = PLEASE_STOP;
|
|
||||||
result = pthread_kill(p -> id, SIG_SUSPEND);
|
|
||||||
/* GC_printf1("Sent signal to 0x%x\n", p -> id); */
|
|
||||||
switch(result) {
|
|
||||||
case ESRCH:
|
|
||||||
/* Not really there anymore. Possible? */
|
|
||||||
p -> stop = STOPPED;
|
|
||||||
break;
|
|
||||||
case 0:
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
ABORT("pthread_kill failed");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pthread_mutex_lock(&GC_suspend_lock);
|
|
||||||
for (i = 0; i < THREAD_TABLE_SZ; i++) {
|
|
||||||
for (p = GC_threads[i]; p != 0; p = p -> next) {
|
|
||||||
while (p -> id != my_thread && p -> stop != STOPPED) {
|
|
||||||
clock_gettime(CLOCK_REALTIME, &timeout);
|
|
||||||
timeout.tv_nsec += 50000000; /* 50 msecs */
|
|
||||||
if (timeout.tv_nsec >= 1000000000) {
|
|
||||||
timeout.tv_nsec -= 1000000000;
|
|
||||||
++timeout.tv_sec;
|
|
||||||
}
|
|
||||||
result = pthread_cond_timedwait(&GC_suspend_ack_cv,
|
|
||||||
&GC_suspend_lock,
|
|
||||||
&timeout);
|
|
||||||
if (result == ETIMEDOUT) {
|
|
||||||
/* Signal was lost or misdirected. Try again. */
|
|
||||||
/* Duplicate signals should be benign. */
|
|
||||||
result = pthread_kill(p -> id, SIG_SUSPEND);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pthread_mutex_unlock(&GC_suspend_lock);
|
|
||||||
/* GC_printf1("World stopped 0x%x\n", pthread_self()); */
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Caller holds allocation lock. */
|
|
||||||
void GC_start_world()
|
|
||||||
{
|
|
||||||
GC_thread p;
|
|
||||||
unsigned i;
|
|
||||||
|
|
||||||
/* GC_printf0("World starting\n"); */
|
|
||||||
GC_ASSERT(I_HOLD_LOCK());
|
|
||||||
for (i = 0; i < THREAD_TABLE_SZ; i++) {
|
|
||||||
for (p = GC_threads[i]; p != 0; p = p -> next) {
|
|
||||||
p -> stop = NOT_STOPPED;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pthread_mutex_lock(&GC_suspend_lock);
|
|
||||||
/* All other threads are at pthread_cond_wait in signal handler. */
|
|
||||||
/* Otherwise we couldn't have acquired the lock. */
|
|
||||||
pthread_mutex_unlock(&GC_suspend_lock);
|
|
||||||
pthread_cond_broadcast(&GC_continue_cv);
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif /* GC_AIX_THREADS */
|
|
||||||
|
|
||||||
|
|
||||||
/* We hold allocation lock. Should do exactly the right thing if the */
|
|
||||||
/* world is stopped. Should not fail if it isn't. */
|
|
||||||
void GC_push_all_stacks()
|
|
||||||
{
|
|
||||||
register int i;
|
|
||||||
register GC_thread p;
|
|
||||||
register ptr_t hot, cold;
|
|
||||||
pthread_t me = pthread_self();
|
|
||||||
|
|
||||||
/* GC_init() should have been called before GC_push_all_stacks is
|
|
||||||
* invoked, and GC_init calls GC_thr_init(), which sets
|
|
||||||
* GC_thr_initialized. */
|
|
||||||
GC_ASSERT(GC_thr_initialized);
|
|
||||||
|
|
||||||
/* GC_printf1("Pushing stacks from thread 0x%x\n", me); */
|
|
||||||
GC_ASSERT(I_HOLD_LOCK());
|
|
||||||
for (i = 0; i < THREAD_TABLE_SZ; i++) {
|
|
||||||
for (p = GC_threads[i]; p != 0; p = p -> next) {
|
|
||||||
if (p -> flags & FINISHED) continue;
|
|
||||||
cold = p->stack_cold;
|
|
||||||
if (!cold) cold=GC_stackbottom; /* 0 indicates 'original stack' */
|
|
||||||
if (pthread_equal(p -> id, me)) {
|
|
||||||
hot = GC_approx_sp();
|
|
||||||
} else {
|
|
||||||
# ifdef GC_AIX_THREADS
|
|
||||||
/* AIX doesn't use signals to suspend, so we need to get an */
|
|
||||||
/* accurate hot stack pointer. */
|
|
||||||
/* See http://publib16.boulder.ibm.com/pseries/en_US/libs/basetrf1/pthread_getthrds_np.htm */
|
|
||||||
pthread_t id = p -> id;
|
|
||||||
struct __pthrdsinfo pinfo;
|
|
||||||
int regbuf[64];
|
|
||||||
int val = sizeof(regbuf);
|
|
||||||
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();
|
|
||||||
}
|
|
||||||
/* according to the AIX ABI,
|
|
||||||
"the lowest possible valid stack address is 288 bytes (144 + 144)
|
|
||||||
less than the current value of the stack pointer. Functions may
|
|
||||||
use this stack space as volatile storage which is not preserved
|
|
||||||
across function calls."
|
|
||||||
ftp://ftp.penguinppc64.org/pub/people/amodra/PPC-elf64abi.txt.gz
|
|
||||||
*/
|
|
||||||
hot = (ptr_t)(unsigned long)pinfo.__pi_ustk-288;
|
|
||||||
cold = (ptr_t)pinfo.__pi_stackend; /* more precise */
|
|
||||||
/* 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_hot;
|
|
||||||
# endif
|
|
||||||
}
|
|
||||||
# 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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* We hold the allocation lock. */
|
|
||||||
void GC_thr_init()
|
|
||||||
{
|
|
||||||
GC_thread t;
|
|
||||||
struct sigaction act;
|
|
||||||
|
|
||||||
if (GC_thr_initialized) return;
|
|
||||||
GC_ASSERT(I_HOLD_LOCK());
|
|
||||||
GC_thr_initialized = TRUE;
|
|
||||||
#ifndef GC_AIX_THREADS
|
|
||||||
(void) sigaction(SIG_SUSPEND, 0, &act);
|
|
||||||
if (act.sa_handler != SIG_DFL)
|
|
||||||
ABORT("Previously installed SIG_SUSPEND handler");
|
|
||||||
/* Install handler. */
|
|
||||||
act.sa_handler = GC_suspend_handler;
|
|
||||||
act.sa_flags = SA_RESTART;
|
|
||||||
(void) sigemptyset(&act.sa_mask);
|
|
||||||
if (0 != sigaction(SIG_SUSPEND, &act, 0))
|
|
||||||
ABORT("Failed to install SIG_SUSPEND handler");
|
|
||||||
#endif
|
|
||||||
/* Add the initial thread, so we can stop it. */
|
|
||||||
t = GC_new_thread(pthread_self());
|
|
||||||
/* use '0' to indicate GC_stackbottom, since GC_init() has not
|
|
||||||
* completed by the time we are called (from GC_init_inner()) */
|
|
||||||
t -> stack_cold = 0; /* the original stack. */
|
|
||||||
t -> stack_hot = (ptr_t)(&t);
|
|
||||||
t -> flags = DETACHED;
|
|
||||||
}
|
|
||||||
|
|
||||||
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);
|
|
||||||
set = &fudged_set;
|
|
||||||
}
|
|
||||||
return(pthread_sigmask(how, set, oset));
|
|
||||||
}
|
|
||||||
|
|
||||||
struct start_info {
|
|
||||||
void *(*start_routine)(void *);
|
|
||||||
void *arg;
|
|
||||||
word flags;
|
|
||||||
pthread_mutex_t registeredlock;
|
|
||||||
pthread_cond_t registered;
|
|
||||||
int volatile registereddone;
|
|
||||||
};
|
|
||||||
|
|
||||||
void GC_thread_exit_proc(void *arg)
|
|
||||||
{
|
|
||||||
GC_thread me;
|
|
||||||
|
|
||||||
LOCK();
|
|
||||||
me = GC_lookup_thread(pthread_self());
|
|
||||||
me -> flags |= FINISHED;
|
|
||||||
/* reclaim DETACHED thread right away; otherwise wait until join() */
|
|
||||||
if (me -> flags & DETACHED) {
|
|
||||||
GC_delete_gc_thread(pthread_self(), me);
|
|
||||||
}
|
|
||||||
UNLOCK();
|
|
||||||
}
|
|
||||||
|
|
||||||
int GC_pthread_join(pthread_t thread, void **retval)
|
|
||||||
{
|
|
||||||
int result;
|
|
||||||
GC_thread thread_gc_id;
|
|
||||||
|
|
||||||
LOCK();
|
|
||||||
thread_gc_id = GC_lookup_thread(thread);
|
|
||||||
/* This is guaranteed to be the intended one, since the thread id */
|
|
||||||
/* cant have been recycled by pthreads. */
|
|
||||||
UNLOCK();
|
|
||||||
GC_ASSERT(!(thread_gc_id->flags & DETACHED));
|
|
||||||
result = pthread_join(thread, retval);
|
|
||||||
/* Some versions of the Irix pthreads library can erroneously */
|
|
||||||
/* return EINTR when the call succeeds. */
|
|
||||||
if (EINTR == result) result = 0;
|
|
||||||
GC_ASSERT(thread_gc_id->flags & FINISHED);
|
|
||||||
LOCK();
|
|
||||||
/* Here the pthread thread id may have been recycled. */
|
|
||||||
GC_delete_gc_thread(thread, thread_gc_id);
|
|
||||||
UNLOCK();
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
void * GC_start_routine(void * arg)
|
|
||||||
{
|
|
||||||
int dummy;
|
|
||||||
struct start_info * si = arg;
|
|
||||||
void * result;
|
|
||||||
GC_thread me;
|
|
||||||
pthread_t my_pthread;
|
|
||||||
void *(*start)(void *);
|
|
||||||
void *start_arg;
|
|
||||||
|
|
||||||
my_pthread = pthread_self();
|
|
||||||
/* If a GC occurs before the thread is registered, that GC will */
|
|
||||||
/* ignore this thread. That's fine, since it will block trying to */
|
|
||||||
/* acquire the allocation lock, and won't yet hold interesting */
|
|
||||||
/* pointers. */
|
|
||||||
LOCK();
|
|
||||||
/* We register the thread here instead of in the parent, so that */
|
|
||||||
/* we don't need to hold the allocation lock during pthread_create. */
|
|
||||||
/* Holding the allocation lock there would make REDIRECT_MALLOC */
|
|
||||||
/* impossible. It probably still doesn't work, but we're a little */
|
|
||||||
/* closer ... */
|
|
||||||
/* This unfortunately means that we have to be careful the parent */
|
|
||||||
/* doesn't try to do a pthread_join before we're registered. */
|
|
||||||
me = GC_new_thread(my_pthread);
|
|
||||||
me -> flags = si -> flags;
|
|
||||||
me -> stack_cold = (ptr_t) &dummy; /* this now the 'start of stack' */
|
|
||||||
me -> stack_hot = me->stack_cold;/* this field should always be sensible */
|
|
||||||
UNLOCK();
|
|
||||||
start = si -> start_routine;
|
|
||||||
start_arg = si -> arg;
|
|
||||||
|
|
||||||
pthread_mutex_lock(&(si->registeredlock));
|
|
||||||
si->registereddone = 1;
|
|
||||||
pthread_cond_signal(&(si->registered));
|
|
||||||
pthread_mutex_unlock(&(si->registeredlock));
|
|
||||||
/* si went away as soon as we did this unlock */
|
|
||||||
|
|
||||||
pthread_cleanup_push(GC_thread_exit_proc, 0);
|
|
||||||
result = (*start)(start_arg);
|
|
||||||
me -> status = result;
|
|
||||||
pthread_cleanup_pop(1);
|
|
||||||
/* This involves acquiring the lock, ensuring that we can't exit */
|
|
||||||
/* while a collection that thinks we're alive is trying to stop */
|
|
||||||
/* us. */
|
|
||||||
return(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
GC_pthread_create(pthread_t *new_thread,
|
|
||||||
const pthread_attr_t *attr,
|
|
||||||
void *(*start_routine)(void *), void *arg)
|
|
||||||
{
|
|
||||||
int result;
|
|
||||||
GC_thread t;
|
|
||||||
int detachstate;
|
|
||||||
word my_flags = 0;
|
|
||||||
struct start_info * si;
|
|
||||||
/* This is otherwise saved only in an area mmapped by the thread */
|
|
||||||
/* library, which isn't visible to the collector. */
|
|
||||||
|
|
||||||
LOCK();
|
|
||||||
/* GC_INTERNAL_MALLOC implicitly calls GC_init() if required */
|
|
||||||
si = (struct start_info *)GC_INTERNAL_MALLOC(sizeof(struct start_info),
|
|
||||||
NORMAL);
|
|
||||||
GC_ASSERT(GC_thr_initialized); /* initialized by GC_init() */
|
|
||||||
UNLOCK();
|
|
||||||
if (0 == si) return(ENOMEM);
|
|
||||||
pthread_mutex_init(&(si->registeredlock), NULL);
|
|
||||||
pthread_cond_init(&(si->registered),NULL);
|
|
||||||
pthread_mutex_lock(&(si->registeredlock));
|
|
||||||
si -> start_routine = start_routine;
|
|
||||||
si -> arg = arg;
|
|
||||||
|
|
||||||
pthread_attr_getdetachstate(attr, &detachstate);
|
|
||||||
if (PTHREAD_CREATE_DETACHED == detachstate) my_flags |= DETACHED;
|
|
||||||
si -> flags = my_flags;
|
|
||||||
result = pthread_create(new_thread, attr, GC_start_routine, si);
|
|
||||||
|
|
||||||
/* Wait until child has been added to the thread table. */
|
|
||||||
/* This also ensures that we hold onto si until the child is done */
|
|
||||||
/* with it. Thus it doesn't matter whether it is otherwise */
|
|
||||||
/* visible to the collector. */
|
|
||||||
|
|
||||||
if (0 == result) {
|
|
||||||
si->registereddone = 0;
|
|
||||||
while (!si->registereddone)
|
|
||||||
pthread_cond_wait(&(si->registered), &(si->registeredlock));
|
|
||||||
}
|
|
||||||
pthread_mutex_unlock(&(si->registeredlock));
|
|
||||||
|
|
||||||
pthread_cond_destroy(&(si->registered));
|
|
||||||
pthread_mutex_destroy(&(si->registeredlock));
|
|
||||||
LOCK();
|
|
||||||
GC_INTERNAL_FREE(si);
|
|
||||||
UNLOCK();
|
|
||||||
|
|
||||||
return(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 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. */
|
|
||||||
|
|
||||||
/* Reasonably fast spin locks. Basically the same implementation */
|
|
||||||
/* as STL alloc.h. */
|
|
||||||
|
|
||||||
#define SLEEP_THRESHOLD 3
|
|
||||||
|
|
||||||
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()
|
|
||||||
{
|
|
||||||
# define low_spin_max 30 /* spin cycles if we suspect uniprocessor */
|
|
||||||
# define high_spin_max 1000 /* spin cycles for multiprocessor */
|
|
||||||
static unsigned spin_max = low_spin_max;
|
|
||||||
unsigned my_spin_max;
|
|
||||||
static unsigned last_spins = 0;
|
|
||||||
unsigned my_last_spins;
|
|
||||||
volatile unsigned junk;
|
|
||||||
# define PAUSE junk *= junk; junk *= junk; junk *= junk; junk *= junk
|
|
||||||
int i;
|
|
||||||
|
|
||||||
if (GC_TRY_LOCK()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
junk = 0;
|
|
||||||
my_spin_max = spin_max;
|
|
||||||
my_last_spins = last_spins;
|
|
||||||
for (i = 0; i < my_spin_max; i++) {
|
|
||||||
if (GC_collecting) goto yield;
|
|
||||||
if (i < my_last_spins/2 || GC_LOCK_TAKEN) {
|
|
||||||
PAUSE;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (GC_TRY_LOCK()) {
|
|
||||||
/*
|
|
||||||
* got it!
|
|
||||||
* Spinning worked. Thus we're probably not being scheduled
|
|
||||||
* against the other process with which we were contending.
|
|
||||||
* Thus it makes sense to spin longer the next time.
|
|
||||||
*/
|
|
||||||
last_spins = i;
|
|
||||||
spin_max = high_spin_max;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/* We are probably being scheduled against the other process. Sleep. */
|
|
||||||
spin_max = low_spin_max;
|
|
||||||
yield:
|
|
||||||
for (i = 0;; ++i) {
|
|
||||||
if (GC_TRY_LOCK()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (i < SLEEP_THRESHOLD) {
|
|
||||||
sched_yield();
|
|
||||||
} else {
|
|
||||||
struct timespec ts;
|
|
||||||
|
|
||||||
if (i > 26) i = 26;
|
|
||||||
/* Don't wait for more than about 60msecs, even */
|
|
||||||
/* under extreme contention. */
|
|
||||||
ts.tv_sec = 0;
|
|
||||||
ts.tv_nsec = 1 << i;
|
|
||||||
nanosleep(&ts, 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
# else /* !GC_IRIX_THREADS && !GC_AIX_THREADS */
|
|
||||||
|
|
||||||
#ifndef LINT
|
|
||||||
int GC_no_Irix_threads;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
# endif /* IRIX_THREADS */
|
|
||||||
|
|
|
@ -285,8 +285,8 @@ int n;
|
||||||
GET_HDR(hhdr -> hb_prev, phdr);
|
GET_HDR(hhdr -> hb_prev, phdr);
|
||||||
phdr -> hb_next = hhdr -> hb_next;
|
phdr -> hb_next = hhdr -> hb_next;
|
||||||
}
|
}
|
||||||
|
FREE_ASSERT(GC_free_bytes[index] >= hhdr -> hb_sz);
|
||||||
INCR_FREE_BYTES(index, - (signed_word)(hhdr -> hb_sz));
|
INCR_FREE_BYTES(index, - (signed_word)(hhdr -> hb_sz));
|
||||||
FREE_ASSERT(GC_free_bytes[index] >= 0);
|
|
||||||
if (0 != hhdr -> hb_next) {
|
if (0 != hhdr -> hb_next) {
|
||||||
hdr * nhdr;
|
hdr * nhdr;
|
||||||
GC_ASSERT(!IS_FORWARDING_ADDR_OR_NIL(NHDR(hhdr)));
|
GC_ASSERT(!IS_FORWARDING_ADDR_OR_NIL(NHDR(hhdr)));
|
||||||
|
|
|
@ -92,6 +92,16 @@ char * GC_copyright[] =
|
||||||
|
|
||||||
# include "version.h"
|
# include "version.h"
|
||||||
|
|
||||||
|
#if defined(SAVE_CALL_CHAIN) && \
|
||||||
|
!(defined(REDIRECT_MALLOC) && defined(GC_HAVE_BUILTIN_BACKTRACE))
|
||||||
|
# define SAVE_CALL_CHAIN_IN_GC
|
||||||
|
/* This is only safe if the call chain save mechanism won't end up */
|
||||||
|
/* calling GC_malloc. The GNU C library documentation suggests */
|
||||||
|
/* that backtrace doesn't use malloc, but at least the initial */
|
||||||
|
/* call in some versions does seem to invoke the dynamic linker, */
|
||||||
|
/* which uses malloc. */
|
||||||
|
#endif
|
||||||
|
|
||||||
/* some more variables */
|
/* some more variables */
|
||||||
|
|
||||||
extern signed_word GC_mem_found; /* Number of reclaimed longwords */
|
extern signed_word GC_mem_found; /* Number of reclaimed longwords */
|
||||||
|
@ -196,7 +206,8 @@ word GC_adj_words_allocd()
|
||||||
/* had been reallocated this round. Finalization is user */
|
/* had been reallocated this round. Finalization is user */
|
||||||
/* visible progress. And if we don't count this, we have */
|
/* visible progress. And if we don't count this, we have */
|
||||||
/* stability problems for programs that finalize all objects. */
|
/* stability problems for programs that finalize all objects. */
|
||||||
result += GC_words_wasted;
|
if ((GC_words_wasted >> 3) < result)
|
||||||
|
result += GC_words_wasted;
|
||||||
/* This doesn't reflect useful work. But if there is lots of */
|
/* This doesn't reflect useful work. But if there is lots of */
|
||||||
/* new fragmentation, the same is probably true of the heap, */
|
/* new fragmentation, the same is probably true of the heap, */
|
||||||
/* and the collection will be correspondingly cheaper. */
|
/* and the collection will be correspondingly cheaper. */
|
||||||
|
@ -221,6 +232,8 @@ void GC_clear_a_few_frames()
|
||||||
{
|
{
|
||||||
# define NWORDS 64
|
# define NWORDS 64
|
||||||
word frames[NWORDS];
|
word frames[NWORDS];
|
||||||
|
/* Some compilers will warn that frames was set but never used. */
|
||||||
|
/* That's the whole idea ... */
|
||||||
register int i;
|
register int i;
|
||||||
|
|
||||||
for (i = 0; i < NWORDS; i++) frames[i] = 0;
|
for (i = 0; i < NWORDS; i++) frames[i] = 0;
|
||||||
|
@ -293,7 +306,7 @@ void GC_maybe_gc()
|
||||||
# endif
|
# endif
|
||||||
if (GC_stopped_mark(GC_time_limit == GC_TIME_UNLIMITED?
|
if (GC_stopped_mark(GC_time_limit == GC_TIME_UNLIMITED?
|
||||||
GC_never_stop_func : GC_timeout_stop_func)) {
|
GC_never_stop_func : GC_timeout_stop_func)) {
|
||||||
# ifdef SAVE_CALL_CHAIN
|
# ifdef SAVE_CALL_CHAIN_IN_GC
|
||||||
GC_save_callers(GC_last_stack);
|
GC_save_callers(GC_last_stack);
|
||||||
# endif
|
# endif
|
||||||
GC_finish_collection();
|
GC_finish_collection();
|
||||||
|
@ -358,7 +371,7 @@ GC_stop_func stop_func;
|
||||||
}
|
}
|
||||||
GC_invalidate_mark_state(); /* Flush mark stack. */
|
GC_invalidate_mark_state(); /* Flush mark stack. */
|
||||||
GC_clear_marks();
|
GC_clear_marks();
|
||||||
# ifdef SAVE_CALL_CHAIN
|
# ifdef SAVE_CALL_CHAIN_IN_GC
|
||||||
GC_save_callers(GC_last_stack);
|
GC_save_callers(GC_last_stack);
|
||||||
# endif
|
# endif
|
||||||
GC_is_full_gc = TRUE;
|
GC_is_full_gc = TRUE;
|
||||||
|
@ -413,7 +426,7 @@ int n;
|
||||||
for (i = GC_deficit; i < GC_RATE*n; i++) {
|
for (i = GC_deficit; i < GC_RATE*n; i++) {
|
||||||
if (GC_mark_some((ptr_t)0)) {
|
if (GC_mark_some((ptr_t)0)) {
|
||||||
/* Need to finish a collection */
|
/* Need to finish a collection */
|
||||||
# ifdef SAVE_CALL_CHAIN
|
# ifdef SAVE_CALL_CHAIN_IN_GC
|
||||||
GC_save_callers(GC_last_stack);
|
GC_save_callers(GC_last_stack);
|
||||||
# endif
|
# endif
|
||||||
# ifdef PARALLEL_MARK
|
# ifdef PARALLEL_MARK
|
||||||
|
@ -929,7 +942,7 @@ word n;
|
||||||
# endif
|
# endif
|
||||||
expansion_slop = WORDS_TO_BYTES(min_words_allocd()) + 4*MAXHINCR*HBLKSIZE;
|
expansion_slop = WORDS_TO_BYTES(min_words_allocd()) + 4*MAXHINCR*HBLKSIZE;
|
||||||
if (GC_last_heap_addr == 0 && !((word)space & SIGNB)
|
if (GC_last_heap_addr == 0 && !((word)space & SIGNB)
|
||||||
|| GC_last_heap_addr != 0 && GC_last_heap_addr < (ptr_t)space) {
|
|| (GC_last_heap_addr != 0 && GC_last_heap_addr < (ptr_t)space)) {
|
||||||
/* Assume the heap is growing up */
|
/* Assume the heap is growing up */
|
||||||
GC_greatest_plausible_heap_addr =
|
GC_greatest_plausible_heap_addr =
|
||||||
(GC_PTR)GC_max((ptr_t)GC_greatest_plausible_heap_addr,
|
(GC_PTR)GC_max((ptr_t)GC_greatest_plausible_heap_addr,
|
||||||
|
@ -992,7 +1005,7 @@ word needed_blocks;
|
||||||
GC_bool ignore_off_page;
|
GC_bool ignore_off_page;
|
||||||
{
|
{
|
||||||
if (!GC_incremental && !GC_dont_gc &&
|
if (!GC_incremental && !GC_dont_gc &&
|
||||||
(GC_dont_expand && GC_words_allocd > 0 || GC_should_collect())) {
|
((GC_dont_expand && GC_words_allocd > 0) || GC_should_collect())) {
|
||||||
GC_gcollect_inner();
|
GC_gcollect_inner();
|
||||||
} else {
|
} else {
|
||||||
word blocks_to_get = GC_heapsize/(HBLKSIZE*GC_free_space_divisor)
|
word blocks_to_get = GC_heapsize/(HBLKSIZE*GC_free_space_divisor)
|
||||||
|
@ -1001,6 +1014,9 @@ GC_bool ignore_off_page;
|
||||||
if (blocks_to_get > MAXHINCR) {
|
if (blocks_to_get > MAXHINCR) {
|
||||||
word slop;
|
word slop;
|
||||||
|
|
||||||
|
/* Get the minimum required to make it likely that we */
|
||||||
|
/* can satisfy the current request in the presence of black- */
|
||||||
|
/* listing. This will probably be more than MAXHINCR. */
|
||||||
if (ignore_off_page) {
|
if (ignore_off_page) {
|
||||||
slop = 4;
|
slop = 4;
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
# $Id: alpha_mach_dep.s,v 1.2 1993/01/18 22:54:51 dosser Exp $
|
|
||||||
.arch ev6
|
.arch ev6
|
||||||
|
|
||||||
.text
|
.text
|
||||||
|
@ -12,13 +11,13 @@ GC_push_regs:
|
||||||
.mask 0x04000000, 0
|
.mask 0x04000000, 0
|
||||||
.frame $sp, 16, $26, 0
|
.frame $sp, 16, $26, 0
|
||||||
|
|
||||||
# $0 integer result
|
/* $0 integer result */
|
||||||
# $1-$8 temp regs - not preserved cross calls
|
/* $1-$8 temp regs - not preserved cross calls */
|
||||||
# $9-$15 call saved regs
|
/* $9-$15 call saved regs */
|
||||||
# $16-$21 argument regs - not preserved cross calls
|
/* $16-$21 argument regs - not preserved cross calls */
|
||||||
# $22-$28 temp regs - not preserved cross calls
|
/* $22-$28 temp regs - not preserved cross calls */
|
||||||
# $29 global pointer - not preserved cross calls
|
/* $29 global pointer - not preserved cross calls */
|
||||||
# $30 stack pointer
|
/* $30 stack pointer */
|
||||||
|
|
||||||
# define call_push(x) \
|
# define call_push(x) \
|
||||||
mov x, $16; \
|
mov x, $16; \
|
||||||
|
@ -33,12 +32,12 @@ GC_push_regs:
|
||||||
call_push($14)
|
call_push($14)
|
||||||
call_push($15)
|
call_push($15)
|
||||||
|
|
||||||
# $f0-$f1 floating point results
|
/* $f0-$f1 floating point results */
|
||||||
# $f2-$f9 call saved regs
|
/* $f2-$f9 call saved regs */
|
||||||
# $f10-$f30 temp regs - not preserved cross calls
|
/* $f10-$f30 temp regs - not preserved cross calls */
|
||||||
|
|
||||||
# Use the most efficient transfer method for this hardware.
|
/* Use the most efficient transfer method for this hardware. */
|
||||||
# Bit 1 detects the FIX extension, which includes ftoit.
|
/* Bit 1 detects the FIX extension, which includes ftoit. */
|
||||||
amask 2, $0
|
amask 2, $0
|
||||||
bne $0, $use_stack
|
bne $0, $use_stack
|
||||||
|
|
||||||
|
|
|
@ -1767,7 +1767,7 @@ fi
|
||||||
|
|
||||||
# Define the identity of the package.
|
# Define the identity of the package.
|
||||||
PACKAGE=gc
|
PACKAGE=gc
|
||||||
VERSION=6.3
|
VERSION=6.6
|
||||||
|
|
||||||
|
|
||||||
# Some tools Automake needs.
|
# Some tools Automake needs.
|
||||||
|
|
|
@ -36,7 +36,7 @@ ACX_NONCANONICAL_TARGET
|
||||||
mkinstalldirs="`cd $ac_aux_dir && ${PWDCMD-pwd}`/mkinstalldirs"
|
mkinstalldirs="`cd $ac_aux_dir && ${PWDCMD-pwd}`/mkinstalldirs"
|
||||||
AC_SUBST(mkinstalldirs)
|
AC_SUBST(mkinstalldirs)
|
||||||
|
|
||||||
AM_INIT_AUTOMAKE(gc, 6.3, no-define)
|
AM_INIT_AUTOMAKE(gc, 6.6, no-define)
|
||||||
|
|
||||||
# The autoconf 2.5x version of the no-executables hack.
|
# The autoconf 2.5x version of the no-executables hack.
|
||||||
GCC_NO_EXECUTABLES
|
GCC_NO_EXECUTABLES
|
||||||
|
|
|
@ -59,7 +59,7 @@ static int extract_conv_spec(CORD_pos source, char *buf,
|
||||||
register int result = 0;
|
register int result = 0;
|
||||||
register int current_number = 0;
|
register int current_number = 0;
|
||||||
register int saw_period = 0;
|
register int saw_period = 0;
|
||||||
register int saw_number;
|
register int saw_number = 0;
|
||||||
register int chars_so_far = 0;
|
register int chars_so_far = 0;
|
||||||
register char current;
|
register char current;
|
||||||
|
|
||||||
|
@ -243,7 +243,7 @@ int CORD_vsprintf(CORD * out, CORD format, va_list args)
|
||||||
char * str = va_arg(args, char *);
|
char * str = va_arg(args, char *);
|
||||||
register char c;
|
register char c;
|
||||||
|
|
||||||
while (c = *str++) {
|
while ((c = *str++)) {
|
||||||
CORD_ec_append(result, c);
|
CORD_ec_append(result, c);
|
||||||
}
|
}
|
||||||
goto done;
|
goto done;
|
||||||
|
@ -320,7 +320,7 @@ int CORD_vsprintf(CORD * out, CORD format, va_list args)
|
||||||
if (buf != result[0].ec_bufptr) {
|
if (buf != result[0].ec_bufptr) {
|
||||||
register char c;
|
register char c;
|
||||||
|
|
||||||
while (c = *buf++) {
|
while ((c = *buf++)) {
|
||||||
CORD_ec_append(result, c);
|
CORD_ec_append(result, c);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -221,7 +221,7 @@ void test_printf()
|
||||||
if (CORD_cmp(result, result2) != 0)ABORT("CORD_sprintf goofed 5");
|
if (CORD_cmp(result, result2) != 0)ABORT("CORD_sprintf goofed 5");
|
||||||
}
|
}
|
||||||
|
|
||||||
main()
|
int main()
|
||||||
{
|
{
|
||||||
# ifdef THINK_C
|
# ifdef THINK_C
|
||||||
printf("cordtest:\n");
|
printf("cordtest:\n");
|
||||||
|
|
Before Width: | Height: | Size: 766 B After Width: | Height: | Size: 766 B |
|
@ -14,7 +14,13 @@
|
||||||
Page 50: "If a leaf procedure's red zone usage would exceed 224 bytes, then
|
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."
|
it must set up a stack frame just like routines that call other routines."
|
||||||
*/
|
*/
|
||||||
#define PPC_RED_ZONE_SIZE 224
|
#ifdef POWERPC
|
||||||
|
# if CPP_WORDSZ == 32
|
||||||
|
# define PPC_RED_ZONE_SIZE 224
|
||||||
|
# elif CPP_WORDSZ == 64
|
||||||
|
# define PPC_RED_ZONE_SIZE 320
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
|
||||||
typedef struct StackFrame {
|
typedef struct StackFrame {
|
||||||
unsigned long savedSP;
|
unsigned long savedSP;
|
||||||
|
@ -24,12 +30,17 @@ typedef struct StackFrame {
|
||||||
unsigned long savedRTOC;
|
unsigned long savedRTOC;
|
||||||
} StackFrame;
|
} StackFrame;
|
||||||
|
|
||||||
|
unsigned long FindTopOfStack(unsigned int stack_start) {
|
||||||
unsigned int FindTopOfStack(unsigned int stack_start) {
|
|
||||||
StackFrame *frame;
|
StackFrame *frame;
|
||||||
|
|
||||||
if (stack_start == 0) {
|
if (stack_start == 0) {
|
||||||
__asm__ volatile("lwz %0,0(r1)" : "=r" (frame));
|
# ifdef POWERPC
|
||||||
|
# if CPP_WORDSZ == 32
|
||||||
|
__asm__ volatile("lwz %0,0(r1)" : "=r" (frame));
|
||||||
|
# else
|
||||||
|
__asm__ volatile("ldz %0,0(r1)" : "=r" (frame));
|
||||||
|
# endif
|
||||||
|
# endif
|
||||||
} else {
|
} else {
|
||||||
frame = (StackFrame *)stack_start;
|
frame = (StackFrame *)stack_start;
|
||||||
}
|
}
|
||||||
|
@ -38,7 +49,7 @@ unsigned int FindTopOfStack(unsigned int stack_start) {
|
||||||
/* GC_printf1("FindTopOfStack start at sp = %p\n", frame); */
|
/* GC_printf1("FindTopOfStack start at sp = %p\n", frame); */
|
||||||
# endif
|
# endif
|
||||||
do {
|
do {
|
||||||
if (frame->savedSP == NULL) break;
|
if (frame->savedSP == 0) break;
|
||||||
/* if there are no more stack frames, stop */
|
/* if there are no more stack frames, stop */
|
||||||
|
|
||||||
frame = (StackFrame*)frame->savedSP;
|
frame = (StackFrame*)frame->savedSP;
|
||||||
|
@ -54,9 +65,88 @@ unsigned int FindTopOfStack(unsigned int stack_start) {
|
||||||
/* GC_printf1("FindTopOfStack finish at sp = %p\n", frame); */
|
/* GC_printf1("FindTopOfStack finish at sp = %p\n", frame); */
|
||||||
# endif
|
# endif
|
||||||
|
|
||||||
return (unsigned int)frame;
|
return (unsigned long)frame;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef DARWIN_DONT_PARSE_STACK
|
||||||
|
void GC_push_all_stacks() {
|
||||||
|
int i;
|
||||||
|
kern_return_t r;
|
||||||
|
GC_thread p;
|
||||||
|
pthread_t me;
|
||||||
|
ptr_t lo, hi;
|
||||||
|
ppc_thread_state_t state;
|
||||||
|
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");
|
||||||
|
|
||||||
|
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);
|
||||||
|
} /* 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...) */
|
||||||
|
}
|
||||||
|
|
||||||
|
#else /* !DARWIN_DONT_PARSE_STACK; Use FindTopOfStack() */
|
||||||
|
|
||||||
void GC_push_all_stacks() {
|
void GC_push_all_stacks() {
|
||||||
int i;
|
int i;
|
||||||
kern_return_t r;
|
kern_return_t r;
|
||||||
|
@ -76,8 +166,12 @@ void GC_push_all_stacks() {
|
||||||
lo = GC_approx_sp();
|
lo = GC_approx_sp();
|
||||||
hi = (ptr_t)FindTopOfStack(0);
|
hi = (ptr_t)FindTopOfStack(0);
|
||||||
} else {
|
} else {
|
||||||
# ifdef POWERPC
|
# if defined(POWERPC)
|
||||||
|
# if CPP_WORDSZ == 32
|
||||||
ppc_thread_state_t info;
|
ppc_thread_state_t info;
|
||||||
|
# else
|
||||||
|
ppc_thread_state64_t info;
|
||||||
|
# endif
|
||||||
mach_msg_type_number_t outCount = THREAD_STATE_MAX;
|
mach_msg_type_number_t outCount = THREAD_STATE_MAX;
|
||||||
r = thread_get_state(thread, MACHINE_THREAD_STATE,
|
r = thread_get_state(thread, MACHINE_THREAD_STATE,
|
||||||
(natural_t *)&info, &outCount);
|
(natural_t *)&info, &outCount);
|
||||||
|
@ -156,6 +250,7 @@ void GC_push_all_stacks() {
|
||||||
GC_push_all_stack(lo, hi);
|
GC_push_all_stack(lo, hi);
|
||||||
} /* for(p=GC_threads[i]...) */
|
} /* for(p=GC_threads[i]...) */
|
||||||
}
|
}
|
||||||
|
#endif /* !DARWIN_DONT_PARSE_STACK */
|
||||||
|
|
||||||
static mach_port_t GC_mach_handler_thread;
|
static mach_port_t GC_mach_handler_thread;
|
||||||
static int GC_use_mach_handler_thread = 0;
|
static int GC_use_mach_handler_thread = 0;
|
||||||
|
@ -325,6 +420,8 @@ void GC_start_world()
|
||||||
kern_return_t kern_result;
|
kern_return_t kern_result;
|
||||||
thread_act_array_t act_list;
|
thread_act_array_t act_list;
|
||||||
mach_msg_type_number_t listcount;
|
mach_msg_type_number_t listcount;
|
||||||
|
struct thread_basic_info info;
|
||||||
|
mach_msg_type_number_t outCount = THREAD_INFO_MAX;
|
||||||
|
|
||||||
# if DEBUG_THREADS
|
# if DEBUG_THREADS
|
||||||
GC_printf0("World starting\n");
|
GC_printf0("World starting\n");
|
||||||
|
@ -351,8 +448,6 @@ void GC_start_world()
|
||||||
# endif
|
# endif
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
struct thread_basic_info info;
|
|
||||||
mach_msg_type_number_t outCount = THREAD_INFO_MAX;
|
|
||||||
kern_result = thread_info(thread, THREAD_BASIC_INFO,
|
kern_result = thread_info(thread, THREAD_BASIC_INFO,
|
||||||
(thread_info_t)&info, &outCount);
|
(thread_info_t)&info, &outCount);
|
||||||
if(kern_result != KERN_SUCCESS) ABORT("thread_info failed");
|
if(kern_result != KERN_SUCCESS) ABORT("thread_info failed");
|
||||||
|
|
|
@ -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
|
collector. (If you are concerned about such things, I recommend you look
|
||||||
at the notice in config.guess or ltmain.sh.)
|
at the notice in config.guess or ltmain.sh.)
|
||||||
|
|
||||||
This is version 6.3 of a conservative garbage collector for C and C++.
|
This is version 6.6 of a conservative garbage collector for C and C++.
|
||||||
|
|
||||||
You might find a more recent version of this at
|
You might find a more recent version of this at
|
||||||
|
|
||||||
|
|
|
@ -2100,7 +2100,151 @@ Since gc6.3alpha6:
|
||||||
to Andrew Begel.)
|
to Andrew Begel.)
|
||||||
- Fix GC_task_self declaration in os_dep.c. (Thanks to Andrew Pinski.)
|
- Fix GC_task_self declaration in os_dep.c. (Thanks to Andrew Pinski.)
|
||||||
- Increase INITIAL_BUF_SZ in os_dep.c for Solaris /proc reads.
|
- Increase INITIAL_BUF_SZ in os_dep.c for Solaris /proc reads.
|
||||||
|
|
||||||
|
Since 6.3:
|
||||||
|
- Merge gcconfig.h changes from gcc tree.
|
||||||
|
- Unconditionally include gc_priv.h in solaris_pthreads.c, win32_threads.h,
|
||||||
|
aix_irix_threads.c, and solaris_threads.c to get thread definitions.
|
||||||
|
- Start marker threads in GC_thr_init, so that they get started even
|
||||||
|
if no other threads are ever started. (Oddly enough, the parallel
|
||||||
|
collector worked correctly, though not well, with no helper threads.)
|
||||||
|
- Go ahead and split large blocks in GC_allochblk_nth if GC_dont_gc
|
||||||
|
is set. (Thanks to Alexander Petrossian.)
|
||||||
|
- GC_PRINT_BACK_HEIGHT would deadlock with thread support.
|
||||||
|
- Let in_progress_space in backgraph.s grow dynamically.
|
||||||
|
- Fix README.solaris2. The GC_thr_init() hack doesn't work anymore.
|
||||||
|
- Convert GC_finalizer_mem_freed to bytes in allchblk.c.
|
||||||
|
- Add missing declaration for GC_generic_malloc_words_small_inner.
|
||||||
|
Without it, s390x breaks. (Thanks to Ulrich Weigand.)
|
||||||
|
- Applied several MacOSX patches to support older tool chains.
|
||||||
|
(Thanks to Stefan Ring.)
|
||||||
|
- Bug fix for NetBSD/amd64. (Thanks to Marc Recht.) Add NetBSD/sh3
|
||||||
|
support. (Thanks to Uchiyama Yasushi.)
|
||||||
|
- Fixed an uninitialized variable in cordprnt.c. (Thanks to gcc for
|
||||||
|
providing the warning.)
|
||||||
|
- Eliminated some, but not all, gcc -Wall warnings.
|
||||||
|
- Changed some old style casts to reinterpret_cast in new_gc_alloc.h.
|
||||||
|
(Thanks to Dan Grayson.)
|
||||||
|
- GC_extend_size_map shouldn't adjust for GC_all_interior_pointers if
|
||||||
|
GC_DONT_ADD_BYTE_AT_END is set.
|
||||||
|
- Changed some (long) casts to (word) in preparation for win64.
|
||||||
|
(Thanks to Peter Colson.)
|
||||||
|
- Changed "int stack_size" declaration in pthread_support.c to use
|
||||||
|
size_t. (Only mattered with GC_ASSERTIONS enabled.)
|
||||||
|
- Added CRIS (etrax) support. (Thanks to Simon Posnjak and
|
||||||
|
Hans-Peter Nilsson.)
|
||||||
|
- Removed GC_IGNORE_FB frame buffer recognition, and replaced
|
||||||
|
it with a check that the mapping type is MEM_IMAGE.
|
||||||
|
In theory, this should work much better, but it is a high
|
||||||
|
risk change for win32. (Thanks to Ashley Bone for the crucial
|
||||||
|
experimental data behind this, and to Rutger Ovidus for
|
||||||
|
some further experiments.)
|
||||||
|
- Fixed print_block_list to print the correct kind number for
|
||||||
|
STUBBORN. (Thanks to Rutger Ovidus.)
|
||||||
|
- GC_allochblk_nth incremented GC_words_wasted by bytes rather than
|
||||||
|
words.
|
||||||
|
- Consider GC_words_wasted in GC_adj_words_allocd only if it is within
|
||||||
|
reason. (A hack to avoid some extremely unlikely scenarios in which
|
||||||
|
we manage to allocate only "wasted" space. 7.0 has a better fix.)
|
||||||
|
- Changed PowerPC GC_clear implementation to use lwsync instead of
|
||||||
|
eieio, since the documentation recommends against eieio, and
|
||||||
|
it seems to be incorrect if the preceding memory op is a load.
|
||||||
|
- Fixed print_block_list to print the correct kind number for
|
||||||
|
STUBBORN. (Thanks to Rutger Ovidus.)
|
||||||
|
- Have configure.in generate an error if it is asked to support
|
||||||
|
pthreads, but doesn't know how to.
|
||||||
|
- Added Kazuhiro Inaoka's patch for Renesas M32R support.
|
||||||
|
- Have the GNU build mechanism link with -ldl. Rename THREADLIBS
|
||||||
|
to THREADDLLIBS to reflect this. (Thanks to Sven Verdoolaege.)
|
||||||
|
- Added Hannes Mehnert's patch for FreeBSD/SPARC support.
|
||||||
|
- Merged some FreeBSD specific patches to threadlibs.c and dyn_load.c.
|
||||||
|
(Thanks tp John Merryweather Cooper.)
|
||||||
|
- Define MPROTECT_VDB on MACOSX only if threads are being used, since the
|
||||||
|
dirty page tracking mechanism uses threads. (This avoids an undefined
|
||||||
|
reference to _GC_darwin_register_mach_handler_thread.)
|
||||||
|
- By popular demand, use __libc symbols only if we are built with
|
||||||
|
USE_LIBC_PRIVATES, which is off by default, and not otherwise documented.
|
||||||
|
- Ignore GC_enable_incremental() requests when KEEP_BACK_PTRS is set.
|
||||||
|
The GC itself will dirty lots of pages in this cases, probably making
|
||||||
|
it counterproductive on all platforms. And the DARWIN port crashes.
|
||||||
|
|
||||||
|
Since GC6.4:
|
||||||
|
- Integrated Paolo Molaro's patch to deal with EINTR in sem_wait.
|
||||||
|
- Make GC_approx_sp() write to dummy location to ensure that stack
|
||||||
|
is grown here, when sp looks reasonable, rather than later, when
|
||||||
|
it might look like a bad memory reference. (Problem was never
|
||||||
|
observed that I know of. But on rereading the code it seemed
|
||||||
|
dubious.)
|
||||||
|
- Separate out GC_with_callee_saves_pushed and sometimes call
|
||||||
|
it from GC_suspend_handler in pthread_stop_world.c. Callee-save
|
||||||
|
register values sometimes failed to get traced under HP/UX on
|
||||||
|
PA-RISC. Linux/IA64 had the same problem, though non-stacked
|
||||||
|
callee-save registers seem to be so rarely used there that nobody
|
||||||
|
ever noticed.
|
||||||
|
- Integrated an ancient Darwin powerpc_darwin_machine_dep.s patch
|
||||||
|
from Andreas Tobler, which I had lost.
|
||||||
|
- Fix compare_and_exchange implementation for gcc/IA64 to deal with
|
||||||
|
pickier compiler versions.
|
||||||
|
- Fixed Itanium 32-bit ABI support (HP/UX). In particular, the
|
||||||
|
compare_and_exchange implementation didn't consider that possibility.
|
||||||
|
- Undefine GC_pthread_detach in win32_threads.c. (Thanks to
|
||||||
|
Tagliapietra Tommaso.)
|
||||||
|
- Fixed inclusion of frame.h for NETBSD in os_dep.c.
|
||||||
|
- Applied Dan Bonachea's patch to use mmap on AIX.
|
||||||
|
- Several fixes to resurrect the Irix port on recent OS versions.
|
||||||
|
- Change ALPHA to use LINUX_STACKBOTTOM.
|
||||||
|
- Change SPARC64/LINUX to also use LINUX_STACKBOTTOM. Deal with potential
|
||||||
|
bad values of __libc_stack_end on that platform. (Thanks to David Miller.)
|
||||||
|
- Relax gctest to allow larger heap if ALIGN_DOUBLE isn't set.
|
||||||
|
(Unnecessary in 7.0)
|
||||||
|
- Force a define of __STDC__=0 for the IBM compiler on AIX, so that
|
||||||
|
we get prototypes. (Unnecessary in 7.0)
|
||||||
|
- GC_INIT definition for AIX and CYGWIN referred to DATASTART and DATAEND
|
||||||
|
which are only defined in private include files.
|
||||||
|
- Integrated some small gcconfig.h patches from Dan Bonachea. Also
|
||||||
|
relaxed assertion about FreeBSD stack size in pthread_support.c.
|
||||||
|
- Integrated Andrew Begel's darwin_stop_world.c patch for 64-bit
|
||||||
|
support. This may need additional work.
|
||||||
|
- Avoided potentially infinite recursion in GC_save_callers if
|
||||||
|
the system backtrace calls malloc. The workaround currently requires
|
||||||
|
__thread support if this code is used with threads.
|
||||||
|
- Avoided another similar infinite recursion by conditionally
|
||||||
|
invoking GC_save_callers in alloc.c. (Thanks to Matthias Andree
|
||||||
|
for helping to track down both of these.)
|
||||||
|
- Removed all traces of aix_irix_threads.c. AIX and Irix now use
|
||||||
|
pthread_support.c and pthread_stop_world.c. The old code appeared
|
||||||
|
to be unreliable for AIX, and was not regularly maintained.
|
||||||
|
- On Irix, ignore segments with MA_FETCHOP or MA_NOTCACHED attributed;
|
||||||
|
they're not always safe to read.
|
||||||
|
- Fixed a previously vacuous assertion (diagnosed by the SGI compiler)
|
||||||
|
in GC_remove_from_fl.
|
||||||
|
- Fix stack_size assertion in GC_pthread_create.
|
||||||
|
- Fix assertion in GC_steal_mark_stack.
|
||||||
|
|
||||||
|
Since 6.5
|
||||||
|
- Fix CPU count detection for Irix and FreeBSD. (Thanks to Dan Bonachea.)
|
||||||
|
- Integrate Dan Bonachea's patch for the IBM XLC compiler on Darwin.
|
||||||
|
- Integrated Andreas Tobler's FreeBSD/PowerPC patch.
|
||||||
|
- Don't access the GC thread structure from the restart handler. It's
|
||||||
|
unsafe, since the handler may run too late. (Thanks to Ben Maurer for
|
||||||
|
tracking this down.)
|
||||||
|
- Applied Christian Thalinger's patch to change comment syntax in
|
||||||
|
alpha_mach_dep.S.
|
||||||
|
- Added test for GC_no_dls in GC_dyld_image_add for DARWIN. (Thanks to
|
||||||
|
Juan Jose Garcia Ripoli).
|
||||||
|
- Use LINUX_STACKBOTTOM for Linux/SH and LINUX/ARM. (Thanks to Sugioka
|
||||||
|
Toshinobu and Christian Thalinger.)
|
||||||
|
- Rewrote GC_parse_map_entry. This assumed a fixed column layout of
|
||||||
|
/proc/self/maps on Linux. This ceased to be true about 2 years ago.
|
||||||
|
The old code is probably quite problemetic with -DREDIRECT_MALLOC. It
|
||||||
|
is also used by default for IA64, though I haven't seen actual failures
|
||||||
|
there.
|
||||||
|
- More consistently define HBLKSIZE to 4096 on 64 bit architectures with
|
||||||
|
4K pages. (Thanks to Andrew Haley.)
|
||||||
|
- With win32 threads, GC_stop_world needs to acquire GC_write_cs. (Thanks
|
||||||
|
to Ben Hutchings for the observation and patch.)
|
||||||
|
- Move up struct callinfo declaration to make gcc 4.0.2. happy.
|
||||||
|
|
||||||
To do:
|
To do:
|
||||||
- The USE_MUNMAP code should really use a separate data structure
|
- The USE_MUNMAP code should really use a separate data structure
|
||||||
indexed by physical page to keep track of time since last use of
|
indexed by physical page to keep track of time since last use of
|
||||||
|
|
|
@ -1,3 +1,16 @@
|
||||||
|
6.5 update:
|
||||||
|
I disabled incremental GC on Darwin in this version, since I couldn't
|
||||||
|
get gctest to pass when the GC was built as a dynamic library. Building
|
||||||
|
with -DMPROTECT_VDB (and threads) on the command line should get you
|
||||||
|
back to the old state. - HB
|
||||||
|
|
||||||
|
./configure --enable-cplusplus results in a "make check" failure, probably
|
||||||
|
because the ::delete override ends up in a separate dl, and Darwin dynamic
|
||||||
|
loader semantics appear to be such that this is not really visible to the
|
||||||
|
main program, unlike on ELF systems. Someone who understands dynamic
|
||||||
|
loading needs to lookat this. For now, gc_cpp.o needs to be linked
|
||||||
|
statically, if needed. - HB
|
||||||
|
|
||||||
Darwin/MacOSX Support - December 16, 2003
|
Darwin/MacOSX Support - December 16, 2003
|
||||||
=========================================
|
=========================================
|
||||||
|
|
||||||
|
|
|
@ -115,6 +115,7 @@ GC_IGNORE_FB[=<n>] - (Win32 only.) Try to avoid treating a mapped
|
||||||
are never honored, eliminating this risk for most,
|
are never honored, eliminating this risk for most,
|
||||||
but not all, applications. This feature is likely to disappear
|
but not all, applications. This feature is likely to disappear
|
||||||
if/when we find a less disgusting "solution".
|
if/when we find a less disgusting "solution".
|
||||||
|
IN VERSION 6.4 AND LATER, THIS SHOULD BE UNNECESSARY.
|
||||||
|
|
||||||
The following turn on runtime flags that are also program settable. Checked
|
The following turn on runtime flags that are also program settable. Checked
|
||||||
only during initialization. We expect that they will usually be set through
|
only during initialization. We expect that they will usually be set through
|
||||||
|
|
|
@ -19,10 +19,10 @@ Linux threads. These should not be touched by the client program.
|
||||||
|
|
||||||
To use threads, you need to abide by the following requirements:
|
To use threads, you need to abide by the following requirements:
|
||||||
|
|
||||||
1) You need to use LinuxThreads (which are included in libc6).
|
1) You need to use LinuxThreads or NPTL (which are included in libc6).
|
||||||
|
|
||||||
The collector relies on some implementation details of the LinuxThreads
|
The collector relies on some implementation details of the LinuxThreads
|
||||||
package. It is unlikely that this code will work on other
|
package. This code may not work on other
|
||||||
pthread implementations (in particular it will *not* work with
|
pthread implementations (in particular it will *not* work with
|
||||||
MIT pthreads).
|
MIT pthreads).
|
||||||
|
|
||||||
|
|
|
@ -43,9 +43,7 @@ can result in unpleasant heap growth. But it seems better than the
|
||||||
race/deadlock issues we had before.
|
race/deadlock issues we had before.
|
||||||
|
|
||||||
If solaris_threads are used on an X86 processor with malloc redirected to
|
If solaris_threads are used on an X86 processor with malloc redirected to
|
||||||
GC_malloc, it is necessary to call GC_thr_init explicitly before forking the
|
GC_malloc a deadlock is likely to result.
|
||||||
first thread. (This avoids a deadlock arising from calling GC_thr_init
|
|
||||||
with the allocation lock held.)
|
|
||||||
|
|
||||||
It appears that there is a problem in using gc_cpp.h in conjunction with
|
It appears that there is a problem in using gc_cpp.h in conjunction with
|
||||||
Solaris threads and Sun's C++ runtime. Apparently the overloaded new operator
|
Solaris threads and Sun's C++ runtime. Apparently the overloaded new operator
|
||||||
|
|
|
@ -96,17 +96,25 @@
|
||||||
/* Newer versions of GNU/Linux define this macro. We
|
/* Newer versions of GNU/Linux define this macro. We
|
||||||
* define it similarly for any ELF systems that don't. */
|
* define it similarly for any ELF systems that don't. */
|
||||||
# ifndef ElfW
|
# ifndef ElfW
|
||||||
# ifdef __NetBSD__
|
# if defined(FREEBSD)
|
||||||
# if ELFSIZE == 32
|
# if __ELF_WORD_SIZE == 32
|
||||||
# define ElfW(type) Elf32_##type
|
# define ElfW(type) Elf32_##type
|
||||||
# else
|
# else
|
||||||
# define ElfW(type) Elf64_##type
|
# define ElfW(type) Elf64_##type
|
||||||
# endif
|
# endif
|
||||||
# else
|
# else
|
||||||
# if !defined(ELF_CLASS) || ELF_CLASS == ELFCLASS32
|
# ifdef NETBSD
|
||||||
# define ElfW(type) Elf32_##type
|
# if ELFSIZE == 32
|
||||||
|
# define ElfW(type) Elf32_##type
|
||||||
|
# else
|
||||||
|
# define ElfW(type) Elf64_##type
|
||||||
|
# endif
|
||||||
# else
|
# else
|
||||||
# define ElfW(type) Elf64_##type
|
# if !defined(ELF_CLASS) || ELF_CLASS == ELFCLASS32
|
||||||
|
# define ElfW(type) Elf32_##type
|
||||||
|
# else
|
||||||
|
# define ElfW(type) Elf64_##type
|
||||||
|
# endif
|
||||||
# endif
|
# endif
|
||||||
# endif
|
# endif
|
||||||
# endif
|
# endif
|
||||||
|
@ -485,7 +493,6 @@ static struct link_map *
|
||||||
GC_FirstDLOpenedLinkMap()
|
GC_FirstDLOpenedLinkMap()
|
||||||
{
|
{
|
||||||
ElfW(Dyn) *dp;
|
ElfW(Dyn) *dp;
|
||||||
struct r_debug *r;
|
|
||||||
static struct link_map *cachedResult = 0;
|
static struct link_map *cachedResult = 0;
|
||||||
|
|
||||||
if( _DYNAMIC == 0) {
|
if( _DYNAMIC == 0) {
|
||||||
|
@ -494,6 +501,12 @@ GC_FirstDLOpenedLinkMap()
|
||||||
if( cachedResult == 0 ) {
|
if( cachedResult == 0 ) {
|
||||||
int tag;
|
int tag;
|
||||||
for( dp = _DYNAMIC; (tag = dp->d_tag) != 0; dp++ ) {
|
for( dp = _DYNAMIC; (tag = dp->d_tag) != 0; dp++ ) {
|
||||||
|
/* FIXME: The DT_DEBUG header is not mandated by the */
|
||||||
|
/* ELF spec. This code appears to be dependent on */
|
||||||
|
/* idiosynchracies of older GNU tool chains. If this code */
|
||||||
|
/* fails for you, the real problem is probably that it is */
|
||||||
|
/* being used at all. You should be getting the */
|
||||||
|
/* dl_iterate_phdr version. */
|
||||||
if( tag == DT_DEBUG ) {
|
if( tag == DT_DEBUG ) {
|
||||||
struct link_map *lm
|
struct link_map *lm
|
||||||
= ((struct r_debug *)(dp->d_un.d_ptr))->r_map;
|
= ((struct r_debug *)(dp->d_un.d_ptr))->r_map;
|
||||||
|
@ -618,7 +631,8 @@ void GC_register_dynamic_libraries()
|
||||||
}
|
}
|
||||||
for (i = 0; i < needed_sz; i++) {
|
for (i = 0; i < needed_sz; i++) {
|
||||||
flags = addr_map[i].pr_mflags;
|
flags = addr_map[i].pr_mflags;
|
||||||
if ((flags & (MA_BREAK | MA_STACK | MA_PHYS)) != 0) goto irrelevant;
|
if ((flags & (MA_BREAK | MA_STACK | MA_PHYS
|
||||||
|
| MA_FETCHOP | MA_NOTCACHED)) != 0) goto irrelevant;
|
||||||
if ((flags & (MA_READ | MA_WRITE)) != (MA_READ | MA_WRITE))
|
if ((flags & (MA_READ | MA_WRITE)) != (MA_READ | MA_WRITE))
|
||||||
goto irrelevant;
|
goto irrelevant;
|
||||||
/* The latter test is empirically useless in very old Irix */
|
/* The latter test is empirically useless in very old Irix */
|
||||||
|
@ -758,25 +772,27 @@ void GC_register_dynamic_libraries()
|
||||||
|
|
||||||
/* Should [start, start+len) be treated as a frame buffer */
|
/* Should [start, start+len) be treated as a frame buffer */
|
||||||
/* and ignored? */
|
/* and ignored? */
|
||||||
/* Unfortunately, we currently have no real way to tell */
|
/* Unfortunately, we currently are not quite sure how to tell */
|
||||||
/* automatically, and rely largely on user input. */
|
/* this automatically, and rely largely on user input. */
|
||||||
/* FIXME: If we had more data on this phenomenon (e.g. */
|
/* We expect that any mapping with type MEM_MAPPED (which */
|
||||||
/* is start aligned to a MB multiple?) we should be able to */
|
/* apparently excludes library data sections) can be safely */
|
||||||
/* do better. */
|
/* ignored. But we're too chicken to do that in this */
|
||||||
|
/* version. */
|
||||||
/* Based on a very limited sample, it appears that: */
|
/* Based on a very limited sample, it appears that: */
|
||||||
/* - Frame buffer mappings appear as mappings of length */
|
/* - Frame buffer mappings appear as mappings of large */
|
||||||
/* 2**n MB - 192K. (We guess the 192K can vary a bit.) */
|
/* length, usually a bit less than a power of two. */
|
||||||
/* - Have a stating address at best 64K aligned. */
|
/* - The definition of "a bit less" in the above cannot */
|
||||||
/* I'd love more information about the mapping, since I */
|
/* be made more precise. */
|
||||||
/* can't reproduce the problem. */
|
/* - Have a starting address at best 64K aligned. */
|
||||||
static GC_bool is_frame_buffer(ptr_t start, size_t len)
|
/* - Have type == MEM_MAPPED. */
|
||||||
|
static GC_bool is_frame_buffer(ptr_t start, size_t len, DWORD tp)
|
||||||
{
|
{
|
||||||
static GC_bool initialized = FALSE;
|
static GC_bool initialized = FALSE;
|
||||||
# define MB (1024*1024)
|
# define MB (1024*1024)
|
||||||
# define DEFAULT_FB_MB 15
|
# define DEFAULT_FB_MB 15
|
||||||
# define MIN_FB_MB 3
|
# define MIN_FB_MB 3
|
||||||
|
|
||||||
if (GC_disallow_ignore_fb) return FALSE;
|
if (GC_disallow_ignore_fb || tp != MEM_MAPPED) return FALSE;
|
||||||
if (!initialized) {
|
if (!initialized) {
|
||||||
char * ignore_fb_string = GETENV("GC_IGNORE_FB");
|
char * ignore_fb_string = GETENV("GC_IGNORE_FB");
|
||||||
|
|
||||||
|
@ -869,7 +885,7 @@ void GC_register_dynamic_libraries()
|
||||||
* !is_frame_buffer(p, buf.RegionSize, buf.Type)
|
* !is_frame_buffer(p, buf.RegionSize, buf.Type)
|
||||||
* instead of just checking for MEM_IMAGE.
|
* instead of just checking for MEM_IMAGE.
|
||||||
* If something breaks, change it back. */
|
* If something breaks, change it back. */
|
||||||
&& buf.Type == MEM_IMAGE) {
|
&& buf.Type == MEM_IMAGE) {
|
||||||
# ifdef DEBUG_VIRTUALQUERY
|
# ifdef DEBUG_VIRTUALQUERY
|
||||||
GC_dump_meminfo(&buf);
|
GC_dump_meminfo(&buf);
|
||||||
# endif
|
# endif
|
||||||
|
@ -1125,21 +1141,22 @@ static const char *GC_dyld_name_for_hdr(struct mach_header *hdr) {
|
||||||
static void GC_dyld_image_add(struct mach_header* hdr, unsigned long slide) {
|
static void GC_dyld_image_add(struct mach_header* hdr, unsigned long slide) {
|
||||||
unsigned long start,end,i;
|
unsigned long start,end,i;
|
||||||
const struct section *sec;
|
const struct section *sec;
|
||||||
|
if (GC_no_dls) return;
|
||||||
for(i=0;i<sizeof(GC_dyld_sections)/sizeof(GC_dyld_sections[0]);i++) {
|
for(i=0;i<sizeof(GC_dyld_sections)/sizeof(GC_dyld_sections[0]);i++) {
|
||||||
sec = getsectbynamefromheader(
|
sec = getsectbynamefromheader(
|
||||||
hdr,GC_dyld_sections[i].seg,GC_dyld_sections[i].sect);
|
hdr,GC_dyld_sections[i].seg,GC_dyld_sections[i].sect);
|
||||||
if(sec == NULL || sec->size == 0) continue;
|
if(sec == NULL || sec->size == 0) continue;
|
||||||
start = slide + sec->addr;
|
start = slide + sec->addr;
|
||||||
end = start + sec->size;
|
end = start + sec->size;
|
||||||
# ifdef DARWIN_DEBUG
|
|
||||||
GC_printf4("Adding section at %p-%p (%lu bytes) from image %s\n",
|
|
||||||
start,end,sec->size,GC_dyld_name_for_hdr(hdr));
|
|
||||||
# endif
|
|
||||||
GC_add_roots((char*)start,(char*)end);
|
|
||||||
}
|
|
||||||
# ifdef DARWIN_DEBUG
|
# ifdef DARWIN_DEBUG
|
||||||
GC_print_static_roots();
|
GC_printf4("Adding section at %p-%p (%lu bytes) from image %s\n",
|
||||||
# endif
|
start,end,sec->size,GC_dyld_name_for_hdr(hdr));
|
||||||
|
# endif
|
||||||
|
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 */
|
/* This should never be called by a thread holding the lock */
|
||||||
|
@ -1152,15 +1169,15 @@ static void GC_dyld_image_remove(struct mach_header* hdr, unsigned long slide) {
|
||||||
if(sec == NULL || sec->size == 0) continue;
|
if(sec == NULL || sec->size == 0) continue;
|
||||||
start = slide + sec->addr;
|
start = slide + sec->addr;
|
||||||
end = start + sec->size;
|
end = start + sec->size;
|
||||||
# ifdef DARWIN_DEBUG
|
# ifdef DARWIN_DEBUG
|
||||||
GC_printf4("Removing section at %p-%p (%lu bytes) from image %s\n",
|
GC_printf4("Removing section at %p-%p (%lu bytes) from image %s\n",
|
||||||
start,end,sec->size,GC_dyld_name_for_hdr(hdr));
|
start,end,sec->size,GC_dyld_name_for_hdr(hdr));
|
||||||
# endif
|
# endif
|
||||||
GC_remove_roots((char*)start,(char*)end);
|
GC_remove_roots((char*)start,(char*)end);
|
||||||
}
|
}
|
||||||
# ifdef DARWIN_DEBUG
|
# ifdef DARWIN_DEBUG
|
||||||
GC_print_static_roots();
|
GC_print_static_roots();
|
||||||
# endif
|
# endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void GC_register_dynamic_libraries() {
|
void GC_register_dynamic_libraries() {
|
||||||
|
|
|
@ -43,6 +43,8 @@ DIST_COMMON = $(noinst_HEADERS) $(srcdir)/Makefile.am \
|
||||||
$(srcdir)/gc_ext_config.h.in
|
$(srcdir)/gc_ext_config.h.in
|
||||||
ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
|
ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
|
||||||
am__aclocal_m4_deps = $(top_srcdir)/../config/acx.m4 \
|
am__aclocal_m4_deps = $(top_srcdir)/../config/acx.m4 \
|
||||||
|
$(top_srcdir)/../config/depstand.m4 \
|
||||||
|
$(top_srcdir)/../config/lead-dot.m4 \
|
||||||
$(top_srcdir)/../config/no-executables.m4 \
|
$(top_srcdir)/../config/no-executables.m4 \
|
||||||
$(top_srcdir)/../libtool.m4 $(top_srcdir)/configure.ac
|
$(top_srcdir)/../libtool.m4 $(top_srcdir)/configure.ac
|
||||||
am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
|
am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
|
||||||
|
|
|
@ -55,7 +55,7 @@
|
||||||
# include <gc_config.h>
|
# include <gc_config.h>
|
||||||
# include "gc_config_macros.h"
|
# include "gc_config_macros.h"
|
||||||
|
|
||||||
# if defined(__STDC__) || defined(__cplusplus)
|
# if defined(__STDC__) || defined(__cplusplus) || defined(_AIX)
|
||||||
# define GC_PROTO(args) args
|
# define GC_PROTO(args) args
|
||||||
typedef void * GC_PTR;
|
typedef void * GC_PTR;
|
||||||
# define GC_CONST const
|
# define GC_CONST const
|
||||||
|
@ -214,7 +214,7 @@ GC_API GC_word GC_free_space_divisor;
|
||||||
/* least N/GC_free_space_divisor bytes between */
|
/* least N/GC_free_space_divisor bytes between */
|
||||||
/* collections, where N is the heap size plus */
|
/* collections, where N is the heap size plus */
|
||||||
/* a rough estimate of the root set size. */
|
/* a rough estimate of the root set size. */
|
||||||
/* Initially, GC_free_space_divisor = 4. */
|
/* Initially, GC_free_space_divisor = 3. */
|
||||||
/* Increasing its value will use less space */
|
/* Increasing its value will use less space */
|
||||||
/* but more collection time. Decreasing it */
|
/* but more collection time. Decreasing it */
|
||||||
/* will appreciably decrease collection time */
|
/* will appreciably decrease collection time */
|
||||||
|
@ -340,6 +340,9 @@ GC_API void GC_end_stubborn_change GC_PROTO((GC_PTR));
|
||||||
/* the base of the user object. */
|
/* the base of the user object. */
|
||||||
/* Return 0 if displaced_pointer doesn't point to within a valid */
|
/* Return 0 if displaced_pointer doesn't point to within a valid */
|
||||||
/* object. */
|
/* object. */
|
||||||
|
/* Note that a deallocated object in the garbage collected heap */
|
||||||
|
/* may be considered valid, even if it has been deallocated with */
|
||||||
|
/* GC_free. */
|
||||||
GC_API GC_PTR GC_base GC_PROTO((GC_PTR displaced_pointer));
|
GC_API GC_PTR GC_base GC_PROTO((GC_PTR displaced_pointer));
|
||||||
|
|
||||||
/* Given a pointer to the base of an object, return its size in bytes. */
|
/* Given a pointer to the base of an object, return its size in bytes. */
|
||||||
|
@ -877,7 +880,7 @@ GC_API GC_PTR GC_is_valid_displacement GC_PROTO((GC_PTR p));
|
||||||
|
|
||||||
/* Safer assignment of a pointer to a nonstack location. */
|
/* Safer assignment of a pointer to a nonstack location. */
|
||||||
#ifdef GC_DEBUG
|
#ifdef GC_DEBUG
|
||||||
# ifdef __STDC__
|
# if defined(__STDC__) || defined(_AIX)
|
||||||
# define GC_PTR_STORE(p, q) \
|
# define GC_PTR_STORE(p, q) \
|
||||||
(*(void **)GC_is_visible(p) = GC_is_valid_displacement(q))
|
(*(void **)GC_is_visible(p) = GC_is_valid_displacement(q))
|
||||||
# else
|
# else
|
||||||
|
@ -972,12 +975,32 @@ extern void GC_thr_init GC_PROTO((void));/* Needed for Solaris/X86 */
|
||||||
# define GC_INIT() { extern end, etext; \
|
# define GC_INIT() { extern end, etext; \
|
||||||
GC_noop(&end, &etext); }
|
GC_noop(&end, &etext); }
|
||||||
#else
|
#else
|
||||||
# if defined(__CYGWIN32__) && defined(GC_DLL) || defined (_AIX)
|
# if defined(__CYGWIN32__) || defined (_AIX)
|
||||||
/*
|
/*
|
||||||
* Similarly gnu-win32 DLLs need explicit initialization from
|
* Similarly gnu-win32 DLLs need explicit initialization from
|
||||||
* the main program, as does AIX.
|
* the main program, as does AIX.
|
||||||
*/
|
*/
|
||||||
# define GC_INIT() { GC_add_roots(DATASTART, DATAEND); }
|
# ifdef __CYGWIN32__
|
||||||
|
extern int _data_start__[];
|
||||||
|
extern int _data_end__[];
|
||||||
|
extern int _bss_start__[];
|
||||||
|
extern int _bss_end__[];
|
||||||
|
# define GC_MAX(x,y) ((x) > (y) ? (x) : (y))
|
||||||
|
# define GC_MIN(x,y) ((x) < (y) ? (x) : (y))
|
||||||
|
# define GC_DATASTART ((GC_PTR) GC_MIN(_data_start__, _bss_start__))
|
||||||
|
# define GC_DATAEND ((GC_PTR) GC_MAX(_data_end__, _bss_end__))
|
||||||
|
# ifdef GC_DLL
|
||||||
|
# define GC_INIT() { GC_add_roots(GC_DATASTART, GC_DATAEND); }
|
||||||
|
# else
|
||||||
|
# define GC_INIT()
|
||||||
|
# endif
|
||||||
|
# endif
|
||||||
|
# if defined(_AIX)
|
||||||
|
extern int _data[], _end[];
|
||||||
|
# define GC_DATASTART ((GC_PTR)((ulong)_data))
|
||||||
|
# define GC_DATAEND ((GC_PTR)((ulong)_end))
|
||||||
|
# define GC_INIT() { GC_add_roots(GC_DATASTART, GC_DATAEND); }
|
||||||
|
# endif
|
||||||
# else
|
# else
|
||||||
# if defined(__APPLE__) && defined(__MACH__) || defined(GC_WIN32_THREADS)
|
# if defined(__APPLE__) && defined(__MACH__) || defined(GC_WIN32_THREADS)
|
||||||
# define GC_INIT() { GC_init(); }
|
# define GC_INIT() { GC_init(); }
|
||||||
|
|
|
@ -59,6 +59,10 @@
|
||||||
# define GC_DGUX386_THREADS
|
# define GC_DGUX386_THREADS
|
||||||
# define GC_PTHREADS
|
# define GC_PTHREADS
|
||||||
# endif
|
# endif
|
||||||
|
# if defined(_AIX)
|
||||||
|
# define GC_AIX_THREADS
|
||||||
|
# define GC_PTHREADS
|
||||||
|
# endif
|
||||||
#endif /* GC_THREADS */
|
#endif /* GC_THREADS */
|
||||||
|
|
||||||
#if defined(GC_THREADS) && !defined(GC_PTHREADS) && \
|
#if defined(GC_THREADS) && !defined(GC_PTHREADS) && \
|
||||||
|
|
|
@ -74,7 +74,7 @@ cycle, then that's considered a storage leak, and neither will be
|
||||||
collectable. See the interface gc.h for low-level facilities for
|
collectable. See the interface gc.h for low-level facilities for
|
||||||
handling such cycles of objects with clean-up.
|
handling such cycles of objects with clean-up.
|
||||||
|
|
||||||
The collector cannot guarrantee that it will find all inaccessible
|
The collector cannot guarantee that it will find all inaccessible
|
||||||
objects. In practice, it finds almost all of them.
|
objects. In practice, it finds almost all of them.
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -109,7 +109,7 @@ enum { GC_byte_alignment = 8 };
|
||||||
enum { GC_word_alignment = GC_byte_alignment/GC_bytes_per_word };
|
enum { GC_word_alignment = GC_byte_alignment/GC_bytes_per_word };
|
||||||
|
|
||||||
inline void * &GC_obj_link(void * p)
|
inline void * &GC_obj_link(void * p)
|
||||||
{ return *(void **)p; }
|
{ return *reinterpret_cast<void **>(p); }
|
||||||
|
|
||||||
// Compute a number of words >= n+1 bytes.
|
// Compute a number of words >= n+1 bytes.
|
||||||
// The +1 allows for pointers one past the end.
|
// The +1 allows for pointers one past the end.
|
||||||
|
@ -228,7 +228,7 @@ class single_client_gc_alloc_template {
|
||||||
} else {
|
} else {
|
||||||
flh = GC_objfreelist_ptr + nwords;
|
flh = GC_objfreelist_ptr + nwords;
|
||||||
GC_obj_link(p) = *flh;
|
GC_obj_link(p) = *flh;
|
||||||
memset((char *)p + GC_bytes_per_word, 0,
|
memset(reinterpret_cast<char *>(p) + GC_bytes_per_word, 0,
|
||||||
GC_bytes_per_word * (nwords - 1));
|
GC_bytes_per_word * (nwords - 1));
|
||||||
*flh = p;
|
*flh = p;
|
||||||
GC_aux::GC_mem_recently_freed += nwords;
|
GC_aux::GC_mem_recently_freed += nwords;
|
||||||
|
@ -352,9 +352,9 @@ class simple_alloc<T, alloc> { \
|
||||||
public: \
|
public: \
|
||||||
static T *allocate(size_t n) \
|
static T *allocate(size_t n) \
|
||||||
{ return 0 == n? 0 : \
|
{ return 0 == n? 0 : \
|
||||||
(T*) alloc::ptr_free_allocate(n * sizeof (T)); } \
|
reinterpret_cast<T*>(alloc::ptr_free_allocate(n * sizeof (T))); } \
|
||||||
static T *allocate(void) \
|
static T *allocate(void) \
|
||||||
{ return (T*) alloc::ptr_free_allocate(sizeof (T)); } \
|
{ return reinterpret_cast<T*>(alloc::ptr_free_allocate(sizeof (T))); } \
|
||||||
static void deallocate(T *p, size_t n) \
|
static void deallocate(T *p, size_t n) \
|
||||||
{ if (0 != n) alloc::ptr_free_deallocate(p, n * sizeof (T)); } \
|
{ if (0 != n) alloc::ptr_free_deallocate(p, n * sizeof (T)); } \
|
||||||
static void deallocate(T *p) \
|
static void deallocate(T *p) \
|
||||||
|
|
|
@ -108,7 +108,7 @@ extern hdr * GC_invalid_header; /* header for an imaginary block */
|
||||||
|
|
||||||
/* Analogous to GET_HDR, except that in the case of large objects, it */
|
/* Analogous to GET_HDR, except that in the case of large objects, it */
|
||||||
/* Returns the header for the object beginning, and updates p. */
|
/* Returns the header for the object beginning, and updates p. */
|
||||||
/* Returns &GC_bad_header instead of 0. All of this saves a branch */
|
/* Returns GC_invalid_header instead of 0. All of this saves a branch */
|
||||||
/* in the fast path. */
|
/* in the fast path. */
|
||||||
# define HC_GET_HDR(p, hhdr, source) \
|
# define HC_GET_HDR(p, hhdr, source) \
|
||||||
{ \
|
{ \
|
||||||
|
|
|
@ -139,6 +139,25 @@
|
||||||
# define GC_TEST_AND_SET_DEFINED
|
# define GC_TEST_AND_SET_DEFINED
|
||||||
# endif
|
# endif
|
||||||
# if defined(POWERPC)
|
# if defined(POWERPC)
|
||||||
|
# if CPP_WORDSZ == 64
|
||||||
|
inline static int GC_test_and_set(volatile unsigned int *addr) {
|
||||||
|
unsigned long oldval;
|
||||||
|
unsigned long temp = 1; /* locked value */
|
||||||
|
|
||||||
|
__asm__ __volatile__(
|
||||||
|
"1:\tldarx %0,0,%3\n" /* load and reserve */
|
||||||
|
"\tcmpdi %0, 0\n" /* if load is */
|
||||||
|
"\tbne 2f\n" /* non-zero, return already set */
|
||||||
|
"\tstdcx. %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)
|
||||||
|
: "cr0","memory");
|
||||||
|
return (int)oldval;
|
||||||
|
}
|
||||||
|
# else
|
||||||
inline static int GC_test_and_set(volatile unsigned int *addr) {
|
inline static int GC_test_and_set(volatile unsigned int *addr) {
|
||||||
int oldval;
|
int oldval;
|
||||||
int temp = 1; /* locked value */
|
int temp = 1; /* locked value */
|
||||||
|
@ -156,12 +175,13 @@
|
||||||
: "cr0","memory");
|
: "cr0","memory");
|
||||||
return oldval;
|
return oldval;
|
||||||
}
|
}
|
||||||
# define GC_TEST_AND_SET_DEFINED
|
# endif
|
||||||
inline static void GC_clear(volatile unsigned int *addr) {
|
# define GC_TEST_AND_SET_DEFINED
|
||||||
__asm__ __volatile__("eieio" : : : "memory");
|
inline static void GC_clear(volatile unsigned int *addr) {
|
||||||
*(addr) = 0;
|
__asm__ __volatile__("lwsync" : : : "memory");
|
||||||
}
|
*(addr) = 0;
|
||||||
# define GC_CLEAR_DEFINED
|
}
|
||||||
|
# define GC_CLEAR_DEFINED
|
||||||
# endif
|
# endif
|
||||||
# if defined(ALPHA)
|
# if defined(ALPHA)
|
||||||
inline static int GC_test_and_set(volatile unsigned int * addr)
|
inline static int GC_test_and_set(volatile unsigned int * addr)
|
||||||
|
@ -282,6 +302,8 @@
|
||||||
# define GC_test_and_set(addr) test_and_set((void *)addr,1)
|
# define GC_test_and_set(addr) test_and_set((void *)addr,1)
|
||||||
# endif
|
# endif
|
||||||
# else
|
# else
|
||||||
|
# include <sgidefs.h>
|
||||||
|
# include <mutex.h>
|
||||||
# define GC_test_and_set(addr) __test_and_set32((void *)addr,1)
|
# define GC_test_and_set(addr) __test_and_set32((void *)addr,1)
|
||||||
# define GC_clear(addr) __lock_release(addr);
|
# define GC_clear(addr) __lock_release(addr);
|
||||||
# define GC_CLEAR_DEFINED
|
# define GC_CLEAR_DEFINED
|
||||||
|
@ -354,7 +376,7 @@
|
||||||
# endif
|
# endif
|
||||||
|
|
||||||
# if defined(GC_PTHREADS) && !defined(GC_SOLARIS_THREADS) \
|
# if defined(GC_PTHREADS) && !defined(GC_SOLARIS_THREADS) \
|
||||||
&& !defined(GC_IRIX_THREADS) && !defined(GC_WIN32_THREADS)
|
&& !defined(GC_WIN32_THREADS)
|
||||||
# define NO_THREAD (pthread_t)(-1)
|
# define NO_THREAD (pthread_t)(-1)
|
||||||
# include <pthread.h>
|
# include <pthread.h>
|
||||||
# if defined(PARALLEL_MARK)
|
# if defined(PARALLEL_MARK)
|
||||||
|
@ -401,6 +423,29 @@
|
||||||
|
|
||||||
# if defined(POWERPC)
|
# if defined(POWERPC)
|
||||||
# if !defined(GENERIC_COMPARE_AND_SWAP)
|
# if !defined(GENERIC_COMPARE_AND_SWAP)
|
||||||
|
# if CPP_WORDSZ == 64
|
||||||
|
/* 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)
|
||||||
|
{
|
||||||
|
unsigned long result, dummy;
|
||||||
|
__asm__ __volatile__(
|
||||||
|
"1:\tldarx %0,0,%5\n"
|
||||||
|
"\tcmpd %0,%4\n"
|
||||||
|
"\tbne 2f\n"
|
||||||
|
"\tstdcx. %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;
|
||||||
|
}
|
||||||
|
# else
|
||||||
/* Returns TRUE if the comparison succeeded. */
|
/* Returns TRUE if the comparison succeeded. */
|
||||||
inline static GC_bool GC_compare_and_exchange(volatile GC_word *addr,
|
inline static GC_bool GC_compare_and_exchange(volatile GC_word *addr,
|
||||||
GC_word old, GC_word new_val)
|
GC_word old, GC_word new_val)
|
||||||
|
@ -422,6 +467,7 @@
|
||||||
: "cr0","memory");
|
: "cr0","memory");
|
||||||
return (GC_bool) result;
|
return (GC_bool) result;
|
||||||
}
|
}
|
||||||
|
# endif
|
||||||
# endif /* !GENERIC_COMPARE_AND_SWAP */
|
# endif /* !GENERIC_COMPARE_AND_SWAP */
|
||||||
inline static void GC_memory_barrier()
|
inline static void GC_memory_barrier()
|
||||||
{
|
{
|
||||||
|
@ -598,33 +644,6 @@
|
||||||
extern pthread_t GC_mark_lock_holder;
|
extern pthread_t GC_mark_lock_holder;
|
||||||
# endif
|
# endif
|
||||||
# endif /* GC_PTHREADS with linux_threads.c implementation */
|
# endif /* GC_PTHREADS with linux_threads.c implementation */
|
||||||
# if defined(GC_IRIX_THREADS)
|
|
||||||
# include <pthread.h>
|
|
||||||
/* This probably should never be included, but I can't test */
|
|
||||||
/* on Irix anymore. */
|
|
||||||
# include <mutex.h>
|
|
||||||
|
|
||||||
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. */
|
|
||||||
extern pthread_t GC_lock_holder;
|
|
||||||
extern void GC_lock(void);
|
|
||||||
/* Allocation lock holder. Only set if acquired by client through */
|
|
||||||
/* GC_call_with_alloc_lock. */
|
|
||||||
# define SET_LOCK_HOLDER() GC_lock_holder = pthread_self()
|
|
||||||
# define NO_THREAD (pthread_t)(-1)
|
|
||||||
# define UNSET_LOCK_HOLDER() GC_lock_holder = NO_THREAD
|
|
||||||
# define I_HOLD_LOCK() (pthread_equal(GC_lock_holder, pthread_self()))
|
|
||||||
# define LOCK() { if (GC_test_and_set(&GC_allocate_lock)) GC_lock(); }
|
|
||||||
# define UNLOCK() GC_clear(&GC_allocate_lock);
|
|
||||||
extern VOLATILE GC_bool GC_collecting;
|
|
||||||
# define ENTER_GC() \
|
|
||||||
{ \
|
|
||||||
GC_collecting = 1; \
|
|
||||||
}
|
|
||||||
# define EXIT_GC() GC_collecting = 0;
|
|
||||||
# endif /* GC_IRIX_THREADS */
|
|
||||||
# if defined(GC_WIN32_THREADS)
|
# if defined(GC_WIN32_THREADS)
|
||||||
# if defined(GC_PTHREADS)
|
# if defined(GC_PTHREADS)
|
||||||
# include <pthread.h>
|
# include <pthread.h>
|
||||||
|
|
|
@ -262,17 +262,6 @@ typedef char * ptr_t; /* A generic pointer to which we can add */
|
||||||
/* */
|
/* */
|
||||||
/*********************************/
|
/*********************************/
|
||||||
|
|
||||||
#ifdef SAVE_CALL_CHAIN
|
|
||||||
|
|
||||||
/* Fill in the pc and argument information for up to NFRAMES of my */
|
|
||||||
/* callers. Ignore my frame and my callers frame. */
|
|
||||||
struct callinfo;
|
|
||||||
void GC_save_callers GC_PROTO((struct callinfo info[NFRAMES]));
|
|
||||||
|
|
||||||
void GC_print_callers GC_PROTO((struct callinfo info[NFRAMES]));
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef NEED_CALLINFO
|
#ifdef NEED_CALLINFO
|
||||||
struct callinfo {
|
struct callinfo {
|
||||||
word ci_pc; /* Caller, not callee, pc */
|
word ci_pc; /* Caller, not callee, pc */
|
||||||
|
@ -286,6 +275,16 @@ void GC_print_callers GC_PROTO((struct callinfo info[NFRAMES]));
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef SAVE_CALL_CHAIN
|
||||||
|
|
||||||
|
/* Fill in the pc and argument information for up to NFRAMES of my */
|
||||||
|
/* callers. Ignore my frame and my callers frame. */
|
||||||
|
void GC_save_callers GC_PROTO((struct callinfo info[NFRAMES]));
|
||||||
|
|
||||||
|
void GC_print_callers GC_PROTO((struct callinfo info[NFRAMES]));
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
/*********************************/
|
/*********************************/
|
||||||
/* */
|
/* */
|
||||||
|
|
|
@ -55,7 +55,7 @@
|
||||||
# endif
|
# endif
|
||||||
|
|
||||||
/* And one for FreeBSD: */
|
/* And one for FreeBSD: */
|
||||||
# if defined(__FreeBSD__)
|
# if defined(__FreeBSD__) && !defined(FREEBSD)
|
||||||
# define FREEBSD
|
# define FREEBSD
|
||||||
# endif
|
# endif
|
||||||
|
|
||||||
|
@ -97,6 +97,10 @@
|
||||||
# define ARM32
|
# define ARM32
|
||||||
# define mach_type_known
|
# define mach_type_known
|
||||||
# endif
|
# endif
|
||||||
|
# if defined(NETBSD) && defined(__sh__)
|
||||||
|
# define SH
|
||||||
|
# define mach_type_known
|
||||||
|
# endif
|
||||||
# if defined(vax)
|
# if defined(vax)
|
||||||
# define VAX
|
# define VAX
|
||||||
# ifdef ultrix
|
# ifdef ultrix
|
||||||
|
@ -167,7 +171,7 @@
|
||||||
# define mach_type_known
|
# define mach_type_known
|
||||||
# endif
|
# endif
|
||||||
# if defined(sparc) && defined(unix) && !defined(sun) && !defined(linux) \
|
# if defined(sparc) && defined(unix) && !defined(sun) && !defined(linux) \
|
||||||
&& !defined(__OpenBSD__) && !(__NetBSD__)
|
&& !defined(__OpenBSD__) && !defined(__NetBSD__) && !defined(__FreeBSD__)
|
||||||
# define SPARC
|
# define SPARC
|
||||||
# define DRSNX
|
# define DRSNX
|
||||||
# define mach_type_known
|
# define mach_type_known
|
||||||
|
@ -198,14 +202,16 @@
|
||||||
# if defined(_PA_RISC1_0) || defined(_PA_RISC1_1) || defined(_PA_RISC2_0) \
|
# if defined(_PA_RISC1_0) || defined(_PA_RISC1_1) || defined(_PA_RISC2_0) \
|
||||||
|| defined(hppa) || defined(__hppa__)
|
|| defined(hppa) || defined(__hppa__)
|
||||||
# define HP_PA
|
# define HP_PA
|
||||||
# ifndef LINUX
|
# if !defined(LINUX) && !defined(HPUX)
|
||||||
# define HPUX
|
# define HPUX
|
||||||
# endif
|
# endif
|
||||||
# define mach_type_known
|
# define mach_type_known
|
||||||
# endif
|
# endif
|
||||||
# if defined(__ia64) && defined(_HPUX_SOURCE)
|
# if defined(__ia64) && defined(_HPUX_SOURCE)
|
||||||
# define IA64
|
# define IA64
|
||||||
# define HPUX
|
# ifndef HPUX
|
||||||
|
# define HPUX
|
||||||
|
# endif
|
||||||
# define mach_type_known
|
# define mach_type_known
|
||||||
# endif
|
# endif
|
||||||
# if defined(__BEOS__) && defined(_X86_)
|
# if defined(__BEOS__) && defined(_X86_)
|
||||||
|
@ -235,7 +241,8 @@
|
||||||
# endif
|
# endif
|
||||||
# define mach_type_known
|
# define mach_type_known
|
||||||
# endif
|
# endif
|
||||||
# if defined(LINUX) && (defined(powerpc) || defined(__powerpc__) || defined(powerpc64) || defined(__powerpc64__))
|
# if defined(LINUX) && (defined(powerpc) || defined(__powerpc__) || \
|
||||||
|
defined(powerpc64) || defined(__powerpc64__))
|
||||||
# define POWERPC
|
# define POWERPC
|
||||||
# define mach_type_known
|
# define mach_type_known
|
||||||
# endif
|
# endif
|
||||||
|
@ -293,11 +300,11 @@
|
||||||
# define DARWIN
|
# define DARWIN
|
||||||
# define POWERPC
|
# define POWERPC
|
||||||
# define mach_type_known
|
# define mach_type_known
|
||||||
# endif
|
# else
|
||||||
# if defined(__APPLE__) && defined(__MACH__) && defined(__i386__)
|
# if defined(__i386__)
|
||||||
# define DARWIN
|
# define I386
|
||||||
# define I386
|
|
||||||
--> Not really supported, but at least we recognize it.
|
--> Not really supported, but at least we recognize it.
|
||||||
|
# endif
|
||||||
# endif
|
# endif
|
||||||
# if defined(NeXT) && defined(mc68000)
|
# if defined(NeXT) && defined(mc68000)
|
||||||
# define M68K
|
# define M68K
|
||||||
|
@ -326,6 +333,10 @@
|
||||||
# define X86_64
|
# define X86_64
|
||||||
# define mach_type_known
|
# define mach_type_known
|
||||||
# endif
|
# endif
|
||||||
|
# if defined(FREEBSD) && defined(__sparc__)
|
||||||
|
# define SPARC
|
||||||
|
# define mach_type_known
|
||||||
|
#endif
|
||||||
# if defined(bsdi) && (defined(i386) || defined(__i386__))
|
# if defined(bsdi) && (defined(i386) || defined(__i386__))
|
||||||
# define I386
|
# define I386
|
||||||
# define BSDI
|
# define BSDI
|
||||||
|
@ -486,6 +497,9 @@
|
||||||
/* POWERPC ==> IBM/Apple PowerPC */
|
/* POWERPC ==> IBM/Apple PowerPC */
|
||||||
/* (MACOS(<=9),DARWIN(incl.MACOSX),*/
|
/* (MACOS(<=9),DARWIN(incl.MACOSX),*/
|
||||||
/* LINUX, NETBSD, NOSYS variants) */
|
/* LINUX, NETBSD, NOSYS variants) */
|
||||||
|
/* Handles 32 and 64-bit variants. */
|
||||||
|
/* AIX should be handled here, but */
|
||||||
|
/* that's called an RS6000. */
|
||||||
/* CRIS ==> Axis Etrax */
|
/* CRIS ==> Axis Etrax */
|
||||||
/* M32R ==> Renesas M32R */
|
/* M32R ==> Renesas M32R */
|
||||||
|
|
||||||
|
@ -493,12 +507,12 @@
|
||||||
/*
|
/*
|
||||||
* For each architecture and OS, the following need to be defined:
|
* For each architecture and OS, the following need to be defined:
|
||||||
*
|
*
|
||||||
* CPP_WORD_SZ is a simple integer constant representing the word size.
|
* CPP_WORDSZ is a simple integer constant representing the word size.
|
||||||
* in bits. We assume byte addressibility, where a byte has 8 bits.
|
* in bits. We assume byte addressibility, where a byte has 8 bits.
|
||||||
* We also assume CPP_WORD_SZ is either 32 or 64.
|
* We also assume CPP_WORDSZ is either 32 or 64.
|
||||||
* (We care about the length of pointers, not hardware
|
* (We care about the length of pointers, not hardware
|
||||||
* bus widths. Thus a 64 bit processor with a C compiler that uses
|
* bus widths. Thus a 64 bit processor with a C compiler that uses
|
||||||
* 32 bit pointers should use CPP_WORD_SZ of 32, not 64. Default is 32.)
|
* 32 bit pointers should use CPP_WORDSZ of 32, not 64. Default is 32.)
|
||||||
*
|
*
|
||||||
* MACH_TYPE is a string representation of the machine type.
|
* MACH_TYPE is a string representation of the machine type.
|
||||||
* OS_TYPE is analogous for the OS.
|
* OS_TYPE is analogous for the OS.
|
||||||
|
@ -615,7 +629,8 @@
|
||||||
*/
|
*/
|
||||||
# if defined(__GNUC__) && ((__GNUC__ >= 3) || \
|
# if defined(__GNUC__) && ((__GNUC__ >= 3) || \
|
||||||
(__GNUC__ == 2 && __GNUC_MINOR__ >= 8)) \
|
(__GNUC__ == 2 && __GNUC_MINOR__ >= 8)) \
|
||||||
&& !defined(__INTEL_COMPILER)
|
&& !defined(__INTEL_COMPILER) \
|
||||||
|
&& !defined(__PATHCC__)
|
||||||
# define HAVE_BUILTIN_UNWIND_INIT
|
# define HAVE_BUILTIN_UNWIND_INIT
|
||||||
# endif
|
# endif
|
||||||
|
|
||||||
|
@ -740,7 +755,7 @@
|
||||||
# endif
|
# endif
|
||||||
# endif
|
# endif
|
||||||
|
|
||||||
# ifdef POWERPC
|
# if defined(POWERPC)
|
||||||
# define MACH_TYPE "POWERPC"
|
# define MACH_TYPE "POWERPC"
|
||||||
# ifdef MACOS
|
# ifdef MACOS
|
||||||
# define ALIGNMENT 2 /* Still necessary? Could it be 4? */
|
# define ALIGNMENT 2 /* Still necessary? Could it be 4? */
|
||||||
|
@ -753,10 +768,12 @@
|
||||||
# define DATAEND /* not needed */
|
# define DATAEND /* not needed */
|
||||||
# endif
|
# endif
|
||||||
# ifdef LINUX
|
# ifdef LINUX
|
||||||
# if (defined (powerpc64) || defined(__powerpc64__))
|
# if defined(__powerpc64__)
|
||||||
# define ALIGNMENT 8
|
# define ALIGNMENT 8
|
||||||
# define CPP_WORDSZ 64
|
# define CPP_WORDSZ 64
|
||||||
# define HBLKSIZE 4096
|
# ifndef HBLKSIZE
|
||||||
|
# define HBLKSIZE 4096
|
||||||
|
# endif
|
||||||
# else
|
# else
|
||||||
# define ALIGNMENT 4
|
# define ALIGNMENT 4
|
||||||
# endif
|
# endif
|
||||||
|
@ -770,7 +787,7 @@
|
||||||
# define DATAEND (_end)
|
# define DATAEND (_end)
|
||||||
# endif
|
# endif
|
||||||
# ifdef DARWIN
|
# ifdef DARWIN
|
||||||
# if (defined (__ppc64__))
|
# ifdef __ppc64__
|
||||||
# define ALIGNMENT 8
|
# define ALIGNMENT 8
|
||||||
# define CPP_WORDSZ 64
|
# define CPP_WORDSZ 64
|
||||||
# else
|
# else
|
||||||
|
@ -787,8 +804,10 @@
|
||||||
# define USE_MMAP_ANON
|
# define USE_MMAP_ANON
|
||||||
# define USE_ASM_PUSH_REGS
|
# define USE_ASM_PUSH_REGS
|
||||||
/* This is potentially buggy. It needs more testing. See the comments in
|
/* This is potentially buggy. It needs more testing. See the comments in
|
||||||
os_dep.c */
|
os_dep.c. It relies on threads to track writes. */
|
||||||
# define MPROTECT_VDB
|
# ifdef GC_DARWIN_THREADS
|
||||||
|
/* # define MPROTECT_VDB -- diabled for now. May work for some apps. */
|
||||||
|
# endif
|
||||||
# include <unistd.h>
|
# include <unistd.h>
|
||||||
# define GETPAGESIZE() getpagesize()
|
# define GETPAGESIZE() getpagesize()
|
||||||
# if defined(USE_PPC_PREFETCH) && defined(__GNUC__)
|
# if defined(USE_PPC_PREFETCH) && defined(__GNUC__)
|
||||||
|
@ -975,6 +994,23 @@
|
||||||
# define DATASTART ((ptr_t)(etext))
|
# define DATASTART ((ptr_t)(etext))
|
||||||
# endif
|
# endif
|
||||||
# endif
|
# endif
|
||||||
|
# ifdef FREEBSD
|
||||||
|
# define OS_TYPE "FREEBSD"
|
||||||
|
# define SIG_SUSPEND SIGUSR1
|
||||||
|
# define SIG_THR_RESTART SIGUSR2
|
||||||
|
# define FREEBSD_STACKBOTTOM
|
||||||
|
# ifdef __ELF__
|
||||||
|
# define DYNAMIC_LOADING
|
||||||
|
# endif
|
||||||
|
extern char etext[];
|
||||||
|
extern char edata[];
|
||||||
|
extern char end[];
|
||||||
|
# define NEED_FIND_LIMIT
|
||||||
|
# define DATASTART ((ptr_t)(&etext))
|
||||||
|
# define DATAEND (GC_find_limit (DATASTART, TRUE))
|
||||||
|
# define DATASTART2 ((ptr_t)(&edata))
|
||||||
|
# define DATAEND2 ((ptr_t)(&end))
|
||||||
|
# endif
|
||||||
# endif
|
# endif
|
||||||
|
|
||||||
# ifdef I386
|
# ifdef I386
|
||||||
|
@ -1158,26 +1194,8 @@
|
||||||
# endif
|
# endif
|
||||||
# ifdef CYGWIN32
|
# ifdef CYGWIN32
|
||||||
# define OS_TYPE "CYGWIN32"
|
# define OS_TYPE "CYGWIN32"
|
||||||
extern int _data_start__[];
|
# define DATASTART ((ptr_t)GC_DATASTART) /* From gc.h */
|
||||||
extern int _data_end__[];
|
# define DATAEND ((ptr_t)GC_DATAEND)
|
||||||
extern int _bss_start__[];
|
|
||||||
extern int _bss_end__[];
|
|
||||||
/* For binutils 2.9.1, we have */
|
|
||||||
/* DATASTART = _data_start__ */
|
|
||||||
/* DATAEND = _bss_end__ */
|
|
||||||
/* whereas for some earlier versions it was */
|
|
||||||
/* DATASTART = _bss_start__ */
|
|
||||||
/* 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
|
# undef STACK_GRAN
|
||||||
# define STACK_GRAN 0x10000
|
# define STACK_GRAN 0x10000
|
||||||
# define HEURISTIC1
|
# define HEURISTIC1
|
||||||
|
@ -1421,6 +1439,8 @@
|
||||||
# define CPP_WORDSZ 32
|
# define CPP_WORDSZ 32
|
||||||
# define STACKBOTTOM ((ptr_t)((ulong)&errno))
|
# define STACKBOTTOM ((ptr_t)((ulong)&errno))
|
||||||
# endif
|
# endif
|
||||||
|
# define USE_MMAP
|
||||||
|
# define USE_MMAP_ANON
|
||||||
/* From AIX linker man page:
|
/* From AIX linker man page:
|
||||||
_text Specifies the first location of the program.
|
_text Specifies the first location of the program.
|
||||||
_etext Specifies the first location after the program.
|
_etext Specifies the first location after the program.
|
||||||
|
@ -1728,7 +1748,7 @@
|
||||||
# define USE_GENERIC_PUSH_REGS
|
# define USE_GENERIC_PUSH_REGS
|
||||||
# ifdef UTS4
|
# ifdef UTS4
|
||||||
# define OS_TYPE "UTS4"
|
# define OS_TYPE "UTS4"
|
||||||
extern int etext[];
|
extern int etext[];
|
||||||
extern int _etext[];
|
extern int _etext[];
|
||||||
extern int _end[];
|
extern int _end[];
|
||||||
extern ptr_t GC_SysVGetDataStart();
|
extern ptr_t GC_SysVGetDataStart();
|
||||||
|
@ -1742,18 +1762,20 @@
|
||||||
# define MACH_TYPE "S390"
|
# define MACH_TYPE "S390"
|
||||||
# define USE_GENERIC_PUSH_REGS
|
# define USE_GENERIC_PUSH_REGS
|
||||||
# ifndef __s390x__
|
# ifndef __s390x__
|
||||||
# define ALIGNMENT 4
|
# define ALIGNMENT 4
|
||||||
# define CPP_WORDSZ 32
|
# define CPP_WORDSZ 32
|
||||||
# else
|
# else
|
||||||
# define ALIGNMENT 8
|
# define ALIGNMENT 8
|
||||||
# define CPP_WORDSZ 64
|
# define CPP_WORDSZ 64
|
||||||
# define HBLKSIZE 4096
|
# endif
|
||||||
|
# ifndef HBLKSIZE
|
||||||
|
# define HBLKSIZE 4096
|
||||||
# endif
|
# endif
|
||||||
# ifdef LINUX
|
# ifdef LINUX
|
||||||
# define OS_TYPE "LINUX"
|
# define OS_TYPE "LINUX"
|
||||||
# define LINUX_STACKBOTTOM
|
# define LINUX_STACKBOTTOM
|
||||||
# define DYNAMIC_LOADING
|
# define DYNAMIC_LOADING
|
||||||
extern int __data_start[];
|
extern int __data_start[];
|
||||||
# define DATASTART ((ptr_t)(__data_start))
|
# define DATASTART ((ptr_t)(__data_start))
|
||||||
extern int _end[];
|
extern int _end[];
|
||||||
# define DATAEND (_end)
|
# define DATAEND (_end)
|
||||||
|
@ -1859,6 +1881,13 @@
|
||||||
extern int _end[];
|
extern int _end[];
|
||||||
# define DATAEND (_end)
|
# define DATAEND (_end)
|
||||||
# endif
|
# endif
|
||||||
|
# ifdef NETBSD
|
||||||
|
# define OS_TYPE "NETBSD"
|
||||||
|
# define HEURISTIC2
|
||||||
|
# define DATASTART GC_data_start
|
||||||
|
# define USE_GENERIC_PUSH_REGS
|
||||||
|
# define DYNAMIC_LOADING
|
||||||
|
# endif
|
||||||
# endif
|
# endif
|
||||||
|
|
||||||
# ifdef SH4
|
# ifdef SH4
|
||||||
|
@ -2107,7 +2136,8 @@
|
||||||
# define THREADS
|
# define THREADS
|
||||||
# endif
|
# endif
|
||||||
|
|
||||||
# if defined(HP_PA) || defined(M88K) || defined(POWERPC) && !defined(DARWIN) \
|
# if defined(HP_PA) || defined(M88K) \
|
||||||
|
|| defined(POWERPC) && !defined(DARWIN) \
|
||||||
|| defined(LINT) || defined(MSWINCE) || defined(ARM32) || defined(CRIS) \
|
|| defined(LINT) || defined(MSWINCE) || defined(ARM32) || defined(CRIS) \
|
||||||
|| (defined(I386) && defined(__LCC__))
|
|| (defined(I386) && defined(__LCC__))
|
||||||
/* Use setjmp based hack to mark from callee-save registers. */
|
/* Use setjmp based hack to mark from callee-save registers. */
|
||||||
|
@ -2249,7 +2279,7 @@
|
||||||
# else
|
# else
|
||||||
# if defined(AMIGA) && defined(GC_AMIGA_FASTALLOC)
|
# if defined(AMIGA) && defined(GC_AMIGA_FASTALLOC)
|
||||||
extern void *GC_amiga_get_mem(size_t size);
|
extern void *GC_amiga_get_mem(size_t size);
|
||||||
# define GET_MEM(bytes) HBLKPTR((size_t) \
|
# define GET_MEM(bytes) HBLKPTR((size_t) \
|
||||||
GC_amiga_get_mem((size_t)bytes + GC_page_size) \
|
GC_amiga_get_mem((size_t)bytes + GC_page_size) \
|
||||||
+ GC_page_size-1)
|
+ GC_page_size-1)
|
||||||
# else
|
# else
|
||||||
|
@ -2265,4 +2295,10 @@
|
||||||
|
|
||||||
#endif /* GC_PRIVATE_H */
|
#endif /* GC_PRIVATE_H */
|
||||||
|
|
||||||
|
#if defined(_AIX) && !defined(__GNUC__) && !defined(__STDC__)
|
||||||
|
/* IBMs xlc compiler doesn't appear to follow the convention of */
|
||||||
|
/* defining __STDC__ to be zero in extended mode. */
|
||||||
|
# define __STDC__ 0
|
||||||
|
#endif
|
||||||
|
|
||||||
# endif /* GCCONFIG_H */
|
# endif /* GCCONFIG_H */
|
||||||
|
|
|
@ -2,7 +2,6 @@
|
||||||
#define GC_PTHREAD_STOP_WORLD_H
|
#define GC_PTHREAD_STOP_WORLD_H
|
||||||
|
|
||||||
struct thread_stop_info {
|
struct thread_stop_info {
|
||||||
int signal;
|
|
||||||
word last_stop_count; /* GC_last_stop_count value when thread */
|
word last_stop_count; /* GC_last_stop_count value when thread */
|
||||||
/* last successfully handled a suspend */
|
/* last successfully handled a suspend */
|
||||||
/* signal. */
|
/* signal. */
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
# include "private/gc_priv.h"
|
# include "private/gc_priv.h"
|
||||||
|
|
||||||
# if defined(GC_PTHREADS) && !defined(GC_SOLARIS_THREADS) \
|
# if defined(GC_PTHREADS) && !defined(GC_SOLARIS_THREADS) \
|
||||||
&& !defined(GC_IRIX_THREADS) && !defined(GC_WIN32_THREADS)
|
&& !defined(GC_WIN32_THREADS)
|
||||||
|
|
||||||
#if defined(GC_DARWIN_THREADS)
|
#if defined(GC_DARWIN_THREADS)
|
||||||
# include "private/darwin_stop_world.h"
|
# include "private/darwin_stop_world.h"
|
||||||
|
|
|
@ -27,6 +27,10 @@
|
||||||
# endif
|
# endif
|
||||||
# endif
|
# endif
|
||||||
|
|
||||||
|
#if defined(RS6000) || defined(POWERPC)
|
||||||
|
# include <ucontext.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#if defined(__MWERKS__) && !defined(POWERPC)
|
#if defined(__MWERKS__) && !defined(POWERPC)
|
||||||
|
|
||||||
asm static void PushMacRegisters()
|
asm static void PushMacRegisters()
|
||||||
|
@ -413,6 +417,13 @@ ptr_t arg;
|
||||||
/* the stack. */
|
/* the stack. */
|
||||||
__builtin_unwind_init();
|
__builtin_unwind_init();
|
||||||
# else /* !HAVE_BUILTIN_UNWIND_INIT */
|
# else /* !HAVE_BUILTIN_UNWIND_INIT */
|
||||||
|
# if defined(RS6000) || defined(POWERPC)
|
||||||
|
/* FIXME: RS6000 means AIX. */
|
||||||
|
/* This should probably be used in all Posix/non-gcc */
|
||||||
|
/* settings. We defer that change to minimize risk. */
|
||||||
|
ucontext_t ctxt;
|
||||||
|
getcontext(&ctxt);
|
||||||
|
# else
|
||||||
/* Generic code */
|
/* Generic code */
|
||||||
/* The idea is due to Parag Patel at HP. */
|
/* The idea is due to Parag Patel at HP. */
|
||||||
/* We're not sure whether he would like */
|
/* We're not sure whether he would like */
|
||||||
|
@ -426,7 +437,7 @@ ptr_t arg;
|
||||||
for (; (char *)i < lim; i++) {
|
for (; (char *)i < lim; i++) {
|
||||||
*i = 0;
|
*i = 0;
|
||||||
}
|
}
|
||||||
# if defined(POWERPC) || defined(MSWIN32) || defined(MSWINCE) \
|
# if defined(MSWIN32) || defined(MSWINCE) \
|
||||||
|| defined(UTS4) || defined(LINUX) || defined(EWS4800)
|
|| defined(UTS4) || defined(LINUX) || defined(EWS4800)
|
||||||
(void) setjmp(regs);
|
(void) setjmp(regs);
|
||||||
# else
|
# else
|
||||||
|
@ -435,15 +446,16 @@ ptr_t arg;
|
||||||
/* SUSV3, setjmp() may or may not save signal mask. */
|
/* SUSV3, setjmp() may or may not save signal mask. */
|
||||||
/* _setjmp won't, but is less portable. */
|
/* _setjmp won't, but is less portable. */
|
||||||
# endif
|
# endif
|
||||||
|
# endif /* !AIX ... */
|
||||||
# endif /* !HAVE_BUILTIN_UNWIND_INIT */
|
# endif /* !HAVE_BUILTIN_UNWIND_INIT */
|
||||||
# elif defined(PTHREADS) && !defined(MSWIN32) /* !USE_GENERIC_PUSH_REGS */
|
# else
|
||||||
/* We may still need this to save thread contexts. */
|
# if defined(PTHREADS) && !defined(MSWIN32) /* !USE_GENERIC_PUSH_REGS */
|
||||||
/* This should probably be used in all Posix/non-gcc */
|
/* We may still need this to save thread contexts. */
|
||||||
/* settings. We defer that change to minimize risk. */
|
ucontext_t ctxt;
|
||||||
ucontext_t ctxt;
|
getcontext(&ctxt);
|
||||||
getcontext(&ctxt);
|
# else /* Shouldn't be needed */
|
||||||
# else /* Shouldn't be needed */
|
ABORT("Unexpected call to GC_with_callee_saves_pushed");
|
||||||
ABORT("Unexpected call to GC_with_callee_saves_pushed");
|
# endif
|
||||||
# endif
|
# endif
|
||||||
# if (defined(SPARC) && !defined(HAVE_BUILTIN_UNWIND_INIT)) \
|
# if (defined(SPARC) && !defined(HAVE_BUILTIN_UNWIND_INIT)) \
|
||||||
|| defined(IA64)
|
|| defined(IA64)
|
||||||
|
@ -480,7 +492,7 @@ ptr_t cold_gc_frame;
|
||||||
/* the stack. Return sp. */
|
/* the stack. Return sp. */
|
||||||
# ifdef SPARC
|
# ifdef SPARC
|
||||||
asm(" .seg \"text\"");
|
asm(" .seg \"text\"");
|
||||||
# if defined(SVR4) || defined(NETBSD)
|
# if defined(SVR4) || defined(NETBSD) || defined(FREEBSD)
|
||||||
asm(" .globl GC_save_regs_in_stack");
|
asm(" .globl GC_save_regs_in_stack");
|
||||||
asm("GC_save_regs_in_stack:");
|
asm("GC_save_regs_in_stack:");
|
||||||
asm(" .type GC_save_regs_in_stack,#function");
|
asm(" .type GC_save_regs_in_stack,#function");
|
||||||
|
|
|
@ -172,7 +172,8 @@ int obj_kind;
|
||||||
# endif /* REDIRECT_REALLOC */
|
# endif /* REDIRECT_REALLOC */
|
||||||
|
|
||||||
|
|
||||||
/* The same thing, except caller does not hold allocation lock. */
|
/* Allocate memory such that only pointers to near the */
|
||||||
|
/* beginning of the object are considered. */
|
||||||
/* We avoid holding allocation lock while we clear memory. */
|
/* We avoid holding allocation lock while we clear memory. */
|
||||||
ptr_t GC_generic_malloc_ignore_off_page(lb, k)
|
ptr_t GC_generic_malloc_ignore_off_page(lb, k)
|
||||||
register size_t lb;
|
register size_t lb;
|
||||||
|
|
|
@ -858,9 +858,9 @@ mse * GC_steal_mark_stack(mse * low, mse * high, mse * local,
|
||||||
++top;
|
++top;
|
||||||
top -> mse_descr = descr;
|
top -> mse_descr = descr;
|
||||||
top -> mse_start = p -> mse_start;
|
top -> mse_start = p -> mse_start;
|
||||||
GC_ASSERT( top -> mse_descr & GC_DS_TAGS != GC_DS_LENGTH ||
|
GC_ASSERT( (top -> mse_descr & GC_DS_TAGS) != GC_DS_LENGTH ||
|
||||||
top -> mse_descr < GC_greatest_plausible_heap_addr
|
top -> mse_descr < (ptr_t)GC_greatest_plausible_heap_addr
|
||||||
- GC_least_plausible_heap_addr);
|
- (ptr_t)GC_least_plausible_heap_addr);
|
||||||
/* If this is a big object, count it as */
|
/* If this is a big object, count it as */
|
||||||
/* size/256 + 1 objects. */
|
/* size/256 + 1 objects. */
|
||||||
++i;
|
++i;
|
||||||
|
@ -1450,8 +1450,8 @@ void GC_push_all_eager(bottom, top)
|
||||||
ptr_t bottom;
|
ptr_t bottom;
|
||||||
ptr_t top;
|
ptr_t top;
|
||||||
{
|
{
|
||||||
word * b = (word *)(((long) bottom + ALIGNMENT-1) & ~(ALIGNMENT-1));
|
word * b = (word *)(((word) bottom + ALIGNMENT-1) & ~(ALIGNMENT-1));
|
||||||
word * t = (word *)(((long) top) & ~(ALIGNMENT-1));
|
word * t = (word *)(((word) top) & ~(ALIGNMENT-1));
|
||||||
register word *p;
|
register word *p;
|
||||||
register word q;
|
register word q;
|
||||||
register word *lim;
|
register word *lim;
|
||||||
|
|
|
@ -246,7 +246,7 @@ void *arg2;
|
||||||
byte_sz = WORDS_TO_BYTES(word_sz);
|
byte_sz = WORDS_TO_BYTES(word_sz);
|
||||||
if (GC_all_interior_pointers) {
|
if (GC_all_interior_pointers) {
|
||||||
/* We need one extra byte; don't fill in GC_size_map[byte_sz] */
|
/* We need one extra byte; don't fill in GC_size_map[byte_sz] */
|
||||||
byte_sz--;
|
byte_sz -= EXTRA_BYTES;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (j = low_limit; j <= byte_sz; j++) GC_size_map[j] = word_sz;
|
for (j = low_limit; j <= byte_sz; j++) GC_size_map[j] = word_sz;
|
||||||
|
@ -805,7 +805,10 @@ void GC_init_inner()
|
||||||
|
|
||||||
void GC_enable_incremental GC_PROTO(())
|
void GC_enable_incremental GC_PROTO(())
|
||||||
{
|
{
|
||||||
# if !defined(SMALL_CONFIG)
|
# if !defined(SMALL_CONFIG) && !defined(KEEP_BACK_PTRS)
|
||||||
|
/* If we are keeping back pointers, the GC itself dirties all */
|
||||||
|
/* pages on which objects have been marked, making */
|
||||||
|
/* incremental GC pointless. */
|
||||||
if (!GC_find_leak) {
|
if (!GC_find_leak) {
|
||||||
DCL_LOCK_STATE;
|
DCL_LOCK_STATE;
|
||||||
|
|
||||||
|
|
|
@ -60,6 +60,10 @@
|
||||||
# include <signal.h>
|
# include <signal.h>
|
||||||
# endif
|
# endif
|
||||||
|
|
||||||
|
#if defined(LINUX) || defined(LINUX_STACKBOTTOM)
|
||||||
|
# include <ctype.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Blatantly OS dependent routines, except for those that are related */
|
/* Blatantly OS dependent routines, except for those that are related */
|
||||||
/* to dynamic loading. */
|
/* to dynamic loading. */
|
||||||
|
|
||||||
|
@ -245,30 +249,11 @@ word GC_apply_to_maps(word (*fn)(char *))
|
||||||
// XXXXXXXX-XXXXXXXX r-xp 00000000 30:05 260537 name of mapping...\n
|
// XXXXXXXX-XXXXXXXX r-xp 00000000 30:05 260537 name of mapping...\n
|
||||||
// ^^^^^^^^ ^^^^^^^^ ^^^^ ^^
|
// ^^^^^^^^ ^^^^^^^^ ^^^^ ^^
|
||||||
// start end prot maj_dev
|
// start end prot maj_dev
|
||||||
// 0 9 18 32
|
|
||||||
//
|
|
||||||
// For 64 bit ABIs:
|
|
||||||
// 0 17 34 56
|
|
||||||
//
|
//
|
||||||
// The parser is called with a pointer to the entry and the return value
|
// Note that since about auguat 2003 kernels, the columns no longer have
|
||||||
// is either NULL or is advanced to the next entry(the byte after the
|
// fixed offsets on 64-bit kernels. Hence we no longer rely on fixed offsets
|
||||||
// trailing '\n'.)
|
// anywhere, which is safer anyway.
|
||||||
//
|
//
|
||||||
#if CPP_WORDSZ == 32
|
|
||||||
# define OFFSET_MAP_START 0
|
|
||||||
# define OFFSET_MAP_END 9
|
|
||||||
# define OFFSET_MAP_PROT 18
|
|
||||||
# define OFFSET_MAP_MAJDEV 32
|
|
||||||
# define ADDR_WIDTH 8
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if CPP_WORDSZ == 64
|
|
||||||
# define OFFSET_MAP_START 0
|
|
||||||
# define OFFSET_MAP_END 17
|
|
||||||
# define OFFSET_MAP_PROT 34
|
|
||||||
# define OFFSET_MAP_MAJDEV 56
|
|
||||||
# define ADDR_WIDTH 16
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Assign various fields of the first line in buf_ptr to *start, *end,
|
* Assign various fields of the first line in buf_ptr to *start, *end,
|
||||||
|
@ -277,37 +262,46 @@ word GC_apply_to_maps(word (*fn)(char *))
|
||||||
char *GC_parse_map_entry(char *buf_ptr, word *start, word *end,
|
char *GC_parse_map_entry(char *buf_ptr, word *start, word *end,
|
||||||
char *prot_buf, unsigned int *maj_dev)
|
char *prot_buf, unsigned int *maj_dev)
|
||||||
{
|
{
|
||||||
int i;
|
char *start_start, *end_start, *prot_start, *maj_dev_start;
|
||||||
char *tok;
|
char *p;
|
||||||
|
char *endp;
|
||||||
|
|
||||||
if (buf_ptr == NULL || *buf_ptr == '\0') {
|
if (buf_ptr == NULL || *buf_ptr == '\0') {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
memcpy(prot_buf, buf_ptr+OFFSET_MAP_PROT, 4);
|
p = buf_ptr;
|
||||||
/* do the protections first. */
|
while (isspace(*p)) ++p;
|
||||||
|
start_start = p;
|
||||||
|
GC_ASSERT(isxdigit(*start_start));
|
||||||
|
*start = strtoul(start_start, &endp, 16); p = endp;
|
||||||
|
GC_ASSERT(*p=='-');
|
||||||
|
|
||||||
|
++p;
|
||||||
|
end_start = p;
|
||||||
|
GC_ASSERT(isxdigit(*end_start));
|
||||||
|
*end = strtoul(end_start, &endp, 16); p = endp;
|
||||||
|
GC_ASSERT(isspace(*p));
|
||||||
|
|
||||||
|
while (isspace(*p)) ++p;
|
||||||
|
prot_start = p;
|
||||||
|
GC_ASSERT(*prot_start == 'r' || *prot_start == '-');
|
||||||
|
memcpy(prot_buf, prot_start, 4);
|
||||||
prot_buf[4] = '\0';
|
prot_buf[4] = '\0';
|
||||||
|
if (prot_buf[1] == 'w') {/* we can skip the rest if it's not writable. */
|
||||||
if (prot_buf[1] == 'w') {/* we can skip all of this if it's not writable. */
|
/* Skip past protection field to offset field */
|
||||||
|
while (!isspace(*p)) ++p; while (isspace(*p)) ++p;
|
||||||
tok = buf_ptr;
|
GC_ASSERT(isxdigit(*p));
|
||||||
buf_ptr[OFFSET_MAP_START+ADDR_WIDTH] = '\0';
|
/* Skip past offset field, which we ignore */
|
||||||
*start = strtoul(tok, NULL, 16);
|
while (!isspace(*p)) ++p; while (isspace(*p)) ++p;
|
||||||
|
maj_dev_start = p;
|
||||||
tok = buf_ptr+OFFSET_MAP_END;
|
GC_ASSERT(isxdigit(*maj_dev_start));
|
||||||
buf_ptr[OFFSET_MAP_END+ADDR_WIDTH] = '\0';
|
*maj_dev = strtoul(maj_dev_start, NULL, 16);
|
||||||
*end = strtoul(tok, NULL, 16);
|
|
||||||
|
|
||||||
buf_ptr += OFFSET_MAP_MAJDEV;
|
|
||||||
tok = buf_ptr;
|
|
||||||
while (*buf_ptr != ':') buf_ptr++;
|
|
||||||
*buf_ptr++ = '\0';
|
|
||||||
*maj_dev = strtoul(tok, NULL, 16);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
while (*buf_ptr && *buf_ptr++ != '\n');
|
while (*p && *p++ != '\n');
|
||||||
|
|
||||||
return buf_ptr;
|
return p;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif /* Need to parse /proc/self/maps. */
|
#endif /* Need to parse /proc/self/maps. */
|
||||||
|
@ -699,7 +693,7 @@ ptr_t GC_get_stack_base()
|
||||||
# if defined(SUNOS5SIGS) || defined(IRIX5) || defined(OSF1) \
|
# if defined(SUNOS5SIGS) || defined(IRIX5) || defined(OSF1) \
|
||||||
|| defined(HURD) || defined(NETBSD)
|
|| defined(HURD) || defined(NETBSD)
|
||||||
static struct sigaction old_segv_act;
|
static struct sigaction old_segv_act;
|
||||||
# if defined(_sigargs) /* !Irix6.x */ || defined(HPUX) \
|
# if defined(IRIX5) || defined(HPUX) \
|
||||||
|| defined(HURD) || defined(NETBSD)
|
|| defined(HURD) || defined(NETBSD)
|
||||||
static struct sigaction old_bus_act;
|
static struct sigaction old_bus_act;
|
||||||
# endif
|
# endif
|
||||||
|
@ -732,9 +726,11 @@ ptr_t GC_get_stack_base()
|
||||||
/* and setting a handler at the same time. */
|
/* and setting a handler at the same time. */
|
||||||
(void) sigaction(SIGSEGV, 0, &old_segv_act);
|
(void) sigaction(SIGSEGV, 0, &old_segv_act);
|
||||||
(void) sigaction(SIGSEGV, &act, 0);
|
(void) sigaction(SIGSEGV, &act, 0);
|
||||||
|
(void) sigaction(SIGBUS, 0, &old_bus_act);
|
||||||
|
(void) sigaction(SIGBUS, &act, 0);
|
||||||
# else
|
# else
|
||||||
(void) sigaction(SIGSEGV, &act, &old_segv_act);
|
(void) sigaction(SIGSEGV, &act, &old_segv_act);
|
||||||
# if defined(IRIX5) && defined(_sigargs) /* Irix 5.x, not 6.x */ \
|
# if defined(IRIX5) \
|
||||||
|| defined(HPUX) || defined(HURD) || defined(NETBSD)
|
|| defined(HPUX) || defined(HURD) || defined(NETBSD)
|
||||||
/* Under Irix 5.x or HP/UX, we may get SIGBUS. */
|
/* Under Irix 5.x or HP/UX, we may get SIGBUS. */
|
||||||
/* Pthreads doesn't exist under Irix 5.x, so we */
|
/* Pthreads doesn't exist under Irix 5.x, so we */
|
||||||
|
@ -773,7 +769,7 @@ ptr_t GC_get_stack_base()
|
||||||
# if defined(SUNOS5SIGS) || defined(IRIX5) \
|
# if defined(SUNOS5SIGS) || defined(IRIX5) \
|
||||||
|| defined(OSF1) || defined(HURD) || defined(NETBSD)
|
|| defined(OSF1) || defined(HURD) || defined(NETBSD)
|
||||||
(void) sigaction(SIGSEGV, &old_segv_act, 0);
|
(void) sigaction(SIGSEGV, &old_segv_act, 0);
|
||||||
# if defined(IRIX5) && defined(_sigargs) /* Irix 5.x, not 6.x */ \
|
# if defined(IRIX5) \
|
||||||
|| defined(HPUX) || defined(HURD) || defined(NETBSD)
|
|| defined(HPUX) || defined(HURD) || defined(NETBSD)
|
||||||
(void) sigaction(SIGBUS, &old_bus_act, 0);
|
(void) sigaction(SIGBUS, &old_bus_act, 0);
|
||||||
# endif
|
# endif
|
||||||
|
@ -854,13 +850,14 @@ ptr_t GC_get_stack_base()
|
||||||
|
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include <ctype.h>
|
|
||||||
|
|
||||||
# define STAT_SKIP 27 /* Number of fields preceding startstack */
|
# define STAT_SKIP 27 /* Number of fields preceding startstack */
|
||||||
/* field in /proc/self/stat */
|
/* field in /proc/self/stat */
|
||||||
|
|
||||||
|
#ifdef USE_LIBC_PRIVATES
|
||||||
# pragma weak __libc_stack_end
|
# pragma weak __libc_stack_end
|
||||||
extern ptr_t __libc_stack_end;
|
extern ptr_t __libc_stack_end;
|
||||||
|
#endif
|
||||||
|
|
||||||
# ifdef IA64
|
# ifdef IA64
|
||||||
/* Try to read the backing store base from /proc/self/maps. */
|
/* Try to read the backing store base from /proc/self/maps. */
|
||||||
|
@ -890,30 +887,33 @@ ptr_t GC_get_stack_base()
|
||||||
return GC_apply_to_maps(backing_store_base_from_maps);
|
return GC_apply_to_maps(backing_store_base_from_maps);
|
||||||
}
|
}
|
||||||
|
|
||||||
# pragma weak __libc_ia64_register_backing_store_base
|
# ifdef USE_LIBC_PRIVATES
|
||||||
extern ptr_t __libc_ia64_register_backing_store_base;
|
# pragma weak __libc_ia64_register_backing_store_base
|
||||||
|
extern ptr_t __libc_ia64_register_backing_store_base;
|
||||||
|
# endif
|
||||||
|
|
||||||
ptr_t GC_get_register_stack_base(void)
|
ptr_t GC_get_register_stack_base(void)
|
||||||
{
|
{
|
||||||
if (0 != &__libc_ia64_register_backing_store_base
|
# ifdef USE_LIBC_PRIVATES
|
||||||
&& 0 != __libc_ia64_register_backing_store_base) {
|
if (0 != &__libc_ia64_register_backing_store_base
|
||||||
/* Glibc 2.2.4 has a bug such that for dynamically linked */
|
&& 0 != __libc_ia64_register_backing_store_base) {
|
||||||
/* executables __libc_ia64_register_backing_store_base is */
|
/* Glibc 2.2.4 has a bug such that for dynamically linked */
|
||||||
/* defined but uninitialized during constructor calls. */
|
/* executables __libc_ia64_register_backing_store_base is */
|
||||||
/* Hence we check for both nonzero address and value. */
|
/* defined but uninitialized during constructor calls. */
|
||||||
return __libc_ia64_register_backing_store_base;
|
/* Hence we check for both nonzero address and value. */
|
||||||
} else {
|
return __libc_ia64_register_backing_store_base;
|
||||||
word result = backing_store_base_from_proc();
|
}
|
||||||
if (0 == result) {
|
# endif
|
||||||
|
word result = backing_store_base_from_proc();
|
||||||
|
if (0 == result) {
|
||||||
/* Use dumb heuristics. Works only for default configuration. */
|
/* Use dumb heuristics. Works only for default configuration. */
|
||||||
result = (word)GC_stackbottom - BACKING_STORE_DISPLACEMENT;
|
result = (word)GC_stackbottom - BACKING_STORE_DISPLACEMENT;
|
||||||
result += BACKING_STORE_ALIGNMENT - 1;
|
result += BACKING_STORE_ALIGNMENT - 1;
|
||||||
result &= ~(BACKING_STORE_ALIGNMENT - 1);
|
result &= ~(BACKING_STORE_ALIGNMENT - 1);
|
||||||
/* Verify that it's at least readable. If not, we goofed. */
|
/* Verify that it's at least readable. If not, we goofed. */
|
||||||
GC_noop1(*(word *)result);
|
GC_noop1(*(word *)result);
|
||||||
}
|
|
||||||
return (ptr_t)result;
|
|
||||||
}
|
}
|
||||||
|
return (ptr_t)result;
|
||||||
}
|
}
|
||||||
# endif
|
# endif
|
||||||
|
|
||||||
|
@ -936,6 +936,7 @@ ptr_t GC_get_stack_base()
|
||||||
/* since the correct value of __libc_stack_end never */
|
/* since the correct value of __libc_stack_end never */
|
||||||
/* becomes visible to us. The second test works around */
|
/* becomes visible to us. The second test works around */
|
||||||
/* this. */
|
/* this. */
|
||||||
|
# ifdef USE_LIBC_PRIVATES
|
||||||
if (0 != &__libc_stack_end && 0 != __libc_stack_end ) {
|
if (0 != &__libc_stack_end && 0 != __libc_stack_end ) {
|
||||||
# ifdef IA64
|
# ifdef IA64
|
||||||
/* Some versions of glibc set the address 16 bytes too */
|
/* Some versions of glibc set the address 16 bytes too */
|
||||||
|
@ -957,6 +958,7 @@ ptr_t GC_get_stack_base()
|
||||||
# endif
|
# endif
|
||||||
# endif
|
# endif
|
||||||
}
|
}
|
||||||
|
# endif
|
||||||
f = open("/proc/self/stat", O_RDONLY);
|
f = open("/proc/self/stat", O_RDONLY);
|
||||||
if (f < 0 || STAT_READ(f, stat_buf, STAT_BUF_SIZE) < 2 * STAT_SKIP) {
|
if (f < 0 || STAT_READ(f, stat_buf, STAT_BUF_SIZE) < 2 * STAT_SKIP) {
|
||||||
ABORT("Couldn't read /proc/self/stat");
|
ABORT("Couldn't read /proc/self/stat");
|
||||||
|
@ -1508,7 +1510,7 @@ void GC_register_data_segments()
|
||||||
# endif
|
# endif
|
||||||
|
|
||||||
|
|
||||||
# ifdef RS6000
|
# if 0 && defined(RS6000) /* We now use mmap */
|
||||||
/* The compiler seems to generate speculative reads one past the end of */
|
/* The compiler seems to generate speculative reads one past the end of */
|
||||||
/* an allocated object. Hence we need to make sure that the page */
|
/* an allocated object. Hence we need to make sure that the page */
|
||||||
/* following the last heap page is also mapped. */
|
/* following the last heap page is also mapped. */
|
||||||
|
@ -2381,7 +2383,7 @@ SIG_PF GC_old_segv_handler; /* Also old MSWIN32 ACCESS_VIOLATION filter */
|
||||||
# endif
|
# endif
|
||||||
# ifdef FREEBSD
|
# ifdef FREEBSD
|
||||||
# define SIG_OK (sig == SIGBUS)
|
# define SIG_OK (sig == SIGBUS)
|
||||||
# define CODE_OK (code == BUS_PAGE_FAULT)
|
# define CODE_OK TRUE
|
||||||
# endif
|
# endif
|
||||||
# endif /* SUNOS4 || (FREEBSD && !SUNOS5SIGS) */
|
# endif /* SUNOS4 || (FREEBSD && !SUNOS5SIGS) */
|
||||||
|
|
||||||
|
@ -3726,7 +3728,7 @@ static kern_return_t GC_forward_exception(
|
||||||
exception_behavior_t behavior;
|
exception_behavior_t behavior;
|
||||||
thread_state_flavor_t flavor;
|
thread_state_flavor_t flavor;
|
||||||
|
|
||||||
thread_state_data_t thread_state;
|
thread_state_t thread_state;
|
||||||
mach_msg_type_number_t thread_state_count = THREAD_STATE_MAX;
|
mach_msg_type_number_t thread_state_count = THREAD_STATE_MAX;
|
||||||
|
|
||||||
for(i=0;i<GC_old_exc_ports.count;i++)
|
for(i=0;i<GC_old_exc_ports.count;i++)
|
||||||
|
@ -3787,13 +3789,19 @@ catch_exception_raise(
|
||||||
char *addr;
|
char *addr;
|
||||||
struct hblk *h;
|
struct hblk *h;
|
||||||
int i;
|
int i;
|
||||||
#ifdef POWERPC
|
# if defined(POWERPC)
|
||||||
thread_state_flavor_t flavor = PPC_EXCEPTION_STATE;
|
# if CPP_WORDSZ == 32
|
||||||
mach_msg_type_number_t exc_state_count = PPC_EXCEPTION_STATE_COUNT;
|
thread_state_flavor_t flavor = PPC_EXCEPTION_STATE;
|
||||||
ppc_exception_state_t exc_state;
|
mach_msg_type_number_t exc_state_count = PPC_EXCEPTION_STATE_COUNT;
|
||||||
#else
|
ppc_exception_state_t exc_state;
|
||||||
|
# else
|
||||||
|
thread_state_flavor_t flavor = PPC_EXCEPTION_STATE64;
|
||||||
|
mach_msg_type_number_t exc_state_count = PPC_EXCEPTION_STATE64_COUNT;
|
||||||
|
ppc_exception_state64_t exc_state;
|
||||||
|
# endif
|
||||||
|
# else
|
||||||
# error FIXME for non-ppc darwin
|
# error FIXME for non-ppc darwin
|
||||||
#endif
|
# endif
|
||||||
|
|
||||||
|
|
||||||
if(exception != EXC_BAD_ACCESS || code[0] != KERN_PROTECTION_FAILURE) {
|
if(exception != EXC_BAD_ACCESS || code[0] != KERN_PROTECTION_FAILURE) {
|
||||||
|
@ -3953,10 +3961,14 @@ kern_return_t catch_exception_raise_state_identity(
|
||||||
# if defined (DRSNX)
|
# if defined (DRSNX)
|
||||||
# include <sys/sparc/frame.h>
|
# include <sys/sparc/frame.h>
|
||||||
# else
|
# else
|
||||||
# if defined(OPENBSD) || defined(NETBSD)
|
# if defined(OPENBSD)
|
||||||
# include <frame.h>
|
# include <frame.h>
|
||||||
# else
|
# else
|
||||||
# include <sys/frame.h>
|
# if defined(FREEBSD) || defined(NETBSD)
|
||||||
|
# include <machine/frame.h>
|
||||||
|
# else
|
||||||
|
# include <sys/frame.h>
|
||||||
|
# endif
|
||||||
# endif
|
# endif
|
||||||
# endif
|
# endif
|
||||||
# endif
|
# endif
|
||||||
|
@ -3985,6 +3997,16 @@ kern_return_t catch_exception_raise_state_identity(
|
||||||
#if NARGS == 0 && NFRAMES % 2 == 0 /* No padding */ \
|
#if NARGS == 0 && NFRAMES % 2 == 0 /* No padding */ \
|
||||||
&& defined(GC_HAVE_BUILTIN_BACKTRACE)
|
&& defined(GC_HAVE_BUILTIN_BACKTRACE)
|
||||||
|
|
||||||
|
#ifdef REDIRECT_MALLOC
|
||||||
|
/* Deal with possible malloc calls in backtrace by omitting */
|
||||||
|
/* the infinitely recursing backtrace. */
|
||||||
|
# ifdef THREADS
|
||||||
|
__thread /* If your compiler doesn't understand this */
|
||||||
|
/* you could use something like pthread_getspecific. */
|
||||||
|
# endif
|
||||||
|
GC_in_save_callers = FALSE;
|
||||||
|
#endif
|
||||||
|
|
||||||
void GC_save_callers (info)
|
void GC_save_callers (info)
|
||||||
struct callinfo info[NFRAMES];
|
struct callinfo info[NFRAMES];
|
||||||
{
|
{
|
||||||
|
@ -3994,15 +4016,26 @@ struct callinfo info[NFRAMES];
|
||||||
|
|
||||||
/* We retrieve NFRAMES+1 pc values, but discard the first, since it */
|
/* We retrieve NFRAMES+1 pc values, but discard the first, since it */
|
||||||
/* points to our own frame. */
|
/* points to our own frame. */
|
||||||
|
# ifdef REDIRECT_MALLOC
|
||||||
|
if (GC_in_save_callers) {
|
||||||
|
info[0].ci_pc = (word)(&GC_save_callers);
|
||||||
|
for (i = 1; i < NFRAMES; ++i) info[i].ci_pc = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
GC_in_save_callers = TRUE;
|
||||||
|
# endif
|
||||||
GC_ASSERT(sizeof(struct callinfo) == sizeof(void *));
|
GC_ASSERT(sizeof(struct callinfo) == sizeof(void *));
|
||||||
npcs = backtrace((void **)tmp_info, NFRAMES + IGNORE_FRAMES);
|
npcs = backtrace((void **)tmp_info, NFRAMES + IGNORE_FRAMES);
|
||||||
BCOPY(tmp_info+IGNORE_FRAMES, info, (npcs - IGNORE_FRAMES) * sizeof(void *));
|
BCOPY(tmp_info+IGNORE_FRAMES, info, (npcs - IGNORE_FRAMES) * sizeof(void *));
|
||||||
for (i = npcs - IGNORE_FRAMES; i < NFRAMES; ++i) info[i].ci_pc = 0;
|
for (i = npcs - IGNORE_FRAMES; i < NFRAMES; ++i) info[i].ci_pc = 0;
|
||||||
|
# ifdef REDIRECT_MALLOC
|
||||||
|
GC_in_save_callers = FALSE;
|
||||||
|
# endif
|
||||||
}
|
}
|
||||||
|
|
||||||
#else /* No builtin backtrace; do it ourselves */
|
#else /* No builtin backtrace; do it ourselves */
|
||||||
|
|
||||||
#if (defined(OPENBSD) || defined(NETBSD)) && defined(SPARC)
|
#if (defined(OPENBSD) || defined(NETBSD) || defined(FREEBSD)) && defined(SPARC)
|
||||||
# define FR_SAVFP fr_fp
|
# define FR_SAVFP fr_fp
|
||||||
# define FR_SAVPC fr_pc
|
# define FR_SAVPC fr_pc
|
||||||
#else
|
#else
|
||||||
|
|
|
@ -12,7 +12,7 @@
|
||||||
|
|
||||||
; GC_push_regs function. Under some optimization levels GCC will clobber
|
; 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
|
; some of the non-volatile registers before we get a chance to save them
|
||||||
; therefore, this can't be inline asm.
|
; therefore, this cannot be inline asm.
|
||||||
|
|
||||||
.text
|
.text
|
||||||
.align LOG2_GPR_BYTES
|
.align LOG2_GPR_BYTES
|
||||||
|
|
|
@ -1,13 +1,17 @@
|
||||||
#include "private/pthread_support.h"
|
#include "private/pthread_support.h"
|
||||||
|
|
||||||
#if defined(GC_PTHREADS) && !defined(GC_SOLARIS_THREADS) \
|
#if defined(GC_PTHREADS) && !defined(GC_SOLARIS_THREADS) \
|
||||||
&& !defined(GC_IRIX_THREADS) && !defined(GC_WIN32_THREADS) \
|
&& !defined(GC_WIN32_THREADS) && !defined(GC_DARWIN_THREADS)
|
||||||
&& !defined(GC_DARWIN_THREADS) && !defined(GC_AIX_THREADS)
|
|
||||||
|
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
#include <semaphore.h>
|
#include <semaphore.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
#include <sys/time.h>
|
||||||
|
#ifndef HPUX
|
||||||
|
# include <sys/select.h>
|
||||||
|
/* Doesn't exist on HP/UX 11.11. */
|
||||||
|
#endif
|
||||||
|
|
||||||
#if DEBUG_THREADS
|
#if DEBUG_THREADS
|
||||||
|
|
||||||
|
@ -67,7 +71,22 @@ void GC_remove_allowed_signals(sigset_t *set)
|
||||||
|
|
||||||
static sigset_t suspend_handler_mask;
|
static sigset_t suspend_handler_mask;
|
||||||
|
|
||||||
word GC_stop_count; /* Incremented at the beginning of GC_stop_world. */
|
volatile sig_atomic_t GC_stop_count;
|
||||||
|
/* Incremented at the beginning of GC_stop_world. */
|
||||||
|
|
||||||
|
volatile sig_atomic_t GC_world_is_stopped = FALSE;
|
||||||
|
/* FALSE ==> it is safe for threads to restart, i.e. */
|
||||||
|
/* they will see another suspend signal before they */
|
||||||
|
/* are expected to stop (unless they have voluntarily */
|
||||||
|
/* stopped). */
|
||||||
|
|
||||||
|
void GC_brief_async_signal_safe_sleep()
|
||||||
|
{
|
||||||
|
struct timeval tv;
|
||||||
|
tv.tv_sec = 0;
|
||||||
|
tv.tv_usec = 1000 * TIME_LIMIT / 2;
|
||||||
|
select(0, 0, 0, 0, &tv);
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef GC_OSF1_THREADS
|
#ifdef GC_OSF1_THREADS
|
||||||
GC_bool GC_retry_signals = TRUE;
|
GC_bool GC_retry_signals = TRUE;
|
||||||
|
@ -108,7 +127,9 @@ extern void GC_with_callee_saves_pushed();
|
||||||
|
|
||||||
void GC_suspend_handler(int sig)
|
void GC_suspend_handler(int sig)
|
||||||
{
|
{
|
||||||
|
int old_errno = errno;
|
||||||
GC_with_callee_saves_pushed(GC_suspend_handler_inner, (ptr_t)(word)sig);
|
GC_with_callee_saves_pushed(GC_suspend_handler_inner, (ptr_t)(word)sig);
|
||||||
|
errno = old_errno;
|
||||||
}
|
}
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
@ -116,7 +137,9 @@ void GC_suspend_handler(int sig)
|
||||||
/* in the signal handler frame. */
|
/* in the signal handler frame. */
|
||||||
void GC_suspend_handler(int sig)
|
void GC_suspend_handler(int sig)
|
||||||
{
|
{
|
||||||
|
int old_errno = errno;
|
||||||
GC_suspend_handler_inner((ptr_t)(word)sig);
|
GC_suspend_handler_inner((ptr_t)(word)sig);
|
||||||
|
errno = old_errno;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -172,16 +195,26 @@ void GC_suspend_handler_inner(ptr_t sig_arg)
|
||||||
/* this thread a SIG_THR_RESTART signal. */
|
/* this thread a SIG_THR_RESTART signal. */
|
||||||
/* SIG_THR_RESTART should be masked at this point. Thus there */
|
/* SIG_THR_RESTART should be masked at this point. Thus there */
|
||||||
/* is no race. */
|
/* is no race. */
|
||||||
do {
|
/* We do not continue until we receive a SIG_THR_RESTART, */
|
||||||
me->stop_info.signal = 0;
|
/* but we do not take that as authoritative. (We may be */
|
||||||
sigsuspend(&suspend_handler_mask); /* Wait for signal */
|
/* accidentally restarted by one of the user signals we */
|
||||||
} while (me->stop_info.signal != SIG_THR_RESTART);
|
/* don't block.) After we receive the signal, we use a */
|
||||||
|
/* primitive and expensive mechanism to wait until it's */
|
||||||
|
/* really safe to proceed. Under normal circumstances, */
|
||||||
|
/* this code should not be executed. */
|
||||||
|
sigsuspend(&suspend_handler_mask); /* Wait for signal */
|
||||||
|
while (GC_world_is_stopped && GC_stop_count == my_stop_count) {
|
||||||
|
GC_brief_async_signal_safe_sleep();
|
||||||
|
# if DEBUG_THREADS
|
||||||
|
GC_err_printf0("Sleeping in signal handler");
|
||||||
|
# endif
|
||||||
|
}
|
||||||
/* If the RESTART signal gets lost, we can still lose. That should be */
|
/* 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 */
|
/* less likely than losing the SUSPEND signal, since we don't do much */
|
||||||
/* between the sem_post and sigsuspend. */
|
/* between the sem_post and sigsuspend. */
|
||||||
/* We'd need more handshaking to work around that, since we don't want */
|
/* We'd need more handshaking to work around that. */
|
||||||
/* to accidentally leave a RESTART signal pending, thus causing us to */
|
/* Simply dropping the sigsuspend call should be safe, but is unlikely */
|
||||||
/* continue prematurely in a future round. */
|
/* to be efficient. */
|
||||||
|
|
||||||
#if DEBUG_THREADS
|
#if DEBUG_THREADS
|
||||||
GC_printf1("Continuing 0x%lx\n", my_thread);
|
GC_printf1("Continuing 0x%lx\n", my_thread);
|
||||||
|
@ -191,20 +224,11 @@ void GC_suspend_handler_inner(ptr_t sig_arg)
|
||||||
void GC_restart_handler(int sig)
|
void GC_restart_handler(int sig)
|
||||||
{
|
{
|
||||||
pthread_t my_thread = pthread_self();
|
pthread_t my_thread = pthread_self();
|
||||||
GC_thread me;
|
|
||||||
|
|
||||||
if (sig != SIG_THR_RESTART) ABORT("Bad signal in suspend_handler");
|
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,
|
** Note: even if we don't do anything useful here,
|
||||||
** it would still be necessary to have a signal handler,
|
** it would still be necessary to have a signal handler,
|
||||||
** rather than ignoring the signals, otherwise
|
** rather than ignoring the signals, otherwise
|
||||||
** the signals will not be delivered at all, and
|
** the signals will not be delivered at all, and
|
||||||
|
@ -357,6 +381,7 @@ void GC_stop_world()
|
||||||
/* We should have previously waited for it to become zero. */
|
/* We should have previously waited for it to become zero. */
|
||||||
# endif /* PARALLEL_MARK */
|
# endif /* PARALLEL_MARK */
|
||||||
++GC_stop_count;
|
++GC_stop_count;
|
||||||
|
GC_world_is_stopped = TRUE;
|
||||||
n_live_threads = GC_suspend_all();
|
n_live_threads = GC_suspend_all();
|
||||||
|
|
||||||
if (GC_retry_signals) {
|
if (GC_retry_signals) {
|
||||||
|
@ -390,10 +415,10 @@ void GC_stop_world()
|
||||||
}
|
}
|
||||||
for (i = 0; i < n_live_threads; i++) {
|
for (i = 0; i < n_live_threads; i++) {
|
||||||
while (0 != (code = sem_wait(&GC_suspend_ack_sem))) {
|
while (0 != (code = sem_wait(&GC_suspend_ack_sem))) {
|
||||||
if (errno != EINTR) {
|
if (errno != EINTR) {
|
||||||
GC_err_printf1("Sem_wait returned %ld\n", (unsigned long)code);
|
GC_err_printf1("Sem_wait returned %ld\n", (unsigned long)code);
|
||||||
ABORT("sem_wait for handler failed");
|
ABORT("sem_wait for handler failed");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
# ifdef PARALLEL_MARK
|
# ifdef PARALLEL_MARK
|
||||||
|
@ -419,6 +444,7 @@ void GC_start_world()
|
||||||
GC_printf0("World starting\n");
|
GC_printf0("World starting\n");
|
||||||
# endif
|
# endif
|
||||||
|
|
||||||
|
GC_world_is_stopped = FALSE;
|
||||||
for (i = 0; i < THREAD_TABLE_SZ; i++) {
|
for (i = 0; i < THREAD_TABLE_SZ; i++) {
|
||||||
for (p = GC_threads[i]; p != 0; p = p -> next) {
|
for (p = GC_threads[i]; p != 0; p = p -> next) {
|
||||||
if (p -> id != my_thread) {
|
if (p -> id != my_thread) {
|
||||||
|
@ -428,8 +454,7 @@ void GC_start_world()
|
||||||
#if DEBUG_THREADS
|
#if DEBUG_THREADS
|
||||||
GC_printf1("Sending restart signal to 0x%lx\n", p -> id);
|
GC_printf1("Sending restart signal to 0x%lx\n", p -> id);
|
||||||
#endif
|
#endif
|
||||||
|
result = pthread_kill(p -> id, SIG_THR_RESTART);
|
||||||
result = pthread_kill(p -> id, SIG_THR_RESTART);
|
|
||||||
switch(result) {
|
switch(result) {
|
||||||
case ESRCH:
|
case ESRCH:
|
||||||
/* Not really there anymore. Possible? */
|
/* Not really there anymore. Possible? */
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
* Copyright (c) 1994 by Xerox Corporation. All rights reserved.
|
* Copyright (c) 1994 by Xerox Corporation. All rights reserved.
|
||||||
* Copyright (c) 1996 by Silicon Graphics. All rights reserved.
|
* Copyright (c) 1996 by Silicon Graphics. All rights reserved.
|
||||||
* Copyright (c) 1998 by Fergus Henderson. All rights reserved.
|
* Copyright (c) 1998 by Fergus Henderson. All rights reserved.
|
||||||
* Copyright (c) 2000-2001 by Hewlett-Packard Company. All rights reserved.
|
* Copyright (c) 2000-2004 by Hewlett-Packard Company. All rights reserved.
|
||||||
*
|
*
|
||||||
* THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
|
* THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
|
||||||
* OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
|
* OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
|
||||||
|
@ -51,8 +51,7 @@
|
||||||
# include "private/pthread_support.h"
|
# include "private/pthread_support.h"
|
||||||
|
|
||||||
# if defined(GC_PTHREADS) && !defined(GC_SOLARIS_THREADS) \
|
# if defined(GC_PTHREADS) && !defined(GC_SOLARIS_THREADS) \
|
||||||
&& !defined(GC_IRIX_THREADS) && !defined(GC_WIN32_THREADS) \
|
&& !defined(GC_WIN32_THREADS)
|
||||||
&& !defined(GC_AIX_THREADS)
|
|
||||||
|
|
||||||
# if defined(GC_HPUX_THREADS) && !defined(USE_PTHREAD_SPECIFIC) \
|
# if defined(GC_HPUX_THREADS) && !defined(USE_PTHREAD_SPECIFIC) \
|
||||||
&& !defined(USE_COMPILER_TLS)
|
&& !defined(USE_COMPILER_TLS)
|
||||||
|
@ -69,7 +68,8 @@
|
||||||
# endif
|
# endif
|
||||||
|
|
||||||
# if (defined(GC_DGUX386_THREADS) || defined(GC_OSF1_THREADS) || \
|
# if (defined(GC_DGUX386_THREADS) || defined(GC_OSF1_THREADS) || \
|
||||||
defined(GC_DARWIN_THREADS)) && !defined(USE_PTHREAD_SPECIFIC)
|
defined(GC_DARWIN_THREADS) || defined(GC_AIX_THREADS)) \
|
||||||
|
&& !defined(USE_PTHREAD_SPECIFIC)
|
||||||
# define USE_PTHREAD_SPECIFIC
|
# define USE_PTHREAD_SPECIFIC
|
||||||
# endif
|
# endif
|
||||||
|
|
||||||
|
@ -117,7 +117,7 @@
|
||||||
# include <semaphore.h>
|
# include <semaphore.h>
|
||||||
#endif /* !GC_DARWIN_THREADS */
|
#endif /* !GC_DARWIN_THREADS */
|
||||||
|
|
||||||
#if defined(GC_DARWIN_THREADS)
|
#if defined(GC_DARWIN_THREADS) || defined(GC_FREEBSD_THREADS)
|
||||||
# include <sys/sysctl.h>
|
# include <sys/sysctl.h>
|
||||||
#endif /* GC_DARWIN_THREADS */
|
#endif /* GC_DARWIN_THREADS */
|
||||||
|
|
||||||
|
@ -840,9 +840,9 @@ int GC_get_nprocs()
|
||||||
/* We hold the allocation lock. */
|
/* We hold the allocation lock. */
|
||||||
void GC_thr_init()
|
void GC_thr_init()
|
||||||
{
|
{
|
||||||
# ifndef GC_DARWIN_THREADS
|
# ifndef GC_DARWIN_THREADS
|
||||||
int dummy;
|
int dummy;
|
||||||
# endif
|
# endif
|
||||||
GC_thread t;
|
GC_thread t;
|
||||||
|
|
||||||
if (GC_thr_initialized) return;
|
if (GC_thr_initialized) return;
|
||||||
|
@ -874,14 +874,15 @@ void GC_thr_init()
|
||||||
# if defined(GC_HPUX_THREADS)
|
# if defined(GC_HPUX_THREADS)
|
||||||
GC_nprocs = pthread_num_processors_np();
|
GC_nprocs = pthread_num_processors_np();
|
||||||
# endif
|
# endif
|
||||||
# if defined(GC_OSF1_THREADS)
|
# if defined(GC_OSF1_THREADS) || defined(GC_AIX_THREADS)
|
||||||
GC_nprocs = sysconf(_SC_NPROCESSORS_ONLN);
|
GC_nprocs = sysconf(_SC_NPROCESSORS_ONLN);
|
||||||
if (GC_nprocs <= 0) GC_nprocs = 1;
|
if (GC_nprocs <= 0) GC_nprocs = 1;
|
||||||
# endif
|
# endif
|
||||||
# if defined(GC_FREEBSD_THREADS)
|
# if defined(GC_IRIX_THREADS)
|
||||||
GC_nprocs = 1;
|
GC_nprocs = sysconf(_SC_NPROC_ONLN);
|
||||||
|
if (GC_nprocs <= 0) GC_nprocs = 1;
|
||||||
# endif
|
# endif
|
||||||
# if defined(GC_DARWIN_THREADS)
|
# if defined(GC_DARWIN_THREADS) || defined(GC_FREEBSD_THREADS)
|
||||||
int ncpus = 1;
|
int ncpus = 1;
|
||||||
size_t len = sizeof(ncpus);
|
size_t len = sizeof(ncpus);
|
||||||
sysctl((int[2]) {CTL_HW, HW_NCPU}, 2, &ncpus, &len, NULL, 0);
|
sysctl((int[2]) {CTL_HW, HW_NCPU}, 2, &ncpus, &len, NULL, 0);
|
||||||
|
@ -928,6 +929,8 @@ void GC_thr_init()
|
||||||
/* Disable true incremental collection, but generational is OK. */
|
/* Disable true incremental collection, but generational is OK. */
|
||||||
GC_time_limit = GC_TIME_UNLIMITED;
|
GC_time_limit = GC_TIME_UNLIMITED;
|
||||||
}
|
}
|
||||||
|
/* If we are using a parallel marker, actually start helper threads. */
|
||||||
|
if (GC_parallel) start_mark_threads();
|
||||||
# endif
|
# endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -944,10 +947,6 @@ void GC_init_parallel()
|
||||||
|
|
||||||
/* 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 (!GC_is_initialized) GC_init();
|
||||||
/* If we are using a parallel marker, start the helper threads. */
|
|
||||||
# ifdef PARALLEL_MARK
|
|
||||||
if (GC_parallel) start_mark_threads();
|
|
||||||
# endif
|
|
||||||
/* Initialize thread local free lists if used. */
|
/* Initialize thread local free lists if used. */
|
||||||
# if defined(THREAD_LOCAL_ALLOC) && !defined(DBG_HDRS_ALL)
|
# if defined(THREAD_LOCAL_ALLOC) && !defined(DBG_HDRS_ALL)
|
||||||
LOCK();
|
LOCK();
|
||||||
|
@ -1223,7 +1222,7 @@ WRAP_FUNC(pthread_create)(pthread_t *new_thread,
|
||||||
if (!GC_thr_initialized) GC_thr_init();
|
if (!GC_thr_initialized) GC_thr_init();
|
||||||
# ifdef GC_ASSERTIONS
|
# ifdef GC_ASSERTIONS
|
||||||
{
|
{
|
||||||
int stack_size;
|
size_t stack_size;
|
||||||
if (NULL == attr) {
|
if (NULL == attr) {
|
||||||
pthread_attr_t my_attr;
|
pthread_attr_t my_attr;
|
||||||
pthread_attr_init(&my_attr);
|
pthread_attr_init(&my_attr);
|
||||||
|
@ -1231,7 +1230,13 @@ WRAP_FUNC(pthread_create)(pthread_t *new_thread,
|
||||||
} else {
|
} else {
|
||||||
pthread_attr_getstacksize(attr, &stack_size);
|
pthread_attr_getstacksize(attr, &stack_size);
|
||||||
}
|
}
|
||||||
GC_ASSERT(stack_size >= (8*HBLKSIZE*sizeof(word)));
|
# ifdef PARALLEL_MARK
|
||||||
|
GC_ASSERT(stack_size >= (8*HBLKSIZE*sizeof(word)));
|
||||||
|
# else
|
||||||
|
/* FreeBSD-5.3/Alpha: default pthread stack is 64K, */
|
||||||
|
/* HBLKSIZE=8192, sizeof(word)=8 */
|
||||||
|
GC_ASSERT(stack_size >= 65536);
|
||||||
|
# endif
|
||||||
/* Our threads may need to do some work for the GC. */
|
/* Our threads may need to do some work for the GC. */
|
||||||
/* Ridiculously small threads won't work, and they */
|
/* Ridiculously small threads won't work, and they */
|
||||||
/* probably wouldn't work anyway. */
|
/* probably wouldn't work anyway. */
|
||||||
|
|
|
@ -888,7 +888,7 @@ void GC_print_block_list()
|
||||||
{
|
{
|
||||||
struct Print_stats pstats;
|
struct Print_stats pstats;
|
||||||
|
|
||||||
GC_printf0("(kind(0=ptrfree,1=normal,2=unc.,3=stubborn):size_in_bytes, #_marks_set)\n");
|
GC_printf1("(kind(0=ptrfree,1=normal,2=unc.,%lu=stubborn):size_in_bytes, #_marks_set)\n", STUBBORN);
|
||||||
pstats.number_of_blocks = 0;
|
pstats.number_of_blocks = 0;
|
||||||
pstats.total_bytes = 0;
|
pstats.total_bytes = 0;
|
||||||
GC_apply_to_all_blocks(GC_print_block_descr, (word)&pstats);
|
GC_apply_to_all_blocks(GC_print_block_descr, (word)&pstats);
|
||||||
|
|
|
@ -16,7 +16,7 @@
|
||||||
* Modified by Peter C. for Solaris Posix Threads.
|
* Modified by Peter C. for Solaris Posix Threads.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "private/gc_priv.h"
|
# include "private/gc_priv.h"
|
||||||
|
|
||||||
# if defined(GC_SOLARIS_PTHREADS)
|
# if defined(GC_SOLARIS_PTHREADS)
|
||||||
# include <pthread.h>
|
# include <pthread.h>
|
||||||
|
|
|
@ -16,7 +16,7 @@
|
||||||
*/
|
*/
|
||||||
/* Boehm, September 14, 1994 4:44 pm PDT */
|
/* Boehm, September 14, 1994 4:44 pm PDT */
|
||||||
|
|
||||||
#include "private/gc_priv.h"
|
# include "private/gc_priv.h"
|
||||||
|
|
||||||
# if defined(GC_SOLARIS_THREADS) || defined(GC_SOLARIS_PTHREADS)
|
# if defined(GC_SOLARIS_THREADS) || defined(GC_SOLARIS_PTHREADS)
|
||||||
# include "private/solaris_threads.h"
|
# include "private/solaris_threads.h"
|
||||||
|
@ -248,8 +248,8 @@ static void stop_all_lwps()
|
||||||
for (i = 0; i < max_lwps; i++)
|
for (i = 0; i < max_lwps; i++)
|
||||||
last_ids[i] = 0;
|
last_ids[i] = 0;
|
||||||
for (;;) {
|
for (;;) {
|
||||||
if (syscall(SYS_ioctl, GC_main_proc_fd, PIOCSTATUS, &status) < 0)
|
if (syscall(SYS_ioctl, GC_main_proc_fd, PIOCSTATUS, &status) < 0)
|
||||||
ABORT("Main PIOCSTATUS failed");
|
ABORT("Main PIOCSTATUS failed");
|
||||||
if (status.pr_nlwp < 1)
|
if (status.pr_nlwp < 1)
|
||||||
ABORT("Invalid number of lwps returned by PIOCSTATUS");
|
ABORT("Invalid number of lwps returned by PIOCSTATUS");
|
||||||
if (status.pr_nlwp >= max_lwps) {
|
if (status.pr_nlwp >= max_lwps) {
|
||||||
|
@ -262,7 +262,7 @@ static void stop_all_lwps()
|
||||||
for (i = 0; i < max_lwps; i++)
|
for (i = 0; i < max_lwps; i++)
|
||||||
last_ids[i] = 0;
|
last_ids[i] = 0;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (syscall(SYS_ioctl, GC_main_proc_fd, PIOCLWPIDS, GC_current_ids) < 0)
|
if (syscall(SYS_ioctl, GC_main_proc_fd, PIOCLWPIDS, GC_current_ids) < 0)
|
||||||
ABORT("PIOCLWPIDS failed");
|
ABORT("PIOCLWPIDS failed");
|
||||||
changed = FALSE;
|
changed = FALSE;
|
||||||
|
|
|
@ -1367,6 +1367,10 @@ void check_heap_stats()
|
||||||
max_heap_sz = 11000000;
|
max_heap_sz = 11000000;
|
||||||
}
|
}
|
||||||
# endif
|
# endif
|
||||||
|
# ifndef ALIGN_DOUBLE
|
||||||
|
/* We end up needing more small object pages. */
|
||||||
|
max_heap_sz += 2000000;
|
||||||
|
# endif
|
||||||
# ifdef GC_DEBUG
|
# ifdef GC_DEBUG
|
||||||
max_heap_sz *= 2;
|
max_heap_sz *= 2;
|
||||||
# ifdef SAVE_CALL_CHAIN
|
# ifdef SAVE_CALL_CHAIN
|
||||||
|
|
|
@ -11,10 +11,17 @@ int main()
|
||||||
"-Wl,--wrap -Wl,pthread_sigmask -Wl,--wrap -Wl,sleep\n");
|
"-Wl,--wrap -Wl,pthread_sigmask -Wl,--wrap -Wl,sleep\n");
|
||||||
# endif
|
# endif
|
||||||
# if defined(GC_LINUX_THREADS) || defined(GC_IRIX_THREADS) \
|
# if defined(GC_LINUX_THREADS) || defined(GC_IRIX_THREADS) \
|
||||||
|| defined(GC_FREEBSD_THREADS) || defined(GC_SOLARIS_PTHREADS) \
|
|| defined(GC_SOLARIS_PTHREADS) \
|
||||||
|| defined(GC_DARWIN_THREADS) || defined(GC_AIX_THREADS)
|
|| defined(GC_DARWIN_THREADS) || defined(GC_AIX_THREADS)
|
||||||
printf("-lpthread\n");
|
printf("-lpthread\n");
|
||||||
# endif
|
# endif
|
||||||
|
# if defined(GC_FREEBSD_THREADS)
|
||||||
|
# if (__FREEBSD_version >= 500000)
|
||||||
|
printf("-lpthread\n");
|
||||||
|
# else
|
||||||
|
printf("-pthread\n");
|
||||||
|
# endif
|
||||||
|
# endif
|
||||||
# if defined(GC_HPUX_THREADS) || defined(GC_OSF1_THREADS)
|
# if defined(GC_HPUX_THREADS) || defined(GC_OSF1_THREADS)
|
||||||
printf("-lpthread -lrt\n");
|
printf("-lpthread -lrt\n");
|
||||||
# endif
|
# endif
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
/* Eventually this one may become unnecessary. For now we need */
|
/* Eventually this one may become unnecessary. For now we need */
|
||||||
/* it to keep the old-style build process working. */
|
/* it to keep the old-style build process working. */
|
||||||
#define GC_TMP_VERSION_MAJOR 6
|
#define GC_TMP_VERSION_MAJOR 6
|
||||||
#define GC_TMP_VERSION_MINOR 3
|
#define GC_TMP_VERSION_MINOR 6
|
||||||
#define GC_TMP_ALPHA_VERSION GC_NOT_ALPHA
|
#define GC_TMP_ALPHA_VERSION GC_NOT_ALPHA
|
||||||
|
|
||||||
#ifndef GC_NOT_ALPHA
|
#ifndef GC_NOT_ALPHA
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
# undef pthread_create
|
# undef pthread_create
|
||||||
# undef pthread_sigmask
|
# undef pthread_sigmask
|
||||||
# undef pthread_join
|
# undef pthread_join
|
||||||
|
# undef pthread_detach
|
||||||
# undef dlopen
|
# undef dlopen
|
||||||
|
|
||||||
# define DEBUG_CYGWIN_THREADS 0
|
# define DEBUG_CYGWIN_THREADS 0
|
||||||
|
@ -185,7 +186,7 @@ static void GC_delete_thread(DWORD thread_id) {
|
||||||
/* Must still be in_use, since nobody else can store our thread_id. */
|
/* Must still be in_use, since nobody else can store our thread_id. */
|
||||||
i++) {}
|
i++) {}
|
||||||
if (i > my_max) {
|
if (i > my_max) {
|
||||||
WARN("Removing nonexisiting thread %ld\n", (GC_word)thread_id);
|
WARN("Removing nonexistent thread %ld\n", (GC_word)thread_id);
|
||||||
} else {
|
} else {
|
||||||
GC_delete_gc_thread(thread_table+i);
|
GC_delete_gc_thread(thread_table+i);
|
||||||
}
|
}
|
||||||
|
@ -232,6 +233,9 @@ void GC_push_thread_structures GC_PROTO((void))
|
||||||
# endif
|
# endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Defined in misc.c */
|
||||||
|
extern CRITICAL_SECTION GC_write_cs;
|
||||||
|
|
||||||
void GC_stop_world()
|
void GC_stop_world()
|
||||||
{
|
{
|
||||||
DWORD thread_id = GetCurrentThreadId();
|
DWORD thread_id = GetCurrentThreadId();
|
||||||
|
@ -240,6 +244,9 @@ void GC_stop_world()
|
||||||
if (!GC_thr_initialized) ABORT("GC_stop_world() called before GC_thr_init()");
|
if (!GC_thr_initialized) ABORT("GC_stop_world() called before GC_thr_init()");
|
||||||
|
|
||||||
GC_please_stop = TRUE;
|
GC_please_stop = TRUE;
|
||||||
|
# ifndef CYGWIN32
|
||||||
|
EnterCriticalSection(&GC_write_cs);
|
||||||
|
# endif /* !CYGWIN32 */
|
||||||
for (i = 0; i <= GC_get_max_thread_index(); i++)
|
for (i = 0; i <= GC_get_max_thread_index(); i++)
|
||||||
if (thread_table[i].stack_base != 0
|
if (thread_table[i].stack_base != 0
|
||||||
&& thread_table[i].id != thread_id) {
|
&& thread_table[i].id != thread_id) {
|
||||||
|
@ -270,6 +277,9 @@ void GC_stop_world()
|
||||||
# endif
|
# endif
|
||||||
thread_table[i].suspended = TRUE;
|
thread_table[i].suspended = TRUE;
|
||||||
}
|
}
|
||||||
|
# ifndef CYGWIN32
|
||||||
|
LeaveCriticalSection(&GC_write_cs);
|
||||||
|
# endif /* !CYGWIN32 */
|
||||||
}
|
}
|
||||||
|
|
||||||
void GC_start_world()
|
void GC_start_world()
|
||||||
|
|
Loading…
Reference in New Issue