$OpenBSD$
--- src/boehm-gc/pthread_support.c.orig	Mon Feb 13 18:14:20 2006
+++ src/boehm-gc/pthread_support.c	Sun Apr 30 19:30:37 2006
@@ -46,7 +46,7 @@
 
 #include "config.h"
 
-/*#define DEBUG_THREADS 1*/
+#define DEBUG_THREADS 1
 /*#define GC_ASSERTIONS*/
 
 # include "private/pthread_support.h"
@@ -555,11 +555,24 @@ void GC_mark_thread_local_free_lists(voi
 
 static struct GC_Thread_Rep first_thread;
 
+#if !defined(HASH_SHIFT) && defined(GC_OPENBSD_PTHREADS)
+#define HASH_SHIFT	10	/* OpenBSD aligns the pthread structure widely */
+#endif
+
+#if !defined(HASH_SHIFT)
+#define HASH_SHIFT	2	/* Always safe because of pointer alignment in 32-bit machines */
+#endif
+
+/* NB: THREAD_TABLE_SZ must be a power of two */
+static inline word hashNo(word id) {
+	return (id >> HASH_SHIFT) & (THREAD_TABLE_SZ - 1);
+}
+
 /* Add a thread to GC_threads.  We assume it wasn't already there.	*/
 /* Caller holds allocation lock.					*/
 GC_thread GC_new_thread(pthread_t id)
 {
-    int hv = ((word)id) % THREAD_TABLE_SZ;
+    int hv = hashNo((word)id);
     GC_thread result;
     static GC_bool first_thread_used = FALSE;
     
@@ -574,6 +587,9 @@ GC_thread GC_new_thread(pthread_t id)
     result -> id = id;
     result -> next = GC_threads[hv];
     GC_threads[hv] = result;
+#ifdef DEBUG_THREADS
+	GC_printf2("GC_new_thread pthread_t %lx hashes to GC_threads[%d]\n",id,hv);
+#endif
     GC_ASSERT(result -> flags == 0 && result -> thread_blocked == 0);
     return(result);
 }
@@ -583,7 +599,7 @@ GC_thread GC_new_thread(pthread_t id)
 /* Caller holds allocation lock.				*/
 void GC_delete_thread(pthread_t id)
 {
-    int hv = ((word)id) % THREAD_TABLE_SZ;
+    int hv = hashNo((word)id);
     register GC_thread p = GC_threads[hv];
     register GC_thread prev = 0;
     
@@ -605,7 +621,7 @@ void GC_delete_thread(pthread_t id)
 /* This is OK, but we need a way to delete a specific one.	*/
 void GC_delete_gc_thread(pthread_t id, GC_thread gc_id)
 {
-    int hv = ((word)id) % THREAD_TABLE_SZ;
+    int hv = hashNo((word)id);
     register GC_thread p = GC_threads[hv];
     register GC_thread prev = 0;
 
@@ -629,7 +645,7 @@ void GC_delete_gc_thread(pthread_t id, G
 /* return the most recent one.					*/
 GC_thread GC_lookup_thread(pthread_t id)
 {
-    int hv = ((word)id) % THREAD_TABLE_SZ;
+    int hv = hashNo((word)id);
     register GC_thread p = GC_threads[hv];
     
     while (p != 0 && !pthread_equal(p -> id, id)) p = p -> next;
@@ -889,6 +905,9 @@ void GC_thr_init()
 	  sysctl((int[2]) {CTL_HW, HW_NCPU}, 2, &ncpus, &len, NULL, 0);
 	  GC_nprocs = ncpus;
 #       endif
+#		if defined(GC_OPENBSD_PTHREADS)
+	  GC_nprocs = 1; /* FreeBSD code may work as well */
+#		endif
 #	if defined(GC_LINUX_THREADS) || defined(GC_DGUX386_THREADS)
           GC_nprocs = GC_get_nprocs();
 #	endif
@@ -1266,9 +1285,10 @@ WRAP_FUNC(pthread_create)(pthread_t *new
     /* with it.  Thus it doesn't matter whether it is otherwise		*/
     /* visible to the collector.					*/
     if (0 == result) {
-	while (0 != sem_wait(&(si -> registered))) {
-            if (EINTR != errno) ABORT("sem_wait failed");
-	}
+		while (0 != sem_wait(&(si -> registered))) {
+			if (EINTR != errno)
+				ABORT("sem_wait failed");
+		}
     }
     sem_destroy(&(si -> registered));
     LOCK();
