diff options
author | Ivan Maidanski <ivmai@mail.ru> | 2011-07-26 15:43:46 +0200 |
---|---|---|
committer | Ivan Maidanski <ivmai@mail.ru> | 2011-07-26 15:43:46 +0200 |
commit | 8c9e394bc270dbaa121f3f0af5a68c2876ab3fff (patch) | |
tree | c6e0b47bf496ae3d10f367c7130f8cdb912df8eb | |
parent | 111a44f98adde07d205c92656ad9b935ca2a39a8 (diff) |
gc6.3alpha1 tarball importgc6_3alpha1
-rw-r--r-- | aix_irix_threads.c | 354 | ||||
-rwxr-xr-x | configure | 22 | ||||
-rw-r--r-- | configure.host | 8 | ||||
-rw-r--r-- | configure.in | 4 | ||||
-rw-r--r-- | doc/README | 2 | ||||
-rw-r--r-- | doc/README.changes | 18 | ||||
-rw-r--r-- | doc/README.darwin | 22 | ||||
-rw-r--r-- | dyn_load.c | 63 | ||||
-rw-r--r-- | include/gc.h | 4 | ||||
-rw-r--r-- | include/gc_pthread_redirects.h | 15 | ||||
-rw-r--r-- | include/private/gc_locks.h | 6 | ||||
-rw-r--r-- | include/private/gcconfig.h | 17 | ||||
-rw-r--r-- | pthread_support.c | 21 | ||||
-rw-r--r-- | version.h | 4 | ||||
-rwxr-xr-x | win32_threads.c | 17 |
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)®buf[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); } @@ -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= @@ -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 @@ -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); } @@ -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); |