$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