config.guess config.sub depcomp install-sh ltmain.sh missing \
mkinstalldirs
-#TESTS += tracetest
+#TESTS += tracetest$(EXEEXT)
#check_PROGRAMS += tracetest
#tracetest_SOURCES = tests/trace_test.c
#tracetest_LDADD = $(test_ldadd)
-@THREADS_TRUE@am__append_1 = threadleaktest
+@THREADS_TRUE@am__append_1 = threadleaktest$(EXEEXT)
@THREADS_TRUE@am__append_2 = threadleaktest
-@CPLUSPLUS_TRUE@am__append_3 = test_cpp
+@CPLUSPLUS_TRUE@am__append_3 = test_cpp$(EXEEXT)
@CPLUSPLUS_TRUE@am__append_4 = test_cpp
# C Library: Architecture Dependent
include/private/darwin_stop_world.h \
include/private/thread_local_alloc.h include/cord.h \
include/ec.h include/javaxfc.h version.h
-TESTS = gctest leaktest middletest $(am__append_1) $(am__append_3)
+TESTS = gctest$(EXEEXT) leaktest$(EXEEXT) middletest$(EXEEXT) \
+ $(am__append_1) $(am__append_3)
pkgconfigdir = $(libdir)/pkgconfig
dist_pkgconfig_DATA = bdw-gc.pc
libcord_la_SOURCES = \
#! /bin/sh
-# From configure.ac Revision: 1.2 .
+# From configure.ac Revision: 1.3 .
# Guess values for system-dependent variables and create Makefiles.
# Generated by GNU Autoconf 2.59 for gc 7.0alpha6.
#
INCLUDES="$INCLUDES -pthread"
THREADDLLIBS=-pthread
;;
+ *-*-netbsd*)
+ { echo "$as_me:$LINENO: WARNING: \"Only on NetBSD 2.0 or later.\"" >&5
+echo "$as_me: WARNING: \"Only on NetBSD 2.0 or later.\"" >&2;}
+ cat >>confdefs.h <<\_ACEOF
+#define GC_NETBSD_THREADS 1
+_ACEOF
+
+ cat >>confdefs.h <<\_ACEOF
+#define _REENTRANT 1
+_ACEOF
+
+ cat >>confdefs.h <<\_ACEOF
+#define _PTHREADS 1
+_ACEOF
+
+ THREADDLLIBS="-lpthread -lrt"
+ ;;
*-*-solaris*)
cat >>confdefs.h <<\_ACEOF
#define GC_SOLARIS_THREADS 1
case $host in
*-*-irix6*)
# Find out which ABI we are using.
- echo '#line 6220 "configure"' > conftest.$ac_ext
+ echo '#line 6237 "configure"' > conftest.$ac_ext
if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
(eval $ac_compile) 2>&5
ac_status=$?
save_CFLAGS="$CFLAGS"
CFLAGS="$CFLAGS -o out/conftest2.$ac_objext"
compiler_c_o=no
-if { (eval echo configure:6793: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>out/conftest.err; } && test -s out/conftest2.$ac_objext; then
+if { (eval echo configure:6810: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>out/conftest.err; } && test -s out/conftest2.$ac_objext; then
# The compiler can only warn and ignore the option if not recognized
# So say no if there are warnings
if test -s out/conftest.err; then
lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
lt_status=$lt_dlunknown
cat > conftest.$ac_ext <<EOF
-#line 8720 "configure"
+#line 8737 "configure"
#include "confdefs.h"
#if HAVE_DLFCN_H
lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
lt_status=$lt_dlunknown
cat > conftest.$ac_ext <<EOF
-#line 8818 "configure"
+#line 8835 "configure"
#include "confdefs.h"
#if HAVE_DLFCN_H
AC_CONFIG_SRCDIR(gcj_mlc.c)
AC_CANONICAL_TARGET
AC_PREREQ(2.53)
-AC_REVISION($Revision: 1.3 $)
+AC_REVISION($Revision: 1.4 $)
GC_SET_VERSION
AM_INIT_AUTOMAKE([foreign dist-bzip2 subdir-objects nostdinc])
AM_MAINTAINER_MODE
INCLUDES="$INCLUDES -pthread"
THREADDLLIBS=-pthread
;;
+ *-*-netbsd*)
+ AC_MSG_WARN("Only on NetBSD 2.0 or later.")
+ AC_DEFINE(GC_NETBSD_THREADS)
+ AC_DEFINE(_REENTRANT)
+ AC_DEFINE(_PTHREADS)
+ THREADDLLIBS="-lpthread -lrt"
+ ;;
*-*-solaris*)
AC_DEFINE(GC_SOLARIS_THREADS)
AC_DEFINE(GC_SOLARIS_PTHREADS)
* modified is included with the above copyright notice.
*/
+#include <errno.h>
+#include <string.h>
#include "private/dbg_mlc.h"
void GC_default_print_heap_obj_proc();
return (GC_store_debug_info(result, (word)lb, s, (word)i));
}
+char *GC_debug_strdup(const char *str, GC_EXTRA_PARAMS)
+{
+ char *copy;
+ if (str == NULL) return NULL;
+ copy = GC_debug_malloc_atomic(strlen(str) + 1, OPT_RA s, i);
+ if (copy == NULL) {
+ errno = ENOMEM;
+ return NULL;
+ }
+ strcpy(copy, str);
+ return copy;
+}
+
void * GC_debug_malloc_uncollectable(size_t lb, GC_EXTRA_PARAMS)
{
void * result = GC_malloc_uncollectable(lb + UNCOLLECTABLE_DEBUG_BYTES);
developers.)
- Merge in some recent gcc fixes. Add ppc64 asm code. (Thanks to Bryce
McKinley and other gcj developers.)
+ - Scan MEM_PRIVATE sections under Windows ME and predecessors.
+ - Interior pointers with some largish offsets into large objects could
+ be ignored, if GC_all_interior_pointers was set. (Oddly this worked
+ correctly for stack references if it was not set. Otherwise it failed
+ for both stack and heap references.) Thanks to Andrew McKinlay for the
+ critical test case.
+ - Integrated Tatsuya Bizenn's NETBSD threads support, with some
+ untested changes.
+ - Added GC_strdup and friends to make leak detection work correctly
+ for strdup clients. (Thanks to Jon Moore.) Fixed the existing strdup
+ with malloc redirection to handle a null malloc return correctly.
Since gc6.7:
- Remove GC_PROTO, VOLATILE, GC_PTR, and GC_CONST. Assume ANSI C compiler
- Fix typo in DARWIN section of gcconfig.h.
- Fix Darwin thread memory leak. (Thanks to Bruce Mitchener.)
- Update x86 AO_test_and_set implementation to use "=q".
+ - Add $(EXEEXT) to many tests in tests/tests.am. (Corresponds to a
+ 6.7 fix, which no longer applied.)
To do:
- REDIRECT_MALLOC and threads combination is getting closer, but currently
The header file <TT>gc.h</tt> must be included
in files that use either GC or threads primitives, since threads primitives
will be redefined to cooperate with the GC on many platforms.
+<P>
+Thread users should also be aware that on many platforms objects reachable
+only from thread-local variables may be prematurely reclaimed.
+Thus objects pointed to by thread-local variables should also be pointed to
+by a globally visible data structure. (This is viewed as a bug, but as
+one that is exceedingly hard to fix without some libc hooks.)
<DL>
<DT> <B>void * GC_MALLOC(size_t <I>nbytes</i>)</b>
<DD>
They are usually allocated by <TT>GC_MALLOC_UNCOLLECTABLE</tt>, as described
above, and through some interfaces described below.
<P>
+(On most platforms, the collector may not trace correctly from in-flight
+exception objects. Thus objects thrown as exceptions should only
+point to otherwise reachable memory. This is another bug whose
+proper repair requires platform hooks.)
+<P>
The easiest way to ensure that collectable objects are properly referenced
is to allocate only collectable objects. This requires that every
allocation go through one of the following interfaces, each one of
}
# endif /* DEBUG_VIRTUALQUERY */
+ extern GC_bool GC_wnt; /* Is Windows NT derivative. */
+ /* Defined and set in os_dep.c. */
+
void GC_register_dynamic_libraries()
{
MEMORY_BASIC_INFORMATION buf;
&& (protect == PAGE_EXECUTE_READWRITE
|| protect == PAGE_READWRITE)
&& !GC_is_heap_base(buf.AllocationBase)
- && buf.Type == MEM_IMAGE) {
+ /* There is some evidence that we cannot always
+ * ignore MEM_PRIVATE sections under Windows ME
+ * and predecessors. Hence we now also check for
+ * that case. */
+ && (buf.Type == MEM_IMAGE ||
+ !GC_wnt && buf.Type == MEM_PRIVATE)) {
# ifdef DEBUG_VIRTUALQUERY
GC_dump_meminfo(&buf);
# endif
*/
GC_API void * GC_malloc(size_t size_in_bytes);
GC_API void * GC_malloc_atomic(size_t size_in_bytes);
+GC_API char * GC_strdup (const char *str);
GC_API void * GC_malloc_uncollectable(size_t size_in_bytes);
GC_API void * GC_malloc_stubborn(size_t size_in_bytes);
/* objects allocated in this way for overwrites, etc. */
GC_API void * GC_debug_malloc(size_t size_in_bytes, GC_EXTRA_PARAMS);
GC_API void * GC_debug_malloc_atomic(size_t size_in_bytes, GC_EXTRA_PARAMS);
+GC_API char * GC_debug_strdup(const char *str, GC_EXTRA_PARAMS);
GC_API void * GC_debug_malloc_uncollectable
(size_t size_in_bytes, GC_EXTRA_PARAMS);
GC_API void * GC_debug_malloc_stubborn
# ifdef GC_DEBUG
# define GC_MALLOC(sz) GC_debug_malloc(sz, GC_EXTRAS)
# define GC_MALLOC_ATOMIC(sz) GC_debug_malloc_atomic(sz, GC_EXTRAS)
+# define GC_STRDUP(s) GC_debug_strdup((s), GC_EXTRAS)
# define GC_MALLOC_UNCOLLECTABLE(sz) \
GC_debug_malloc_uncollectable(sz, GC_EXTRAS)
# define GC_MALLOC_IGNORE_OFF_PAGE(sz) \
# else
# define GC_MALLOC(sz) GC_malloc(sz)
# define GC_MALLOC_ATOMIC(sz) GC_malloc_atomic(sz)
+# define GC_STRDUP(s) GC_strdup(s)
# define GC_MALLOC_UNCOLLECTABLE(sz) GC_malloc_uncollectable(sz)
# define GC_MALLOC_IGNORE_OFF_PAGE(sz) \
GC_malloc_ignore_off_page(sz)
#if !defined(_REENTRANT) && (defined(GC_SOLARIS_THREADS) \
|| defined(GC_HPUX_THREADS) \
|| defined(GC_AIX_THREADS) \
- || defined(GC_LINUX_THREADS))
+ || defined(GC_LINUX_THREADS) \
+ || defined(GC_NETBSD_THREADS))
# define _REENTRANT
/* Better late than never. This fails if system headers that */
/* depend on this were previously included. */
#endif
+#if !defined(_PTHREADS) && defined(GC_NETBSD_THREADS)
+# define _PTHREADS
+#endif
+
#if defined(GC_DGUX386_THREADS) && !defined(_POSIX4A_DRAFT10_SOURCE)
# define _POSIX4A_DRAFT10_SOURCE 1
#endif
defined(GC_IRIX_THREADS) || defined(GC_LINUX_THREADS) || \
defined(GC_HPUX_THREADS) || defined(GC_OSF1_THREADS) || \
defined(GC_DGUX386_THREADS) || defined(GC_DARWIN_THREADS) || \
- defined(GC_AIX_THREADS) || \
+ defined(GC_AIX_THREADS) || defined(GC_NETBSD_THREADS) || \
(defined(GC_WIN32_THREADS) && defined(__CYGWIN32__))
# define GC_PTHREADS
# endif
# define GC_FREEBSD_THREADS
# define GC_PTHREADS
# endif
+# if !defined(GC_PTHREADS) && defined(__NetBSD__)
+# define GC_NETBSD_THREADS
+# define GC_PTHREADS
+# endif
# if defined(DGUX) && (defined(i386) || defined(__i386__))
# define GC_DGUX386_THREADS
# define GC_PTHREADS
# define pthread_detach GC_pthread_detach
#ifndef GC_DARWIN_THREADS
+# ifdef pthread_sigmask
+# undef pthread_sigmask
+# endif /* pthread_sigmask */
# define pthread_sigmask GC_pthread_sigmask
# define dlopen GC_dlopen
#endif
#define calloc(m,n) GC_MALLOC((m)*(n))
#define free(p) GC_FREE(p)
#define realloc(p,n) GC_REALLOC((p),(n))
+#undef strdup
+#define strdup(s) GC_STRDUP((s))
#define CHECK_LEAKS() GC_gcollect()
# define SUNOS5SIGS
# endif
+# ifdef GC_NETBSD_THREADS
+# define SIGRTMIN 33
+# define SIGRTMAX 63
+# endif
+
# if defined(SVR4) || defined(LINUX) || defined(IRIX5) || defined(HPUX) \
|| defined(OPENBSD) || defined(NETBSD) || defined(FREEBSD) \
|| defined(DGUX) || defined(BSD) \
# if defined(GC_LINUX_THREADS) && !defined(LINUX)
--> inconsistent configuration
# endif
+# if defined(GC_NETBSD_THREADS) && !defined(NETBSD)
+ --> inconsistent configuration
+# endif
# if defined(GC_SOLARIS_THREADS) && !defined(SUNOS5)
--> inconsistent configuration
# endif
# elif defined(LINUX) && defined(__GNUC__)
# define USE_COMPILER_TLS
# elif (defined(GC_DGUX386_THREADS) || defined(GC_OSF1_THREADS) || \
- defined(GC_DARWIN_THREADS) || defined(GC_AIX_THREADS))
+ defined(GC_DARWIN_THREADS) || defined(GC_AIX_THREADS)) || \
+ defined(GC_NETBSD_THREADS)
# define USE_PTHREAD_SPECIFIC
# elif defined(GC_HPUX_THREADS)
# ifdef __GNUC__
*/
#include <stdio.h>
+#include <string.h>
+#include <errno.h>
#include "private/gc_priv.h"
extern void * GC_clear_stack(void *); /* in misc.c, behaves like identity */
}
}
+/* provide a version of strdup() that uses the collector to allocate the
+ copy of the string */
+# ifdef __STDC__
+ char *GC_strdup(const char *s)
+# else
+ char *GC_strdup(s)
+ char *s;
+#endif
+{
+ char *copy;
+
+ if (s == NULL) return NULL;
+ if ((copy = GC_malloc_atomic(strlen(s) + 1)) == NULL) {
+ errno = ENOMEM;
+ return NULL;
+ }
+ strcpy(copy, s);
+ return copy;
+}
+
/* Allocate lb bytes of composite (pointerful) data */
#ifdef THREAD_LOCAL_ALLOC
void * GC_core_malloc(size_t lb)
{
size_t len = strlen(s) + 1;
char * result = ((char *)REDIRECT_MALLOC(len+1));
+ if (result == 0) {
+ errno = ENOMEM;
+ return 0;
+ }
BCOPY(s, result, len+1);
return result;
}
}
# endif
+
+ GC_bool GC_wnt = FALSE;
+ /* This is a Windows NT derivative, i.e. NT, W2K, XP or later. */
void GC_init_win32(void)
{
- /* if we're running under win32s, assume that no DLLs will be loaded */
+ /* Set GC_wnt. */
+ /* If we're running under win32s, assume that no DLLs will be loaded */
+ /* I doubt anyone still runs win32s, but ... */
DWORD v = GetVersion();
- GC_no_win32_dlls |= ((v & 0x80000000) && (v & 0xff) <= 3);
+ GC_wnt = !(v & 0x80000000);
+ GC_no_win32_dlls |= ((!GC_wnt) && (v & 0xff) <= 3);
}
/* Return the smallest address a such that VirtualQuery */
*/
#ifndef SIG_THR_RESTART
-# if defined(GC_HPUX_THREADS) || defined(GC_OSF1_THREADS)
+# if defined(GC_HPUX_THREADS) || defined(GC_OSF1_THREADS) || defined(GC_NETBSD_THREADS)
# ifdef _SIGRTMIN
# define SIG_THR_RESTART _SIGRTMIN + 5
# else
sem_t GC_suspend_ack_sem;
+#ifdef GC_NETBSD_THREADS
+# define GC_NETBSD_THREADS_WORKAROUND
+ /* It seems to be necessary to wait until threads have restarted. */
+ /* But it is unclear why that is the case. */
+ sem_t GC_restart_ack_sem;
+#endif
+
void GC_suspend_handler_inner(ptr_t sig_arg, void *context);
#if defined(IA64) || defined(HP_PA)
if (sig != SIG_THR_RESTART) ABORT("Bad signal in suspend_handler");
+#ifdef GC_NETBSD_THREADS_WORKAROUND
+ sem_post(&GC_restart_ack_sem);
+#endif
+
/*
** Note: even if we don't do anything useful here,
** it would still be necessary to have a signal handler,
register GC_thread p;
register int n_live_threads = 0;
register int result;
+#ifdef GC_NETBSD_THREADS_WORKAROUND
+ int code;
+#endif
# if DEBUG_THREADS
GC_printf("World starting\n");
}
}
}
+#ifdef GC_NETBSD_THREADS_WORKAROUND
+ for (i = 0; i < n_live_threads; i++)
+ while (0 != (code = sem_wait(&GC_restart_ack_sem)))
+ if (errno != EINTR) {
+ GC_err_printf1("sem_wait() returned %ld\n", (unsigned long)code);
+ ABORT("sem_wait() for restart handler failed");
+ }
+#endif
#if DEBUG_THREADS
GC_printf("World started\n");
#endif
if (sem_init(&GC_suspend_ack_sem, 0, 0) != 0)
ABORT("sem_init failed");
+#ifdef GC_NETBSD_THREADS_WORKAROUND
+ if (sem_init(&GC_restart_ack_sem, 0, 0) != 0)
+ ABORT("sem_init failed");
+#endif
act.sa_flags = SA_RESTART | SA_SIGINFO;
if (sigfillset(&act.sa_mask) != 0) {
# include <sys/sysctl.h>
#endif /* GC_DARWIN_THREADS */
+#if defined(GC_NETBSD_THREADS)
+# include <sys/param.h>
+# include <sys/sysctl.h>
+#endif /* GC_NETBSD_THREADS */
+
/* Allocator lock definitions. */
#if defined(USE_SPIN_LOCK)
pthread_t GC_lock_holder = NO_THREAD;
}
#endif /* GC_DGUX386_THREADS */
+#if defined(GC_NETBSD_THREADS)
+static int get_ncpu(void)
+{
+ int mib[] = {CTL_HW,HW_NCPU};
+ int res;
+ size_t len = sizeof(res);
+
+ sysctl(mib, sizeof(mib)/sizeof(int), &res, &len, NULL, 0);
+ return res;
+}
+#endif /* GC_NETBSD_THREADS */
+
/* We hold the allocation lock. */
void GC_thr_init(void)
{
GC_nprocs = sysconf(_SC_NPROC_ONLN);
if (GC_nprocs <= 0) GC_nprocs = 1;
# endif
+# if defined(GC_NETBSD_THREADS)
+ GC_nprocs = get_ncpu();
+# endif
# if defined(GC_DARWIN_THREADS) || defined(GC_FREEBSD_THREADS)
int ncpus = 1;
size_t len = sizeof(ncpus);
-TESTS += gctest
+TESTS += gctest$(EXEEXT)
check_PROGRAMS += gctest
gctest_SOURCES = tests/test.c
gctest_LDADD = $(test_ldadd)
gctest_DEPENDENCIES = $(top_builddir)/libgc.la
-TESTS += leaktest
+TESTS += leaktest$(EXEEXT)
check_PROGRAMS += leaktest
leaktest_SOURCES = tests/leak_test.c
leaktest_LDADD = $(test_ldadd)
-TESTS += middletest
+TESTS += middletest$(EXEEXT)
check_PROGRAMS += middletest
middletest_SOURCES = tests/middle.c
middletest_LDADD = $(test_ldadd)
-#TESTS += tracetest
+#TESTS += tracetest$(EXEEXT)
#check_PROGRAMS += tracetest
#tracetest_SOURCES = tests/trace_test.c
#tracetest_LDADD = $(test_ldadd)
if THREADS
-TESTS += threadleaktest
+TESTS += threadleaktest$(EXEEXT)
check_PROGRAMS += threadleaktest
threadleaktest_SOURCES = tests/thread_leak_test.c
threadleaktest_LDADD = $(test_ldadd)
endif
if CPLUSPLUS
-TESTS += test_cpp
+TESTS += test_cpp$(EXEEXT)
check_PROGRAMS += test_cpp
test_cpp_SOURCES = tests/test_cpp.cc
test_cpp_LDADD = libgccpp.la $(test_ldadd)
printf("-pthread\n");
# endif
# endif
+# if defined(GC_NETBSD_THREADS)
+ printf("-lpthread -lrt\n");
+# endif
+
# if defined(GC_HPUX_THREADS) || defined(GC_OSF1_THREADS)
printf("-lpthread -lrt\n");
# endif