]> granicus.if.org Git - gc/commitdiff
gc6.3alpha1 tarball import gc6_3alpha1
authorIvan Maidanski <ivmai@mail.ru>
Tue, 26 Jul 2011 13:43:46 +0000 (17:43 +0400)
committerIvan Maidanski <ivmai@mail.ru>
Tue, 26 Jul 2011 13:43:46 +0000 (17:43 +0400)
15 files changed:
aix_irix_threads.c
configure
configure.host
configure.in
doc/README
doc/README.changes
doc/README.darwin
dyn_load.c
include/gc.h
include/gc_pthread_redirects.h
include/private/gc_locks.h
include/private/gcconfig.h
pthread_support.c
version.h
win32_threads.c

index d3e8ae0f2dbca6479c92c6434502b66a77261713..d8ac3454af9036ed989b6706773b1b89b5a6b841 100644 (file)
@@ -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);
 }
index 7fdfcd532481cc4a12efdc365dfb4a5c007be844..011e747edc0d75a66938ac1ab7b66d05fc87b208 100755 (executable)
--- 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'`\\"
 
index 068ee39a42a972ab29c5a80cfafca7ce03a2ba98..a98a0a7cb30cc48a0035ac6b2fa4954b6542cf31 100644 (file)
@@ -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"
        ;;
   *)
        ;;
index 4f9e0d756bdd705e5dbaa4c49ea4419e870d00fa..eeb231a42772aaf162a762e65a72bf1a68a910bb 100644 (file)
@@ -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=
index 04e24a9a53715f2e006bce84d320261ca7bb283f..29d954f023ee9f2ea6dc14f50c41bd34a33a5a20 100644 (file)
@@ -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
 
index 1a0fcb387b1431925e82f6dfeb6414b6e1e3dddc..619ea2e4a4963ffa4536efb014796cd5de2b411f 100644 (file)
@@ -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
index 5bca9e18feccaad036febffba2a0d95e2f8e039a..3cd1b818b196badbf4269cfe29353223a66f772c 100644 (file)
@@ -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
index 9a530a23bf5b2105406e052e4430c190f58bf214..162f7dcb124a98c6e770cc64937cbe9325f3868e 100644 (file)
@@ -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
index f3e31d986e98eee21da2fefb7f1e8e89a0acb8b2..2d536ca3f9085ce61f50371039ad7f39ed5f8419 100644 (file)
@@ -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));
index 99a3e8da6404601828184feffcadedbd7d1835b1..842518cfcc48c2a0657b1cc6581994abf5cd8a44 100644 (file)
   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
 
index 250760516309325c239eeb821d76f7f97cab4c68..a079ebf86450bf104c017ed548a841e05e5e8191 100644 (file)
                              "       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");
index 43e66258bee839cd7b52e18b778f770dc5e37e73..51d8e8da4feadcce76ca18ea2613340908364e56 100644 (file)
@@ -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
 #    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)
 #   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"
index de450da184009a26f6da7a2b8f364c1629638f72..b302817bfdf46a4efa74d834d1f9947d66543058 100644 (file)
 #   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);
 }
index 4c193a26dba373180e1f0ef4870d105a932b0982..9d858b2aaa6798dcc23016a9788c13497aeab3d3 100644 (file)
--- 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
index a2f65a5d797fd59cc987ca634438c1dcc199c5b0..ff1d06625f86d3de60aa5f216066974e27607f0f 100755 (executable)
@@ -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);