mirror of
git://gcc.gnu.org/git/gcc.git
synced 2025-01-31 22:10:17 +08:00
Import Boehm GC version 6.6.
From-SVN: r110204
This commit is contained in:
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>
|
||||
|
||||
PR libobjc/13946
|
||||
|
@ -17,28 +17,27 @@ else
|
||||
asm_libgc_sources =
|
||||
endif
|
||||
|
||||
GC_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 \
|
||||
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 \
|
||||
malloc.c mallocx.c mark.c mark_rts.c misc.c new_hblk.c \
|
||||
obj_map.c os_dep.c pcr_interface.c ptr_chck.c real_malloc.c reclaim.c \
|
||||
solaris_pthreads.c solaris_threads.c specific.c stubborn.c typd_mlc.c \
|
||||
backgraph.c win32_threads.c \
|
||||
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 \
|
||||
mips_sgi_mach_dep.s mips_ultrix_mach_dep.s powerpc_darwin_mach_dep.s \
|
||||
rs6000_mach_dep.s sparc_mach_dep.S sparc_netbsd_mach_dep.s \
|
||||
sparc_sunos4_mach_dep.s ia64_save_regs_in_stack.s
|
||||
|
||||
libgcjgc_la_SOURCES = $(GC_SOURCES)
|
||||
libgcjgc_convenience_la_SOURCES = $(GC_SOURCES)
|
||||
|
||||
# Include THREADLIBS here to ensure that the correct versions of
|
||||
# linuxthread semaphore functions get linked:
|
||||
libgcjgc_la_LIBADD = @addobjs@ $(THREADLIBS)
|
||||
libgcjgc_la_LIBADD = @addobjs@ $(THREADLIBS) $(UNWINDLIBS)
|
||||
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_DEPENDENCIES = @addobjs@
|
||||
@ -48,7 +47,7 @@ AM_CFLAGS = @GC_CFLAGS@
|
||||
|
||||
check_PROGRAMS = gctest
|
||||
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
|
||||
TESTS_ENVIRONMENT = LD_LIBRARY_PATH=../../$(MULTIBUILDTOP)gcc
|
||||
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
|
||||
# To build the parallel collector in a static library on HP/UX,
|
||||
# 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:
|
||||
# -pthread -DGC_OSF1_THREADS
|
||||
|
||||
@ -70,10 +70,11 @@ HOSTCFLAGS=$(CFLAGS)
|
||||
# Also requires -D_REENTRANT or -D_POSIX_C_SOURCE=199506L. See README.hp.
|
||||
# -DGC_LINUX_THREADS enables support for Xavier Leroy's Linux threads.
|
||||
# see README.linux. -D_REENTRANT may also be required.
|
||||
# -DGC_OSF1_THREADS enables support for Tru64 pthreads. Untested.
|
||||
# -DGC_FREEBSD_THREADS enables support for FreeBSD pthreads. Untested.
|
||||
# -DGC_OSF1_THREADS enables support for Tru64 pthreads.
|
||||
# -DGC_FREEBSD_THREADS enables support for FreeBSD pthreads.
|
||||
# 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.
|
||||
# See README.DGUX386.
|
||||
# -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()
|
||||
# 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.
|
||||
# Currently requires -DGC_LINUX_THREADS, but should be easy to port to
|
||||
# other pthreads environments. Recommended for multiprocessors.
|
||||
# Currently works only on platforms such as Linux which use pthread_support.c.
|
||||
# Recommended for multiprocessors.
|
||||
# -DUSE_COMPILER_TLS causes thread local allocation to use compiler-supported
|
||||
# "__thread" thread-local variables. This is the default in HP/UX. It
|
||||
# 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
|
||||
# by the indicated amount before trying to interpret them. Applied
|
||||
# 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)
|
||||
@ -283,9 +288,9 @@ AR= ar
|
||||
RANLIB= ranlib
|
||||
|
||||
|
||||
OBJS= alloc.o reclaim.o allchblk.o misc.o mach_dep.o os_dep.o mark_rts.o headers.o mark.o obj_map.o blacklst.o finalize.o new_hblk.o dbg_mlc.o malloc.o stubborn.o checksums.o solaris_threads.o 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
|
||||
|
||||
|
@ -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)/../ltmain.sh $(srcdir)/../config.guess \
|
||||
$(srcdir)/../config.sub
|
||||
$(srcdir)/../compile $(srcdir)/../ltmain.sh \
|
||||
$(srcdir)/../config.guess $(srcdir)/../config.sub
|
||||
subdir = .
|
||||
ACLOCAL_M4 = $(top_srcdir)/aclocal.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)/../libtool.m4 $(top_srcdir)/configure.ac
|
||||
am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
|
||||
@ -82,34 +83,36 @@ CONFIG_HEADER = $(top_builddir)/include/gc_config.h \
|
||||
CONFIG_CLEAN_FILES =
|
||||
LTLIBRARIES = $(noinst_LTLIBRARIES)
|
||||
am__DEPENDENCIES_1 =
|
||||
@POWERPC_DARWIN_TRUE@am__objects_1 = powerpc_darwin_mach_dep.lo
|
||||
am__objects_2 = allchblk.lo alloc.lo blacklst.lo checksums.lo \
|
||||
am_libgcjgc_la_OBJECTS = allchblk.lo alloc.lo blacklst.lo checksums.lo \
|
||||
dbg_mlc.lo dyn_load.lo finalize.lo gc_dlopen.lo gcj_mlc.lo \
|
||||
headers.lo aix_irix_threads.lo malloc.lo mallocx.lo mark.lo \
|
||||
mark_rts.lo misc.lo new_hblk.lo obj_map.lo os_dep.lo \
|
||||
pcr_interface.lo ptr_chck.lo real_malloc.lo reclaim.lo \
|
||||
solaris_pthreads.lo solaris_threads.lo specific.lo stubborn.lo \
|
||||
typd_mlc.lo backgraph.lo win32_threads.lo pthread_support.lo \
|
||||
pthread_stop_world.lo darwin_stop_world.lo $(am__objects_1)
|
||||
am_libgcjgc_la_OBJECTS = $(am__objects_2)
|
||||
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
|
||||
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 = \
|
||||
$(am_libgcjgc_convenience_la_OBJECTS)
|
||||
am__dirstamp = $(am__leading_dot)dirstamp
|
||||
am_gctest_OBJECTS = tests/test.$(OBJEXT)
|
||||
gctest_OBJECTS = $(am_gctest_OBJECTS)
|
||||
gctest_DEPENDENCIES = ./libgcjgc.la $(am__DEPENDENCIES_1) \
|
||||
$(am__DEPENDENCIES_1)
|
||||
gctest_DEPENDENCIES = ./libgcjgc.la $(am__DEPENDENCIES_1)
|
||||
DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir)/include -I$(top_builddir)/include
|
||||
depcomp =
|
||||
am__depfiles_maybe =
|
||||
COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
|
||||
$(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
|
||||
CCLD = $(CC)
|
||||
CCASCOMPILE = $(CCAS) $(AM_CCASFLAGS) $(CCASFLAGS)
|
||||
LTCCASCOMPILE = $(LIBTOOL) --mode=compile $(CCAS) $(AM_CCASFLAGS) \
|
||||
$(CCASFLAGS)
|
||||
SOURCES = $(libgcjgc_la_SOURCES) $(libgcjgc_convenience_la_SOURCES) \
|
||||
$(gctest_SOURCES)
|
||||
MULTISRCTOP =
|
||||
@ -254,34 +257,33 @@ SUBDIRS = include
|
||||
noinst_LTLIBRARIES = libgcjgc.la libgcjgc_convenience.la
|
||||
@POWERPC_DARWIN_FALSE@asm_libgc_sources =
|
||||
@POWERPC_DARWIN_TRUE@asm_libgc_sources = powerpc_darwin_mach_dep.s
|
||||
GC_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 \
|
||||
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 \
|
||||
malloc.c mallocx.c mark.c mark_rts.c misc.c new_hblk.c \
|
||||
obj_map.c os_dep.c pcr_interface.c ptr_chck.c real_malloc.c reclaim.c \
|
||||
solaris_pthreads.c solaris_threads.c specific.c stubborn.c typd_mlc.c \
|
||||
backgraph.c win32_threads.c \
|
||||
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 \
|
||||
mips_sgi_mach_dep.s mips_ultrix_mach_dep.s powerpc_darwin_mach_dep.s \
|
||||
rs6000_mach_dep.s sparc_mach_dep.S sparc_netbsd_mach_dep.s \
|
||||
sparc_sunos4_mach_dep.s ia64_save_regs_in_stack.s
|
||||
|
||||
libgcjgc_la_SOURCES = $(GC_SOURCES)
|
||||
libgcjgc_convenience_la_SOURCES = $(GC_SOURCES)
|
||||
|
||||
# Include THREADLIBS here to ensure that the correct versions of
|
||||
# linuxthread semaphore functions get linked:
|
||||
libgcjgc_la_LIBADD = @addobjs@ $(THREADLIBS)
|
||||
libgcjgc_la_LIBADD = @addobjs@ $(THREADLIBS) $(UNWINDLIBS)
|
||||
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_DEPENDENCIES = @addobjs@
|
||||
AM_CXXFLAGS = @GC_CFLAGS@
|
||||
AM_CFLAGS = @GC_CFLAGS@
|
||||
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
|
||||
TESTS_ENVIRONMENT = LD_LIBRARY_PATH=../../$(MULTIBUILDTOP)gcc
|
||||
TESTS = gctest
|
||||
@ -414,12 +416,6 @@ distclean-compile:
|
||||
.c.lo:
|
||||
$(LTCOMPILE) -c -o $@ $<
|
||||
|
||||
.s.o:
|
||||
$(CCASCOMPILE) -c $<
|
||||
|
||||
.s.obj:
|
||||
$(CCASCOMPILE) -c `$(CYGPATH_W) '$<'`
|
||||
|
||||
mostlyclean-libtool:
|
||||
-rm -f *.lo
|
||||
|
||||
|
35
boehm-gc/aclocal.m4
vendored
35
boehm-gc/aclocal.m4
vendored
@ -547,39 +547,6 @@ AC_DEFUN([AM_PROG_INSTALL_SH],
|
||||
install_sh=${install_sh-"$am_aux_dir/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.
|
||||
# From Jim Meyering
|
||||
|
||||
@ -1168,5 +1135,7 @@ AC_SUBST([am__untar])
|
||||
]) # _AM_PROG_TAR
|
||||
|
||||
m4_include([../config/acx.m4])
|
||||
m4_include([../config/depstand.m4])
|
||||
m4_include([../config/lead-dot.m4])
|
||||
m4_include([../config/no-executables.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);
|
||||
phdr -> hb_next = hhdr -> hb_next;
|
||||
}
|
||||
FREE_ASSERT(GC_free_bytes[index] >= hhdr -> hb_sz);
|
||||
INCR_FREE_BYTES(index, - (signed_word)(hhdr -> hb_sz));
|
||||
FREE_ASSERT(GC_free_bytes[index] >= 0);
|
||||
if (0 != hhdr -> hb_next) {
|
||||
hdr * nhdr;
|
||||
GC_ASSERT(!IS_FORWARDING_ADDR_OR_NIL(NHDR(hhdr)));
|
||||
|
@ -92,6 +92,16 @@ char * GC_copyright[] =
|
||||
|
||||
# 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 */
|
||||
|
||||
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 */
|
||||
/* visible progress. And if we don't count this, we have */
|
||||
/* 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 */
|
||||
/* new fragmentation, the same is probably true of the heap, */
|
||||
/* and the collection will be correspondingly cheaper. */
|
||||
@ -221,6 +232,8 @@ void GC_clear_a_few_frames()
|
||||
{
|
||||
# define NWORDS 64
|
||||
word frames[NWORDS];
|
||||
/* Some compilers will warn that frames was set but never used. */
|
||||
/* That's the whole idea ... */
|
||||
register int i;
|
||||
|
||||
for (i = 0; i < NWORDS; i++) frames[i] = 0;
|
||||
@ -293,7 +306,7 @@ void GC_maybe_gc()
|
||||
# endif
|
||||
if (GC_stopped_mark(GC_time_limit == GC_TIME_UNLIMITED?
|
||||
GC_never_stop_func : GC_timeout_stop_func)) {
|
||||
# ifdef SAVE_CALL_CHAIN
|
||||
# ifdef SAVE_CALL_CHAIN_IN_GC
|
||||
GC_save_callers(GC_last_stack);
|
||||
# endif
|
||||
GC_finish_collection();
|
||||
@ -358,7 +371,7 @@ GC_stop_func stop_func;
|
||||
}
|
||||
GC_invalidate_mark_state(); /* Flush mark stack. */
|
||||
GC_clear_marks();
|
||||
# ifdef SAVE_CALL_CHAIN
|
||||
# ifdef SAVE_CALL_CHAIN_IN_GC
|
||||
GC_save_callers(GC_last_stack);
|
||||
# endif
|
||||
GC_is_full_gc = TRUE;
|
||||
@ -413,7 +426,7 @@ int n;
|
||||
for (i = GC_deficit; i < GC_RATE*n; i++) {
|
||||
if (GC_mark_some((ptr_t)0)) {
|
||||
/* Need to finish a collection */
|
||||
# ifdef SAVE_CALL_CHAIN
|
||||
# ifdef SAVE_CALL_CHAIN_IN_GC
|
||||
GC_save_callers(GC_last_stack);
|
||||
# endif
|
||||
# ifdef PARALLEL_MARK
|
||||
@ -929,7 +942,7 @@ word n;
|
||||
# endif
|
||||
expansion_slop = WORDS_TO_BYTES(min_words_allocd()) + 4*MAXHINCR*HBLKSIZE;
|
||||
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 */
|
||||
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;
|
||||
{
|
||||
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();
|
||||
} else {
|
||||
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) {
|
||||
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) {
|
||||
slop = 4;
|
||||
} else {
|
||||
|
@ -1,4 +1,3 @@
|
||||
# $Id: alpha_mach_dep.s,v 1.2 1993/01/18 22:54:51 dosser Exp $
|
||||
.arch ev6
|
||||
|
||||
.text
|
||||
@ -12,13 +11,13 @@ GC_push_regs:
|
||||
.mask 0x04000000, 0
|
||||
.frame $sp, 16, $26, 0
|
||||
|
||||
# $0 integer result
|
||||
# $1-$8 temp regs - not preserved cross calls
|
||||
# $9-$15 call saved regs
|
||||
# $16-$21 argument regs - not preserved cross calls
|
||||
# $22-$28 temp regs - not preserved cross calls
|
||||
# $29 global pointer - not preserved cross calls
|
||||
# $30 stack pointer
|
||||
/* $0 integer result */
|
||||
/* $1-$8 temp regs - not preserved cross calls */
|
||||
/* $9-$15 call saved regs */
|
||||
/* $16-$21 argument regs - not preserved cross calls */
|
||||
/* $22-$28 temp regs - not preserved cross calls */
|
||||
/* $29 global pointer - not preserved cross calls */
|
||||
/* $30 stack pointer */
|
||||
|
||||
# define call_push(x) \
|
||||
mov x, $16; \
|
||||
@ -33,12 +32,12 @@ GC_push_regs:
|
||||
call_push($14)
|
||||
call_push($15)
|
||||
|
||||
# $f0-$f1 floating point results
|
||||
# $f2-$f9 call saved regs
|
||||
# $f10-$f30 temp regs - not preserved cross calls
|
||||
/* $f0-$f1 floating point results */
|
||||
/* $f2-$f9 call saved regs */
|
||||
/* $f10-$f30 temp regs - not preserved cross calls */
|
||||
|
||||
# Use the most efficient transfer method for this hardware.
|
||||
# Bit 1 detects the FIX extension, which includes ftoit.
|
||||
/* Use the most efficient transfer method for this hardware. */
|
||||
/* Bit 1 detects the FIX extension, which includes ftoit. */
|
||||
amask 2, $0
|
||||
bne $0, $use_stack
|
||||
|
||||
|
2
boehm-gc/configure
vendored
2
boehm-gc/configure
vendored
@ -1767,7 +1767,7 @@ fi
|
||||
|
||||
# Define the identity of the package.
|
||||
PACKAGE=gc
|
||||
VERSION=6.3
|
||||
VERSION=6.6
|
||||
|
||||
|
||||
# Some tools Automake needs.
|
||||
|
@ -36,7 +36,7 @@ ACX_NONCANONICAL_TARGET
|
||||
mkinstalldirs="`cd $ac_aux_dir && ${PWDCMD-pwd}`/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.
|
||||
GCC_NO_EXECUTABLES
|
||||
|
@ -59,7 +59,7 @@ static int extract_conv_spec(CORD_pos source, char *buf,
|
||||
register int result = 0;
|
||||
register int current_number = 0;
|
||||
register int saw_period = 0;
|
||||
register int saw_number;
|
||||
register int saw_number = 0;
|
||||
register int chars_so_far = 0;
|
||||
register char current;
|
||||
|
||||
@ -243,7 +243,7 @@ int CORD_vsprintf(CORD * out, CORD format, va_list args)
|
||||
char * str = va_arg(args, char *);
|
||||
register char c;
|
||||
|
||||
while (c = *str++) {
|
||||
while ((c = *str++)) {
|
||||
CORD_ec_append(result, c);
|
||||
}
|
||||
goto done;
|
||||
@ -320,7 +320,7 @@ int CORD_vsprintf(CORD * out, CORD format, va_list args)
|
||||
if (buf != result[0].ec_bufptr) {
|
||||
register char c;
|
||||
|
||||
while (c = *buf++) {
|
||||
while ((c = *buf++)) {
|
||||
CORD_ec_append(result, c);
|
||||
}
|
||||
} else {
|
||||
|
@ -221,7 +221,7 @@ void test_printf()
|
||||
if (CORD_cmp(result, result2) != 0)ABORT("CORD_sprintf goofed 5");
|
||||
}
|
||||
|
||||
main()
|
||||
int main()
|
||||
{
|
||||
# ifdef THINK_C
|
||||
printf("cordtest:\n");
|
||||
|
0
boehm-gc/cord/de_win.ICO
Normal file → Executable file
0
boehm-gc/cord/de_win.ICO
Normal file → Executable file
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
|
||||
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 {
|
||||
unsigned long savedSP;
|
||||
@ -24,12 +30,17 @@ typedef struct StackFrame {
|
||||
unsigned long savedRTOC;
|
||||
} StackFrame;
|
||||
|
||||
|
||||
unsigned int FindTopOfStack(unsigned int stack_start) {
|
||||
unsigned long FindTopOfStack(unsigned int stack_start) {
|
||||
StackFrame *frame;
|
||||
|
||||
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 {
|
||||
frame = (StackFrame *)stack_start;
|
||||
}
|
||||
@ -38,7 +49,7 @@ unsigned int FindTopOfStack(unsigned int stack_start) {
|
||||
/* GC_printf1("FindTopOfStack start at sp = %p\n", frame); */
|
||||
# endif
|
||||
do {
|
||||
if (frame->savedSP == NULL) break;
|
||||
if (frame->savedSP == 0) break;
|
||||
/* if there are no more stack frames, stop */
|
||||
|
||||
frame = (StackFrame*)frame->savedSP;
|
||||
@ -54,9 +65,88 @@ unsigned int FindTopOfStack(unsigned int stack_start) {
|
||||
/* GC_printf1("FindTopOfStack finish at sp = %p\n", frame); */
|
||||
# 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() {
|
||||
int i;
|
||||
kern_return_t r;
|
||||
@ -76,8 +166,12 @@ void GC_push_all_stacks() {
|
||||
lo = GC_approx_sp();
|
||||
hi = (ptr_t)FindTopOfStack(0);
|
||||
} else {
|
||||
# ifdef POWERPC
|
||||
# if defined(POWERPC)
|
||||
# if CPP_WORDSZ == 32
|
||||
ppc_thread_state_t info;
|
||||
# else
|
||||
ppc_thread_state64_t info;
|
||||
# endif
|
||||
mach_msg_type_number_t outCount = THREAD_STATE_MAX;
|
||||
r = thread_get_state(thread, MACHINE_THREAD_STATE,
|
||||
(natural_t *)&info, &outCount);
|
||||
@ -156,6 +250,7 @@ void GC_push_all_stacks() {
|
||||
GC_push_all_stack(lo, hi);
|
||||
} /* for(p=GC_threads[i]...) */
|
||||
}
|
||||
#endif /* !DARWIN_DONT_PARSE_STACK */
|
||||
|
||||
static mach_port_t GC_mach_handler_thread;
|
||||
static int GC_use_mach_handler_thread = 0;
|
||||
@ -325,6 +420,8 @@ void GC_start_world()
|
||||
kern_return_t kern_result;
|
||||
thread_act_array_t act_list;
|
||||
mach_msg_type_number_t listcount;
|
||||
struct thread_basic_info info;
|
||||
mach_msg_type_number_t outCount = THREAD_INFO_MAX;
|
||||
|
||||
# if DEBUG_THREADS
|
||||
GC_printf0("World starting\n");
|
||||
@ -351,8 +448,6 @@ void GC_start_world()
|
||||
# endif
|
||||
continue;
|
||||
}
|
||||
struct thread_basic_info info;
|
||||
mach_msg_type_number_t outCount = THREAD_INFO_MAX;
|
||||
kern_result = thread_info(thread, THREAD_BASIC_INFO,
|
||||
(thread_info_t)&info, &outCount);
|
||||
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
|
||||
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
|
||||
|
||||
|
@ -2100,7 +2100,151 @@ Since gc6.3alpha6:
|
||||
to Andrew Begel.)
|
||||
- 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.
|
||||
|
||||
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:
|
||||
- The USE_MUNMAP code should really use a separate data structure
|
||||
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
|
||||
=========================================
|
||||
|
||||
|
@ -115,6 +115,7 @@ GC_IGNORE_FB[=<n>] - (Win32 only.) Try to avoid treating a mapped
|
||||
are never honored, eliminating this risk for most,
|
||||
but not all, applications. This feature is likely to disappear
|
||||
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
|
||||
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:
|
||||
|
||||
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
|
||||
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
|
||||
MIT pthreads).
|
||||
|
||||
|
@ -43,9 +43,7 @@ can result in unpleasant heap growth. But it seems better than the
|
||||
race/deadlock issues we had before.
|
||||
|
||||
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
|
||||
first thread. (This avoids a deadlock arising from calling GC_thr_init
|
||||
with the allocation lock held.)
|
||||
GC_malloc a deadlock is likely to result.
|
||||
|
||||
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
|
||||
|
@ -96,17 +96,25 @@
|
||||
/* Newer versions of GNU/Linux define this macro. We
|
||||
* define it similarly for any ELF systems that don't. */
|
||||
# ifndef ElfW
|
||||
# ifdef __NetBSD__
|
||||
# if ELFSIZE == 32
|
||||
# if defined(FREEBSD)
|
||||
# if __ELF_WORD_SIZE == 32
|
||||
# define ElfW(type) Elf32_##type
|
||||
# else
|
||||
# define ElfW(type) Elf64_##type
|
||||
# endif
|
||||
# else
|
||||
# if !defined(ELF_CLASS) || ELF_CLASS == ELFCLASS32
|
||||
# define ElfW(type) Elf32_##type
|
||||
# ifdef NETBSD
|
||||
# if ELFSIZE == 32
|
||||
# define ElfW(type) Elf32_##type
|
||||
# else
|
||||
# define ElfW(type) Elf64_##type
|
||||
# endif
|
||||
# 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
|
||||
@ -485,7 +493,6 @@ static struct link_map *
|
||||
GC_FirstDLOpenedLinkMap()
|
||||
{
|
||||
ElfW(Dyn) *dp;
|
||||
struct r_debug *r;
|
||||
static struct link_map *cachedResult = 0;
|
||||
|
||||
if( _DYNAMIC == 0) {
|
||||
@ -494,6 +501,12 @@ GC_FirstDLOpenedLinkMap()
|
||||
if( cachedResult == 0 ) {
|
||||
int tag;
|
||||
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 ) {
|
||||
struct link_map *lm
|
||||
= ((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++) {
|
||||
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))
|
||||
goto irrelevant;
|
||||
/* 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 */
|
||||
/* and ignored? */
|
||||
/* Unfortunately, we currently have no real way to tell */
|
||||
/* automatically, and rely largely on user input. */
|
||||
/* FIXME: If we had more data on this phenomenon (e.g. */
|
||||
/* is start aligned to a MB multiple?) we should be able to */
|
||||
/* do better. */
|
||||
/* Unfortunately, we currently are not quite sure how to tell */
|
||||
/* this automatically, and rely largely on user input. */
|
||||
/* We expect that any mapping with type MEM_MAPPED (which */
|
||||
/* apparently excludes library data sections) can be safely */
|
||||
/* ignored. But we're too chicken to do that in this */
|
||||
/* version. */
|
||||
/* Based on a very limited sample, it appears that: */
|
||||
/* - Frame buffer mappings appear as mappings of length */
|
||||
/* 2**n MB - 192K. (We guess the 192K can vary a bit.) */
|
||||
/* - Have a stating address at best 64K aligned. */
|
||||
/* I'd love more information about the mapping, since I */
|
||||
/* can't reproduce the problem. */
|
||||
static GC_bool is_frame_buffer(ptr_t start, size_t len)
|
||||
/* - Frame buffer mappings appear as mappings of large */
|
||||
/* length, usually a bit less than a power of two. */
|
||||
/* - The definition of "a bit less" in the above cannot */
|
||||
/* be made more precise. */
|
||||
/* - Have a starting address at best 64K aligned. */
|
||||
/* - Have type == MEM_MAPPED. */
|
||||
static GC_bool is_frame_buffer(ptr_t start, size_t len, DWORD tp)
|
||||
{
|
||||
static GC_bool initialized = FALSE;
|
||||
# define MB (1024*1024)
|
||||
# define DEFAULT_FB_MB 15
|
||||
# define MIN_FB_MB 3
|
||||
|
||||
if (GC_disallow_ignore_fb) return FALSE;
|
||||
if (GC_disallow_ignore_fb || tp != MEM_MAPPED) return FALSE;
|
||||
if (!initialized) {
|
||||
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)
|
||||
* instead of just checking for MEM_IMAGE.
|
||||
* If something breaks, change it back. */
|
||||
&& buf.Type == MEM_IMAGE) {
|
||||
&& buf.Type == MEM_IMAGE) {
|
||||
# ifdef DEBUG_VIRTUALQUERY
|
||||
GC_dump_meminfo(&buf);
|
||||
# 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) {
|
||||
unsigned long start,end,i;
|
||||
const struct section *sec;
|
||||
if (GC_no_dls) return;
|
||||
for(i=0;i<sizeof(GC_dyld_sections)/sizeof(GC_dyld_sections[0]);i++) {
|
||||
sec = getsectbynamefromheader(
|
||||
hdr,GC_dyld_sections[i].seg,GC_dyld_sections[i].sect);
|
||||
if(sec == NULL || sec->size == 0) continue;
|
||||
start = slide + sec->addr;
|
||||
end = start + sec->size;
|
||||
# ifdef DARWIN_DEBUG
|
||||
GC_printf4("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);
|
||||
}
|
||||
if(sec == NULL || sec->size == 0) continue;
|
||||
start = slide + sec->addr;
|
||||
end = start + sec->size;
|
||||
# ifdef DARWIN_DEBUG
|
||||
GC_print_static_roots();
|
||||
# endif
|
||||
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
|
||||
GC_print_static_roots();
|
||||
# endif
|
||||
}
|
||||
|
||||
/* 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;
|
||||
start = slide + sec->addr;
|
||||
end = start + sec->size;
|
||||
# ifdef DARWIN_DEBUG
|
||||
# ifdef DARWIN_DEBUG
|
||||
GC_printf4("Removing section at %p-%p (%lu bytes) from image %s\n",
|
||||
start,end,sec->size,GC_dyld_name_for_hdr(hdr));
|
||||
# endif
|
||||
GC_remove_roots((char*)start,(char*)end);
|
||||
}
|
||||
# ifdef DARWIN_DEBUG
|
||||
GC_print_static_roots();
|
||||
# endif
|
||||
# ifdef DARWIN_DEBUG
|
||||
GC_print_static_roots();
|
||||
# endif
|
||||
}
|
||||
|
||||
void GC_register_dynamic_libraries() {
|
||||
|
@ -43,6 +43,8 @@ DIST_COMMON = $(noinst_HEADERS) $(srcdir)/Makefile.am \
|
||||
$(srcdir)/gc_ext_config.h.in
|
||||
ACLOCAL_M4 = $(top_srcdir)/aclocal.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)/../libtool.m4 $(top_srcdir)/configure.ac
|
||||
am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
|
||||
|
@ -55,7 +55,7 @@
|
||||
# include <gc_config.h>
|
||||
# include "gc_config_macros.h"
|
||||
|
||||
# if defined(__STDC__) || defined(__cplusplus)
|
||||
# if defined(__STDC__) || defined(__cplusplus) || defined(_AIX)
|
||||
# define GC_PROTO(args) args
|
||||
typedef void * GC_PTR;
|
||||
# define GC_CONST const
|
||||
@ -214,7 +214,7 @@ GC_API GC_word GC_free_space_divisor;
|
||||
/* least N/GC_free_space_divisor bytes between */
|
||||
/* collections, where N is the heap size plus */
|
||||
/* 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 */
|
||||
/* but more collection time. Decreasing it */
|
||||
/* 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. */
|
||||
/* Return 0 if displaced_pointer doesn't point to within a valid */
|
||||
/* 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));
|
||||
|
||||
/* 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. */
|
||||
#ifdef GC_DEBUG
|
||||
# ifdef __STDC__
|
||||
# if defined(__STDC__) || defined(_AIX)
|
||||
# define GC_PTR_STORE(p, q) \
|
||||
(*(void **)GC_is_visible(p) = GC_is_valid_displacement(q))
|
||||
# else
|
||||
@ -972,12 +975,32 @@ extern void GC_thr_init GC_PROTO((void));/* Needed for Solaris/X86 */
|
||||
# define GC_INIT() { extern end, etext; \
|
||||
GC_noop(&end, &etext); }
|
||||
#else
|
||||
# if defined(__CYGWIN32__) && defined(GC_DLL) || defined (_AIX)
|
||||
# if defined(__CYGWIN32__) || defined (_AIX)
|
||||
/*
|
||||
* Similarly gnu-win32 DLLs need explicit initialization from
|
||||
* 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
|
||||
# if defined(__APPLE__) && defined(__MACH__) || defined(GC_WIN32_THREADS)
|
||||
# define GC_INIT() { GC_init(); }
|
||||
|
@ -59,6 +59,10 @@
|
||||
# define GC_DGUX386_THREADS
|
||||
# define GC_PTHREADS
|
||||
# endif
|
||||
# if defined(_AIX)
|
||||
# define GC_AIX_THREADS
|
||||
# define GC_PTHREADS
|
||||
# endif
|
||||
#endif /* GC_THREADS */
|
||||
|
||||
#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
|
||||
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.
|
||||
|
||||
|
||||
|
@ -109,7 +109,7 @@ enum { GC_byte_alignment = 8 };
|
||||
enum { GC_word_alignment = GC_byte_alignment/GC_bytes_per_word };
|
||||
|
||||
inline void * &GC_obj_link(void * p)
|
||||
{ return *(void **)p; }
|
||||
{ return *reinterpret_cast<void **>(p); }
|
||||
|
||||
// Compute a number of words >= n+1 bytes.
|
||||
// The +1 allows for pointers one past the end.
|
||||
@ -228,7 +228,7 @@ class single_client_gc_alloc_template {
|
||||
} else {
|
||||
flh = GC_objfreelist_ptr + nwords;
|
||||
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));
|
||||
*flh = p;
|
||||
GC_aux::GC_mem_recently_freed += nwords;
|
||||
@ -352,9 +352,9 @@ class simple_alloc<T, alloc> { \
|
||||
public: \
|
||||
static T *allocate(size_t n) \
|
||||
{ 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) \
|
||||
{ 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) \
|
||||
{ if (0 != n) alloc::ptr_free_deallocate(p, n * sizeof (T)); } \
|
||||
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 */
|
||||
/* 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. */
|
||||
# define HC_GET_HDR(p, hhdr, source) \
|
||||
{ \
|
||||
|
@ -139,6 +139,25 @@
|
||||
# define GC_TEST_AND_SET_DEFINED
|
||||
# endif
|
||||
# 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) {
|
||||
int oldval;
|
||||
int temp = 1; /* locked value */
|
||||
@ -156,12 +175,13 @@
|
||||
: "cr0","memory");
|
||||
return oldval;
|
||||
}
|
||||
# define GC_TEST_AND_SET_DEFINED
|
||||
inline static void GC_clear(volatile unsigned int *addr) {
|
||||
__asm__ __volatile__("eieio" : : : "memory");
|
||||
*(addr) = 0;
|
||||
}
|
||||
# define GC_CLEAR_DEFINED
|
||||
# endif
|
||||
# define GC_TEST_AND_SET_DEFINED
|
||||
inline static void GC_clear(volatile unsigned int *addr) {
|
||||
__asm__ __volatile__("lwsync" : : : "memory");
|
||||
*(addr) = 0;
|
||||
}
|
||||
# define GC_CLEAR_DEFINED
|
||||
# endif
|
||||
# if defined(ALPHA)
|
||||
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)
|
||||
# endif
|
||||
# else
|
||||
# include <sgidefs.h>
|
||||
# include <mutex.h>
|
||||
# define GC_test_and_set(addr) __test_and_set32((void *)addr,1)
|
||||
# define GC_clear(addr) __lock_release(addr);
|
||||
# define GC_CLEAR_DEFINED
|
||||
@ -354,7 +376,7 @@
|
||||
# endif
|
||||
|
||||
# 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)
|
||||
# include <pthread.h>
|
||||
# if defined(PARALLEL_MARK)
|
||||
@ -401,6 +423,29 @@
|
||||
|
||||
# if defined(POWERPC)
|
||||
# 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. */
|
||||
inline static GC_bool GC_compare_and_exchange(volatile GC_word *addr,
|
||||
GC_word old, GC_word new_val)
|
||||
@ -422,6 +467,7 @@
|
||||
: "cr0","memory");
|
||||
return (GC_bool) result;
|
||||
}
|
||||
# endif
|
||||
# endif /* !GENERIC_COMPARE_AND_SWAP */
|
||||
inline static void GC_memory_barrier()
|
||||
{
|
||||
@ -598,33 +644,6 @@
|
||||
extern pthread_t GC_mark_lock_holder;
|
||||
# endif
|
||||
# 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_PTHREADS)
|
||||
# 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
|
||||
struct callinfo {
|
||||
word ci_pc; /* Caller, not callee, pc */
|
||||
@ -286,6 +275,16 @@ void GC_print_callers GC_PROTO((struct callinfo info[NFRAMES]));
|
||||
};
|
||||
#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
|
||||
|
||||
/* And one for FreeBSD: */
|
||||
# if defined(__FreeBSD__)
|
||||
# if defined(__FreeBSD__) && !defined(FREEBSD)
|
||||
# define FREEBSD
|
||||
# endif
|
||||
|
||||
@ -97,6 +97,10 @@
|
||||
# define ARM32
|
||||
# define mach_type_known
|
||||
# endif
|
||||
# if defined(NETBSD) && defined(__sh__)
|
||||
# define SH
|
||||
# define mach_type_known
|
||||
# endif
|
||||
# if defined(vax)
|
||||
# define VAX
|
||||
# ifdef ultrix
|
||||
@ -167,7 +171,7 @@
|
||||
# define mach_type_known
|
||||
# endif
|
||||
# if defined(sparc) && defined(unix) && !defined(sun) && !defined(linux) \
|
||||
&& !defined(__OpenBSD__) && !(__NetBSD__)
|
||||
&& !defined(__OpenBSD__) && !defined(__NetBSD__) && !defined(__FreeBSD__)
|
||||
# define SPARC
|
||||
# define DRSNX
|
||||
# define mach_type_known
|
||||
@ -198,14 +202,16 @@
|
||||
# if defined(_PA_RISC1_0) || defined(_PA_RISC1_1) || defined(_PA_RISC2_0) \
|
||||
|| defined(hppa) || defined(__hppa__)
|
||||
# define HP_PA
|
||||
# ifndef LINUX
|
||||
# if !defined(LINUX) && !defined(HPUX)
|
||||
# define HPUX
|
||||
# endif
|
||||
# define mach_type_known
|
||||
# endif
|
||||
# if defined(__ia64) && defined(_HPUX_SOURCE)
|
||||
# define IA64
|
||||
# define HPUX
|
||||
# ifndef HPUX
|
||||
# define HPUX
|
||||
# endif
|
||||
# define mach_type_known
|
||||
# endif
|
||||
# if defined(__BEOS__) && defined(_X86_)
|
||||
@ -235,7 +241,8 @@
|
||||
# endif
|
||||
# define mach_type_known
|
||||
# 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 mach_type_known
|
||||
# endif
|
||||
@ -293,11 +300,11 @@
|
||||
# define DARWIN
|
||||
# define POWERPC
|
||||
# define mach_type_known
|
||||
# endif
|
||||
# if defined(__APPLE__) && defined(__MACH__) && defined(__i386__)
|
||||
# define DARWIN
|
||||
# define I386
|
||||
# else
|
||||
# if defined(__i386__)
|
||||
# define I386
|
||||
--> Not really supported, but at least we recognize it.
|
||||
# endif
|
||||
# endif
|
||||
# if defined(NeXT) && defined(mc68000)
|
||||
# define M68K
|
||||
@ -326,6 +333,10 @@
|
||||
# define X86_64
|
||||
# define mach_type_known
|
||||
# endif
|
||||
# if defined(FREEBSD) && defined(__sparc__)
|
||||
# define SPARC
|
||||
# define mach_type_known
|
||||
#endif
|
||||
# if defined(bsdi) && (defined(i386) || defined(__i386__))
|
||||
# define I386
|
||||
# define BSDI
|
||||
@ -486,6 +497,9 @@
|
||||
/* POWERPC ==> IBM/Apple PowerPC */
|
||||
/* (MACOS(<=9),DARWIN(incl.MACOSX),*/
|
||||
/* LINUX, NETBSD, NOSYS variants) */
|
||||
/* Handles 32 and 64-bit variants. */
|
||||
/* AIX should be handled here, but */
|
||||
/* that's called an RS6000. */
|
||||
/* CRIS ==> Axis Etrax */
|
||||
/* M32R ==> Renesas M32R */
|
||||
|
||||
@ -493,12 +507,12 @@
|
||||
/*
|
||||
* 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.
|
||||
* 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
|
||||
* 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.
|
||||
* OS_TYPE is analogous for the OS.
|
||||
@ -615,7 +629,8 @@
|
||||
*/
|
||||
# if defined(__GNUC__) && ((__GNUC__ >= 3) || \
|
||||
(__GNUC__ == 2 && __GNUC_MINOR__ >= 8)) \
|
||||
&& !defined(__INTEL_COMPILER)
|
||||
&& !defined(__INTEL_COMPILER) \
|
||||
&& !defined(__PATHCC__)
|
||||
# define HAVE_BUILTIN_UNWIND_INIT
|
||||
# endif
|
||||
|
||||
@ -740,7 +755,7 @@
|
||||
# endif
|
||||
# endif
|
||||
|
||||
# ifdef POWERPC
|
||||
# if defined(POWERPC)
|
||||
# define MACH_TYPE "POWERPC"
|
||||
# ifdef MACOS
|
||||
# define ALIGNMENT 2 /* Still necessary? Could it be 4? */
|
||||
@ -753,10 +768,12 @@
|
||||
# define DATAEND /* not needed */
|
||||
# endif
|
||||
# ifdef LINUX
|
||||
# if (defined (powerpc64) || defined(__powerpc64__))
|
||||
# if defined(__powerpc64__)
|
||||
# define ALIGNMENT 8
|
||||
# define CPP_WORDSZ 64
|
||||
# define HBLKSIZE 4096
|
||||
# ifndef HBLKSIZE
|
||||
# define HBLKSIZE 4096
|
||||
# endif
|
||||
# else
|
||||
# define ALIGNMENT 4
|
||||
# endif
|
||||
@ -770,7 +787,7 @@
|
||||
# define DATAEND (_end)
|
||||
# endif
|
||||
# ifdef DARWIN
|
||||
# if (defined (__ppc64__))
|
||||
# ifdef __ppc64__
|
||||
# define ALIGNMENT 8
|
||||
# define CPP_WORDSZ 64
|
||||
# else
|
||||
@ -787,8 +804,10 @@
|
||||
# define USE_MMAP_ANON
|
||||
# define USE_ASM_PUSH_REGS
|
||||
/* This is potentially buggy. It needs more testing. See the comments in
|
||||
os_dep.c */
|
||||
# define MPROTECT_VDB
|
||||
os_dep.c. It relies on threads to track writes. */
|
||||
# ifdef GC_DARWIN_THREADS
|
||||
/* # define MPROTECT_VDB -- diabled for now. May work for some apps. */
|
||||
# endif
|
||||
# include <unistd.h>
|
||||
# define GETPAGESIZE() getpagesize()
|
||||
# if defined(USE_PPC_PREFETCH) && defined(__GNUC__)
|
||||
@ -975,6 +994,23 @@
|
||||
# define DATASTART ((ptr_t)(etext))
|
||||
# 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
|
||||
|
||||
# ifdef I386
|
||||
@ -1158,26 +1194,8 @@
|
||||
# endif
|
||||
# ifdef CYGWIN32
|
||||
# define OS_TYPE "CYGWIN32"
|
||||
extern int _data_start__[];
|
||||
extern int _data_end__[];
|
||||
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__))
|
||||
# define DATASTART ((ptr_t)GC_DATASTART) /* From gc.h */
|
||||
# define DATAEND ((ptr_t)GC_DATAEND)
|
||||
# undef STACK_GRAN
|
||||
# define STACK_GRAN 0x10000
|
||||
# define HEURISTIC1
|
||||
@ -1421,6 +1439,8 @@
|
||||
# define CPP_WORDSZ 32
|
||||
# define STACKBOTTOM ((ptr_t)((ulong)&errno))
|
||||
# endif
|
||||
# define USE_MMAP
|
||||
# define USE_MMAP_ANON
|
||||
/* From AIX linker man page:
|
||||
_text Specifies the first location of the program.
|
||||
_etext Specifies the first location after the program.
|
||||
@ -1728,7 +1748,7 @@
|
||||
# define USE_GENERIC_PUSH_REGS
|
||||
# ifdef UTS4
|
||||
# define OS_TYPE "UTS4"
|
||||
extern int etext[];
|
||||
extern int etext[];
|
||||
extern int _etext[];
|
||||
extern int _end[];
|
||||
extern ptr_t GC_SysVGetDataStart();
|
||||
@ -1742,18 +1762,20 @@
|
||||
# define MACH_TYPE "S390"
|
||||
# define USE_GENERIC_PUSH_REGS
|
||||
# ifndef __s390x__
|
||||
# define ALIGNMENT 4
|
||||
# define CPP_WORDSZ 32
|
||||
# define ALIGNMENT 4
|
||||
# define CPP_WORDSZ 32
|
||||
# else
|
||||
# define ALIGNMENT 8
|
||||
# define CPP_WORDSZ 64
|
||||
# define HBLKSIZE 4096
|
||||
# define ALIGNMENT 8
|
||||
# define CPP_WORDSZ 64
|
||||
# endif
|
||||
# ifndef HBLKSIZE
|
||||
# define HBLKSIZE 4096
|
||||
# endif
|
||||
# ifdef LINUX
|
||||
# define OS_TYPE "LINUX"
|
||||
# define LINUX_STACKBOTTOM
|
||||
# define DYNAMIC_LOADING
|
||||
extern int __data_start[];
|
||||
extern int __data_start[];
|
||||
# define DATASTART ((ptr_t)(__data_start))
|
||||
extern int _end[];
|
||||
# define DATAEND (_end)
|
||||
@ -1859,6 +1881,13 @@
|
||||
extern int _end[];
|
||||
# define DATAEND (_end)
|
||||
# endif
|
||||
# ifdef NETBSD
|
||||
# define OS_TYPE "NETBSD"
|
||||
# define HEURISTIC2
|
||||
# define DATASTART GC_data_start
|
||||
# define USE_GENERIC_PUSH_REGS
|
||||
# define DYNAMIC_LOADING
|
||||
# endif
|
||||
# endif
|
||||
|
||||
# ifdef SH4
|
||||
@ -2107,7 +2136,8 @@
|
||||
# define THREADS
|
||||
# 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(I386) && defined(__LCC__))
|
||||
/* Use setjmp based hack to mark from callee-save registers. */
|
||||
@ -2249,7 +2279,7 @@
|
||||
# else
|
||||
# if defined(AMIGA) && defined(GC_AMIGA_FASTALLOC)
|
||||
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_page_size-1)
|
||||
# else
|
||||
@ -2265,4 +2295,10 @@
|
||||
|
||||
#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 */
|
||||
|
@ -2,7 +2,6 @@
|
||||
#define GC_PTHREAD_STOP_WORLD_H
|
||||
|
||||
struct thread_stop_info {
|
||||
int signal;
|
||||
word last_stop_count; /* GC_last_stop_count value when thread */
|
||||
/* last successfully handled a suspend */
|
||||
/* signal. */
|
||||
|
@ -4,7 +4,7 @@
|
||||
# include "private/gc_priv.h"
|
||||
|
||||
# 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)
|
||||
# include "private/darwin_stop_world.h"
|
||||
|
@ -27,6 +27,10 @@
|
||||
# endif
|
||||
# endif
|
||||
|
||||
#if defined(RS6000) || defined(POWERPC)
|
||||
# include <ucontext.h>
|
||||
#endif
|
||||
|
||||
#if defined(__MWERKS__) && !defined(POWERPC)
|
||||
|
||||
asm static void PushMacRegisters()
|
||||
@ -413,6 +417,13 @@ ptr_t arg;
|
||||
/* the stack. */
|
||||
__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 */
|
||||
/* The idea is due to Parag Patel at HP. */
|
||||
/* We're not sure whether he would like */
|
||||
@ -426,7 +437,7 @@ ptr_t arg;
|
||||
for (; (char *)i < lim; i++) {
|
||||
*i = 0;
|
||||
}
|
||||
# if defined(POWERPC) || defined(MSWIN32) || defined(MSWINCE) \
|
||||
# if defined(MSWIN32) || defined(MSWINCE) \
|
||||
|| defined(UTS4) || defined(LINUX) || defined(EWS4800)
|
||||
(void) setjmp(regs);
|
||||
# else
|
||||
@ -435,15 +446,16 @@ ptr_t arg;
|
||||
/* SUSV3, setjmp() may or may not save signal mask. */
|
||||
/* _setjmp won't, but is less portable. */
|
||||
# endif
|
||||
# endif /* !AIX ... */
|
||||
# endif /* !HAVE_BUILTIN_UNWIND_INIT */
|
||||
# elif defined(PTHREADS) && !defined(MSWIN32) /* !USE_GENERIC_PUSH_REGS */
|
||||
/* We may still need this to save thread contexts. */
|
||||
/* This should probably be used in all Posix/non-gcc */
|
||||
/* settings. We defer that change to minimize risk. */
|
||||
ucontext_t ctxt;
|
||||
getcontext(&ctxt);
|
||||
# else /* Shouldn't be needed */
|
||||
ABORT("Unexpected call to GC_with_callee_saves_pushed");
|
||||
# else
|
||||
# if defined(PTHREADS) && !defined(MSWIN32) /* !USE_GENERIC_PUSH_REGS */
|
||||
/* We may still need this to save thread contexts. */
|
||||
ucontext_t ctxt;
|
||||
getcontext(&ctxt);
|
||||
# else /* Shouldn't be needed */
|
||||
ABORT("Unexpected call to GC_with_callee_saves_pushed");
|
||||
# endif
|
||||
# endif
|
||||
# if (defined(SPARC) && !defined(HAVE_BUILTIN_UNWIND_INIT)) \
|
||||
|| defined(IA64)
|
||||
@ -480,7 +492,7 @@ ptr_t cold_gc_frame;
|
||||
/* the stack. Return sp. */
|
||||
# ifdef SPARC
|
||||
asm(" .seg \"text\"");
|
||||
# if defined(SVR4) || defined(NETBSD)
|
||||
# if defined(SVR4) || defined(NETBSD) || defined(FREEBSD)
|
||||
asm(" .globl GC_save_regs_in_stack");
|
||||
asm("GC_save_regs_in_stack:");
|
||||
asm(" .type GC_save_regs_in_stack,#function");
|
||||
|
@ -172,7 +172,8 @@ int obj_kind;
|
||||
# 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. */
|
||||
ptr_t GC_generic_malloc_ignore_off_page(lb, k)
|
||||
register size_t lb;
|
||||
|
@ -858,9 +858,9 @@ mse * GC_steal_mark_stack(mse * low, mse * high, mse * local,
|
||||
++top;
|
||||
top -> mse_descr = descr;
|
||||
top -> mse_start = p -> mse_start;
|
||||
GC_ASSERT( top -> mse_descr & GC_DS_TAGS != GC_DS_LENGTH ||
|
||||
top -> mse_descr < GC_greatest_plausible_heap_addr
|
||||
- GC_least_plausible_heap_addr);
|
||||
GC_ASSERT( (top -> mse_descr & GC_DS_TAGS) != GC_DS_LENGTH ||
|
||||
top -> mse_descr < (ptr_t)GC_greatest_plausible_heap_addr
|
||||
- (ptr_t)GC_least_plausible_heap_addr);
|
||||
/* If this is a big object, count it as */
|
||||
/* size/256 + 1 objects. */
|
||||
++i;
|
||||
@ -1450,8 +1450,8 @@ void GC_push_all_eager(bottom, top)
|
||||
ptr_t bottom;
|
||||
ptr_t top;
|
||||
{
|
||||
word * b = (word *)(((long) bottom + ALIGNMENT-1) & ~(ALIGNMENT-1));
|
||||
word * t = (word *)(((long) top) & ~(ALIGNMENT-1));
|
||||
word * b = (word *)(((word) bottom + ALIGNMENT-1) & ~(ALIGNMENT-1));
|
||||
word * t = (word *)(((word) top) & ~(ALIGNMENT-1));
|
||||
register word *p;
|
||||
register word q;
|
||||
register word *lim;
|
||||
|
@ -246,7 +246,7 @@ void *arg2;
|
||||
byte_sz = WORDS_TO_BYTES(word_sz);
|
||||
if (GC_all_interior_pointers) {
|
||||
/* 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;
|
||||
@ -805,7 +805,10 @@ void GC_init_inner()
|
||||
|
||||
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) {
|
||||
DCL_LOCK_STATE;
|
||||
|
||||
|
@ -60,6 +60,10 @@
|
||||
# include <signal.h>
|
||||
# endif
|
||||
|
||||
#if defined(LINUX) || defined(LINUX_STACKBOTTOM)
|
||||
# include <ctype.h>
|
||||
#endif
|
||||
|
||||
/* Blatantly OS dependent routines, except for those that are related */
|
||||
/* 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
|
||||
// ^^^^^^^^ ^^^^^^^^ ^^^^ ^^
|
||||
// start end prot maj_dev
|
||||
// 0 9 18 32
|
||||
//
|
||||
// For 64 bit ABIs:
|
||||
// 0 17 34 56
|
||||
//
|
||||
// The parser is called with a pointer to the entry and the return value
|
||||
// is either NULL or is advanced to the next entry(the byte after the
|
||||
// trailing '\n'.)
|
||||
// Note that since about auguat 2003 kernels, the columns no longer have
|
||||
// fixed offsets on 64-bit kernels. Hence we no longer rely on fixed offsets
|
||||
// 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,
|
||||
@ -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 *prot_buf, unsigned int *maj_dev)
|
||||
{
|
||||
int i;
|
||||
char *tok;
|
||||
char *start_start, *end_start, *prot_start, *maj_dev_start;
|
||||
char *p;
|
||||
char *endp;
|
||||
|
||||
if (buf_ptr == NULL || *buf_ptr == '\0') {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memcpy(prot_buf, buf_ptr+OFFSET_MAP_PROT, 4);
|
||||
/* do the protections first. */
|
||||
p = buf_ptr;
|
||||
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';
|
||||
|
||||
if (prot_buf[1] == 'w') {/* we can skip all of this if it's not writable. */
|
||||
|
||||
tok = buf_ptr;
|
||||
buf_ptr[OFFSET_MAP_START+ADDR_WIDTH] = '\0';
|
||||
*start = strtoul(tok, NULL, 16);
|
||||
|
||||
tok = buf_ptr+OFFSET_MAP_END;
|
||||
buf_ptr[OFFSET_MAP_END+ADDR_WIDTH] = '\0';
|
||||
*end = strtoul(tok, NULL, 16);
|
||||
|
||||
buf_ptr += OFFSET_MAP_MAJDEV;
|
||||
tok = buf_ptr;
|
||||
while (*buf_ptr != ':') buf_ptr++;
|
||||
*buf_ptr++ = '\0';
|
||||
*maj_dev = strtoul(tok, NULL, 16);
|
||||
if (prot_buf[1] == 'w') {/* we can skip the rest if it's not writable. */
|
||||
/* Skip past protection field to offset field */
|
||||
while (!isspace(*p)) ++p; while (isspace(*p)) ++p;
|
||||
GC_ASSERT(isxdigit(*p));
|
||||
/* Skip past offset field, which we ignore */
|
||||
while (!isspace(*p)) ++p; while (isspace(*p)) ++p;
|
||||
maj_dev_start = p;
|
||||
GC_ASSERT(isxdigit(*maj_dev_start));
|
||||
*maj_dev = strtoul(maj_dev_start, NULL, 16);
|
||||
}
|
||||
|
||||
while (*buf_ptr && *buf_ptr++ != '\n');
|
||||
while (*p && *p++ != '\n');
|
||||
|
||||
return buf_ptr;
|
||||
return p;
|
||||
}
|
||||
|
||||
#endif /* Need to parse /proc/self/maps. */
|
||||
@ -699,7 +693,7 @@ ptr_t GC_get_stack_base()
|
||||
# if defined(SUNOS5SIGS) || defined(IRIX5) || defined(OSF1) \
|
||||
|| defined(HURD) || defined(NETBSD)
|
||||
static struct sigaction old_segv_act;
|
||||
# if defined(_sigargs) /* !Irix6.x */ || defined(HPUX) \
|
||||
# if defined(IRIX5) || defined(HPUX) \
|
||||
|| defined(HURD) || defined(NETBSD)
|
||||
static struct sigaction old_bus_act;
|
||||
# endif
|
||||
@ -732,9 +726,11 @@ ptr_t GC_get_stack_base()
|
||||
/* and setting a handler at the same time. */
|
||||
(void) sigaction(SIGSEGV, 0, &old_segv_act);
|
||||
(void) sigaction(SIGSEGV, &act, 0);
|
||||
(void) sigaction(SIGBUS, 0, &old_bus_act);
|
||||
(void) sigaction(SIGBUS, &act, 0);
|
||||
# else
|
||||
(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)
|
||||
/* Under Irix 5.x or HP/UX, we may get SIGBUS. */
|
||||
/* 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) \
|
||||
|| defined(OSF1) || defined(HURD) || defined(NETBSD)
|
||||
(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)
|
||||
(void) sigaction(SIGBUS, &old_bus_act, 0);
|
||||
# endif
|
||||
@ -854,13 +850,14 @@ ptr_t GC_get_stack_base()
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <ctype.h>
|
||||
|
||||
# define STAT_SKIP 27 /* Number of fields preceding startstack */
|
||||
/* field in /proc/self/stat */
|
||||
|
||||
#ifdef USE_LIBC_PRIVATES
|
||||
# pragma weak __libc_stack_end
|
||||
extern ptr_t __libc_stack_end;
|
||||
#endif
|
||||
|
||||
# ifdef IA64
|
||||
/* 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);
|
||||
}
|
||||
|
||||
# pragma weak __libc_ia64_register_backing_store_base
|
||||
extern ptr_t __libc_ia64_register_backing_store_base;
|
||||
# ifdef USE_LIBC_PRIVATES
|
||||
# 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)
|
||||
{
|
||||
if (0 != &__libc_ia64_register_backing_store_base
|
||||
&& 0 != __libc_ia64_register_backing_store_base) {
|
||||
/* Glibc 2.2.4 has a bug such that for dynamically linked */
|
||||
/* executables __libc_ia64_register_backing_store_base is */
|
||||
/* defined but uninitialized during constructor calls. */
|
||||
/* Hence we check for both nonzero address and value. */
|
||||
return __libc_ia64_register_backing_store_base;
|
||||
} else {
|
||||
word result = backing_store_base_from_proc();
|
||||
if (0 == result) {
|
||||
# ifdef USE_LIBC_PRIVATES
|
||||
if (0 != &__libc_ia64_register_backing_store_base
|
||||
&& 0 != __libc_ia64_register_backing_store_base) {
|
||||
/* Glibc 2.2.4 has a bug such that for dynamically linked */
|
||||
/* executables __libc_ia64_register_backing_store_base is */
|
||||
/* defined but uninitialized during constructor calls. */
|
||||
/* Hence we check for both nonzero address and value. */
|
||||
return __libc_ia64_register_backing_store_base;
|
||||
}
|
||||
# endif
|
||||
word result = backing_store_base_from_proc();
|
||||
if (0 == result) {
|
||||
/* Use dumb heuristics. Works only for default configuration. */
|
||||
result = (word)GC_stackbottom - BACKING_STORE_DISPLACEMENT;
|
||||
result += BACKING_STORE_ALIGNMENT - 1;
|
||||
result &= ~(BACKING_STORE_ALIGNMENT - 1);
|
||||
/* Verify that it's at least readable. If not, we goofed. */
|
||||
GC_noop1(*(word *)result);
|
||||
}
|
||||
return (ptr_t)result;
|
||||
}
|
||||
return (ptr_t)result;
|
||||
}
|
||||
# endif
|
||||
|
||||
@ -936,6 +936,7 @@ ptr_t GC_get_stack_base()
|
||||
/* since the correct value of __libc_stack_end never */
|
||||
/* becomes visible to us. The second test works around */
|
||||
/* this. */
|
||||
# ifdef USE_LIBC_PRIVATES
|
||||
if (0 != &__libc_stack_end && 0 != __libc_stack_end ) {
|
||||
# ifdef IA64
|
||||
/* Some versions of glibc set the address 16 bytes too */
|
||||
@ -957,6 +958,7 @@ ptr_t GC_get_stack_base()
|
||||
# endif
|
||||
# endif
|
||||
}
|
||||
# endif
|
||||
f = open("/proc/self/stat", O_RDONLY);
|
||||
if (f < 0 || STAT_READ(f, stat_buf, STAT_BUF_SIZE) < 2 * STAT_SKIP) {
|
||||
ABORT("Couldn't read /proc/self/stat");
|
||||
@ -1508,7 +1510,7 @@ void GC_register_data_segments()
|
||||
# endif
|
||||
|
||||
|
||||
# ifdef RS6000
|
||||
# if 0 && defined(RS6000) /* We now use mmap */
|
||||
/* The compiler seems to generate speculative reads one past the end of */
|
||||
/* an allocated object. Hence we need to make sure that the page */
|
||||
/* 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
|
||||
# ifdef FREEBSD
|
||||
# define SIG_OK (sig == SIGBUS)
|
||||
# define CODE_OK (code == BUS_PAGE_FAULT)
|
||||
# define CODE_OK TRUE
|
||||
# endif
|
||||
# endif /* SUNOS4 || (FREEBSD && !SUNOS5SIGS) */
|
||||
|
||||
@ -3726,7 +3728,7 @@ static kern_return_t GC_forward_exception(
|
||||
exception_behavior_t behavior;
|
||||
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;
|
||||
|
||||
for(i=0;i<GC_old_exc_ports.count;i++)
|
||||
@ -3787,13 +3789,19 @@ catch_exception_raise(
|
||||
char *addr;
|
||||
struct hblk *h;
|
||||
int i;
|
||||
#ifdef POWERPC
|
||||
thread_state_flavor_t flavor = PPC_EXCEPTION_STATE;
|
||||
mach_msg_type_number_t exc_state_count = PPC_EXCEPTION_STATE_COUNT;
|
||||
ppc_exception_state_t exc_state;
|
||||
#else
|
||||
# if defined(POWERPC)
|
||||
# if CPP_WORDSZ == 32
|
||||
thread_state_flavor_t flavor = PPC_EXCEPTION_STATE;
|
||||
mach_msg_type_number_t exc_state_count = PPC_EXCEPTION_STATE_COUNT;
|
||||
ppc_exception_state_t exc_state;
|
||||
# else
|
||||
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
|
||||
#endif
|
||||
# endif
|
||||
|
||||
|
||||
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)
|
||||
# include <sys/sparc/frame.h>
|
||||
# else
|
||||
# if defined(OPENBSD) || defined(NETBSD)
|
||||
# if defined(OPENBSD)
|
||||
# include <frame.h>
|
||||
# else
|
||||
# include <sys/frame.h>
|
||||
# if defined(FREEBSD) || defined(NETBSD)
|
||||
# include <machine/frame.h>
|
||||
# else
|
||||
# include <sys/frame.h>
|
||||
# endif
|
||||
# endif
|
||||
# endif
|
||||
# endif
|
||||
@ -3985,6 +3997,16 @@ kern_return_t catch_exception_raise_state_identity(
|
||||
#if NARGS == 0 && NFRAMES % 2 == 0 /* No padding */ \
|
||||
&& 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)
|
||||
struct callinfo info[NFRAMES];
|
||||
{
|
||||
@ -3994,15 +4016,26 @@ struct callinfo info[NFRAMES];
|
||||
|
||||
/* We retrieve NFRAMES+1 pc values, but discard the first, since it */
|
||||
/* 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 *));
|
||||
npcs = backtrace((void **)tmp_info, NFRAMES + IGNORE_FRAMES);
|
||||
BCOPY(tmp_info+IGNORE_FRAMES, info, (npcs - IGNORE_FRAMES) * sizeof(void *));
|
||||
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 */
|
||||
|
||||
#if (defined(OPENBSD) || defined(NETBSD)) && defined(SPARC)
|
||||
#if (defined(OPENBSD) || defined(NETBSD) || defined(FREEBSD)) && defined(SPARC)
|
||||
# define FR_SAVFP fr_fp
|
||||
# define FR_SAVPC fr_pc
|
||||
#else
|
||||
|
@ -12,7 +12,7 @@
|
||||
|
||||
; GC_push_regs function. Under some optimization levels GCC will clobber
|
||||
; some of the non-volatile registers before we get a chance to save them
|
||||
; therefore, this can't be inline asm.
|
||||
; therefore, this cannot be inline asm.
|
||||
|
||||
.text
|
||||
.align LOG2_GPR_BYTES
|
||||
|
@ -1,13 +1,17 @@
|
||||
#include "private/pthread_support.h"
|
||||
|
||||
#if defined(GC_PTHREADS) && !defined(GC_SOLARIS_THREADS) \
|
||||
&& !defined(GC_IRIX_THREADS) && !defined(GC_WIN32_THREADS) \
|
||||
&& !defined(GC_DARWIN_THREADS) && !defined(GC_AIX_THREADS)
|
||||
&& !defined(GC_WIN32_THREADS) && !defined(GC_DARWIN_THREADS)
|
||||
|
||||
#include <signal.h>
|
||||
#include <semaphore.h>
|
||||
#include <errno.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
|
||||
|
||||
@ -67,7 +71,22 @@ void GC_remove_allowed_signals(sigset_t *set)
|
||||
|
||||
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
|
||||
GC_bool GC_retry_signals = TRUE;
|
||||
@ -108,7 +127,9 @@ extern void GC_with_callee_saves_pushed();
|
||||
|
||||
void GC_suspend_handler(int sig)
|
||||
{
|
||||
int old_errno = errno;
|
||||
GC_with_callee_saves_pushed(GC_suspend_handler_inner, (ptr_t)(word)sig);
|
||||
errno = old_errno;
|
||||
}
|
||||
|
||||
#else
|
||||
@ -116,7 +137,9 @@ void GC_suspend_handler(int sig)
|
||||
/* in the signal handler frame. */
|
||||
void GC_suspend_handler(int sig)
|
||||
{
|
||||
int old_errno = errno;
|
||||
GC_suspend_handler_inner((ptr_t)(word)sig);
|
||||
errno = old_errno;
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -172,16 +195,26 @@ void GC_suspend_handler_inner(ptr_t sig_arg)
|
||||
/* this thread a SIG_THR_RESTART signal. */
|
||||
/* SIG_THR_RESTART should be masked at this point. Thus there */
|
||||
/* is no race. */
|
||||
do {
|
||||
me->stop_info.signal = 0;
|
||||
sigsuspend(&suspend_handler_mask); /* Wait for signal */
|
||||
} while (me->stop_info.signal != SIG_THR_RESTART);
|
||||
/* We do not continue until we receive a SIG_THR_RESTART, */
|
||||
/* but we do not take that as authoritative. (We may be */
|
||||
/* accidentally restarted by one of the user signals we */
|
||||
/* 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 */
|
||||
/* less likely than losing the SUSPEND signal, since we don't do much */
|
||||
/* between the sem_post and sigsuspend. */
|
||||
/* We'd need more handshaking to work around that, since we don't want */
|
||||
/* to accidentally leave a RESTART signal pending, thus causing us to */
|
||||
/* continue prematurely in a future round. */
|
||||
/* We'd need more handshaking to work around that. */
|
||||
/* Simply dropping the sigsuspend call should be safe, but is unlikely */
|
||||
/* to be efficient. */
|
||||
|
||||
#if DEBUG_THREADS
|
||||
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)
|
||||
{
|
||||
pthread_t my_thread = pthread_self();
|
||||
GC_thread me;
|
||||
|
||||
if (sig != SIG_THR_RESTART) ABORT("Bad signal in suspend_handler");
|
||||
|
||||
/* Let the GC_suspend_handler() know that we got a SIG_THR_RESTART. */
|
||||
/* The lookup here is safe, since I'm doing this on behalf */
|
||||
/* of a thread which holds the allocation lock in order */
|
||||
/* to stop the world. Thus concurrent modification of the */
|
||||
/* data structure is impossible. */
|
||||
me = GC_lookup_thread(my_thread);
|
||||
me->stop_info.signal = SIG_THR_RESTART;
|
||||
|
||||
/*
|
||||
** Note: even if we didn't do anything useful here,
|
||||
** Note: even if we don't do anything useful here,
|
||||
** it would still be necessary to have a signal handler,
|
||||
** rather than ignoring the signals, otherwise
|
||||
** the signals will not be delivered at all, and
|
||||
@ -357,6 +381,7 @@ void GC_stop_world()
|
||||
/* We should have previously waited for it to become zero. */
|
||||
# endif /* PARALLEL_MARK */
|
||||
++GC_stop_count;
|
||||
GC_world_is_stopped = TRUE;
|
||||
n_live_threads = GC_suspend_all();
|
||||
|
||||
if (GC_retry_signals) {
|
||||
@ -390,10 +415,10 @@ void GC_stop_world()
|
||||
}
|
||||
for (i = 0; i < n_live_threads; i++) {
|
||||
while (0 != (code = sem_wait(&GC_suspend_ack_sem))) {
|
||||
if (errno != EINTR) {
|
||||
GC_err_printf1("Sem_wait returned %ld\n", (unsigned long)code);
|
||||
ABORT("sem_wait for handler failed");
|
||||
}
|
||||
if (errno != EINTR) {
|
||||
GC_err_printf1("Sem_wait returned %ld\n", (unsigned long)code);
|
||||
ABORT("sem_wait for handler failed");
|
||||
}
|
||||
}
|
||||
}
|
||||
# ifdef PARALLEL_MARK
|
||||
@ -419,6 +444,7 @@ void GC_start_world()
|
||||
GC_printf0("World starting\n");
|
||||
# endif
|
||||
|
||||
GC_world_is_stopped = FALSE;
|
||||
for (i = 0; i < THREAD_TABLE_SZ; i++) {
|
||||
for (p = GC_threads[i]; p != 0; p = p -> next) {
|
||||
if (p -> id != my_thread) {
|
||||
@ -428,8 +454,7 @@ void GC_start_world()
|
||||
#if DEBUG_THREADS
|
||||
GC_printf1("Sending restart signal to 0x%lx\n", p -> id);
|
||||
#endif
|
||||
|
||||
result = pthread_kill(p -> id, SIG_THR_RESTART);
|
||||
result = pthread_kill(p -> id, SIG_THR_RESTART);
|
||||
switch(result) {
|
||||
case ESRCH:
|
||||
/* Not really there anymore. Possible? */
|
||||
|
@ -2,7 +2,7 @@
|
||||
* Copyright (c) 1994 by Xerox Corporation. All rights reserved.
|
||||
* Copyright (c) 1996 by Silicon Graphics. All rights reserved.
|
||||
* Copyright (c) 1998 by Fergus Henderson. All rights reserved.
|
||||
* Copyright (c) 2000-2001 by Hewlett-Packard Company. All rights reserved.
|
||||
* Copyright (c) 2000-2004 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.
|
||||
@ -51,8 +51,7 @@
|
||||
# include "private/pthread_support.h"
|
||||
|
||||
# if defined(GC_PTHREADS) && !defined(GC_SOLARIS_THREADS) \
|
||||
&& !defined(GC_IRIX_THREADS) && !defined(GC_WIN32_THREADS) \
|
||||
&& !defined(GC_AIX_THREADS)
|
||||
&& !defined(GC_WIN32_THREADS)
|
||||
|
||||
# if defined(GC_HPUX_THREADS) && !defined(USE_PTHREAD_SPECIFIC) \
|
||||
&& !defined(USE_COMPILER_TLS)
|
||||
@ -69,7 +68,8 @@
|
||||
# endif
|
||||
|
||||
# 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
|
||||
# endif
|
||||
|
||||
@ -117,7 +117,7 @@
|
||||
# include <semaphore.h>
|
||||
#endif /* !GC_DARWIN_THREADS */
|
||||
|
||||
#if defined(GC_DARWIN_THREADS)
|
||||
#if defined(GC_DARWIN_THREADS) || defined(GC_FREEBSD_THREADS)
|
||||
# include <sys/sysctl.h>
|
||||
#endif /* GC_DARWIN_THREADS */
|
||||
|
||||
@ -840,9 +840,9 @@ int GC_get_nprocs()
|
||||
/* We hold the allocation lock. */
|
||||
void GC_thr_init()
|
||||
{
|
||||
# ifndef GC_DARWIN_THREADS
|
||||
int dummy;
|
||||
# endif
|
||||
# ifndef GC_DARWIN_THREADS
|
||||
int dummy;
|
||||
# endif
|
||||
GC_thread t;
|
||||
|
||||
if (GC_thr_initialized) return;
|
||||
@ -874,14 +874,15 @@ void GC_thr_init()
|
||||
# if defined(GC_HPUX_THREADS)
|
||||
GC_nprocs = pthread_num_processors_np();
|
||||
# endif
|
||||
# if defined(GC_OSF1_THREADS)
|
||||
# if defined(GC_OSF1_THREADS) || defined(GC_AIX_THREADS)
|
||||
GC_nprocs = sysconf(_SC_NPROCESSORS_ONLN);
|
||||
if (GC_nprocs <= 0) GC_nprocs = 1;
|
||||
# endif
|
||||
# if defined(GC_FREEBSD_THREADS)
|
||||
GC_nprocs = 1;
|
||||
# if defined(GC_IRIX_THREADS)
|
||||
GC_nprocs = sysconf(_SC_NPROC_ONLN);
|
||||
if (GC_nprocs <= 0) GC_nprocs = 1;
|
||||
# endif
|
||||
# if defined(GC_DARWIN_THREADS)
|
||||
# if defined(GC_DARWIN_THREADS) || defined(GC_FREEBSD_THREADS)
|
||||
int ncpus = 1;
|
||||
size_t len = sizeof(ncpus);
|
||||
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. */
|
||||
GC_time_limit = GC_TIME_UNLIMITED;
|
||||
}
|
||||
/* If we are using a parallel marker, actually start helper threads. */
|
||||
if (GC_parallel) start_mark_threads();
|
||||
# endif
|
||||
}
|
||||
|
||||
@ -944,10 +947,6 @@ void GC_init_parallel()
|
||||
|
||||
/* GC_init() calls us back, so set flag first. */
|
||||
if (!GC_is_initialized) GC_init();
|
||||
/* If we are using a parallel marker, start the helper threads. */
|
||||
# ifdef PARALLEL_MARK
|
||||
if (GC_parallel) start_mark_threads();
|
||||
# endif
|
||||
/* Initialize thread local free lists if used. */
|
||||
# if defined(THREAD_LOCAL_ALLOC) && !defined(DBG_HDRS_ALL)
|
||||
LOCK();
|
||||
@ -1223,7 +1222,7 @@ WRAP_FUNC(pthread_create)(pthread_t *new_thread,
|
||||
if (!GC_thr_initialized) GC_thr_init();
|
||||
# ifdef GC_ASSERTIONS
|
||||
{
|
||||
int stack_size;
|
||||
size_t stack_size;
|
||||
if (NULL == attr) {
|
||||
pthread_attr_t my_attr;
|
||||
pthread_attr_init(&my_attr);
|
||||
@ -1231,7 +1230,13 @@ WRAP_FUNC(pthread_create)(pthread_t *new_thread,
|
||||
} else {
|
||||
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. */
|
||||
/* Ridiculously small threads won't work, and they */
|
||||
/* probably wouldn't work anyway. */
|
||||
|
@ -888,7 +888,7 @@ void GC_print_block_list()
|
||||
{
|
||||
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.total_bytes = 0;
|
||||
GC_apply_to_all_blocks(GC_print_block_descr, (word)&pstats);
|
||||
|
@ -16,7 +16,7 @@
|
||||
* Modified by Peter C. for Solaris Posix Threads.
|
||||
*/
|
||||
|
||||
#include "private/gc_priv.h"
|
||||
# include "private/gc_priv.h"
|
||||
|
||||
# if defined(GC_SOLARIS_PTHREADS)
|
||||
# include <pthread.h>
|
||||
|
@ -16,7 +16,7 @@
|
||||
*/
|
||||
/* 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)
|
||||
# include "private/solaris_threads.h"
|
||||
@ -248,8 +248,8 @@ static void stop_all_lwps()
|
||||
for (i = 0; i < max_lwps; i++)
|
||||
last_ids[i] = 0;
|
||||
for (;;) {
|
||||
if (syscall(SYS_ioctl, GC_main_proc_fd, PIOCSTATUS, &status) < 0)
|
||||
ABORT("Main PIOCSTATUS failed");
|
||||
if (syscall(SYS_ioctl, GC_main_proc_fd, PIOCSTATUS, &status) < 0)
|
||||
ABORT("Main PIOCSTATUS failed");
|
||||
if (status.pr_nlwp < 1)
|
||||
ABORT("Invalid number of lwps returned by PIOCSTATUS");
|
||||
if (status.pr_nlwp >= max_lwps) {
|
||||
@ -262,7 +262,7 @@ static void stop_all_lwps()
|
||||
for (i = 0; i < max_lwps; i++)
|
||||
last_ids[i] = 0;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (syscall(SYS_ioctl, GC_main_proc_fd, PIOCLWPIDS, GC_current_ids) < 0)
|
||||
ABORT("PIOCLWPIDS failed");
|
||||
changed = FALSE;
|
||||
|
@ -1367,6 +1367,10 @@ void check_heap_stats()
|
||||
max_heap_sz = 11000000;
|
||||
}
|
||||
# endif
|
||||
# ifndef ALIGN_DOUBLE
|
||||
/* We end up needing more small object pages. */
|
||||
max_heap_sz += 2000000;
|
||||
# endif
|
||||
# ifdef GC_DEBUG
|
||||
max_heap_sz *= 2;
|
||||
# ifdef SAVE_CALL_CHAIN
|
||||
|
@ -11,10 +11,17 @@ int main()
|
||||
"-Wl,--wrap -Wl,pthread_sigmask -Wl,--wrap -Wl,sleep\n");
|
||||
# endif
|
||||
# if defined(GC_LINUX_THREADS) || defined(GC_IRIX_THREADS) \
|
||||
|| defined(GC_FREEBSD_THREADS) || defined(GC_SOLARIS_PTHREADS) \
|
||||
|| defined(GC_SOLARIS_PTHREADS) \
|
||||
|| defined(GC_DARWIN_THREADS) || defined(GC_AIX_THREADS)
|
||||
printf("-lpthread\n");
|
||||
# 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)
|
||||
printf("-lpthread -lrt\n");
|
||||
# endif
|
||||
|
@ -2,7 +2,7 @@
|
||||
/* Eventually this one may become unnecessary. For now we need */
|
||||
/* it to keep the old-style build process working. */
|
||||
#define GC_TMP_VERSION_MAJOR 6
|
||||
#define GC_TMP_VERSION_MINOR 3
|
||||
#define GC_TMP_VERSION_MINOR 6
|
||||
#define GC_TMP_ALPHA_VERSION GC_NOT_ALPHA
|
||||
|
||||
#ifndef GC_NOT_ALPHA
|
||||
|
12
boehm-gc/win32_threads.c
Normal file → Executable file
12
boehm-gc/win32_threads.c
Normal file → Executable file
@ -11,6 +11,7 @@
|
||||
# undef pthread_create
|
||||
# undef pthread_sigmask
|
||||
# undef pthread_join
|
||||
# undef pthread_detach
|
||||
# undef dlopen
|
||||
|
||||
# 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. */
|
||||
i++) {}
|
||||
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 {
|
||||
GC_delete_gc_thread(thread_table+i);
|
||||
}
|
||||
@ -232,6 +233,9 @@ void GC_push_thread_structures GC_PROTO((void))
|
||||
# endif
|
||||
}
|
||||
|
||||
/* Defined in misc.c */
|
||||
extern CRITICAL_SECTION GC_write_cs;
|
||||
|
||||
void GC_stop_world()
|
||||
{
|
||||
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()");
|
||||
|
||||
GC_please_stop = TRUE;
|
||||
# ifndef CYGWIN32
|
||||
EnterCriticalSection(&GC_write_cs);
|
||||
# endif /* !CYGWIN32 */
|
||||
for (i = 0; i <= GC_get_max_thread_index(); i++)
|
||||
if (thread_table[i].stack_base != 0
|
||||
&& thread_table[i].id != thread_id) {
|
||||
@ -270,6 +277,9 @@ void GC_stop_world()
|
||||
# endif
|
||||
thread_table[i].suspended = TRUE;
|
||||
}
|
||||
# ifndef CYGWIN32
|
||||
LeaveCriticalSection(&GC_write_cs);
|
||||
# endif /* !CYGWIN32 */
|
||||
}
|
||||
|
||||
void GC_start_world()
|
||||
|
Loading…
Reference in New Issue
Block a user