3.4 PATCH: Support boehm-gc with pthreads on Tru64 UNIX

Boehm, Hans hans_boehm@hp.com
Wed Jul 23 22:25:00 GMT 2003


I tested a bit more on X86 and IA64.  It still looks fine to me.

It's OK with me if you go ahead and check it in (after adding the defined(GC_OSF1_THREADS) check in a couple of places, as we discussed).

I am a bit concerned that we're effectively doing a piecemeal merge of GC 6.2/6.3, when we should be doing the merge once and for all.

Tom - Is this patch OK with you as well?  Another possibility might be a full 6.2/6.3 merge, minus the configury changes.  I think I could do that semi-manually without too much effort.  (I'm less certain I can do it in a way that's consistent with GNU ChangeLog standards, etc.)   And it might fix Oyvind's problem, though at most for 3.4.

I think the build changes are relatively independent, and less critical.  I needed to update since I couldn't manage to get the old stuff debugged in the standalone distribution.  Since the current arrangement is working inside gcc, and there are more experienced auto{make,conf} maintainers around ...

Hans

> -----Original Message-----
> From: Rainer Orth [mailto:ro@TechFak.Uni-Bielefeld.DE]
> Sent: Friday, July 11, 2003 12:30 PM
> To: java-patches@gcc.gnu.org
> Cc: gcc-patches@gcc.gnu.org; Richard Henderson
> Subject: 3.4 PATCH: Support boehm-gc with pthreads on Tru64 UNIX
> 
> 
> After I got gc6.2 working on Tru64 UNIX with --enable-threads=posix
> 
> 	http://gcc.gnu.org/ml/java/2003-07/msg00162.html
> 
> it was relatively easy to backport the necessary changes to 
> GCC mainline.
> 
> This patch contains
> 
> * the changes for gc6.2 from the message above,
> 
> * the necessary configure.in support, and
> 
> * a couple of straightforward Tru64 UNIX related changes from gc6.2
>   pthread_support.c, pthread_stop_world.c, 
> include/private/gc_locks.h, and
>   include/private/gcconfig.h.
> 
> The biggest change is the support for GC_retry_signals: this 
> is necessary
> since without it Tru64 UNIX V4.0F seems to loose some restart signals
> (cf. gc6.2 doc/README.environment (GC_RETRY_SIGNALS)) and gctest just
> hangs, though V5.1 works fine without.
> 
> There's currently one change I haven't ported over:
> 
> include/private/gcconfig.h has:
> 
> # ifdef ALPHA
> [...]
> #   ifndef LINUX
> #     define USE_GENERIC_PUSH_REGS
>       /* Gcc and probably the DEC/Compaq compiler spill 
> pointers to preserved */
>       /* fp registers in some cases when the target is a 
> 21264.  The assembly */
>       /* code doesn't handle that yet, and version 
> dependencies make that a   */
>       /* bit tricky.  Do the easy thing for now.		
> 		    */
> #   endif
> 
> I'm not sure this is necessary given this change:
> 
> 2001-06-26  Richard Henderson  <rth@redhat.com>
> 
> 	* alpha_mach_dep.s: Mark call-saved FP registers.
> 	* include/private/gcconfig.h (ALPHA): Remove 
> USE_GENERIC_PUSH_REGS.
> 	* configure.in (alpha*): Re-enable alpha_mach_dep.s
> 	* configure: Rebuild.
> 
> Maybe Richard can comment?
> 
> Anyway, with this patch both make check in boehm-gc works with
> --enable-threads=posix, and a full bootstrap succeeded on 
> alpha-dec-osf4.0f
> and alpha-dec-osf5.1 succeeded.
> 
> With a companion patch to libjava (to be submitted shortly), 
> libjava test
> results look reasonable with this change.  For the moment, 
> this shouldn't
> hurt since --enable-threads=posix isn't considered supported 
> (or even the
> default) on that platform yet.
> 
> Ok for mainline?
> 
> 	Rainer
> 
> --------------------------------------------------------------
> ---------------
> Rainer Orth, Faculty of Technology, Bielefeld University
> 
> 
> Fri Jul 11 20:50:10 2003  Rainer Orth  <ro@TechFak.Uni-Bielefeld.DE>
> 
> 	Backport Tru64 UNIX POSIX threads support from gc6.2.
> 
> 	* configure.in: Handle *-*-osf*.
> 	* configure: Regenerate.
> 	
> 	* include/gc_pthread_redirects.h [!GC_USE_LD_WRAP && GC_PTHREADS
> 	&& !GC_SOLARIS_PTHREADS]: Undef mangled pthreads on 
> Tru64 UNIX if
> 	appropriate.
> 
> 	* include/private/gc_locks.h [THREADS && __GNUC__ && ALPHA]
> 	(GC_test_and_set): Only use ELF section switching if __ELF__.
> 	(GC_clear): Define.
> 
> 	* include/private/gcconfig.h [ALPHA && OSF1]: Only define
> 	MPROTECT_VDB if not GC_OSF1_THREADS.
> 
> 	* linux_threads.c (USE_PTHREAD_SPECIFIC) [GC_OSF1_THREADS &&
> 	!USE_PTHREAD_SPECIFIC]: Define.
> 	[!GC_USE_LD_WRAP && _PTHREAD_USE_MANGLED_NAMES_ &&
> 	!_PTHREAD_USE_PTDNAM_]: Restore	original Tru64 UNIX 
> definitions if
> 	appropriate. 
> 	(struct GC_Thread_Rep): New member last_stop_count.
> 	(GC_stop_count, GC_retry_signals): Define.
> 	(SIG_THR_RESTART): Use SIGRTMIN if _SIGRTMIN is missing.
> 	(GC_suspend_handler): Check for duplicate suspend signal.
> 	Set last_stop_count after suspend.
> 	(GC_suspend_all): New function, extracted from GC_stop_world.
> 	(GC_stop_world): Use it.
> 	Handle GC_retry_signals.
> 	(GC_thr_init): Set GC_retry_signals from environment.
> 	[GC_OSF1_THREADS]: Try setting GC_nprocs via sysconf.
> 
> Index: configure.in
> ===================================================================
> RCS file: /cvs/gcc/gcc/boehm-gc/configure.in,v
> retrieving revision 1.47
> diff -u -p -r1.47 configure.in
> --- configure.in	28 Apr 2003 20:54:37 -0000	1.47
> +++ configure.in	8 Jul 2003 01:17:29 -0000
> @@ -111,6 +111,17 @@ case "$THREADS" in
>       *-*-cygwin*)
>  	THREADLIBS=
>  	;;
> +     *-*-osf*)
> +	AC_DEFINE(GC_OSF1_THREADS)
> +        if test "${enable_parallel_mark}" = yes; then
> +	  AC_DEFINE(PARALLEL_MARK)
> +	  AC_DEFINE(THREAD_LOCAL_ALLOC)
> +	  # May want to enable it in other cases, too.
> +	  # Measurements havent yet been done.
> +	fi
> +	INCLUDES="$INCLUDES -pthread"
> +	THREADLIBS="-lpthread -lrt"
> +	;;
>      esac
>      ;;
>   win32)
> Index: linux_threads.c
> ===================================================================
> RCS file: /cvs/gcc/gcc/boehm-gc/linux_threads.c,v
> retrieving revision 1.20
> diff -u -p -r1.20 linux_threads.c
> --- linux_threads.c	29 Mar 2002 22:52:12 -0000	1.20
> +++ linux_threads.c	8 Jul 2003 01:17:29 -0000
> @@ -28,11 +28,8 @@
>   */
>  /*
>   * Linux_threads.c now also includes some code to support HPUX and
> - * OSF1 (Compaq Tru64 Unix, really).  The OSF1 support is not yet
> - * functional.  The OSF1 code is based on Eric Benson's
> - * patch, though that was originally against 
> hpux_irix_threads.  The code
> - * here is completely untested.  With 0.0000001% 
> probability, it might
> - * actually work.
> + * OSF1 (Compaq Tru64 Unix, really).  The OSF1 support is 
> based on Eric Benson's
> + * patch.
>   *
>   * Eric also suggested an alternate basis for a lock 
> implementation in
>   * his code:
> @@ -62,6 +59,10 @@
>  #   define USE_HPUX_TLS
>  # endif
>  
> +# if defined(GC_OSF1_THREADS) && !defined(USE_PTHREAD_SPECIFIC)
> +#   define USE_PTHREAD_SPECIFIC
> +# endif
> +
>  # ifdef THREAD_LOCAL_ALLOC
>  #   if !defined(USE_PTHREAD_SPECIFIC) && !defined(USE_HPUX_TLS)
>  #     include "private/specific.h"
> @@ -107,6 +108,12 @@
>  #   undef pthread_sigmask
>  #   undef pthread_join
>  #   undef pthread_detach
> +#   if 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
>  
>  
> @@ -143,6 +150,11 @@ typedef struct GC_Thread_Rep {
>  				  /* guaranteed to be dead, but 
> we may  */
>  				  /* not yet have registered 
> the join.) */
>      pthread_t id;
> +    /* Extra bookkeeping information the stopping code uses */
> +    word last_stop_count;	/* GC_last_stop_count value 
> when thread	*/
> +    				/* last successfully handled a 
> suspend	*/
> +    				/* signal.			
> 	*/
> +
>      short flags;
>  #	define FINISHED 1   	/* Thread has exited.	*/
>  #	define DETACHED 2	/* Thread is intended to be 
> detached.	*/
> @@ -435,6 +447,14 @@ GC_PTR GC_local_gcj_malloc(size_t bytes,
>  
>  # endif /* !THREAD_LOCAL_ALLOC */
>  
> +word GC_stop_count;	/* Incremented at the beginning of 
> GC_stop_world. */
> +
> +#ifdef GC_OSF1_THREADS
> +  GC_bool GC_retry_signals = TRUE;
> +#else
> +  GC_bool GC_retry_signals = FALSE;
> +#endif
> +
>  /*
>   * We use signals to stop threads during GC.
>   * 
> @@ -449,7 +469,11 @@ GC_PTR GC_local_gcj_malloc(size_t bytes,
>  
>  #ifndef SIG_THR_RESTART
>  #  if defined(GC_HPUX_THREADS) || defined(GC_OSF1_THREADS)
> -#   define SIG_THR_RESTART _SIGRTMIN + 5
> +#    ifdef _SIGRTMIN
> +#      define SIG_THR_RESTART _SIGRTMIN + 5
> +#    else
> +#      define SIG_THR_RESTART SIGRTMIN + 5
> +#    endif
>  #  else
>  #   define SIG_THR_RESTART SIGXCPU
>  #  endif
> @@ -586,6 +610,7 @@ void GC_suspend_handler(int sig)
>  	/* guaranteed to be the mark_no correspending to our 	
> 	*/
>  	/* suspension, i.e. the marker can't have incremented 
> it yet.	*/
>  #   endif
> +    word my_stop_count = GC_stop_count;
>  
>      if (sig != SIG_SUSPEND) ABORT("Bad signal in suspend_handler");
>  
> @@ -598,6 +623,14 @@ void GC_suspend_handler(int sig)
>      /* of a thread which holds the allocation lock in order	*/
>      /* to stop the world.  Thus concurrent modification of 
> the	*/
>      /* data structure is impossible.				*/
> +    if (me -> last_stop_count == my_stop_count) {
> +	/* Duplicate signal.  OK if we are retrying.	*/
> +	if (!GC_retry_signals) {
> +	    WARN("Duplicate suspend signal in thread %lx\n",
> +		 pthread_self());
> +	}
> +	return;
> +    }
>  #   ifdef SPARC
>  	me -> stack_ptr = (ptr_t)GC_save_regs_in_stack();
>  #   else
> @@ -611,6 +644,7 @@ void GC_suspend_handler(int sig)
>      /* thread has been stopped.  Note that sem_post() is  	*/
>      /* the only async-signal-safe primitive in LinuxThreads.    */
>      sem_post(&GC_suspend_ack_sem);
> +    me -> last_stop_count = my_stop_count;
>  
>      /* Wait until that thread tells us to restart by sending    */
>      /* this thread a SIG_THR_RESTART signal.			*/
> @@ -799,36 +833,31 @@ GC_thread GC_lookup_thread(pthread_t id)
>  pthread_t GC_stopping_thread;
>  int GC_stopping_pid;
>  
> -/* Caller holds allocation lock.	*/
> -void GC_stop_world()
> +/* We hold the allocation lock.  Suspend all threads that 
> might	*/
> +/* still be running.  Return the number of suspend signals 
> that	*/
> +/* were sent. */
> +int GC_suspend_all()
>  {
> +    int n_live_threads = 0;
> +    int i;
> +    GC_thread p;
> +    int result;
>      pthread_t my_thread = pthread_self();
> -    register int i;
> -    register GC_thread p;
> -    register int n_live_threads = 0;
> -    register int result;
> -
> +    
>      GC_stopping_thread = my_thread;    /* debugging only.      */
>      GC_stopping_pid = getpid();                /* debugging 
> only.      */
> -    /* Make sure all free list construction has stopped 
> before we start. */
> -    /* No new construction can start, since free list 
> construction is	*/
> -    /* required to acquire and release the GC lock before it 
> starts,	*/
> -    /* and we have the lock.					
> 	*/
> -#   ifdef PARALLEL_MARK
> -      GC_acquire_mark_lock();
> -      GC_ASSERT(GC_fl_builder_count == 0);
> -      /* We should have previously waited for it to become zero. */
> -#   endif /* PARALLEL_MARK */
>      for (i = 0; i < THREAD_TABLE_SZ; i++) {
>        for (p = GC_threads[i]; p != 0; p = p -> next) {
>          if (p -> id != my_thread) {
>              if (p -> flags & FINISHED) continue;
> +            if (p -> last_stop_count == GC_stop_count) continue;
>  	    if (p -> thread_blocked) /* Will wait */ continue;
>              n_live_threads++;
>  	    #if DEBUG_THREADS
> -	      GC_printf1("Sending suspend signal to 0x%x\n", p -> id);
> +	      GC_printf1("Sending suspend signal to 0x%lx\n", p -> id);
>  	    #endif
> -            result = pthread_kill(p -> id, SIG_SUSPEND);
> +        
> +        result = pthread_kill(p -> id, SIG_SUSPEND);
>  	    switch(result) {
>                  case ESRCH:
>                      /* Not really there anymore.  Possible? */
> @@ -842,6 +871,59 @@ void GC_stop_world()
>          }
>        }
>      }
> +    return n_live_threads;
> +}
> +
> +/* Caller holds allocation lock.	*/
> +void GC_stop_world()
> +{
> +    pthread_t my_thread = pthread_self();
> +    register int i;
> +    register GC_thread p;
> +    register int n_live_threads = 0;
> +    register int result;
> +
> +    /* Make sure all free list construction has stopped 
> before we start. */
> +    /* No new construction can start, since free list 
> construction is	*/
> +    /* required to acquire and release the GC lock before it 
> starts,	*/
> +    /* and we have the lock.					
> 	*/
> +#   ifdef PARALLEL_MARK
> +      GC_acquire_mark_lock();
> +      GC_ASSERT(GC_fl_builder_count == 0);
> +      /* We should have previously waited for it to become zero. */
> +#   endif /* PARALLEL_MARK */
> +    ++GC_stop_count;
> +    n_live_threads = GC_suspend_all();
> +
> +      if (GC_retry_signals) {
> +	  unsigned long wait_usecs = 0;  /* Total wait since 
> retry.	*/
> +#	  define WAIT_UNIT 3000
> +#	  define RETRY_INTERVAL 100000
> +	  for (;;) {
> +	      int ack_count;
> +
> +	      sem_getvalue(&GC_suspend_ack_sem, &ack_count);
> +	      if (ack_count == n_live_threads) break;
> +	      if (wait_usecs > RETRY_INTERVAL) {
> +		  int newly_sent = GC_suspend_all();
> +
> +#                 ifdef CONDPRINT
> +		    if (GC_print_stats) {
> +		      GC_printf1("Resent %ld signals after timeout\n",
> +				 newly_sent);
> +		    }
> +#                 endif
> +		  sem_getvalue(&GC_suspend_ack_sem, &ack_count);
> +		  if (newly_sent < n_live_threads - ack_count) {
> +		      WARN("Lost some threads during 
> GC_stop_world?!\n",0);
> +		      n_live_threads = ack_count + newly_sent;
> +		  }
> +		  wait_usecs = 0;
> +	      }
> +	      usleep(WAIT_UNIT);
> +	      wait_usecs += WAIT_UNIT;
> +	  }
> +      }
>      for (i = 0; i < n_live_threads; i++) {
>      	if (0 != sem_wait(&GC_suspend_ack_sem))
>  	    ABORT("sem_wait in handler failed");
> @@ -1073,6 +1155,19 @@ void GC_thr_init()
>  	}
>  #   endif  /* INSTALL_LOOPING_SEGV_HANDLER */
>  
> +    /* Check for GC_RETRY_SIGNALS.	*/
> +      if (0 != GETENV("GC_RETRY_SIGNALS")) {
> +	  GC_retry_signals = TRUE;
> +      }
> +      if (0 != GETENV("GC_NO_RETRY_SIGNALS")) {
> +	  GC_retry_signals = FALSE;
> +      }
> +#     ifdef CONDPRINT
> +          if (GC_print_stats && GC_retry_signals) {
> +              GC_printf0("Will retry suspend signal if 
> necessary.\n");
> +	  }
> +#     endif
> +
>      /* Add the initial thread, so we can stop it.	*/
>        t = GC_new_thread(pthread_self());
>        t -> stack_ptr = (ptr_t)(&dummy);
> @@ -1088,7 +1183,11 @@ void GC_thr_init()
>  #       if defined(GC_HPUX_THREADS)
>  	  GC_nprocs = pthread_num_processors_np();
>  #       endif
> -#       if defined(GC_OSF1_THREADS) || defined(GC_FREEBSD_THREADS)
> +#	if defined(GC_OSF1_THREADS)
> +	  GC_nprocs = sysconf(_SC_NPROCESSORS_ONLN);
> +	  if (GC_nprocs <= 0) GC_nprocs = 1;
> +#	endif
> +#       if defined(GC_FREEBSD_THREADS)
>            GC_nprocs = 1;
>  #       endif
>  #	if defined(GC_LINUX_THREADS)
> Index: include/gc_pthread_redirects.h
> ===================================================================
> RCS file: /cvs/gcc/gcc/boehm-gc/include/gc_pthread_redirects.h,v
> retrieving revision 1.3
> diff -u -p -r1.3 gc_pthread_redirects.h
> --- include/gc_pthread_redirects.h	17 Oct 2001 04:55:28 
> -0000	1.3
> +++ include/gc_pthread_redirects.h	8 Jul 2003 01:17:30 -0000
> @@ -56,6 +56,15 @@
>    int GC_pthread_join(pthread_t thread, void **retval);
>    int GC_pthread_detach(pthread_t thread);
>  
> +#if 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_sigmask GC_pthread_sigmask
>  # define pthread_join GC_pthread_join
> Index: include/private/gc_locks.h
> ===================================================================
> RCS file: /cvs/gcc/gcc/boehm-gc/include/private/gc_locks.h,v
> retrieving revision 1.8
> diff -u -p -r1.8 gc_locks.h
> --- include/private/gc_locks.h	23 Mar 2003 01:36:22 
> -0000	1.8
> +++ include/private/gc_locks.h	8 Jul 2003 01:17:30 -0000
> @@ -174,12 +174,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");
> @@ -187,8 +193,11 @@
>            return oldvalue;
>          }
>  #       define GC_TEST_AND_SET_DEFINED
> -        /* Should probably also define GC_clear, since it 
> needs	*/
> -        /* a memory barrier ??				
> 	*/
> +        inline static void GC_clear(volatile unsigned int *addr) {
> +          __asm__ __volatile__("mb" : : : "memory");
> +          *(addr) = 0;
> +        }
> +#       define GC_CLEAR_DEFINED
>  #    endif /* ALPHA */
>  #    ifdef ARM32
>          inline static int GC_test_and_set(volatile unsigned 
> int *addr) {
> Index: include/private/gcconfig.h
> ===================================================================
> RCS file: /cvs/gcc/gcc/boehm-gc/include/private/gcconfig.h,v
> retrieving revision 1.31
> diff -u -p -r1.31 gcconfig.h
> --- include/private/gcconfig.h	16 Apr 2003 18:28:29 
> -0000	1.31
> +++ include/private/gcconfig.h	8 Jul 2003 01:17:30 -0000
> @@ -1381,7 +1381,10 @@
>      	extern int __start[];
>  #   	define HEURISTIC2_LIMIT ((ptr_t)((word)(__start) & 
> ~(getpagesize()-1)))
>  #   	define CPP_WORDSZ 64
> -#   	define MPROTECT_VDB
> +#	ifndef GC_OSF1_THREADS
> +	  /* Unresolved signal issues with threads.	*/
> +#   	  define MPROTECT_VDB
> +#       endif
>  #   	define DYNAMIC_LOADING
>  #   endif
>  #   ifdef LINUX
> 



More information about the Java-patches mailing list