linux-packaging-mono/libgc/openbsd_stop_world.c
Jo Shields a575963da9 Imported Upstream version 3.6.0
Former-commit-id: da6be194a6b1221998fc28233f2503bd61dd9d14
2014-08-13 10:39:27 +01:00

162 lines
4.3 KiB
C

#include "private/pthread_support.h"
/* derived from pthread_stop_world.c */
# if defined(GC_OPENBSD_THREADS)
#define THREAD_EQUAL(id1, id2) pthread_equal(id1, id2)
/* 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 (!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