From 00307b9b3037a6bf3ce7d21fba8ea0ff7fef0feb Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Sat, 19 Feb 2011 14:20:02 -0700 Subject: [PATCH] fix Mac OS MySystem::visit and MySystem::Thread::interrupt implementations On Mac OS, signals sent using pthread_kill are never delivered if the target thread is blocked (e.g. acquiring a lock or waiting on a condition), so we can't rely on it and must use the Mach-specific thread execution API instead to implement Thread.getStackTrace. For Thread.interrupt, we must not only use pthread_kill but also pthread_cond_signal to ensure the thread is woken up. --- src/posix.cpp | 39 ++++++++++++++++++++++-- src/powerpc.h | 35 ++++++++++++++++------ src/x86.h | 82 ++++++++++++++++++++++++++++++++++----------------- 3 files changed, 118 insertions(+), 38 deletions(-) diff --git a/src/posix.cpp b/src/posix.cpp index 53dfb0bb90..4187a8e4b6 100644 --- a/src/posix.cpp +++ b/src/posix.cpp @@ -14,6 +14,7 @@ # include "CoreFoundation/CoreFoundation.h" # undef assert # define _XOPEN_SOURCE +# define _DARWIN_C_SOURCE #endif #include "sys/mman.h" @@ -144,6 +145,12 @@ class MySystem: public System { r->setInterrupted(true); pthread_kill(thread, InterruptSignal); + + // pthread_kill won't necessarily wake a thread blocked in + // pthread_cond_{timed}wait (it does on Linux but not Mac OS), + // so we signal the condition as well: + int rv UNUSED = pthread_cond_signal(&condition); + expect(s, rv == 0); } virtual void join() { @@ -641,14 +648,41 @@ class MySystem: public System { return registerHandler(handler, DivideByZeroSignalIndex); } - virtual Status visit(System::Thread* st, System::Thread* sTarget, + virtual Status visit(System::Thread* st UNUSED, System::Thread* sTarget, ThreadVisitor* visitor) { assert(this, st != sTarget); - Thread* t = static_cast(st); Thread* target = static_cast(sTarget); +#ifdef __APPLE__ + // On Mac OS, signals sent using pthread_kill are never delivered + // if the target thread is blocked (e.g. acquiring a lock or + // waiting on a condition), so we can't rely on it and must use + // the Mach-specific thread execution API instead. + + mach_port_t port = pthread_mach_thread_np(target->thread); + + if (thread_suspend(port)) return -1; + + THREAD_STATE_TYPE state; + mach_msg_type_number_t stateCount = THREAD_STATE_COUNT; + kern_return_t rv = thread_get_state + (port, THREAD_STATE, reinterpret_cast(&state), + &stateCount); + + if (rv == 0) { + visitor->visit(reinterpret_cast(THREAD_STATE_IP(state)), + reinterpret_cast(THREAD_STATE_STACK(state)), + reinterpret_cast(THREAD_STATE_LINK(state))); + } + + thread_resume(port); + + return rv ? -1 : 0; +#else // not __APPLE__ + Thread* t = static_cast(st); + ACQUIRE_MONITOR(t, visitLock); while (threadVisitor) visitLock->wait(t, 0); @@ -674,6 +708,7 @@ class MySystem: public System { system->visitLock->notifyAll(t); return result; +#endif // not __APPLE__ } virtual uint64_t call(void* function, uintptr_t* arguments, uint8_t* types, diff --git a/src/powerpc.h b/src/powerpc.h index b109c9dc5a..b519ac8064 100644 --- a/src/powerpc.h +++ b/src/powerpc.h @@ -14,20 +14,37 @@ #include "types.h" #include "common.h" -#define VA_LIST(x) (&x) +#define VA_LIST(x) (&(x)) #ifdef __APPLE__ +# include "mach/mach_types.h" +# include "mach/ppc/thread_act.h" +# include "mach/ppc/thread_status.h" + +# define THREAD_STATE PPC_THREAD_STATE +# define THREAD_STATE_TYPE ppc_thread_state_t +# define THREAD_STATE_COUNT PPC_THREAD_STATE_COUNT + # if __DARWIN_UNIX03 && defined(_STRUCT_PPC_EXCEPTION_STATE) -# define IP_REGISTER(context) (context->uc_mcontext->__ss.__srr0) -# define STACK_REGISTER(context) (context->uc_mcontext->__ss.__r1) -# define THREAD_REGISTER(context) (context->uc_mcontext->__ss.__r13) -# define LINK_REGISTER(context) (context->uc_mcontext->__ss.__lr) +# define FIELD(x) __##x # else -# define IP_REGISTER(context) (context->uc_mcontext->ss.srr0) -# define STACK_REGISTER(context) (context->uc_mcontext->ss.r1) -# define THREAD_REGISTER(context) (context->uc_mcontext->ss.r13) -# define LINK_REGISTER(context) (context->uc_mcontext->ss.lr) +# define FIELD(x) x # endif + +# define THREAD_STATE_IP(state) ((state).FIELD(srr0)) +# define THREAD_STATE_STACK(state) ((state).FIELD(r1)) +# define THREAD_STATE_THREAD(state) ((state).FIELD(r13)) +# define THREAD_STATE_LINK(state) ((state).FIELD(lr)) + +# define IP_REGISTER(context) \ + THREAD_STATE_IP(context->uc_mcontext->FIELD(ss)) +# define STACK_REGISTER(context) \ + THREAD_STATE_STACK(context->uc_mcontext->FIELD(ss)) +# define THREAD_REGISTER(context) \ + THREAD_STATE_THREAD(context->uc_mcontext->FIELD(ss)) +# define LINK_REGISTER(context) \ + THREAD_STATE_LINK(context->uc_mcontext->FIELD(ss)) + #else # error "non-Apple PowerPC-based platforms not yet supported" #endif diff --git a/src/x86.h b/src/x86.h index f393ad8727..9a0b60cccd 100644 --- a/src/x86.h +++ b/src/x86.h @@ -23,27 +23,47 @@ #endif #if (defined ARCH_x86_32) || (defined PLATFORM_WINDOWS) -# define VA_LIST(x) (&x) +# define VA_LIST(x) (&(x)) #else # define VA_LIST(x) (x) #endif +#ifdef __APPLE__ +# include "mach/mach_types.h" +# include "mach/i386/thread_act.h" +# include "mach/i386/thread_status.h" + +# if __DARWIN_UNIX03 && defined(_STRUCT_X86_EXCEPTION_STATE32) +# define FIELD(x) __##x +# else +# define FIELD(x) x +# endif +#endif + #ifdef ARCH_x86_32 # ifdef __APPLE__ -# if __DARWIN_UNIX03 && defined(_STRUCT_X86_EXCEPTION_STATE32) -# define IP_REGISTER(context) (context->uc_mcontext->__ss.__eip) -# define STACK_REGISTER(context) (context->uc_mcontext->__ss.__esp) -# define THREAD_REGISTER(context) (context->uc_mcontext->__ss.__ebx) -# define LINK_REGISTER(context) (context->uc_mcontext->__ss.__ecx) -# define FRAME_REGISTER(context) (context->uc_mcontext->__ss.__ebp) -# else -# define IP_REGISTER(context) (context->uc_mcontext->ss.eip) -# define STACK_REGISTER(context) (context->uc_mcontext->ss.esp) -# define THREAD_REGISTER(context) (context->uc_mcontext->ss.ebx) -# define LINK_REGISTER(context) (context->uc_mcontext->ss.ecx) -# define FRAME_REGISTER(context) (context->uc_mcontext->ss.ebp) -# endif +# define THREAD_STATE x86_THREAD_STATE32 +# define THREAD_STATE_TYPE x86_thread_state32_t +# define THREAD_STATE_COUNT x86_THREAD_STATE32_COUNT + +# define THREAD_STATE_IP(state) ((state).FIELD(eip)) +# define THREAD_STATE_STACK(state) ((state).FIELD(esp)) +# define THREAD_STATE_THREAD(state) ((state).FIELD(ebx)) +# define THREAD_STATE_LINK(state) ((state).FIELD(ecx)) +# define THREAD_STATE_FRAME(state) ((state).FIELD(ebp)) + +# define IP_REGISTER(context) \ + THREAD_STATE_IP(context->uc_mcontext->FIELD(ss)) +# define STACK_REGISTER(context) \ + THREAD_STATE_STACK(context->uc_mcontext->FIELD(ss)) +# define THREAD_REGISTER(context) \ + THREAD_STATE_THREAD(context->uc_mcontext->FIELD(ss)) +# define LINK_REGISTER(context) \ + THREAD_STATE_LINK(context->uc_mcontext->FIELD(ss)) +# define FRAME_REGISTER(context) \ + THREAD_STATE_FRAME(context->uc_mcontext->FIELD(ss)) + # else # define IP_REGISTER(context) (context->uc_mcontext.gregs[REG_EIP]) # define STACK_REGISTER(context) (context->uc_mcontext.gregs[REG_ESP]) @@ -70,19 +90,27 @@ dynamicCall(void* function, uintptr_t* arguments, uint8_t*, #elif defined ARCH_x86_64 # ifdef __APPLE__ -# if __DARWIN_UNIX03 && defined(_STRUCT_X86_EXCEPTION_STATE32) -# define IP_REGISTER(context) (context->uc_mcontext->__ss.__rip) -# define STACK_REGISTER(context) (context->uc_mcontext->__ss.__rsp) -# define THREAD_REGISTER(context) (context->uc_mcontext->__ss.__rbx) -# define LINK_REGISTER(context) (context->uc_mcontext->__ss.__rcx) -# define FRAME_REGISTER(context) (context->uc_mcontext->__ss.__rbp) -# else -# define IP_REGISTER(context) (context->uc_mcontext->ss.rip) -# define STACK_REGISTER(context) (context->uc_mcontext->ss.rsp) -# define THREAD_REGISTER(context) (context->uc_mcontext->ss.rbx) -# define LINK_REGISTER(context) (context->uc_mcontext->ss.rcx) -# define FRAME_REGISTER(context) (context->uc_mcontext->ss.rbp) -# endif +# define THREAD_STATE x86_THREAD_STATE64 +# define THREAD_STATE_TYPE x86_thread_state64_t +# define THREAD_STATE_COUNT x86_THREAD_STATE64_COUNT + +# define THREAD_STATE_IP(state) ((state).FIELD(rip)) +# define THREAD_STATE_STACK(state) ((state).FIELD(rsp)) +# define THREAD_STATE_THREAD(state) ((state).FIELD(rbx)) +# define THREAD_STATE_LINK(state) ((state).FIELD(rcx)) +# define THREAD_STATE_FRAME(state) ((state).FIELD(rbp)) + +# define IP_REGISTER(context) \ + THREAD_STATE_IP(context->uc_mcontext->FIELD(ss)) +# define STACK_REGISTER(context) \ + THREAD_STATE_STACK(context->uc_mcontext->FIELD(ss)) +# define THREAD_REGISTER(context) \ + THREAD_STATE_THREAD(context->uc_mcontext->FIELD(ss)) +# define LINK_REGISTER(context) \ + THREAD_STATE_LINK(context->uc_mcontext->FIELD(ss)) +# define FRAME_REGISTER(context) \ + THREAD_STATE_FRAME(context->uc_mcontext->FIELD(ss)) + # else # define IP_REGISTER(context) (context->uc_mcontext.gregs[REG_RIP]) # define STACK_REGISTER(context) (context->uc_mcontext.gregs[REG_RSP])