blob: 779dc8283c4df3194c4ac529a61887b336572415 [file] [log] [blame]
#include "vmkit/thread.h"
#include "vmkit/system.h"
#include "vmkit/vmkit.h"
#include "vmkit/config.h"
using namespace vmkit;
Thread::Thread(VMKit* vm) {
_vm = vm;
}
void Thread::sigsegvHandler(int n, siginfo_t* info, void* context) {
get()->vm()->sigsegv((uintptr_t)info->si_addr);
}
void* Thread::operator new(size_t n) {
void* res = ThreadAllocator::allocate();
memset(res, 0, n);
return res;
}
void Thread::operator delete(void* p) {
ThreadAllocator::release(p);
}
Thread* Thread::get() {
return get(__builtin_frame_address(0));
}
Thread* Thread::get(void* ptr) {
return (Thread*)((uintptr_t)ptr & getThreadMask());
}
uintptr_t Thread::getThreadMask() {
return -VMKIT_STACK_SIZE;
}
void Thread::registerSignalInternal(int n, sa_action_t handler, bool altStack) {
// Set the SIGSEGV handler to diagnose errors.
struct sigaction sa;
sigset_t mask;
sigemptyset(&mask);
sa.sa_flags = SA_SIGINFO | SA_ONSTACK | SA_NODEFER;
if(altStack)
sa.sa_flags = SA_ONSTACK;
sa.sa_mask = mask;
sa.sa_sigaction = handler;
sigaction(n, &sa, NULL);
}
bool Thread::registerSignal(int n, sa_action_t handler) {
if(n == SIGSEGV || n == SIGBUS)
return 0;
registerSignalInternal(n, handler, 0);
return 1;
}
void* Thread::doRun(void* _thread) {
Thread* thread = (Thread*)_thread;
// Set the alternate stack as the second page of the thread's
// stack.
stack_t st;
st.ss_sp = ThreadAllocator::alternateStackAddr(thread);
st.ss_flags = 0;
st.ss_size = ThreadAllocator::alternateStackSize(thread);
sigaltstack(&st, NULL);
thread->registerSignalInternal(SIGSEGV, sigsegvHandler, 1);
thread->registerSignalInternal(SIGBUS, sigsegvHandler, 1);
try {
thread->run();
} catch(void* e) {
thread->vm()->uncatchedException(e);
}
return 0;
}
void Thread::start() {
pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_attr_setstack(&attr, ThreadAllocator::stackAddr(this), ThreadAllocator::stackSize(this));
pthread_create(&_tid, &attr, doRun, this);
pthread_attr_destroy(&attr);
}
void Thread::join() {
void* res;
pthread_join(_tid, &res);
}
StackWalker::StackWalker(uint32_t initialPop) {
unw_getcontext(&uc);
unw_init_local(&cursor, &uc);
next(initialPop+1);
}
bool StackWalker::next(uint32_t nbPop) {
while(nbPop--) {
if(unw_step(&cursor) <= 0)
return 0;
}
return 1;
}
void* StackWalker::ip() {
unw_word_t ip;
unw_get_reg(&cursor, UNW_REG_IP, &ip);
return (void*)ip;
}
void* StackWalker::sp() {
unw_word_t sp;
unw_get_reg(&cursor, UNW_REG_SP, &sp);
return (void*)sp;
}