openbsd-ports/devel/boehm-gc/patches/patch-openbsd_stop_world_c
kurt 67e36b90b6 - use __data_start symbol to find the beginning of the data sections
and adjust boehm-gc to deal with any number of holes that may appear
between __data_start and _end. (requires -current binutils)
- work-around libpthread bugs that prevent sigsuspend() from working
in a signal handler by using pthread_suspend_np() + an arch/libpthread
specific offset to obtain the suspended thread's stack pointer.

thanks to sthen@ and jasper@ for access to other arches. discussed
with todd@
2008-04-01 17:41:13 +00:00

167 lines
4.7 KiB
Plaintext

$OpenBSD: patch-openbsd_stop_world_c,v 1.1 2008/04/01 17:41:13 kurt Exp $
--- openbsd_stop_world.c.orig Thu Feb 7 11:15:22 2008
+++ openbsd_stop_world.c Thu Feb 7 11:38:22 2008
@@ -0,0 +1,162 @@
+#include "private/pthread_support.h"
+
+/* derived from pthread_stop_world.c */
+
+# if defined(GC_OPENBSD_THREADS)
+
+/* We hold allocation lock. Should do exactly the right thing if the */
+/* world is stopped. Should not fail if it isn't. */
+void GC_push_all_stacks()
+{
+ GC_bool found_me = FALSE;
+ size_t nthreads = 0;
+ int i;
+ GC_thread p;
+ ptr_t lo, hi;
+ pthread_t me = pthread_self();
+
+ if (!GC_thr_initialized) GC_thr_init();
+# if DEBUG_THREADS
+ GC_printf("Pushing stacks from thread 0x%x\n", (unsigned) 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;
+ ++nthreads;
+ if (THREAD_EQUAL(p -> id, me)) {
+# ifdef SPARC
+ lo = (ptr_t)GC_save_regs_in_stack();
+# else
+ lo = GC_approx_sp();
+# endif
+ found_me = TRUE;
+ } else {
+ lo = p -> stop_info.stack_ptr;
+ }
+ if ((p -> flags & MAIN_THREAD) == 0) {
+ hi = p -> stack_end;
+ } else {
+ /* The original stack. */
+ hi = GC_stackbottom;
+ }
+# if DEBUG_THREADS
+ GC_printf("Stack for thread 0x%x = [%p,%p)\n",
+ (unsigned)(p -> id), lo, 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
+ }
+ }
+ if (GC_print_stats == VERBOSE) {
+ GC_log_printf("Pushed %d thread stacks\n", nthreads);
+ }
+ if (!found_me && !GC_in_thread_creation)
+ ABORT("Collecting from unknown thread.");
+}
+
+/* We hold the allocation lock. Suspend all threads that might */
+/* still be running. */
+void GC_suspend_all()
+{
+ int i;
+ GC_thread p;
+ int result;
+ pthread_t my_thread = pthread_self();
+
+ for (i = 0; i < THREAD_TABLE_SZ; i++) {
+ for (p = GC_threads[i]; p != 0; p = p -> next) {
+ if (!THREAD_EQUAL(p -> id, my_thread)) {
+ if (p -> flags & FINISHED) continue;
+ if (p -> thread_blocked) /* Will wait */ continue;
+# if DEBUG_THREADS
+ GC_printf("Suspending thread 0x%x\n",
+ (unsigned)(p -> id));
+# endif
+
+ if (pthread_suspend_np(p -> id) != 0)
+ ABORT("pthread_suspend_np failed");
+
+ /*
+ * This will only work for userland pthreads. It will
+ * fail badly on rthreads. Perhaps we should consider
+ * a pthread_sp_np() function that returns the stack
+ * pointer for a suspended thread and implement in
+ * both pthreads and rthreads.
+ */
+ p -> stop_info.stack_ptr = *(ptr_t*)((char *)p -> id + UTHREAD_SP_OFFSET);
+ }
+ }
+ }
+}
+
+void GC_stop_world()
+{
+ int i;
+
+ GC_ASSERT(I_HOLD_LOCK());
+# if DEBUG_THREADS
+ GC_printf("Stopping the world from 0x%x\n", (unsigned)pthread_self());
+# endif
+
+ /* 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_suspend_all();
+
+# ifdef PARALLEL_MARK
+ GC_release_mark_lock();
+# endif
+ #if DEBUG_THREADS
+ GC_printf("World stopped from 0x%x\n", (unsigned)pthread_self());
+ #endif
+}
+
+/* Caller holds allocation lock, and has held it continuously since */
+/* the world stopped. */
+void GC_start_world()
+{
+ pthread_t my_thread = pthread_self();
+ register int i;
+ register GC_thread p;
+ register int result;
+
+# if DEBUG_THREADS
+ GC_printf("World starting\n");
+# endif
+
+ for (i = 0; i < THREAD_TABLE_SZ; i++) {
+ for (p = GC_threads[i]; p != 0; p = p -> next) {
+ if (!THREAD_EQUAL(p -> id, my_thread)) {
+ if (p -> flags & FINISHED) continue;
+ if (p -> thread_blocked) continue;
+ #if DEBUG_THREADS
+ GC_printf("Resuming thread 0x%x\n",
+ (unsigned)(p -> id));
+ #endif
+
+ if (pthread_resume_np(p -> id) != 0)
+ ABORT("pthread_kill failed");
+ }
+ }
+ }
+# if DEBUG_THREADS
+ GC_printf("World started\n");
+# endif
+}
+
+void GC_stop_init() {
+}
+
+#endif