X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=libgc%2Fpthread_stop_world.c;h=8b25376b54ab6d691176ba61f0d7345c6b5c1ab6;hb=1e726ce7a38a92860acab28f4427813d2ba14c13;hp=5a1b9f37172db62df18dabaa9468a422e07c2058;hpb=58fdac7b8a191881c721c1e04592fc4a8b4b6ab1;p=mono.git diff --git a/libgc/pthread_stop_world.c b/libgc/pthread_stop_world.c index 5a1b9f37172..8b25376b54a 100644 --- a/libgc/pthread_stop_world.c +++ b/libgc/pthread_stop_world.c @@ -2,12 +2,14 @@ #if defined(GC_PTHREADS) && !defined(GC_SOLARIS_THREADS) \ && !defined(GC_IRIX_THREADS) && !defined(GC_WIN32_THREADS) \ - && !defined(GC_DARWIN_THREADS) && !defined(GC_AIX_THREADS) + && !defined(GC_DARWIN_THREADS) && !defined(GC_AIX_THREADS) \ + && !defined(GC_OPENBSD_THREADS) #include #include #include #include +#include /* work around a dlopen issue (bug #75390), undefs to avoid warnings with redefinitions */ #undef PACKAGE_BUGREPORT @@ -21,6 +23,19 @@ #include "include/libgc-mono-debugger.h" #endif +#ifdef NACL +volatile int __nacl_thread_suspension_needed = 0; +pthread_t nacl_thread_parker = -1; + +volatile int nacl_thread_parked[MAX_NACL_GC_THREADS]; +volatile int nacl_thread_used[MAX_NACL_GC_THREADS]; +volatile int nacl_thread_parking_inited = 0; +volatile int nacl_num_gc_threads = 0; +pthread_mutex_t nacl_thread_alloc_lock = PTHREAD_MUTEX_INITIALIZER; +__thread int nacl_thread_idx = -1; +__thread GC_thread nacl_gc_thread_self = NULL; +#endif + #if DEBUG_THREADS #ifndef NSIG @@ -35,6 +50,7 @@ # endif #endif +#ifndef NACL void GC_print_sig_mask() { sigset_t blocked; @@ -48,7 +64,7 @@ void GC_print_sig_mask() } GC_printf0("\n"); } - +#endif /* NACL */ #endif /* Remove the signals that we want to allow in thread stopping */ @@ -115,6 +131,7 @@ sem_t GC_suspend_ack_sem; static void _GC_suspend_handler(int sig) { +#ifndef NACL int dummy; pthread_t my_thread = pthread_self(); GC_thread me; @@ -184,6 +201,8 @@ static void _GC_suspend_handler(int sig) #if DEBUG_THREADS GC_printf1("Continuing 0x%lx\n", my_thread); #endif + +#endif /* NACL */ } void GC_suspend_handler(int sig) @@ -271,12 +290,20 @@ static void pthread_push_all_stacks() (unsigned long) lo, (unsigned long) hi); #endif if (0 == lo) ABORT("GC_push_all_stacks: sp not set!\n"); + if (p->altstack && lo >= p->altstack && lo <= p->altstack + p->altstack_size) + hi = p->altstack + p->altstack_size; + /* FIXME: Need to scan the normal stack too, but how ? */ + # ifdef STACK_GROWS_UP /* We got them backwards! */ GC_push_all_stack(hi, lo); # else GC_push_all_stack(lo, hi); # endif +# ifdef NACL + /* Push reg_storage as roots, this will cover the reg context */ + GC_push_all_stack(p -> stop_info.reg_storage, p -> stop_info.reg_storage + NACL_GC_REG_STORAGE_SIZE); +# endif # ifdef IA64 # if DEBUG_THREADS GC_printf3("Reg stack for thread 0x%lx = [%lx,%lx)\n", @@ -336,6 +363,7 @@ int android_thread_kill(pid_t tid, int sig) /* were sent. */ int GC_suspend_all() { +#ifndef NACL int n_live_threads = 0; int i; GC_thread p; @@ -374,11 +402,15 @@ int GC_suspend_all() } } return n_live_threads; +#else /* NACL */ + return 0; +#endif } /* Caller holds allocation lock. */ static void pthread_stop_world() { +#ifndef NACL int i; int n_live_threads; int code; @@ -430,8 +462,135 @@ static void pthread_stop_world() GC_printf1("World stopped from 0x%lx\n", pthread_self()); #endif GC_stopping_thread = 0; /* debugging only */ +#else /* NACL */ + GC_thread p; + int i; + int num_sleeps = 0; + + #if DEBUG_THREADS + GC_printf1("pthread_stop_world: num_threads %d\n", nacl_num_gc_threads - 1); + #endif + nacl_thread_parker = pthread_self(); + __nacl_thread_suspension_needed = 1; + + while (1) { + #define NACL_PARK_WAIT_NANOSECONDS 100000 + #define NANOS_PER_SECOND 1000000000 + int num_threads_parked = 0; + struct timespec ts; + int num_used = 0; + /* Check the 'parked' flag for each thread the GC knows about */ + for (i = 0; i < MAX_NACL_GC_THREADS && num_used < nacl_num_gc_threads; i++) { + if (nacl_thread_used[i] == 1) { + num_used++; + if (nacl_thread_parked[i] == 1) { + num_threads_parked++; + } + } + } + /* -1 for the current thread */ + if (num_threads_parked >= nacl_num_gc_threads - 1) + break; + ts.tv_sec = 0; + ts.tv_nsec = NACL_PARK_WAIT_NANOSECONDS; + #if DEBUG_THREADS + GC_printf1("sleeping waiting for %d threads to park...\n", nacl_num_gc_threads - num_threads_parked - 1); + #endif + nanosleep(&ts, 0); + if (++num_sleeps > NANOS_PER_SECOND / NACL_PARK_WAIT_NANOSECONDS) { + GC_printf1("GC appears stalled waiting for %d threads to park...\n", nacl_num_gc_threads - num_threads_parked - 1); + num_sleeps = 0; + } + } + +#endif /* NACL */ +} + + +#ifdef NACL + +#if __x86_64__ + +#define NACL_STORE_REGS() \ + do { \ + __asm__ __volatile__ ("push %rbx");\ + __asm__ __volatile__ ("push %rbp");\ + __asm__ __volatile__ ("push %r12");\ + __asm__ __volatile__ ("push %r13");\ + __asm__ __volatile__ ("push %r14");\ + __asm__ __volatile__ ("push %r15");\ + __asm__ __volatile__ ("mov %%esp, %0" : "=m" (nacl_gc_thread_self->stop_info.stack_ptr));\ + memcpy(nacl_gc_thread_self->stop_info.reg_storage, nacl_gc_thread_self->stop_info.stack_ptr, NACL_GC_REG_STORAGE_SIZE * sizeof(ptr_t));\ + __asm__ __volatile__ ("naclasp $48, %r15");\ + } while (0) + +#elif __i386__ + +#define NACL_STORE_REGS() \ + do { \ + __asm__ __volatile__ ("push %ebx");\ + __asm__ __volatile__ ("push %ebp");\ + __asm__ __volatile__ ("push %esi");\ + __asm__ __volatile__ ("push %edi");\ + __asm__ __volatile__ ("mov %%esp, %0" : "=m" (nacl_gc_thread_self->stop_info.stack_ptr));\ + memcpy(nacl_gc_thread_self->stop_info.reg_storage, nacl_gc_thread_self->stop_info.stack_ptr, NACL_GC_REG_STORAGE_SIZE * sizeof(ptr_t));\ + __asm__ __volatile__ ("add $16, %esp");\ + } while (0) + +#endif + +void nacl_pre_syscall_hook() +{ + int local_dummy = 0; + if (nacl_thread_idx != -1) { + NACL_STORE_REGS(); + nacl_gc_thread_self->stop_info.stack_ptr = (ptr_t)(&local_dummy); + nacl_thread_parked[nacl_thread_idx] = 1; + } +} + +void __nacl_suspend_thread_if_needed(); + +void nacl_post_syscall_hook() +{ + /* Calling __nacl_suspend_thread_if_needed() right away should guarantee we don't mutate the GC set. */ + __nacl_suspend_thread_if_needed(); + if (nacl_thread_idx != -1) { + nacl_thread_parked[nacl_thread_idx] = 0; + } +} + +void __nacl_suspend_thread_if_needed() { + if (__nacl_thread_suspension_needed) { + pthread_t self = pthread_self(); + int local_dummy = 0; + /* Don't try to park the thread parker. */ + if (nacl_thread_parker == self) + return; + + /* This can happen when a thread is created */ + /* outside of the GC system (wthread mostly). */ + if (nacl_thread_idx < 0) + return; + + /* If it was already 'parked', we're returning from a syscall, */ + /* so don't bother storing registers again, the GC has a set. */ + if (!nacl_thread_parked[nacl_thread_idx]) { + NACL_STORE_REGS(); + nacl_gc_thread_self->stop_info.stack_ptr = (ptr_t)(&local_dummy); + } + nacl_thread_parked[nacl_thread_idx] = 1; + while (__nacl_thread_suspension_needed) + ; /* spin */ + nacl_thread_parked[nacl_thread_idx] = 0; + + /* Clear out the reg storage for next suspend. */ + memset(nacl_gc_thread_self->stop_info.reg_storage, 0, NACL_GC_REG_STORAGE_SIZE * sizeof(ptr_t)); + } } +#endif /* NACL */ + /* Caller holds allocation lock. */ void GC_stop_world() { @@ -464,6 +623,7 @@ void GC_stop_world() /* the world stopped. */ static void pthread_start_world() { +#ifndef NACL pthread_t my_thread = pthread_self(); register int i; register GC_thread p; @@ -524,6 +684,16 @@ static void pthread_start_world() #if DEBUG_THREADS GC_printf0("World started\n"); #endif +#else /* NACL */ + if (GC_notify_event) + GC_notify_event (GC_EVENT_PRE_START_WORLD); +# if DEBUG_THREADS + GC_printf0("World starting\n"); +# endif + __nacl_thread_suspension_needed = 0; + if (GC_notify_event) + GC_notify_event (GC_EVENT_POST_START_WORLD); +#endif /* NACL */ } void GC_start_world() @@ -537,6 +707,7 @@ void GC_start_world() } static void pthread_stop_init() { +#ifndef NACL struct sigaction act; if (sem_init(&GC_suspend_ack_sem, 0, 0) != 0) @@ -577,6 +748,7 @@ static void pthread_stop_init() { GC_printf0("Will retry suspend signal if necessary.\n"); } # endif +#endif /* NACL */ } /* We hold the allocation lock. */