+
+#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;
+ }
+}
+
+void __nacl_suspend_thread_if_needed() {
+ if (nacl_park_threads_now) {
+ 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_park_threads_now)
+ ; /* 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 */
+