This is the mail archive of the
java-patches@gcc.gnu.org
mailing list for the Java project.
3.4 PATCH: Support boehm-gc with pthreads on Tru64 UNIX
- From: Rainer Orth <ro at TechFak dot Uni-Bielefeld dot DE>
- To: java-patches at gcc dot gnu dot org
- Cc: gcc-patches at gcc dot gnu dot org, Richard Henderson <rth at redhat dot com>
- Date: Fri, 11 Jul 2003 21:29:33 +0200 (MEST)
- 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