2008-01-28 23:17:22 +00:00
|
|
|
#ifdef __APPLE__
|
|
|
|
#include "CoreFoundation/CoreFoundation.h"
|
2008-01-28 23:35:23 +00:00
|
|
|
#undef assert
|
2008-01-28 23:17:22 +00:00
|
|
|
#endif
|
2007-07-20 14:36:31 +00:00
|
|
|
#include "sys/mman.h"
|
|
|
|
#include "sys/types.h"
|
|
|
|
#include "sys/stat.h"
|
|
|
|
#include "sys/time.h"
|
|
|
|
#include "time.h"
|
|
|
|
#include "fcntl.h"
|
|
|
|
#include "dlfcn.h"
|
|
|
|
#include "errno.h"
|
2007-09-17 00:13:36 +00:00
|
|
|
#include "unistd.h"
|
2007-07-20 14:36:31 +00:00
|
|
|
#include "pthread.h"
|
2007-07-28 21:28:25 +00:00
|
|
|
#include "signal.h"
|
2008-01-01 17:08:47 +00:00
|
|
|
#include "ucontext.h"
|
2007-07-20 14:36:31 +00:00
|
|
|
#include "stdint.h"
|
|
|
|
|
2007-10-23 01:00:57 +00:00
|
|
|
#include "x86.h"
|
2007-07-20 14:39:50 +00:00
|
|
|
#include "system.h"
|
|
|
|
|
2007-07-28 21:28:25 +00:00
|
|
|
#define ACQUIRE(x) MutexResource MAKE_NAME(mutexResource_) (x)
|
|
|
|
|
2007-07-20 14:36:31 +00:00
|
|
|
using namespace vm;
|
|
|
|
|
|
|
|
namespace {
|
|
|
|
|
2007-12-30 22:24:48 +00:00
|
|
|
System::SignalHandler* segFaultHandler = 0;
|
|
|
|
struct sigaction oldSegFaultHandler;
|
|
|
|
|
2007-07-28 21:28:25 +00:00
|
|
|
class MutexResource {
|
|
|
|
public:
|
|
|
|
MutexResource(pthread_mutex_t& m): m(&m) {
|
|
|
|
pthread_mutex_lock(&m);
|
|
|
|
}
|
|
|
|
|
|
|
|
~MutexResource() {
|
|
|
|
pthread_mutex_unlock(m);
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
pthread_mutex_t* m;
|
|
|
|
};
|
|
|
|
|
|
|
|
const int InterruptSignal = SIGUSR2;
|
2008-01-01 18:19:55 +00:00
|
|
|
#ifdef __APPLE__
|
|
|
|
const int SegFaultSignal = SIGBUS;
|
|
|
|
#else
|
|
|
|
const int SegFaultSignal = SIGSEGV;
|
|
|
|
#endif
|
2007-07-28 21:28:25 +00:00
|
|
|
|
2007-12-30 22:24:48 +00:00
|
|
|
#ifdef __x86_64__
|
2008-01-01 18:19:55 +00:00
|
|
|
# define IP_REGISTER(context) (context->uc_mcontext.gregs[REG_RIP])
|
|
|
|
# define BASE_REGISTER(context) (context->uc_mcontext.gregs[REG_RBP])
|
|
|
|
# define STACK_REGISTER(context) (context->uc_mcontext.gregs[REG_RSP])
|
|
|
|
# define THREAD_REGISTER(context) (context->uc_mcontext.gregs[REG_RBX])
|
|
|
|
#elif defined __APPLE__
|
2008-01-07 23:20:48 +00:00
|
|
|
# define IP_REGISTER(context) (context->uc_mcontext->__ss.__eip)
|
|
|
|
# define BASE_REGISTER(context) (context->uc_mcontext->__ss.__ebp)
|
|
|
|
# define STACK_REGISTER(context) (context->uc_mcontext->__ss.__esp)
|
|
|
|
# define THREAD_REGISTER(context) (context->uc_mcontext->__ss.__ebx)
|
2007-12-30 22:24:48 +00:00
|
|
|
#elif defined __i386__
|
2008-01-01 18:19:55 +00:00
|
|
|
# define IP_REGISTER(context) (context->uc_mcontext.gregs[REG_EIP])
|
|
|
|
# define BASE_REGISTER(context) (context->uc_mcontext.gregs[REG_EBP])
|
|
|
|
# define STACK_REGISTER(context) (context->uc_mcontext.gregs[REG_ESP])
|
|
|
|
# define THREAD_REGISTER(context) (context->uc_mcontext.gregs[REG_EBX])
|
2007-12-30 22:24:48 +00:00
|
|
|
#else
|
|
|
|
# error unsupported architecture
|
|
|
|
#endif
|
|
|
|
|
2007-07-28 21:28:25 +00:00
|
|
|
void
|
2007-12-30 22:24:48 +00:00
|
|
|
handleSignal(int signal, siginfo_t* info, void* context)
|
2007-07-28 21:28:25 +00:00
|
|
|
{
|
2008-01-01 18:19:55 +00:00
|
|
|
if (signal == SegFaultSignal) {
|
2008-01-01 17:08:47 +00:00
|
|
|
ucontext_t* c = static_cast<ucontext_t*>(context);
|
2007-12-30 22:24:48 +00:00
|
|
|
|
2008-01-01 22:36:26 +00:00
|
|
|
void* ip = reinterpret_cast<void*>(IP_REGISTER(c));
|
|
|
|
void* base = reinterpret_cast<void*>(BASE_REGISTER(c));
|
|
|
|
void* stack = reinterpret_cast<void*>(STACK_REGISTER(c));
|
|
|
|
void* thread = reinterpret_cast<void*>(THREAD_REGISTER(c));
|
|
|
|
|
2008-01-01 17:08:47 +00:00
|
|
|
bool jump = segFaultHandler->handleSignal
|
2008-01-01 22:36:26 +00:00
|
|
|
(&ip, &base, &stack, &thread);
|
2007-12-30 22:24:48 +00:00
|
|
|
|
2008-01-01 17:08:47 +00:00
|
|
|
if (jump) {
|
|
|
|
// I'd like to use setcontext here (and get rid of the
|
2008-01-01 18:19:55 +00:00
|
|
|
// sigprocmask call), but it doesn't work on my Linux x86_64
|
|
|
|
// system, and I can't tell from the documentation if it's even
|
|
|
|
// supposed to work.
|
|
|
|
|
|
|
|
sigset_t set;
|
|
|
|
|
|
|
|
sigemptyset(&set);
|
|
|
|
sigaddset(&set, SegFaultSignal);
|
|
|
|
sigprocmask(SIG_UNBLOCK, &set, 0);
|
|
|
|
|
2008-01-01 22:36:26 +00:00
|
|
|
vmJump(ip, base, stack, thread);
|
2008-01-01 17:08:47 +00:00
|
|
|
} else if (oldSegFaultHandler.sa_flags & SA_SIGINFO) {
|
2007-12-31 23:21:57 +00:00
|
|
|
oldSegFaultHandler.sa_sigaction(signal, info, context);
|
|
|
|
} else if (oldSegFaultHandler.sa_handler) {
|
|
|
|
oldSegFaultHandler.sa_handler(signal);
|
|
|
|
} else {
|
|
|
|
abort();
|
2007-12-30 22:24:48 +00:00
|
|
|
}
|
|
|
|
}
|
2007-07-28 21:28:25 +00:00
|
|
|
}
|
|
|
|
|
2007-07-20 14:36:31 +00:00
|
|
|
void*
|
2007-07-28 21:28:25 +00:00
|
|
|
run(void* r)
|
2007-07-20 14:36:31 +00:00
|
|
|
{
|
2007-07-28 21:28:25 +00:00
|
|
|
static_cast<System::Runnable*>(r)->run();
|
2007-07-20 14:36:31 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2008-01-13 22:05:08 +00:00
|
|
|
void*
|
|
|
|
allocate(System* s, unsigned size)
|
|
|
|
{
|
|
|
|
void* p = s->tryAllocate(size, false);
|
|
|
|
if (p == 0) abort();
|
|
|
|
return p;
|
|
|
|
}
|
|
|
|
|
2008-01-28 23:17:22 +00:00
|
|
|
void
|
|
|
|
pathOfExecutable(System* s, const char** retBuf, unsigned* size)
|
|
|
|
{
|
|
|
|
#ifdef __APPLE__
|
|
|
|
CFBundleRef bundle = CFBundleGetMainBundle();
|
|
|
|
CFURLRef url = CFBundleCopyExecutableURL(bundle);
|
|
|
|
CFStringRef path = CFURLCopyPath(url);
|
|
|
|
CFIndex pathSize = CFStringGetMaximumSizeOfFileSystemRepresentation(path);
|
|
|
|
char* buffer = reinterpret_cast<char*>(allocate(s, pathSize));
|
|
|
|
if (CFStringGetFileSystemRepresentation(path, buffer, pathSize)) {
|
|
|
|
*size = pathSize;
|
|
|
|
*retBuf = buffer;
|
|
|
|
} else {
|
|
|
|
abort();
|
|
|
|
}
|
|
|
|
#else
|
2008-01-28 23:22:16 +00:00
|
|
|
if (s)
|
|
|
|
*size = 0;
|
2008-01-28 23:17:22 +00:00
|
|
|
*retBuf = NULL;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2007-07-20 14:36:31 +00:00
|
|
|
const bool Verbose = false;
|
|
|
|
|
2007-07-28 21:28:25 +00:00
|
|
|
const unsigned Waiting = 1 << 0;
|
|
|
|
const unsigned Notified = 1 << 1;
|
|
|
|
|
2007-07-20 14:36:31 +00:00
|
|
|
class MySystem: public System {
|
|
|
|
public:
|
|
|
|
class Thread: public System::Thread {
|
|
|
|
public:
|
2007-07-28 21:28:25 +00:00
|
|
|
Thread(System* s, System::Runnable* r):
|
|
|
|
s(s),
|
|
|
|
r(r),
|
|
|
|
next(0),
|
|
|
|
flags(0)
|
|
|
|
{
|
|
|
|
pthread_mutex_init(&mutex, 0);
|
|
|
|
pthread_cond_init(&condition, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual void interrupt() {
|
|
|
|
ACQUIRE(mutex);
|
|
|
|
|
|
|
|
r->setInterrupted(true);
|
2007-07-20 14:36:31 +00:00
|
|
|
|
2007-07-28 21:28:25 +00:00
|
|
|
if (flags & Waiting) {
|
|
|
|
pthread_kill(thread, InterruptSignal);
|
|
|
|
}
|
2007-07-20 14:36:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
virtual void join() {
|
2007-08-19 19:45:51 +00:00
|
|
|
int rv UNUSED = pthread_join(thread, 0);
|
2007-11-27 22:23:00 +00:00
|
|
|
expect(s, rv == 0);
|
2007-07-20 14:36:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
virtual void dispose() {
|
2008-01-13 22:05:08 +00:00
|
|
|
s->free(this, sizeof(*this), false);
|
2007-07-20 14:36:31 +00:00
|
|
|
}
|
|
|
|
|
2007-07-28 21:28:25 +00:00
|
|
|
pthread_t thread;
|
|
|
|
pthread_mutex_t mutex;
|
|
|
|
pthread_cond_t condition;
|
2007-07-20 14:36:31 +00:00
|
|
|
System* s;
|
|
|
|
System::Runnable* r;
|
2007-07-28 21:28:25 +00:00
|
|
|
Thread* next;
|
|
|
|
unsigned flags;
|
2007-07-20 14:36:31 +00:00
|
|
|
};
|
|
|
|
|
2008-01-13 22:05:08 +00:00
|
|
|
class Mutex: public System::Mutex {
|
|
|
|
public:
|
|
|
|
Mutex(System* s): s(s) {
|
|
|
|
pthread_mutex_init(&mutex, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual void acquire() {
|
|
|
|
pthread_mutex_lock(&mutex);
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual void release() {
|
|
|
|
pthread_mutex_unlock(&mutex);
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual void dispose() {
|
|
|
|
pthread_mutex_destroy(&mutex);
|
|
|
|
s->free(this, sizeof(*this), false);
|
|
|
|
}
|
|
|
|
|
|
|
|
System* s;
|
|
|
|
pthread_mutex_t mutex;
|
|
|
|
};
|
|
|
|
|
2007-07-20 14:36:31 +00:00
|
|
|
class Monitor: public System::Monitor {
|
|
|
|
public:
|
2007-07-28 21:28:25 +00:00
|
|
|
Monitor(System* s): s(s), owner_(0), first(0), last(0), depth(0) {
|
|
|
|
pthread_mutex_init(&mutex, 0);
|
2007-07-20 14:36:31 +00:00
|
|
|
}
|
|
|
|
|
2007-07-28 21:28:25 +00:00
|
|
|
virtual bool tryAcquire(System::Thread* context) {
|
|
|
|
Thread* t = static_cast<Thread*>(context);
|
|
|
|
|
|
|
|
if (owner_ == t) {
|
2007-07-20 14:36:31 +00:00
|
|
|
++ depth;
|
|
|
|
return true;
|
|
|
|
} else {
|
|
|
|
switch (pthread_mutex_trylock(&mutex)) {
|
|
|
|
case EBUSY:
|
|
|
|
return false;
|
|
|
|
|
|
|
|
case 0:
|
2007-07-28 21:28:25 +00:00
|
|
|
owner_ = t;
|
2007-07-20 14:36:31 +00:00
|
|
|
++ depth;
|
|
|
|
return true;
|
|
|
|
|
|
|
|
default:
|
|
|
|
sysAbort(s);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-07-28 21:28:25 +00:00
|
|
|
virtual void acquire(System::Thread* context) {
|
|
|
|
Thread* t = static_cast<Thread*>(context);
|
|
|
|
|
|
|
|
if (owner_ != t) {
|
2007-07-20 14:36:31 +00:00
|
|
|
pthread_mutex_lock(&mutex);
|
2007-07-28 21:28:25 +00:00
|
|
|
owner_ = t;
|
2007-07-20 14:36:31 +00:00
|
|
|
}
|
|
|
|
++ depth;
|
|
|
|
}
|
|
|
|
|
2007-07-28 21:28:25 +00:00
|
|
|
virtual void release(System::Thread* context) {
|
|
|
|
Thread* t = static_cast<Thread*>(context);
|
|
|
|
|
|
|
|
if (owner_ == t) {
|
2007-07-20 14:36:31 +00:00
|
|
|
if (-- depth == 0) {
|
2007-07-28 21:28:25 +00:00
|
|
|
owner_ = 0;
|
2007-07-20 14:36:31 +00:00
|
|
|
pthread_mutex_unlock(&mutex);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
sysAbort(s);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-07-28 21:28:25 +00:00
|
|
|
void append(Thread* t) {
|
|
|
|
if (last) {
|
|
|
|
last->next = t;
|
2007-11-27 22:23:00 +00:00
|
|
|
last = t;
|
2007-07-28 21:28:25 +00:00
|
|
|
} else {
|
|
|
|
first = last = t;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void remove(Thread* t) {
|
2007-11-27 23:04:15 +00:00
|
|
|
Thread* previous = 0;
|
2007-11-27 22:23:00 +00:00
|
|
|
for (Thread* current = first; current;) {
|
|
|
|
if (t == current) {
|
|
|
|
if (current == first) {
|
|
|
|
first = t->next;
|
|
|
|
} else {
|
|
|
|
previous->next = t->next;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (current == last) {
|
|
|
|
last = previous;
|
2007-07-28 21:28:25 +00:00
|
|
|
}
|
2007-11-27 22:23:00 +00:00
|
|
|
|
|
|
|
t->next = 0;
|
|
|
|
|
2007-07-28 21:28:25 +00:00
|
|
|
break;
|
|
|
|
} else {
|
2007-11-27 22:23:00 +00:00
|
|
|
previous = current;
|
|
|
|
current = current->next;
|
2007-07-28 21:28:25 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual bool wait(System::Thread* context, int64_t time) {
|
|
|
|
Thread* t = static_cast<Thread*>(context);
|
|
|
|
|
|
|
|
if (owner_ == t) {
|
2008-01-16 20:46:39 +00:00
|
|
|
bool interrupted;
|
2008-01-16 21:58:27 +00:00
|
|
|
bool notified;
|
2008-01-16 20:46:39 +00:00
|
|
|
unsigned depth;
|
|
|
|
|
|
|
|
{ ACQUIRE(t->mutex);
|
2007-07-28 21:28:25 +00:00
|
|
|
|
2008-01-16 20:46:39 +00:00
|
|
|
if (t->r->interrupted()) {
|
|
|
|
t->r->setInterrupted(false);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
t->flags |= Waiting;
|
2007-07-28 21:28:25 +00:00
|
|
|
|
2008-01-16 20:46:39 +00:00
|
|
|
append(t);
|
2007-07-28 21:28:25 +00:00
|
|
|
|
2008-01-16 20:46:39 +00:00
|
|
|
depth = this->depth;
|
|
|
|
this->depth = 0;
|
|
|
|
owner_ = 0;
|
|
|
|
pthread_mutex_unlock(&mutex);
|
2007-07-28 21:28:25 +00:00
|
|
|
|
2008-01-16 20:46:39 +00:00
|
|
|
if (time) {
|
|
|
|
int64_t then = s->now() + time;
|
|
|
|
timespec ts = { then / 1000, (then % 1000) * 1000 * 1000 };
|
|
|
|
int rv UNUSED = pthread_cond_timedwait
|
|
|
|
(&(t->condition), &(t->mutex), &ts);
|
|
|
|
expect(s, rv == 0 or rv == ETIMEDOUT or rv == EINTR);
|
|
|
|
} else {
|
|
|
|
int rv UNUSED = pthread_cond_wait(&(t->condition), &(t->mutex));
|
|
|
|
expect(s, rv == 0 or rv == EINTR);
|
|
|
|
}
|
2007-07-28 21:28:25 +00:00
|
|
|
|
2008-01-16 22:17:28 +00:00
|
|
|
notified = ((t->flags & Notified) != 0);
|
2008-01-16 21:58:27 +00:00
|
|
|
|
2008-01-16 20:46:39 +00:00
|
|
|
t->flags = 0;
|
|
|
|
|
2008-01-16 22:17:28 +00:00
|
|
|
interrupted = t->r->interrupted();
|
|
|
|
if (interrupted) {
|
2008-01-16 20:46:39 +00:00
|
|
|
t->r->setInterrupted(false);
|
|
|
|
}
|
2007-07-20 14:36:31 +00:00
|
|
|
}
|
2007-07-28 21:28:25 +00:00
|
|
|
|
|
|
|
pthread_mutex_lock(&mutex);
|
2008-01-16 21:58:27 +00:00
|
|
|
|
|
|
|
if (not notified) {
|
|
|
|
remove(t);
|
|
|
|
}
|
|
|
|
|
2008-01-16 22:17:28 +00:00
|
|
|
t->next = 0;
|
|
|
|
|
2007-07-28 21:28:25 +00:00
|
|
|
owner_ = t;
|
2007-07-20 14:36:31 +00:00
|
|
|
this->depth = depth;
|
2007-07-28 21:28:25 +00:00
|
|
|
|
2008-01-16 20:46:39 +00:00
|
|
|
return interrupted;
|
2007-07-20 14:36:31 +00:00
|
|
|
} else {
|
|
|
|
sysAbort(s);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-07-28 21:28:25 +00:00
|
|
|
void doNotify(Thread* t) {
|
|
|
|
ACQUIRE(t->mutex);
|
|
|
|
|
|
|
|
t->flags |= Notified;
|
2007-08-19 19:45:51 +00:00
|
|
|
int rv UNUSED = pthread_cond_signal(&(t->condition));
|
2007-11-27 22:23:00 +00:00
|
|
|
expect(s, rv == 0);
|
2007-07-28 21:28:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
virtual void notify(System::Thread* context) {
|
|
|
|
Thread* t = static_cast<Thread*>(context);
|
|
|
|
|
|
|
|
if (owner_ == t) {
|
|
|
|
if (first) {
|
|
|
|
Thread* t = first;
|
|
|
|
first = first->next;
|
|
|
|
if (t == last) {
|
|
|
|
last = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
doNotify(t);
|
|
|
|
}
|
2007-07-20 14:36:31 +00:00
|
|
|
} else {
|
|
|
|
sysAbort(s);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-07-28 21:28:25 +00:00
|
|
|
virtual void notifyAll(System::Thread* context) {
|
|
|
|
Thread* t = static_cast<Thread*>(context);
|
|
|
|
|
|
|
|
if (owner_ == t) {
|
2007-07-30 01:18:18 +00:00
|
|
|
for (Thread* t = first; t; t = t->next) {
|
2007-07-28 21:28:25 +00:00
|
|
|
doNotify(t);
|
|
|
|
}
|
2007-07-30 01:18:18 +00:00
|
|
|
first = last = 0;
|
2007-07-20 14:36:31 +00:00
|
|
|
} else {
|
|
|
|
sysAbort(s);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-07-28 21:28:25 +00:00
|
|
|
virtual System::Thread* owner() {
|
|
|
|
return owner_;
|
2007-07-20 14:36:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
virtual void dispose() {
|
2007-11-27 22:23:00 +00:00
|
|
|
expect(s, owner_ == 0);
|
2007-07-20 14:36:31 +00:00
|
|
|
pthread_mutex_destroy(&mutex);
|
2008-01-13 22:05:08 +00:00
|
|
|
s->free(this, sizeof(*this), false);
|
2007-07-20 14:36:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
System* s;
|
|
|
|
pthread_mutex_t mutex;
|
2007-07-28 21:28:25 +00:00
|
|
|
Thread* owner_;
|
|
|
|
Thread* first;
|
|
|
|
Thread* last;
|
2007-07-20 14:36:31 +00:00
|
|
|
unsigned depth;
|
|
|
|
};
|
|
|
|
|
2007-09-10 23:33:58 +00:00
|
|
|
class Local: public System::Local {
|
|
|
|
public:
|
|
|
|
Local(System* s): s(s) {
|
2007-09-11 02:13:55 +00:00
|
|
|
int r UNUSED = pthread_key_create(&key, 0);
|
2007-11-27 22:23:00 +00:00
|
|
|
expect(s, r == 0);
|
2007-09-10 23:33:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
virtual void* get() {
|
|
|
|
return pthread_getspecific(key);
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual void set(void* p) {
|
2007-09-11 02:13:55 +00:00
|
|
|
int r UNUSED = pthread_setspecific(key, p);
|
2007-11-27 22:23:00 +00:00
|
|
|
expect(s, r == 0);
|
2007-09-10 23:33:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
virtual void dispose() {
|
2007-09-11 02:13:55 +00:00
|
|
|
int r UNUSED = pthread_key_delete(key);
|
2007-11-27 22:23:00 +00:00
|
|
|
expect(s, r == 0);
|
2007-09-10 23:33:58 +00:00
|
|
|
|
2008-01-13 22:05:08 +00:00
|
|
|
s->free(this, sizeof(*this), false);
|
2007-09-10 23:33:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
System* s;
|
|
|
|
pthread_key_t key;
|
|
|
|
};
|
|
|
|
|
2007-09-17 00:13:36 +00:00
|
|
|
class Region: public System::Region {
|
|
|
|
public:
|
2008-01-10 01:20:36 +00:00
|
|
|
Region(System* s, uint8_t* start, size_t length):
|
|
|
|
s(s),
|
2007-09-17 00:13:36 +00:00
|
|
|
start_(start),
|
|
|
|
length_(length)
|
|
|
|
{ }
|
|
|
|
|
|
|
|
virtual const uint8_t* start() {
|
|
|
|
return start_;
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual size_t length() {
|
|
|
|
return length_;
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual void dispose() {
|
|
|
|
if (start_) {
|
|
|
|
munmap(start_, length_);
|
|
|
|
}
|
2008-01-13 22:05:08 +00:00
|
|
|
s->free(this, sizeof(*this), false);
|
2007-09-17 00:13:36 +00:00
|
|
|
}
|
|
|
|
|
2008-01-10 01:20:36 +00:00
|
|
|
System* s;
|
2007-09-17 00:13:36 +00:00
|
|
|
uint8_t* start_;
|
|
|
|
size_t length_;
|
|
|
|
};
|
|
|
|
|
2007-07-20 14:36:31 +00:00
|
|
|
class Library: public System::Library {
|
|
|
|
public:
|
2008-01-10 01:20:36 +00:00
|
|
|
Library(System* s, void* p, const char* name, unsigned nameLength,
|
2008-01-25 23:25:30 +00:00
|
|
|
bool mapName):
|
2007-07-20 14:36:31 +00:00
|
|
|
s(s),
|
|
|
|
p(p),
|
2007-09-18 23:30:09 +00:00
|
|
|
name_(name),
|
2008-01-10 01:20:36 +00:00
|
|
|
nameLength(nameLength),
|
2007-09-18 23:30:09 +00:00
|
|
|
mapName_(mapName),
|
2008-01-25 23:25:30 +00:00
|
|
|
next_(0)
|
2007-07-20 14:36:31 +00:00
|
|
|
{ }
|
|
|
|
|
|
|
|
virtual void* resolve(const char* function) {
|
|
|
|
return dlsym(p, function);
|
|
|
|
}
|
|
|
|
|
2007-09-18 23:30:09 +00:00
|
|
|
virtual const char* name() {
|
|
|
|
return name_;
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual bool mapName() {
|
|
|
|
return mapName_;
|
2007-07-21 17:50:26 +00:00
|
|
|
}
|
|
|
|
|
2007-07-20 14:36:31 +00:00
|
|
|
virtual System::Library* next() {
|
|
|
|
return next_;
|
|
|
|
}
|
|
|
|
|
2008-01-25 23:38:26 +00:00
|
|
|
virtual void setNext(System::Library* lib) {
|
|
|
|
next_ = lib;
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual void disposeAll() {
|
2007-07-20 14:36:31 +00:00
|
|
|
if (Verbose) {
|
|
|
|
fprintf(stderr, "close %p\n", p);
|
|
|
|
}
|
|
|
|
|
|
|
|
dlclose(p);
|
|
|
|
|
|
|
|
if (next_) {
|
2008-01-25 23:38:26 +00:00
|
|
|
next_->disposeAll();
|
2007-07-20 14:36:31 +00:00
|
|
|
}
|
2007-07-21 17:50:26 +00:00
|
|
|
|
2007-09-18 23:30:09 +00:00
|
|
|
if (name_) {
|
2008-01-13 22:05:08 +00:00
|
|
|
s->free(name_, nameLength + 1, false);
|
2007-09-18 23:30:09 +00:00
|
|
|
}
|
|
|
|
|
2008-01-13 22:05:08 +00:00
|
|
|
s->free(this, sizeof(*this), false);
|
2007-07-20 14:36:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
System* s;
|
|
|
|
void* p;
|
2007-09-18 23:30:09 +00:00
|
|
|
const char* name_;
|
2008-01-10 01:20:36 +00:00
|
|
|
unsigned nameLength;
|
2007-09-18 23:30:09 +00:00
|
|
|
bool mapName_;
|
2007-07-20 14:36:31 +00:00
|
|
|
System::Library* next_;
|
|
|
|
};
|
|
|
|
|
2008-01-13 22:05:08 +00:00
|
|
|
MySystem() {
|
2007-07-28 21:28:25 +00:00
|
|
|
struct sigaction sa;
|
|
|
|
memset(&sa, 0, sizeof(struct sigaction));
|
|
|
|
sigemptyset(&(sa.sa_mask));
|
2007-12-30 22:24:48 +00:00
|
|
|
sa.sa_flags = SA_SIGINFO;
|
|
|
|
sa.sa_sigaction = handleSignal;
|
2007-07-28 21:28:25 +00:00
|
|
|
|
2007-08-19 19:45:51 +00:00
|
|
|
int rv UNUSED = sigaction(InterruptSignal, &sa, 0);
|
2007-11-27 22:23:00 +00:00
|
|
|
expect(this, rv == 0);
|
2007-07-20 14:36:31 +00:00
|
|
|
}
|
|
|
|
|
2008-01-13 22:05:08 +00:00
|
|
|
virtual void* tryAllocate(unsigned size, bool executable) {
|
|
|
|
assert(this, (not executable) or (size % LikelyPageSizeInBytes == 0));
|
2007-07-20 14:36:31 +00:00
|
|
|
|
2008-01-14 16:33:54 +00:00
|
|
|
#ifndef MAP_32BIT
|
|
|
|
#define MAP_32BIT 0
|
|
|
|
#endif
|
|
|
|
|
2008-01-13 22:05:08 +00:00
|
|
|
if (executable) {
|
|
|
|
void* p = mmap(0, size, PROT_EXEC | PROT_READ | PROT_WRITE,
|
2008-01-14 17:58:11 +00:00
|
|
|
MAP_PRIVATE | MAP_ANON | MAP_32BIT, -1, 0);
|
2007-07-20 14:36:31 +00:00
|
|
|
|
2008-01-13 22:05:08 +00:00
|
|
|
if (p == MAP_FAILED) {
|
2008-01-10 01:20:36 +00:00
|
|
|
return 0;
|
|
|
|
} else {
|
|
|
|
return p;
|
|
|
|
}
|
2008-01-13 22:05:08 +00:00
|
|
|
} else {
|
|
|
|
return malloc(size);
|
2007-07-20 14:36:31 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-01-13 22:05:08 +00:00
|
|
|
virtual void free(const void* p, unsigned size, bool executable) {
|
2007-07-20 14:36:31 +00:00
|
|
|
if (p) {
|
2008-01-13 22:05:08 +00:00
|
|
|
if (executable) {
|
|
|
|
int r UNUSED = munmap(const_cast<void*>(p), size);
|
|
|
|
assert(this, r == 0);
|
|
|
|
} else {
|
|
|
|
::free(const_cast<void*>(p));
|
|
|
|
}
|
2007-07-20 14:36:31 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-01-10 01:20:36 +00:00
|
|
|
virtual bool success(Status s) {
|
|
|
|
return s == 0;
|
|
|
|
}
|
|
|
|
|
2007-07-28 21:28:25 +00:00
|
|
|
virtual Status attach(Runnable* r) {
|
2008-01-13 22:05:08 +00:00
|
|
|
Thread* t = new (allocate(this, sizeof(Thread))) Thread(this, r);
|
2007-07-20 14:36:31 +00:00
|
|
|
t->thread = pthread_self();
|
2007-07-28 21:28:25 +00:00
|
|
|
r->attach(t);
|
2007-07-20 14:36:31 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual Status start(Runnable* r) {
|
2008-01-13 22:05:08 +00:00
|
|
|
Thread* t = new (allocate(this, sizeof(Thread))) Thread(this, r);
|
2007-07-28 21:28:25 +00:00
|
|
|
r->attach(t);
|
2007-08-19 19:45:51 +00:00
|
|
|
int rv UNUSED = pthread_create(&(t->thread), 0, run, r);
|
2007-11-27 22:23:00 +00:00
|
|
|
expect(this, rv == 0);
|
2007-07-20 14:36:31 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2008-01-13 22:05:08 +00:00
|
|
|
virtual Status make(System::Mutex** m) {
|
|
|
|
*m = new (allocate(this, sizeof(Mutex))) Mutex(this);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2007-07-20 14:36:31 +00:00
|
|
|
virtual Status make(System::Monitor** m) {
|
2008-01-13 22:05:08 +00:00
|
|
|
*m = new (allocate(this, sizeof(Monitor))) Monitor(this);
|
2007-07-20 14:36:31 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2007-09-10 23:33:58 +00:00
|
|
|
virtual Status make(System::Local** l) {
|
2008-01-13 22:05:08 +00:00
|
|
|
*l = new (allocate(this, sizeof(Local))) Local(this);
|
2007-09-10 23:33:58 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2007-12-30 22:24:48 +00:00
|
|
|
virtual Status handleSegFault(SignalHandler* handler) {
|
|
|
|
if (handler) {
|
|
|
|
segFaultHandler = handler;
|
|
|
|
|
|
|
|
struct sigaction sa;
|
|
|
|
memset(&sa, 0, sizeof(struct sigaction));
|
|
|
|
sigemptyset(&(sa.sa_mask));
|
|
|
|
sa.sa_flags = SA_SIGINFO;
|
|
|
|
sa.sa_sigaction = handleSignal;
|
|
|
|
|
2008-01-01 18:19:55 +00:00
|
|
|
return sigaction(SegFaultSignal, &sa, &oldSegFaultHandler);
|
2007-12-30 22:24:48 +00:00
|
|
|
} else if (segFaultHandler) {
|
2007-12-31 23:21:57 +00:00
|
|
|
segFaultHandler = 0;
|
2008-01-01 18:19:55 +00:00
|
|
|
return sigaction(SegFaultSignal, &oldSegFaultHandler, 0);
|
2007-12-30 22:24:48 +00:00
|
|
|
} else {
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-07-20 14:36:31 +00:00
|
|
|
virtual uint64_t call(void* function, uintptr_t* arguments, uint8_t* types,
|
|
|
|
unsigned count, unsigned size, unsigned returnType)
|
|
|
|
{
|
|
|
|
return dynamicCall(function, arguments, types, count, size, returnType);
|
|
|
|
}
|
|
|
|
|
2007-09-17 00:13:36 +00:00
|
|
|
virtual Status map(System::Region** region, const char* name) {
|
|
|
|
Status status = 1;
|
|
|
|
|
|
|
|
int fd = open(name, O_RDONLY);
|
|
|
|
if (fd != -1) {
|
|
|
|
struct stat s;
|
|
|
|
int r = fstat(fd, &s);
|
|
|
|
if (r != -1) {
|
|
|
|
void* data = mmap(0, s.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
|
|
|
|
if (data) {
|
2008-01-13 22:05:08 +00:00
|
|
|
*region = new (allocate(this, sizeof(Region)))
|
2007-09-17 00:13:36 +00:00
|
|
|
Region(this, static_cast<uint8_t*>(data), s.st_size);
|
|
|
|
status = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
close(fd);
|
|
|
|
}
|
|
|
|
|
|
|
|
return status;
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual FileType identify(const char* name) {
|
|
|
|
struct stat s;
|
|
|
|
int r = stat(name, &s);
|
2007-09-17 13:16:55 +00:00
|
|
|
if (r == 0) {
|
2007-09-17 00:13:36 +00:00
|
|
|
if (S_ISREG(s.st_mode)) {
|
|
|
|
return File;
|
|
|
|
} else if (S_ISDIR(s.st_mode)) {
|
|
|
|
return Directory;
|
|
|
|
} else {
|
|
|
|
return Unknown;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
return DoesNotExist;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-07-20 14:36:31 +00:00
|
|
|
virtual Status load(System::Library** lib,
|
|
|
|
const char* name,
|
2008-01-25 23:25:30 +00:00
|
|
|
bool mapName)
|
2007-07-20 14:36:31 +00:00
|
|
|
{
|
2007-09-12 01:13:05 +00:00
|
|
|
void* p;
|
2008-01-28 23:17:22 +00:00
|
|
|
bool alreadyAllocated = false;
|
2007-09-18 23:30:09 +00:00
|
|
|
unsigned nameLength = (name ? strlen(name) : 0);
|
2007-09-12 01:13:05 +00:00
|
|
|
if (mapName) {
|
2007-09-20 16:13:41 +00:00
|
|
|
unsigned size = nameLength + 3 + sizeof(SO_SUFFIX);
|
2007-09-20 00:37:25 +00:00
|
|
|
char buffer[size];
|
2007-09-20 16:13:41 +00:00
|
|
|
snprintf(buffer, size, "lib%s" SO_SUFFIX, name);
|
2007-09-12 01:13:05 +00:00
|
|
|
p = dlopen(buffer, RTLD_LAZY);
|
|
|
|
} else {
|
2008-01-28 23:17:22 +00:00
|
|
|
if (!name) {
|
|
|
|
pathOfExecutable(this, &name, &nameLength);
|
|
|
|
alreadyAllocated = true;
|
|
|
|
}
|
2007-09-12 01:13:05 +00:00
|
|
|
p = dlopen(name, RTLD_LAZY);
|
|
|
|
}
|
2007-07-20 14:36:31 +00:00
|
|
|
|
|
|
|
if (p) {
|
|
|
|
if (Verbose) {
|
2007-09-12 01:13:05 +00:00
|
|
|
fprintf(stderr, "open %s as %p\n", name, p);
|
2007-07-20 14:36:31 +00:00
|
|
|
}
|
|
|
|
|
2007-09-18 23:30:09 +00:00
|
|
|
char* n;
|
|
|
|
if (name) {
|
2008-01-13 22:05:08 +00:00
|
|
|
n = static_cast<char*>(allocate(this, nameLength + 1));
|
2007-09-18 23:30:09 +00:00
|
|
|
memcpy(n, name, nameLength + 1);
|
2008-01-28 23:17:22 +00:00
|
|
|
if (alreadyAllocated) {
|
|
|
|
free(name, nameLength, false);
|
|
|
|
}
|
2007-09-18 23:30:09 +00:00
|
|
|
} else {
|
|
|
|
n = 0;
|
|
|
|
}
|
|
|
|
|
2008-01-25 23:38:26 +00:00
|
|
|
*lib = new (allocate(this, sizeof(Library)))
|
2008-01-25 23:25:30 +00:00
|
|
|
Library(this, p, n, nameLength, mapName);
|
|
|
|
|
2007-07-20 14:36:31 +00:00
|
|
|
return 0;
|
|
|
|
} else {
|
2007-09-13 00:21:37 +00:00
|
|
|
// fprintf(stderr, "dlerror: %s\n", dlerror());
|
2007-07-20 14:36:31 +00:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-10-24 15:46:09 +00:00
|
|
|
virtual char pathSeparator() {
|
|
|
|
return ':';
|
|
|
|
}
|
|
|
|
|
2007-10-23 01:00:57 +00:00
|
|
|
virtual int64_t now() {
|
2007-08-18 22:35:22 +00:00
|
|
|
timeval tv = { 0, 0 };
|
|
|
|
gettimeofday(&tv, 0);
|
|
|
|
return (static_cast<int64_t>(tv.tv_sec) * 1000) +
|
|
|
|
(static_cast<int64_t>(tv.tv_usec) / 1000);
|
|
|
|
}
|
|
|
|
|
2007-10-23 01:00:57 +00:00
|
|
|
virtual void exit(int code) {
|
|
|
|
::exit(code);
|
|
|
|
}
|
|
|
|
|
2007-07-20 14:36:31 +00:00
|
|
|
virtual void abort() {
|
|
|
|
::abort();
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual void dispose() {
|
|
|
|
::free(this);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
} // namespace
|
|
|
|
|
|
|
|
namespace vm {
|
|
|
|
|
|
|
|
System*
|
2008-01-13 22:05:08 +00:00
|
|
|
makeSystem()
|
2007-07-20 14:36:31 +00:00
|
|
|
{
|
2008-01-13 22:05:08 +00:00
|
|
|
return new (malloc(sizeof(MySystem))) MySystem();
|
2007-07-20 14:36:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
} // namespace vm
|