67e36b90b6
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@
167 lines
4.7 KiB
Plaintext
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
|