This is the mail archive of the java-patches@gcc.gnu.org mailing list for the Java project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

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


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]