summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--aix_irix_threads.c354
-rwxr-xr-xconfigure22
-rw-r--r--configure.host8
-rw-r--r--configure.in4
-rw-r--r--doc/README2
-rw-r--r--doc/README.changes18
-rw-r--r--doc/README.darwin22
-rw-r--r--dyn_load.c63
-rw-r--r--include/gc.h4
-rw-r--r--include/gc_pthread_redirects.h15
-rw-r--r--include/private/gc_locks.h6
-rw-r--r--include/private/gcconfig.h17
-rw-r--r--pthread_support.c21
-rw-r--r--version.h4
-rwxr-xr-xwin32_threads.c17
15 files changed, 253 insertions, 324 deletions
diff --git a/aix_irix_threads.c b/aix_irix_threads.c
index d3e8ae0..d8ac345 100644
--- a/aix_irix_threads.c
+++ b/aix_irix_threads.c
@@ -87,13 +87,10 @@ typedef struct GC_Thread_Rep {
word flags;
# define FINISHED 1 /* Thread has exited. */
# define DETACHED 2 /* Thread is intended to be detached. */
-# define CLIENT_OWNS_STACK 4
- /* Stack was supplied by client. */
- ptr_t stack;
- ptr_t stack_ptr; /* Valid only when stopped. */
+ 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. */
- size_t stack_size; /* 0 for original thread. */
void * status; /* Used only to avoid premature */
/* reclamation of any data it might */
/* reference. */
@@ -139,7 +136,7 @@ void GC_suspend_handler(int sig)
return;
}
pthread_mutex_lock(&GC_suspend_lock);
- me -> stack_ptr = (ptr_t)(&dummy);
+ 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);
@@ -150,68 +147,6 @@ void GC_suspend_handler(int sig)
GC_bool GC_thr_initialized = FALSE;
-size_t GC_min_stack_sz;
-
-size_t GC_page_sz;
-
-# define N_FREE_LISTS 25
-ptr_t GC_stack_free_lists[N_FREE_LISTS] = { 0 };
- /* GC_stack_free_lists[i] is free list for stacks of */
- /* size GC_min_stack_sz*2**i. */
- /* Free lists are linked through first word. */
-
-/* Return a stack of size at least *stack_size. *stack_size is */
-/* replaced by the actual stack size. */
-/* Caller holds allocation lock. */
-ptr_t GC_stack_alloc(size_t * stack_size)
-{
- register size_t requested_sz = *stack_size;
- register size_t search_sz = GC_min_stack_sz;
- register int index = 0; /* = log2(search_sz/GC_min_stack_sz) */
- register ptr_t result;
-
- while (search_sz < requested_sz) {
- search_sz *= 2;
- index++;
- }
- if ((result = GC_stack_free_lists[index]) == 0
- && (result = GC_stack_free_lists[index+1]) != 0) {
- /* Try next size up. */
- search_sz *= 2; index++;
- }
- if (result != 0) {
- GC_stack_free_lists[index] = *(ptr_t *)result;
- } else {
- result = (ptr_t) GC_scratch_alloc(search_sz + 2*GC_page_sz);
- result = (ptr_t)(((word)result + GC_page_sz) & ~(GC_page_sz - 1));
- /* Protect hottest page to detect overflow. */
-# ifdef STACK_GROWS_UP
- /* mprotect(result + search_sz, GC_page_sz, PROT_NONE); */
-# else
- /* mprotect(result, GC_page_sz, PROT_NONE); */
- result += GC_page_sz;
-# endif
- }
- *stack_size = search_sz;
- return(result);
-}
-
-/* Caller holds allocation lock. */
-void GC_stack_free(ptr_t stack, size_t size)
-{
- register int index = 0;
- register size_t search_sz = GC_min_stack_sz;
-
- while (search_sz < size) {
- search_sz *= 2;
- index++;
- }
- if (search_sz != size) ABORT("Bad stack size");
- *(ptr_t *)stack = GC_stack_free_lists[index];
- GC_stack_free_lists[index] = stack;
-}
-
-
# define THREAD_TABLE_SZ 128 /* Must be power of 2 */
volatile GC_thread GC_threads[THREAD_TABLE_SZ];
@@ -230,6 +165,7 @@ GC_thread GC_new_thread(pthread_t id)
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;
@@ -250,24 +186,8 @@ GC_thread GC_new_thread(pthread_t id)
/* Delete a thread from GC_threads. We assume it is there. */
/* (The code intentionally traps if it wasn't.) */
/* Caller holds allocation lock. */
-void GC_delete_thread(pthread_t id)
-{
- int hv = ((word)id) % THREAD_TABLE_SZ;
- register GC_thread p = GC_threads[hv];
- register GC_thread prev = 0;
-
- while (!pthread_equal(p -> id, id)) {
- prev = p;
- p = p -> next;
- }
- if (prev == 0) {
- GC_threads[hv] = p -> next;
- } else {
- prev -> next = p -> next;
- }
-}
-
-/* If a thread has been joined, but we have not yet */
+/* 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. */
@@ -277,6 +197,7 @@ void GC_delete_gc_thread(pthread_t id, GC_thread gc_id)
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;
@@ -299,6 +220,11 @@ 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);
}
@@ -312,6 +238,7 @@ void GC_stop_world()
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) {
@@ -329,6 +256,7 @@ void GC_start_world()
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) {
@@ -349,6 +277,7 @@ void GC_stop_world()
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) {
@@ -404,6 +333,7 @@ void GC_start_world()
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;
@@ -418,25 +348,6 @@ void GC_start_world()
#endif /* GC_AIX_THREADS */
-# ifdef MMAP_STACKS
---> not really supported yet.
-int GC_is_thread_stack(ptr_t addr)
-{
- register int i;
- register GC_thread p;
-
- for (i = 0; i < THREAD_TABLE_SZ; i++) {
- for (p = GC_threads[i]; p != 0; p = p -> next) {
- if (p -> stack_size != 0) {
- if (p -> stack <= addr &&
- addr < p -> stack + p -> stack_size)
- return 1;
- }
- }
- }
- return 0;
-}
-# endif
/* We hold allocation lock. Should do exactly the right thing if the */
/* world is stopped. Should not fail if it isn't. */
@@ -444,64 +355,55 @@ void GC_push_all_stacks()
{
register int i;
register GC_thread p;
- register ptr_t sp = GC_approx_sp();
register ptr_t hot, cold;
pthread_t me = pthread_self();
- if (!GC_thr_initialized) GC_thr_init();
+ /* GC_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 */
+# 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 val = 255;
- char regbuf[255];
- int retval = pthread_getthrds_np(&id, PTHRDSINFO_QUERY_ALL, &pinfo, sizeof(pinfo), regbuf, &val);
- if (retval != 0) { printf("ERROR: pthread_getthrds_np() failed in GC\n"); abort(); }
- hot = (ptr_t)(unsigned long)pinfo.__pi_ustk;
- if ((p -> stack_size != 0 &&
- (pinfo.__pi_stackend != ((ptr_t)p -> stack) + p -> stack_size ||
- p -> stack_ptr < p -> stack ||
- p -> stack_ptr > ((ptr_t)p -> stack) + p -> stack_size))) {
- printf("ERROR in GC_push_all_stacks() stack state:\n"
- "p->stack: 0x%08x\n"
- "p->stack_size: 0x%08x\n"
- "p->stack_ptr: 0x%08x\n"
- "(p->stack+p->stack_size): 0x%08x\n"
- "pinfo.__pi_stackaddr: 0x%08x\n"
- "pinfo.__pi_stacksize: 0x%08x\n"
- "pinfo.__pi_stackend: 0x%08x\n"
- "GC_stackbottom: 0x%08x\n"
- ,
- (uintptr_t)p->stack, (uintptr_t)p->stack_size,
- (uintptr_t)p->stack_ptr, (uintptr_t)(((ptr_t)(p->stack))+p->stack_size),
- (uintptr_t)pinfo.__pi_stackaddr, (uintptr_t)pinfo.__pi_stacksize, (uintptr_t)pinfo.__pi_stackend,
- (uintptr_t)GC_stackbottom
- );
- }
+ 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_ptr;
-#endif
+ 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
}
- if (p -> stack_size != 0) {
-# ifdef STACK_GROWS_UP
- cold = p -> stack;
-# else
- cold = p -> stack + p -> stack_size;
-# endif
- } else {
- /* The original stack. */
- cold = GC_stackbottom;
- }
# ifdef STACK_GROWS_UP
GC_push_all_stack(cold, hot);
# else
@@ -520,9 +422,13 @@ void GC_thr_init()
struct sigaction act;
if (GC_thr_initialized) return;
+#if 0
+ /* unfortunately, GC_init_inner calls us without the lock, so
+ * this assertion is not always true. */
+ /* Why doesn't GC_init_inner hold the lock? - HB */
+ GC_ASSERT(I_HOLD_LOCK());
+#endif
GC_thr_initialized = TRUE;
- GC_min_stack_sz = HBLKSIZE;
- GC_page_sz = sysconf(_SC_PAGESIZE);
#ifndef GC_AIX_THREADS
(void) sigaction(SIG_SUSPEND, 0, &act);
if (act.sa_handler != SIG_DFL)
@@ -536,8 +442,10 @@ void GC_thr_init()
#endif
/* Add the initial thread, so we can stop it. */
t = GC_new_thread(pthread_self());
- t -> stack_size = 0;
- t -> stack_ptr = (ptr_t)(&t);
+ /* 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;
}
@@ -561,8 +469,6 @@ struct start_info {
void *(*start_routine)(void *);
void *arg;
word flags;
- ptr_t stack;
- size_t stack_size;
pthread_mutex_t registeredlock;
pthread_cond_t registered;
int volatile registereddone;
@@ -574,10 +480,10 @@ void GC_thread_exit_proc(void *arg)
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_thread(pthread_self());
- } else {
- me -> flags |= FINISHED;
+ GC_delete_gc_thread(pthread_self(), me);
}
UNLOCK();
}
@@ -592,10 +498,12 @@ int GC_pthread_join(pthread_t thread, void **retval)
/* 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);
@@ -605,6 +513,7 @@ int GC_pthread_join(pthread_t thread, void **retval)
void * GC_start_routine(void * arg)
{
+ int dummy;
struct start_info * si = arg;
void * result;
GC_thread me;
@@ -627,14 +536,8 @@ void * GC_start_routine(void * arg)
/* doesn't try to do a pthread_join before we're registered. */
me = GC_new_thread(my_pthread);
me -> flags = si -> flags;
- me -> stack = si -> stack;
- me -> stack_size = si -> stack_size;
-#ifdef STACK_GROWS_UP
- me -> stack_ptr = (ptr_t)si -> stack + si -> stack_size - sizeof(word);
-#else
- /* stack_ptr needs to point to the hot part of the stack (or conservatively, past it) */
- me -> stack_ptr = (ptr_t)si -> stack;
-#endif
+ 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;
@@ -643,6 +546,7 @@ void * GC_start_routine(void * arg)
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);
@@ -654,44 +558,6 @@ void * GC_start_routine(void * arg)
return(result);
}
-# if defined(GC_AIX_THREADS)
- /* pthread_attr_t is not a structure, thus a simple structure copy */
- /* won't work. */
- static void copy_attr(pthread_attr_t * pa_ptr,
- const pthread_attr_t * source) {
- int tmp;
- size_t stmp;
- void * vtmp;
- struct sched_param sp_tmp;
-#ifndef GC_AIX_THREADS
- pthread_spu_t ps_tmp;
-#endif
- (void) pthread_attr_init(pa_ptr);
- (void) pthread_attr_getdetachstate(source, &tmp);
- (void) pthread_attr_setdetachstate(pa_ptr, tmp);
- (void) pthread_attr_getinheritsched(source, &tmp);
- (void) pthread_attr_setinheritsched(pa_ptr, tmp);
- (void) pthread_attr_getschedpolicy(source, &tmp);
- (void) pthread_attr_setschedpolicy(pa_ptr, tmp);
- (void) pthread_attr_getstacksize(source, &stmp);
- (void) pthread_attr_setstacksize(pa_ptr, stmp);
- (void) pthread_attr_getguardsize(source, &stmp);
- (void) pthread_attr_setguardsize(pa_ptr, stmp);
- (void) pthread_attr_getstackaddr(source, &vtmp);
- (void) pthread_attr_setstackaddr(pa_ptr, vtmp);
- (void) pthread_attr_getscope(source, &tmp);
- (void) pthread_attr_setscope(pa_ptr, tmp);
- (void) pthread_attr_getschedparam(source, &sp_tmp);
- (void) pthread_attr_setschedparam(pa_ptr, &sp_tmp);
-#ifndef GC_AIX_THREADS
- (void) pthread_attr_getprocessor_np(source, &ps_tmp, &tmp);
- (void) pthread_attr_setprocessor_np(pa_ptr, ps_tmp, tmp);
-#endif
- }
-# else
-# define copy_attr(pa_ptr, source) *(pa_ptr) = *(source)
-# endif
-
int
GC_pthread_create(pthread_t *new_thread,
const pthread_attr_t *attr,
@@ -699,85 +565,47 @@ GC_pthread_create(pthread_t *new_thread,
{
int result;
GC_thread t;
- void * stack;
- size_t stacksize;
- pthread_attr_t new_attr;
int detachstate;
word my_flags = 0;
- struct start_info * si = GC_malloc(sizeof(struct start_info));
-
- /* This is otherwise saved only in an area mmapped by the thread */
- /* library, which isn't visible to the collector. */
+ 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;
- LOCK();
- if (!GC_thr_initialized) GC_thr_init();
-
- if (NULL == attr) {
- stack = 0;
- (void) pthread_attr_init(&new_attr);
- } else {
- copy_attr(&new_attr, attr);
- pthread_attr_getstackaddr(&new_attr, &stack);
- }
- pthread_attr_getstacksize(&new_attr, &stacksize);
- pthread_attr_getdetachstate(&new_attr, &detachstate);
-#ifdef GC_AIX_THREADS
- GC_min_stack_sz = 5*1048576;
- if (stacksize < GC_min_stack_sz) {
- stacksize = GC_min_stack_sz;
- }
- { int alignment = 16*1024; /* size must be multiple of 16KB greater than 56KB */
- int minval = 56*1024;
- if ((stacksize - minval) % alignment != 0) {
- stacksize = minval + alignment * ((stacksize-minval)/alignment + 1);
- }
- }
-#endif
- if (0 == stack) {
- stack = (void *)GC_stack_alloc(&stacksize);
- if (0 == stack) {
- UNLOCK();
- return(ENOMEM);
- }
- pthread_attr_setstacksize(&new_attr, stacksize);
-#ifdef GC_AIX_THREADS
- pthread_attr_setstackaddr(&new_attr, ((char *)stack)+stacksize);
-#else
- pthread_attr_setstackaddr(&new_attr, stack);
-#endif
- } else {
- my_flags |= CLIENT_OWNS_STACK;
- }
+ pthread_attr_getdetachstate(attr, &detachstate);
if (PTHREAD_CREATE_DETACHED == detachstate) my_flags |= DETACHED;
si -> flags = my_flags;
- si -> stack = stack;
- si -> stack_size = stacksize;
- result = pthread_create(new_thread, &new_attr, GC_start_routine, si);
-
- if (0 == new_thread && !(my_flags & CLIENT_OWNS_STACK)) {
- GC_stack_free(stack, stacksize);
- }
- UNLOCK();
+ 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. */
- si->registereddone = 0;
- pthread_mutex_lock(&(si->registeredlock));
- while (!si->registereddone)
- pthread_cond_wait(&(si->registered), &(si->registeredlock));
+ 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));
- pthread_attr_destroy(&new_attr);
+ LOCK();
+ GC_INTERNAL_FREE(si);
+ UNLOCK();
return(result);
}
diff --git a/configure b/configure
index 7fdfcd5..011e747 100755
--- a/configure
+++ b/configure
@@ -1,7 +1,7 @@
#! /bin/sh
# From configure.in Revision: 1.2 .
# Guess values for system-dependent variables and create Makefiles.
-# Generated by GNU Autoconf 2.53 for gc 6.2.
+# Generated by GNU Autoconf 2.53 for gc 6.3alpha1.
#
# Report bugs to <Hans.Boehm@hp.com>.
#
@@ -416,8 +416,8 @@ SHELL=${CONFIG_SHELL-/bin/sh}
# Identity of this package.
PACKAGE_NAME='gc'
PACKAGE_TARNAME='gc'
-PACKAGE_VERSION='6.2'
-PACKAGE_STRING='gc 6.2'
+PACKAGE_VERSION='6.3alpha1'
+PACKAGE_STRING='gc 6.3alpha1'
PACKAGE_BUGREPORT='Hans.Boehm@hp.com'
ac_unique_file="gcj_mlc.c"
@@ -930,7 +930,7 @@ if test "$ac_init_help" = "long"; then
# Omit some internal or obsolete options to make the list less imposing.
# This message is too long to be a string in the A/UX 3.1 sh.
cat <<_ACEOF
-\`configure' configures gc 6.2 to adapt to many kinds of systems.
+\`configure' configures gc 6.3alpha1 to adapt to many kinds of systems.
Usage: $0 [OPTION]... [VAR=VALUE]...
@@ -997,7 +997,7 @@ fi
if test -n "$ac_init_help"; then
case $ac_init_help in
- short | recursive ) echo "Configuration of gc 6.2:";;
+ short | recursive ) echo "Configuration of gc 6.3alpha1:";;
esac
cat <<\_ACEOF
@@ -1106,7 +1106,7 @@ fi
test -n "$ac_init_help" && exit 0
if $ac_init_version; then
cat <<\_ACEOF
-gc configure 6.2
+gc configure 6.3alpha1
generated by GNU Autoconf 2.53
Copyright 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001, 2002
@@ -1121,7 +1121,7 @@ cat >&5 <<_ACEOF
This file contains any messages produced by compilers while
running configure, to aid debugging if configure makes a mistake.
-It was created by gc $as_me 6.2, which was
+It was created by gc $as_me 6.3alpha1, which was
generated by GNU Autoconf 2.53. Invocation command line was
$ $0 $@
@@ -1782,7 +1782,7 @@ fi
# Define the identity of the package.
PACKAGE=gc
- VERSION=6.2
+ VERSION=6.3alpha1
cat >>confdefs.h <<_ACEOF
@@ -8710,7 +8710,7 @@ fi
echo "$as_me:$LINENO: checking whether Solaris gcc optimization fix is necessary" >&5
echo $ECHO_N "checking whether Solaris gcc optimization fix is necessary... $ECHO_C" >&6
case "$host" in
- sparc-sun-solaris2*)
+ sparc-sun-solaris2*|*aix*)
if test "$GCC" = yes; then
echo "$as_me:$LINENO: result: yes" >&5
echo "${ECHO_T}yes" >&6
@@ -9273,7 +9273,7 @@ _ASBOX
} >&5
cat >&5 <<_CSEOF
-This file was extended by gc $as_me 6.2, which was
+This file was extended by gc $as_me 6.3alpha1, which was
generated by GNU Autoconf 2.53. Invocation command line was
CONFIG_FILES = $CONFIG_FILES
@@ -9330,7 +9330,7 @@ _ACEOF
cat >>$CONFIG_STATUS <<_ACEOF
ac_cs_version="\\
-gc config.status 6.2
+gc config.status 6.3alpha1
configured by $0, generated by GNU Autoconf 2.53,
with options \\"`echo "$ac_configure_args" | sed 's/[\\""\`\$]/\\\\&/g'`\\"
diff --git a/configure.host b/configure.host
index 068ee39..a98a0a7 100644
--- a/configure.host
+++ b/configure.host
@@ -27,8 +27,10 @@ if test :"$GCC": = :yes: ; then
gc_cflags="${gc_cflags} -fexceptions"
else
case "$host" in
- *-*-hpux* )
- gc_cflags="${gc_flags} +ESdbgasm"
+ hppa*-*-hpux* )
+ if test :$GCC: != :"yes": ; then
+ gc_cflags="${gc_flags} +ESdbgasm"
+ fi
# :TODO: actaully we should check using Autoconf if
# the compiler supports this option.
;;
@@ -52,7 +54,7 @@ esac
case "${host}" in
mips-tx39-*|mipstx39-unknown-*)
- boehm_gc_cflags="${boehm_gc_cflags} -G 0"
+ gc_cflags="${gc_cflags} -G 0"
;;
*)
;;
diff --git a/configure.in b/configure.in
index 4f9e0d7..eeb231a 100644
--- a/configure.in
+++ b/configure.in
@@ -17,7 +17,7 @@ dnl Process this file with autoconf to produce configure.
# Initialization
# ==============
-AC_INIT(gc,6.2,Hans.Boehm@hp.com)
+AC_INIT(gc,6.3alpha1,Hans.Boehm@hp.com)
## version must conform to [0-9]+[.][0-9]+(alpha[0-9]+)?
AC_CONFIG_SRCDIR(gcj_mlc.c)
AC_CANONICAL_TARGET
@@ -350,7 +350,7 @@ dnl built with gcc and -O. So we remove -O in the appropriate case.
dnl
AC_MSG_CHECKING(whether Solaris gcc optimization fix is necessary)
case "$host" in
- sparc-sun-solaris2*)
+ sparc-sun-solaris2*|*aix*)
if test "$GCC" = yes; then
AC_MSG_RESULT(yes)
new_CFLAGS=
diff --git a/doc/README b/doc/README
index 04e24a9..29d954f 100644
--- a/doc/README
+++ b/doc/README
@@ -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.2 of a conservative garbage collector for C and C++.
+This is version 6.3alpha1 of a conservative garbage collector for C and C++.
You might find a more recent version of this at
diff --git a/doc/README.changes b/doc/README.changes
index 1a0fcb3..619ea2e 100644
--- a/doc/README.changes
+++ b/doc/README.changes
@@ -1876,7 +1876,23 @@ Since 6.2alpha6:
Dick Porter for the small test case that allowed this to be debugged.)
- Fixed version parsing for non-alpha versions in acinclude.m4 and
version checking in version.h.
-
+
+Since 6.2:
+ - Integrated some NetBSD patches forwarded to me by Marc Recht. These
+ were already in the NetBSD package.
+ - GC_pthread_create waited for the semaphore even if pthread_create failed.
+ Thanks to Dick Porter for the pthread_support.c patch. Applied the
+ analogous fix for aix_irix_threads.c.
+ - Added Rainer Orth's Tru64 fixes.
+ - The check for exceeding the thread table size in win32 threadDetach
+ was incorrect. (Thanks to Alexandr Petrosian for the patch.)
+ - Applied Andrew Begel's patch to correct some reentrancy issues
+ with dynamic loading on Darwin.
+ - GC_CreateThread() was neglecting to duplicate the thread handle in
+ the table. (Thanks to Tum Nguyen for the patch.)
+ - Pass +ESdbgasm only on PA-RISC machines with vendor compiler.
+ (Thanks to Roger Sayle for the patch.)
+ - Applied more AIX threads patches from Scott Ananian.
To do:
- A dynamic libgc.so references dlopen unconditionally, but doesn't link
diff --git a/doc/README.darwin b/doc/README.darwin
index 5bca9e1..3cd1b81 100644
--- a/doc/README.darwin
+++ b/doc/README.darwin
@@ -1,4 +1,4 @@
-Darwin/MacOSX Support - May 20, 2003
+Darwin/MacOSX Support - July 22, 2003
====================================
Important Usage Notes
@@ -9,6 +9,26 @@ is necessary to properly register segments in dynamic libraries. This
call is required even if you code does not use dynamic libraries as the
dyld code handles registering all data segments.
+When your use of the garbage collector is confined to dylibs and you
+cannot call GC_init() before your libraries' static initializers have
+run and perhaps called GC_malloc(), create an initialization routine
+for each library to call GC_init():
+
+#include <gc/gc.h>
+void my_library_init() { GC_init(); }
+
+Compile this code into a my_library_init.o, and link it into your
+dylib. When you link the dylib, pass the -init argument with
+_my_library_init (e.g. gcc -dynamiclib -o my_library.dylib a.o b.o c.o
+my_library_init.o -init _my_library_init). This causes
+my_library_init() to be called before any static initializers, and
+will initialize the garbage collector properly.
+
+Note: It doesn't hurt to call GC_init() more than once, so it's best,
+if you have an application or set of libraries that all use the
+garbage collector, to create an initialization routine for each of
+them that calls GC_init(). Better safe than sorry.
+
The incremental collector is still a bit flaky on darwin. It seems to
work reliably with workarounds for a few possible bugs in place however
these workaround may not work correctly in all cases. There may also
diff --git a/dyn_load.c b/dyn_load.c
index 9a530a2..162f7dc 100644
--- a/dyn_load.c
+++ b/dyn_load.c
@@ -446,6 +446,16 @@ GC_bool GC_register_main_static_data()
#if defined(NETBSD)
# include <sys/exec_elf.h>
+/* for compatibility with 1.4.x */
+# ifndef DT_DEBUG
+# define DT_DEBUG 21
+# endif
+# ifndef PT_LOAD
+# define PT_LOAD 1
+# endif
+# ifndef PF_W
+# define PF_W 2
+# endif
#else
# include <elf.h>
#endif
@@ -1049,32 +1059,43 @@ void GC_register_dynamic_libraries() {
allocation lock held. */
void GC_init_dyld() {
- static GC_bool initialized = FALSE;
-
- if(initialized) return;
-
-# ifdef DARWIN_DEBUG
- GC_printf0("Forcing full bind of GC code...\n");
-# endif
- if(!_dyld_bind_fully_image_containing_address((unsigned long*)GC_malloc))
- GC_abort("_dyld_bind_fully_image_containing_addres failed");
-
+ static GC_bool initialized = FALSE;
+ char *bind_fully_env = NULL;
+
+ if(initialized) return;
+
# ifdef DARWIN_DEBUG
- GC_printf0("Registering dyld callbacks...\n");
+ GC_printf0("Registering dyld callbacks...\n");
# endif
-
- /* Apple's Documentation:
- When you call _dyld_register_func_for_add_image, the dynamic linker runtime
- calls the specified callback (func) once for each of the images that is
- currently loaded into the program. When a new image is added to the program,
- your callback is called again with the mach_header for the new image, and the virtual memory slide amount of the new image.
-
- This WILL properly register existing and all future libraries
- */
-
+
+ /* Apple's Documentation:
+ When you call _dyld_register_func_for_add_image, the dynamic linker runtime
+ calls the specified callback (func) once for each of the images that is
+ currently loaded into the program. When a new image is added to the program,
+ your callback is called again with the mach_header for the new image, and the
+ virtual memory slide amount of the new image.
+
+ This WILL properly register already linked libraries and libraries
+ linked in the future
+ */
+
_dyld_register_func_for_add_image(GC_dyld_image_add);
_dyld_register_func_for_remove_image(GC_dyld_image_remove);
+
+ /* Set this early to avoid reentrancy issues. */
initialized = TRUE;
+
+ bind_fully_env = getenv("DYLD_BIND_AT_LAUNCH");
+
+ if (bind_fully_env == NULL) {
+# ifdef DARWIN_DEBUG
+ GC_printf0("Forcing full bind of GC code...\n");
+# endif
+
+ if(!_dyld_bind_fully_image_containing_address((unsigned long*)GC_malloc))
+ GC_abort("_dyld_bind_fully_image_containing_address failed");
+ }
+
}
#define HAVE_REGISTER_MAIN_STATIC_DATA
diff --git a/include/gc.h b/include/gc.h
index f3e31d9..2d536ca 100644
--- a/include/gc.h
+++ b/include/gc.h
@@ -131,7 +131,7 @@ GC_API void (* GC_finalizer_notifier)();
/* thread, which will call GC_invoke_finalizers */
/* in response. */
-GC_API int GC_dont_gc; /* != 0 ==> Dont collect. In versions 7.2a1+, */
+GC_API int GC_dont_gc; /* != 0 ==> Dont collect. In versions 6.2a1+, */
/* this overrides explicit GC_gcollect() calls. */
/* Used as a counter, so that nested enabling */
/* and disabling work correctly. Should */
@@ -397,7 +397,7 @@ GC_API size_t GC_get_total_bytes GC_PROTO((void));
/* ineffective. */
GC_API void GC_disable GC_PROTO((void));
-/* Reenable garbage collection. GC_diable() and GC_enable() calls */
+/* Reenable garbage collection. GC_disable() and GC_enable() calls */
/* nest. Garbage collection is enabled if the number of calls to both */
/* both functions is equal. */
GC_API void GC_enable GC_PROTO((void));
diff --git a/include/gc_pthread_redirects.h b/include/gc_pthread_redirects.h
index 99a3e8d..842518c 100644
--- a/include/gc_pthread_redirects.h
+++ b/include/gc_pthread_redirects.h
@@ -58,13 +58,22 @@
int GC_pthread_join(pthread_t thread, void **retval);
int GC_pthread_detach(pthread_t thread);
-# define pthread_create GC_pthread_create
-#ifndef GC_DARWIN_THREADS
-# define pthread_sigmask GC_pthread_sigmask
+#if defined(GC_OSF1_THREADS) \
+ && defined(_PTHREAD_USE_MANGLED_NAMES_) && !defined(_PTHREAD_USE_PTDNAM_)
+/* Unless the compiler supports #pragma extern_prefix, the Tru64 UNIX
+ <pthread.h> redefines some POSIX thread functions to use mangled names.
+ If so, undef them before redefining. */
+# undef pthread_create
+# undef pthread_join
+# undef pthread_detach
#endif
+
+# define pthread_create GC_pthread_create
# define pthread_join GC_pthread_join
# define pthread_detach GC_pthread_detach
+
#ifndef GC_DARWIN_THREADS
+# define pthread_sigmask GC_pthread_sigmask
# define dlopen GC_dlopen
#endif
diff --git a/include/private/gc_locks.h b/include/private/gc_locks.h
index 2507605..a079ebf 100644
--- a/include/private/gc_locks.h
+++ b/include/private/gc_locks.h
@@ -179,12 +179,18 @@
" bne %2,2f\n"
" xor %0,%3,%0\n"
" stl_c %0,%1\n"
+# ifdef __ELF__
" beq %0,3f\n"
+# else
+ " beq %0,1b\n"
+# endif
" mb\n"
"2:\n"
+# ifdef __ELF__
".section .text2,\"ax\"\n"
"3: br 1b\n"
".previous"
+# endif
:"=&r" (temp), "=m" (*addr), "=&r" (oldvalue)
:"Ir" (1), "m" (*addr)
:"memory");
diff --git a/include/private/gcconfig.h b/include/private/gcconfig.h
index 43e6625..51d8e8d 100644
--- a/include/private/gcconfig.h
+++ b/include/private/gcconfig.h
@@ -85,7 +85,7 @@
# define SPARC
# define mach_type_known
# endif
-# if defined(NETBSD) && defined(m68k)
+# if defined(NETBSD) && (defined(m68k) || defined(__m68k__))
# define M68K
# define mach_type_known
# endif
@@ -93,7 +93,7 @@
# define POWERPC
# define mach_type_known
# endif
-# if defined(NETBSD) && defined(__arm32__)
+# if defined(NETBSD) && (defined(__arm32__) || defined(__arm__))
# define ARM32
# define mach_type_known
# endif
@@ -106,6 +106,10 @@
# endif
# define mach_type_known
# endif
+# if defined(__NetBSD__) && defined(__vax__)
+# define VAX
+# define mach_type_known
+# endif
# if defined(mips) || defined(__mips) || defined(_mips)
# define MIPS
# if defined(nec_ews) || defined(_nec_ews)
@@ -601,8 +605,13 @@
# ifdef NETBSD
# define OS_TYPE "NETBSD"
# define HEURISTIC2
- extern char etext[];
-# define DATASTART ((ptr_t)(etext))
+# ifdef __ELF__
+# define DATASTART GC_data_start
+# define DYNAMIC_LOADING
+# else
+ extern char etext[];
+# define DATASTART ((ptr_t)(etext))
+# endif
# endif
# ifdef LINUX
# define OS_TYPE "LINUX"
diff --git a/pthread_support.c b/pthread_support.c
index de450da..b302817 100644
--- a/pthread_support.c
+++ b/pthread_support.c
@@ -135,10 +135,17 @@
# endif /* GC_DGUX386_THREADS */
# undef pthread_create
# if !defined(GC_DARWIN_THREADS)
-# undef pthread_sigmask
+# undef pthread_sigmask
# endif
# undef pthread_join
# undef pthread_detach
+# if defined(GC_OSF1_THREADS) && defined(_PTHREAD_USE_MANGLED_NAMES_) \
+ && !defined(_PTHREAD_USE_PTDNAM_)
+/* Restore the original mangled names on Tru64 UNIX. */
+# define pthread_create __pthread_create
+# define pthread_join __pthread_join
+# define pthread_detach __pthread_detach
+# endif
#endif
void GC_thr_init();
@@ -1247,13 +1254,15 @@ WRAP_FUNC(pthread_create)(pthread_t *new_thread,
/* This also ensures that we hold onto si until the child is done */
/* with it. Thus it doesn't matter whether it is otherwise */
/* visible to the collector. */
- while (0 != sem_wait(&(si -> registered))) {
- if (EINTR != errno) ABORT("sem_wait failed");
+ if (0 == result) {
+ while (0 != sem_wait(&(si -> registered))) {
+ if (EINTR != errno) ABORT("sem_wait failed");
+ }
}
sem_destroy(&(si -> registered));
- LOCK();
- GC_INTERNAL_FREE(si);
- UNLOCK();
+ LOCK();
+ GC_INTERNAL_FREE(si);
+ UNLOCK();
return(result);
}
diff --git a/version.h b/version.h
index 4c193a2..9d858b2 100644
--- a/version.h
+++ b/version.h
@@ -2,8 +2,8 @@
/* Eventually this one may become unnecessary. For now we need */
/* it to keep the old-style build process working. */
#define GC_TMP_VERSION_MAJOR 6
-#define GC_TMP_VERSION_MINOR 2
-#define GC_TMP_ALPHA_VERSION GC_NOT_ALPHA
+#define GC_TMP_VERSION_MINOR 3
+#define GC_TMP_ALPHA_VERSION 1
#ifndef GC_NOT_ALPHA
# define GC_NOT_ALPHA 0xff
diff --git a/win32_threads.c b/win32_threads.c
index a2f65a5..ff1d066 100755
--- a/win32_threads.c
+++ b/win32_threads.c
@@ -442,7 +442,17 @@ HANDLE WINAPI GC_CreateThread(
/* fill in ID and handle; tell child this is done */
thread_table[i].id = *lpThreadId;
- thread_table[i].handle = thread_h;
+ if (!DuplicateHandle(GetCurrentProcess(),
+ thread_h,
+ GetCurrentProcess(),
+ &thread_table[i].handle,
+ 0,
+ 0,
+ DUPLICATE_SAME_ACCESS)) {
+ DWORD last_error = GetLastError();
+ GC_printf1("Last error code: %lx\n", last_error);
+ ABORT("DuplicateHandle failed");
+ }
SetEvent (parent_ready_h);
/* wait for child to fill in stack and copy args */
@@ -630,12 +640,11 @@ static void threadDetach(DWORD thread_id) {
LOCK();
for (i = 0;
i < MAX_THREADS &&
- !thread_table[i].in_use || thread_table[i].id != thread_id;
+ (!thread_table[i].in_use || thread_table[i].id != thread_id);
i++) {}
if (i >= MAX_THREADS ) {
WARN("thread %ld not found on detach", (GC_word)thread_id);
- }
- else {
+ } else {
thread_table[i].stack = 0;
thread_table[i].in_use = FALSE;
CloseHandle(thread_table[i].handle);