+#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_park_threads_now = 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("push %rbx");\
+ asm("push %rbp");\
+ asm("push %r12");\
+ asm("push %r13");\
+ asm("push %r14");\
+ asm("push %r15");\
+ asm("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("add $48, %esp");\
+ asm("add %r15, %rsp");\
+ } while (0)
+
+#elif __i386__
+
+#define NACL_STORE_REGS() \
+ do { \
+ asm("push %ebx");\
+ asm("push %ebp");\
+ asm("push %esi");\
+ asm("push %edi");\
+ asm("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("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_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;
+ }