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.
This commit is contained in:
Joel Dice 2011-02-19 14:20:02 -07:00
parent 2ce549d3f8
commit 00307b9b30
3 changed files with 118 additions and 38 deletions

View File

@ -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<Thread*>(st);
Thread* target = static_cast<Thread*>(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<thread_state_t>(&state),
&stateCount);
if (rv == 0) {
visitor->visit(reinterpret_cast<void*>(THREAD_STATE_IP(state)),
reinterpret_cast<void*>(THREAD_STATE_STACK(state)),
reinterpret_cast<void*>(THREAD_STATE_LINK(state)));
}
thread_resume(port);
return rv ? -1 : 0;
#else // not __APPLE__
Thread* t = static_cast<Thread*>(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,

View File

@ -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

View File

@ -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])