+
+#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)
+
+#elif __arm__
+
+#define NACL_STORE_REGS() \
+ do { \
+ __asm__ __volatile__ ( \
+ ".align 4\n\t" \
+ "bic %0, %0, #0xc0000000\n\t" \
+ "str sp, [%0]\n\t" \
+ "bic %1, %1, #0xc0000000\n\t" \
+ "stm %1, {r4-r8,r10-r12,lr}\n\t" \
+ : \
+ : "r" (&nacl_gc_thread_self->stop_info.stack_ptr), \
+ "r"(nacl_gc_thread_self->stop_info.reg_storage) \
+ : "memory"); \
+ } while (0)
+#else
+
+#error "Please port NACL_STORE_REGS"
+
+#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 */
+