darwin_stop_world.c [plain text]
#include "private/pthread_support.h"
# if defined(GC_DARWIN_THREADS)
#define DEBUG_THREADS 0
#define PPC_RED_ZONE_SIZE 224
void GC_push_all_stacks() {
int i;
kern_return_t r;
GC_thread p;
pthread_t me;
ptr_t lo, hi;
# if defined(POWERPC)
ppc_thread_state_t state;
# else
# error FIXME for non-ppc OS X
# endif
mach_msg_type_number_t thread_state_count = MACHINE_THREAD_STATE_COUNT;
me = pthread_self();
if (!GC_thr_initialized) GC_thr_init();
for(i=0;i<THREAD_TABLE_SZ;i++) {
for(p=GC_threads[i];p!=0;p=p->next) {
if(p -> flags & FINISHED) continue;
if(pthread_equal(p->id,me)) {
lo = GC_approx_sp();
} else {
r = thread_get_state(
p->stop_info.mach_thread,
MACHINE_THREAD_STATE,
(natural_t*)&state,
&thread_state_count);
if(r != KERN_SUCCESS) ABORT("thread_get_state failed");
#ifdef POWERPC
lo = (void*)(state.r1 - PPC_RED_ZONE_SIZE);
GC_push_one(state.r0);
GC_push_one(state.r2);
GC_push_one(state.r3);
GC_push_one(state.r4);
GC_push_one(state.r5);
GC_push_one(state.r6);
GC_push_one(state.r7);
GC_push_one(state.r8);
GC_push_one(state.r9);
GC_push_one(state.r10);
GC_push_one(state.r11);
GC_push_one(state.r12);
GC_push_one(state.r13);
GC_push_one(state.r14);
GC_push_one(state.r15);
GC_push_one(state.r16);
GC_push_one(state.r17);
GC_push_one(state.r18);
GC_push_one(state.r19);
GC_push_one(state.r20);
GC_push_one(state.r21);
GC_push_one(state.r22);
GC_push_one(state.r23);
GC_push_one(state.r24);
GC_push_one(state.r25);
GC_push_one(state.r26);
GC_push_one(state.r27);
GC_push_one(state.r28);
GC_push_one(state.r29);
GC_push_one(state.r30);
GC_push_one(state.r31);
#else
# error FIXME for non-PPC darwin
#endif
}
if(p->flags & MAIN_THREAD)
hi = GC_stackbottom;
else
hi = p->stack_end;
#if DEBUG_THREADS
GC_printf3("Darwin: Stack for thread 0x%lx = [%lx,%lx)\n",
(unsigned long) p -> id,
(unsigned long) lo,
(unsigned long) hi
);
#endif
GC_push_all_stack(lo,hi);
}
}
}
void GC_stop_world()
{
int i;
GC_thread p;
pthread_t my_thread = pthread_self();
kern_return_t kern_result;
#if DEBUG_THREADS
GC_printf1("Stopping the world from 0x%lx\n", pthread_self());
#endif
# ifdef PARALLEL_MARK
GC_acquire_mark_lock();
GC_ASSERT(GC_fl_builder_count == 0);
# endif
for (i = 0; i < THREAD_TABLE_SZ; i++) {
for (p = GC_threads[i]; p != 0; p = p -> next) {
if (p -> id == my_thread) continue;
if (p -> flags & FINISHED) continue;
if (p -> thread_blocked) continue;
#if DEBUG_THREADS
GC_printf1("Suspending thread 0x%lx\n", p -> id);
#endif
kern_result = thread_suspend(p->stop_info.mach_thread);
if(kern_result != KERN_SUCCESS) ABORT("thread_suspend failed");
}
}
# ifdef MPROTECT_VDB
if(GC_incremental) {
extern void GC_mprotect_stop();
GC_mprotect_stop();
}
# endif
# ifdef PARALLEL_MARK
GC_release_mark_lock();
# endif
#if DEBUG_THREADS
GC_printf1("World stopped from 0x%lx\n", pthread_self());
#endif
}
void GC_start_world()
{
pthread_t my_thread = pthread_self();
int i;
GC_thread p;
kern_return_t kern_result;
# if DEBUG_THREADS
GC_printf0("World starting\n");
# endif
# ifdef MPROTECT_VDB
if(GC_incremental) {
extern void GC_mprotect_resume();
GC_mprotect_resume();
}
# endif
for (i = 0; i < THREAD_TABLE_SZ; i++) {
for (p = GC_threads[i]; p != 0; p = p -> next) {
if (p -> id == my_thread) continue;
if (p -> flags & FINISHED) continue;
if (p -> thread_blocked) continue;
#if DEBUG_THREADS
GC_printf1("Resuming 0x%lx\n", p -> id);
#endif
kern_result = thread_resume(p->stop_info.mach_thread);
if(kern_result != KERN_SUCCESS) ABORT("thread_resume failed");
}
}
#if DEBUG_THREADS
GC_printf0("World started\n");
#endif
}
void GC_stop_init() {
}
#endif