$OpenBSD$
--- src/boehm-gc/pthread_stop_world.c.orig	Mon Feb 13 18:14:20 2006
+++ src/boehm-gc/pthread_stop_world.c	Sun Apr 30 22:19:21 2006
@@ -1,5 +1,7 @@
 #include "config.h"
 
+#define DEBUG_THREADS	1
+
 #include "private/pthread_support.h"
 
 #if defined(GC_PTHREADS) && !defined(GC_SOLARIS_THREADS) \
@@ -15,6 +17,10 @@
   /* Doesn't exist on HP/UX 11.11. */
 #endif
 
+#if defined(OPENBSD)
+#include <pthread_np.h>
+#endif
+
 #if DEBUG_THREADS
 
 #ifndef NSIG
@@ -25,22 +31,23 @@
 # elif defined(__SIGRTMAX)
 #  define NSIG (__SIGRTMAX+1)
 # else
-  --> please fix it
+# error unknown number of signals for this platform: please fix it
 # endif
 #endif
 
 void GC_print_sig_mask()
 {
-    sigset_t blocked;
-    int i;
+	sigset_t blocked;
+	int i;
 
-    if (pthread_sigmask(SIG_BLOCK, NULL, &blocked) != 0)
-    	ABORT("pthread_sigmask");
-    GC_printf0("Blocked: ");
-    for (i = 1; i < NSIG; i++) {
-        if (sigismember(&blocked, i)) { GC_printf1("%ld ",(long) i); }
-    }
-    GC_printf0("\n");
+	if (pthread_sigmask(SIG_BLOCK, NULL, &blocked) != 0)
+		ABORT("pthread_sigmask");
+
+	GC_printf0("Blocked signals: ");
+	for (i = 1; i < NSIG; i++) {
+		if (sigismember(&blocked, i)) { GC_printf1("%ld ",(long) i); }
+	}
+	GC_printf0("\n");
 }
 
 #endif
@@ -142,11 +149,25 @@ void GC_suspend_handler(int sig, siginfo
 {
    int old_errno = errno;
 
-   if (cacao_suspendhandler(uctx))
+#if DEBUG_THREADS
+    GC_printf0("GC_suspend_handler enter\n");
+#endif
+
+   if (cacao_suspendhandler(uctx)) {
+
+#if DEBUG_THREADS
+    GC_printf0("GC_suspend_handler cacao leave\n");
+#endif
+
      return;
+   }
 
    GC_suspend_handler_inner((ptr_t)(word)sig);
    errno = old_errno;
+
+#if DEBUG_THREADS
+    GC_printf0("GC_suspend_handler leave\n");
+#endif
 }
 #endif
  
@@ -213,7 +234,7 @@ void GC_suspend_handler_inner(ptr_t sig_
     while (GC_world_is_stopped && GC_stop_count == my_stop_count) {
         GC_brief_async_signal_safe_sleep();
 #       if DEBUG_THREADS
-	  GC_err_printf0("Sleeping in signal handler");
+	  GC_printf0("Sleeping in signal handler");
 #       endif
     }
     /* If the RESTART signal gets lost, we can still lose.  That should be  */
@@ -260,65 +281,86 @@ void GC_push_all_stacks()
     int i;
     GC_thread p;
     ptr_t lo, hi;
+
     /* On IA64, we also need to scan the register backing store. */
     IF_IA64(ptr_t bs_lo; ptr_t bs_hi;)
+
     pthread_t me = pthread_self();
     
     if (!GC_thr_initialized) GC_thr_init();
-    #if DEBUG_THREADS
-        GC_printf1("Pushing stacks from thread 0x%lx\n", (unsigned long) me);
-    #endif
-    for (i = 0; i < THREAD_TABLE_SZ; i++) {
-      for (p = GC_threads[i]; p != 0; p = p -> next) {
-        if (p -> flags & FINISHED) continue;
-        if (pthread_equal(p -> id, me)) {
-#  	    ifdef SPARC
-	        lo = (ptr_t)GC_save_regs_in_stack();
-#  	    else
- 	        lo = GC_approx_sp();
-#           endif
-	    found_me = TRUE;
-	    IF_IA64(bs_hi = (ptr_t)GC_save_regs_in_stack();)
-	} else {
-	    lo = p -> stop_info.stack_ptr;
-	    IF_IA64(bs_hi = p -> backing_store_ptr;)
-	}
-        if ((p -> flags & MAIN_THREAD) == 0) {
-	    hi = p -> stack_end;
-	    IF_IA64(bs_lo = p -> backing_store_end);
-        } else {
-            /* The original stack. */
-            hi = GC_stackbottom;
-	    IF_IA64(bs_lo = BACKING_STORE_BASE;)
-        }
-        #if DEBUG_THREADS
-            GC_printf3("Stack for thread 0x%lx = [%lx,%lx)\n",
-    	        (unsigned long) p -> id,
-		(unsigned long) lo, (unsigned long) hi);
-        #endif
-	if (0 == lo) ABORT("GC_push_all_stacks: sp not set!\n");
-#       ifdef STACK_GROWS_UP
-	  /* We got them backwards! */
-          GC_push_all_stack(hi, lo);
-#       else
-          GC_push_all_stack(lo, hi);
+
+#if DEBUG_THREADS
+	GC_printf1("Pushing stacks from thread 0x%lx\n", (unsigned long) me);
+#endif
+
+	for (i = 0; i < THREAD_TABLE_SZ; i++) {
+
+		for (p = GC_threads[i]; p != 0; p = p -> next) {
+
+#if DEBUG_THREADS
+			GC_printf4("[i==%d] p=%p pthread_t %lx p->flags= %lx\n", i, p, p->id, p->flags);
+#endif
+
+			if (p -> flags & FINISHED)
+				continue;
+
+			if (pthread_equal(p -> id, me)) {
+
+#	ifdef SPARC
+				lo = (ptr_t)GC_save_regs_in_stack();
+#  	else
+				lo = GC_approx_sp();
 #	endif
+				found_me = TRUE;
+				IF_IA64(bs_hi = (ptr_t)GC_save_regs_in_stack();)
+			} else {
+				lo = p -> stop_info.stack_ptr;
+				IF_IA64(bs_hi = p -> backing_store_ptr;)
+			}
+			if ((p -> flags & MAIN_THREAD) == 0) {
+				hi = p -> stack_end;
+				IF_IA64(bs_lo = p -> backing_store_end);
+			} else {
+	        	/* The original stack. */
+				hi = GC_stackbottom;
+				IF_IA64(bs_lo = BACKING_STORE_BASE;)
+			}
+
+#	if DEBUG_THREADS
+			GC_printf3("Stack for thread 0x%lx = [%lx,%lx)\n",
+					(unsigned long) p -> id,
+					(unsigned long) lo, (unsigned long) hi);
+#	endif
+
+			if (0 == lo)
+				ABORT("GC_push_all_stacks: sp not set!\n");
+
+#	ifdef STACK_GROWS_UP
+			/* We got them backwards! */
+			GC_push_all_stack(hi, lo);
+#	else
+			GC_push_all_stack(lo, hi);
+#	endif
+
 #	ifdef IA64
-#         if DEBUG_THREADS
-            GC_printf3("Reg stack for thread 0x%lx = [%lx,%lx)\n",
-    	        (unsigned long) p -> id,
-		(unsigned long) bs_lo, (unsigned long) bs_hi);
-#	  endif
-          if (pthread_equal(p -> id, me)) {
-	    GC_push_all_eager(bs_lo, bs_hi);
-	  } else {
-	    GC_push_all_stack(bs_lo, bs_hi);
-	  }
+#		if DEBUG_THREADS
+			GC_printf3("Reg stack for thread 0x%lx = [%lx,%lx)\n",
+				(unsigned long) p -> id,
+				(unsigned long) bs_lo, (unsigned long) bs_hi);
+#		endif
+			if (pthread_equal(p -> id, me)) {
+				GC_push_all_eager(bs_lo, bs_hi);
+			} else {
+				GC_push_all_stack(bs_lo, bs_hi);
+			}
 #	endif
-      }
-    }
-    if (!found_me && !GC_in_thread_creation)
-      ABORT("Collecting from unknown thread.");
+
+		} /* end for p != NULL */
+
+	} /* end for i<THREAD_TABLE_SZ */
+
+	if (!found_me && !GC_in_thread_creation)
+		ABORT("Collecting from unknown thread.");
 }
 
 /* There seems to be a very rare thread stopping problem.  To help us  */
@@ -332,38 +374,70 @@ int GC_stopping_pid;
 int GC_suspend_all()
 {
     int n_live_threads = 0;
+
+#if !defined(OPENBSD)
     int i;
     GC_thread p;
     int result;
     pthread_t my_thread = pthread_self();
-    
+
+#if DEBUG_THREADS
+	GC_printf0("GC_suspend_all: entry\n");
     GC_stopping_thread = my_thread;    /* debugging only.      */
-    GC_stopping_pid = getpid();                /* debugging only.      */
-    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 -> stop_info.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%lx\n", p -> id);
-	    #endif
+    GC_stopping_pid = getpid();        /* debugging only.      */
+#endif
+
+	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 -> stop_info.last_stop_count == GC_stop_count) continue;
+				if (p -> thread_blocked) /* Will wait */ continue;
+
+				n_live_threads++;
+
+#if DEBUG_THREADS
+				GC_printf1("GC_suspend_all: Sending suspend signal to 0x%lx\n", p -> id);
+#endif
         
-        result = pthread_kill(p -> id, SIG_SUSPEND);
-	    switch(result) {
-                case ESRCH:
+				result = pthread_kill(p -> id, SIG_SUSPEND);
+
+				switch(result) {
+				case ESRCH:
+#if DEBUG_THREADS
+					GC_printf1("GC_suspend_all: pthread_kill of %lx gives ESRCH\n", p->id );
+#endif
                     /* Not really there anymore.  Possible? */
-                    n_live_threads--;
-                    break;
-                case 0:
-                    break;
-                default:
+					n_live_threads--;
+					break;
+
+				case 0:
+#if DEBUG_THREADS
+					GC_printf1("GC_suspend_all: pthread_kill of %lx gives returns no error\n", p->id );
+#endif
+					sched_yield(); /* may be required ? */
+					break;
+
+				default:
                     ABORT("pthread_kill failed");
-            }
-        }
-      }
-    }
+					break;
+				}
+        	}
+      	} /* for i */
+    } /* for p */
+
+#if DEBUG_THREADS
+	GC_printf1("GC_suspend_all: n_live_threads=%d\n", n_live_threads);
+#endif
+
+#else
+
+	pthread_suspend_all_np();
+
+#endif
     return n_live_threads;
 }
 
@@ -377,9 +451,11 @@ void GC_stop_world()
     int n_live_threads;
     int code;
 
-    #if DEBUG_THREADS
-    GC_printf1("Stopping the world from 0x%lx\n", pthread_self());
-    #endif
+#if DEBUG_THREADS
+	sched_yield();
+	GC_printf1("GC_stop_world: Stopping the world from 0x%lx\n", pthread_self());
+	GC_print_sig_mask();
+#endif
 
     lock_stopworld(1);
        
@@ -396,105 +472,147 @@ void GC_stop_world()
     GC_world_is_stopped = TRUE;
     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;
+#if !defined(OPENBSD)
 
-	      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();
+	if (GC_retry_signals) {
+		unsigned long wait_usecs = 0;  /* Total wait since retry.	*/
+#define WAIT_UNIT 3000
+#define RETRY_INTERVAL 100000
 
-#                 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++) {
-	  while (0 != (code = sem_wait(&GC_suspend_ack_sem))) {
-	      if (errno != EINTR) {
-	         GC_err_printf1("Sem_wait returned %ld\n", (unsigned long)code);
-	         ABORT("sem_wait for handler failed");
-	      }
-	  }
-    }
-#   ifdef PARALLEL_MARK
-      GC_release_mark_lock();
-#   endif
-    #if DEBUG_THREADS
-      GC_printf1("World stopped from 0x%lx\n", pthread_self());
-    #endif
+#ifdef DEBUG_THREADS
+		GC_printf0("GC_stop_world: entrying retry symbols loop\n");
+#endif
+
+		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;
+		}
+	} /* if GC_retry_signals */
+
+	for (i = 0; i < n_live_threads; i++) {
+		GC_printf1("GC_stop_world: entering sem_wait(suspend_ack_sem) with n_live_thread=%d\n",n_live_threads);
+		while (0 != (code = sem_wait(&GC_suspend_ack_sem))) {
+			GC_printf0("GC_stop_world: sem_wait(suspend_ack_sem) returns code %d\n");
+			if (errno != EINTR) {
+				GC_err_printf1("GC_stop_world: sem_wait returned %ld\n", (unsigned long)code);
+				ABORT("sem_wait for handler failed");
+			} else {
+				GC_printf0("GC_stop_world: sem_wait(suspend_ack_sem) interrupted\n");
+			}
+		}
+	}
+
+#endif
+
+#ifdef PARALLEL_MARK
+	GC_release_mark_lock();
+#endif
+
+#if DEBUG_THREADS
+	GC_printf1("GC_stop_world: World stopped from 0x%lx\n", pthread_self());
     GC_stopping_thread = 0;  /* debugging only */
+#endif
+
 }
 
 /* Caller holds allocation lock, and has held it continuously since	*/
 /* the world stopped.							*/
 void GC_start_world()
 {
+
+#if !defined(OPENBSD)
     pthread_t my_thread = pthread_self();
     register int i;
     register GC_thread p;
     register int n_live_threads = 0;
     register int result;
+#endif
 
-#   if DEBUG_THREADS
-      GC_printf0("World starting\n");
-#   endif
+#if DEBUG_THREADS
+	GC_printf0("GC_start_world: enter\n");
+#endif
 
-    GC_world_is_stopped = FALSE;
-    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 -> thread_blocked) continue;
-            n_live_threads++;
-	    #if DEBUG_THREADS
-	      GC_printf1("Sending restart signal to 0x%lx\n", p -> id);
-	    #endif
-            result = pthread_kill(p -> id, SIG_THR_RESTART);
-	    switch(result) {
-                case ESRCH:
-                    /* Not really there anymore.  Possible? */
-                    n_live_threads--;
-                    break;
-                case 0:
-                    break;
-                default:
-                    ABORT("pthread_kill failed");
-            }
-        }
-      }
-    }
+	GC_world_is_stopped = FALSE;
 
-	unlock_stopworld();
+#if !defined(OPENBSD)
 
-    #if DEBUG_THREADS
-      GC_printf0("World started\n");
-    #endif
+	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 -> thread_blocked) continue;
+
+				n_live_threads++;
+
+#if DEBUG_THREADS
+				GC_printf1("GC_start_world: Sending restart signal to 0x%lx\n", p -> id);
+#endif
+
+				result = pthread_kill(p -> id, SIG_THR_RESTART);
+
+				switch(result) {
+				case ESRCH:
+					/* Not really there anymore.  Possible? */
+					n_live_threads--;
+					break;
+
+				case 0:
+					break;
+
+				default:
+					ABORT("pthread_kill failed");
+				}
+			} /* if not this thread */
+		} /* for p */
+	} /* for i */
+
+#else
+
+	pthread_resume_all_np();
+
+#endif
+
+	unlock_stopworld(); /* cacao callback */
+
+#if DEBUG_THREADS
+	GC_printf0("GC_start_world: leave\n");
+#endif
+
 }
 
 void GC_stop_init() {
     struct sigaction act;
+
+#ifdef DEBUG_THREADS
+	GC_printf0("GC_stop_init: entered\n");
+#endif
     
     if (sem_init(&GC_suspend_ack_sem, 0, 0) != 0)
         ABORT("sem_init failed");
 
-    act.sa_flags = SA_RESTART | SA_SIGINFO;
+    act.sa_flags = /*SA_NODEFER |*/ SA_ONSTACK | SA_RESTART | SA_SIGINFO;
     if (sigfillset(&act.sa_mask) != 0) {
     	ABORT("sigfillset() failed");
     }
@@ -529,16 +647,22 @@ void GC_stop_init() {
               GC_printf0("Will retry suspend signal if necessary.\n");
 	  }
 #     endif
+
+#ifdef DEBUG_THREADS
+	GC_printf0("GC_stop_init: leave\n");
+#endif
 }
 
 /* Added for cacao */
 int GC_signum1()
 {
+	GC_printf0("GC_signum1\n");
     return SIG_SUSPEND;
 }
 
 int GC_signum2()
 {
+	GC_printf0("GC_signum2\n");
     return SIG_THR_RESTART;
 }
 /* cacao END */
