a575963da9
Former-commit-id: da6be194a6b1221998fc28233f2503bd61dd9d14
162 lines
4.3 KiB
C
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
|