$NetBSD: patch-aj,v 1.5 2006/01/03 08:03:53 recht Exp $

--- libgc/pthread_stop_world.c.orig	2005-07-05 20:42:42.000000000 +0200
+++ libgc/pthread_stop_world.c
@@ -99,6 +99,7 @@ word GC_stop_count;	/* Incremented at th
 #  endif
 #endif
 
+#if !defined(GC_NETBSD_THREADS)
 sem_t GC_suspend_ack_sem;
 
 static void _GC_suspend_handler(int sig)
@@ -208,6 +209,7 @@ static void _GC_restart_handler(int sig)
     GC_printf1("In GC_restart_handler for 0x%lx\n", pthread_self());
 #endif
 }
+#endif /* !GC_NETBSD_THREADS */
 
 # ifdef IA64
 #   define IF_IA64(x) x
@@ -283,12 +285,14 @@ static void pthread_push_all_stacks()
       ABORT("Collecting from unknown thread.");
 }
 
+#if !defined(GC_NETBSD_THREADS)
 void GC_restart_handler(int sig)
 {
 	int old_errno = errno;
 	_GC_restart_handler (sig);
 	errno = old_errno;
 }
+#endif
 
 /* We hold allocation lock.  Should do exactly the right thing if the	*/
 /* world is stopped.  Should not fail if it isn't.			*/
@@ -297,6 +301,28 @@ void GC_push_all_stacks()
     gc_thread_vtable->push_all_stacks();
 }
 
+#if defined(GC_NETBSD_THREADS)
+/* 
+ * Get the stack start address for the specified address.
+ */ 
+int 
+np_stackinfo(pthread_t p, void **addr) 
+{ 
+	pthread_attr_t attr; 
+	int ret = -1; 
+
+	if (pthread_attr_init(&attr)) 
+		return -1;
+
+	if (!pthread_attr_get_np(p, &attr))
+		if (!pthread_attr_getstackaddr(&attr, addr)) 
+			ret = 0;
+
+	pthread_attr_destroy(&attr); 
+	return ret; 
+}
+#endif
+
 /* There seems to be a very rare thread stopping problem.  To help us  */
 /* debug that, we save the ids of the stopping thread. */
 pthread_t GC_stopping_thread;
@@ -322,6 +348,7 @@ int GC_suspend_all()
             if (p -> stop_info.last_stop_count == GC_stop_count) continue;
 	    if (p -> thread_blocked) /* Will wait */ continue;
             n_live_threads++;
+#if !defined(GC_NETBSD_THREADS)
 	    #if DEBUG_THREADS
 	      GC_printf1("Sending suspend signal to 0x%lx\n", p -> id);
 	    #endif
@@ -337,6 +364,23 @@ int GC_suspend_all()
                 default:
                     ABORT("pthread_kill failed");
             }
+#else
+	    #if DEBUG_THREADS
+	      GC_printf1("Suspending 0x%lx ...\n", p -> id);
+	    #endif
+
+		if(pthread_suspend_np(p -> id) != 0)
+			GC_printf1("Could not susend thread... 0x%lx\n", p -> id);
+
+		/* Right now, this is not enough. Retreiving the stack base address is not the correct */
+		/* info to give to the GC, but since there is no way to get the current stack pointer  */
+		/* for the suspended thread, base pointer will have to be enough. Mono seems to be     */
+		/* happy with it so... */
+		if(np_stackinfo(p -> id, &(p -> stop_info.stack_ptr)) != 0)
+			GC_err_printf1("Could not get thread stack address... 0x%lx\n", p -> id);			
+
+        n_live_threads--;
+#endif /* !GC_NETBSD_THREADS */
         }
       }
     }
@@ -356,6 +400,7 @@ static void pthread_stop_world()
        
     n_live_threads = GC_suspend_all();
 
+#if !defined(GC_NETBSD_THREADS)
       if (GC_retry_signals) {
 	  unsigned long wait_usecs = 0;  /* Total wait since retry.	*/
 #	  define WAIT_UNIT 3000
@@ -393,6 +438,8 @@ static void pthread_stop_world()
 	      }
 	  }
     }
+#endif /* !GC_NETBSD_THREADS */
+
     #if DEBUG_THREADS
       GC_printf1("World stopped from 0x%lx\n", pthread_self());
     #endif
@@ -439,6 +486,7 @@ static void pthread_start_world()
             if (p -> flags & FINISHED) continue;
 	    if (p -> thread_blocked) continue;
             n_live_threads++;
+#if !defined(GC_NETBSD_THREADS)
 	    #if DEBUG_THREADS
 	      GC_printf1("Sending restart signal to 0x%lx\n", p -> id);
 	    #endif
@@ -454,10 +502,18 @@ static void pthread_start_world()
                 default:
                     ABORT("pthread_kill failed");
             }
+#else
+	    #if DEBUG_THREADS
+	      GC_printf1("Resuming Thread 0x%lx\n", p -> id);
+	    #endif
+		pthread_resume_np(p -> id);
+		n_live_threads--;
+#endif /* !GC_NETBSD_THREADS */
         }
       }
     }
 
+#if !defined(GC_NETBSD_THREADS)
     #if DEBUG_THREADS
     GC_printf0 ("All threads signaled");
     #endif
@@ -470,6 +526,7 @@ static void pthread_start_world()
 	    }
 	}
     }
+#endif /* !GC_NETBSD_THREADS */
   
     #if DEBUG_THREADS
       GC_printf0("World started\n");
@@ -482,6 +539,8 @@ void GC_start_world()
 }
 
 static void pthread_stop_init() {
+
+#if !defined(GC_NETBSD_THREADS)
     struct sigaction act;
     
     if (sem_init(&GC_suspend_ack_sem, 0, 0) != 0)
@@ -522,6 +581,16 @@ static void pthread_stop_init() {
               GC_printf0("Will retry suspend signal if necessary.\n");
 	  }
 #     endif
+#else
+    struct sigaction act;
+
+    act.sa_flags = SA_RESTART;
+    if (sigfillset(&act.sa_mask) != 0) {
+    	ABORT("sigfillset() failed");
+    }
+    GC_remove_allowed_signals(&act.sa_mask);
+
+#endif /* !GC_NETBSD_THREADS */
 }
 
 /* We hold the allocation lock.	*/
