2010-12-06 03:21:09 +00:00
|
|
|
/* Copyright (c) 2008-2010, Avian Contributors
|
2008-02-19 18:06:52 +00:00
|
|
|
|
|
|
|
Permission to use, copy, modify, and/or distribute this software
|
|
|
|
for any purpose with or without fee is hereby granted, provided
|
|
|
|
that the above copyright notice and this permission notice appear
|
|
|
|
in all copies.
|
|
|
|
|
|
|
|
There is NO WARRANTY for this software. See license.txt for
|
|
|
|
details. */
|
|
|
|
|
2010-11-08 04:23:25 +00:00
|
|
|
#define __STDC_CONSTANT_MACROS
|
|
|
|
|
2008-01-28 23:17:22 +00:00
|
|
|
#ifdef __APPLE__
|
2008-06-04 22:21:27 +00:00
|
|
|
# include "CoreFoundation/CoreFoundation.h"
|
|
|
|
# undef assert
|
2009-10-14 16:01:37 +00:00
|
|
|
# define _XOPEN_SOURCE
|
2008-01-28 23:17:22 +00:00
|
|
|
#endif
|
2008-06-04 22:21:27 +00:00
|
|
|
|
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"
|
2009-10-29 16:12:30 +00:00
|
|
|
#include "sys/ucontext.h"
|
2007-07-20 14:36:31 +00:00
|
|
|
#include "stdint.h"
|
2008-11-21 23:20:35 +00:00
|
|
|
#include "dirent.h"
|
2007-07-20 14:36:31 +00:00
|
|
|
|
2008-06-04 22:21:27 +00:00
|
|
|
#include "arch.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-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;
|
|
|
|
};
|
|
|
|
|
2009-10-19 16:31:34 +00:00
|
|
|
const int InvalidSignal = -1;
|
2008-04-09 19:08:13 +00:00
|
|
|
const int VisitSignal = SIGUSR1;
|
2009-10-18 00:09:54 +00:00
|
|
|
const unsigned VisitSignalIndex = 0;
|
2009-10-14 16:01:37 +00:00
|
|
|
const int SegFaultSignal = SIGSEGV;
|
2009-10-18 00:09:54 +00:00
|
|
|
const unsigned SegFaultSignalIndex = 1;
|
|
|
|
const int InterruptSignal = SIGUSR2;
|
|
|
|
const unsigned InterruptSignalIndex = 2;
|
2008-01-01 18:19:55 +00:00
|
|
|
#ifdef __APPLE__
|
2009-10-14 16:01:37 +00:00
|
|
|
const int AltSegFaultSignal = SIGBUS;
|
2009-10-19 16:31:34 +00:00
|
|
|
#else
|
|
|
|
const int AltSegFaultSignal = InvalidSignal;
|
2008-01-01 18:19:55 +00:00
|
|
|
#endif
|
2009-10-19 16:31:34 +00:00
|
|
|
const unsigned AltSegFaultSignalIndex = 3;
|
2010-10-14 23:43:35 +00:00
|
|
|
const int PipeSignal = SIGPIPE;
|
|
|
|
const unsigned PipeSignalIndex = 4;
|
2010-12-20 00:47:21 +00:00
|
|
|
const int DivideByZeroSignal = SIGFPE;
|
|
|
|
const unsigned DivideByZeroSignalIndex = 5;
|
2008-04-09 19:08:13 +00:00
|
|
|
|
2009-10-18 00:09:54 +00:00
|
|
|
const int signals[] = { VisitSignal,
|
|
|
|
SegFaultSignal,
|
2009-10-19 16:31:34 +00:00
|
|
|
InterruptSignal,
|
2010-10-14 23:43:35 +00:00
|
|
|
AltSegFaultSignal,
|
2010-12-20 00:47:21 +00:00
|
|
|
PipeSignal,
|
|
|
|
DivideByZeroSignal };
|
2009-10-19 16:31:34 +00:00
|
|
|
|
2010-12-20 00:47:21 +00:00
|
|
|
const unsigned SignalCount = 6;
|
2008-04-09 19:08:13 +00:00
|
|
|
|
|
|
|
class MySystem;
|
|
|
|
MySystem* system;
|
|
|
|
|
2007-07-28 21:28:25 +00:00
|
|
|
void
|
2008-04-09 19:08:13 +00:00
|
|
|
handleSignal(int signal, siginfo_t* info, void* context);
|
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-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);
|
2010-04-26 16:24:53 +00:00
|
|
|
path = CFURLCreateStringByReplacingPercentEscapes(kCFAllocatorDefault,
|
|
|
|
path, CFSTR(""));
|
2008-01-28 23:17:22 +00:00
|
|
|
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
|
|
|
|
}
|
|
|
|
|
2008-02-20 17:14:42 +00:00
|
|
|
const bool Verbose = false;
|
2007-07-20 14:36:31 +00:00
|
|
|
|
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
|
|
|
|
2009-07-23 22:17:52 +00:00
|
|
|
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);
|
2009-08-18 21:29:25 +00:00
|
|
|
expect(s, rv == 0);
|
2007-07-20 14:36:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
virtual void dispose() {
|
2008-04-13 18:15:04 +00:00
|
|
|
s->free(this);
|
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);
|
2008-04-13 18:15:04 +00:00
|
|
|
s->free(this);
|
2008-01-13 22:05:08 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
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-11-11 15:20:49 +00:00
|
|
|
// Initialized here to make gcc 4.2 a happy compiler
|
|
|
|
bool interrupted = false;
|
|
|
|
bool notified = false;
|
|
|
|
unsigned depth = 0;
|
2008-01-16 20:46:39 +00:00
|
|
|
|
|
|
|
{ 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
|
|
|
|
2010-09-17 01:43:27 +00:00
|
|
|
// pretend anything greater than one million years (in
|
|
|
|
// milliseconds) is infinity so as to avoid overflow:
|
|
|
|
if (time and time < INT64_C(31536000000000000)) {
|
2008-01-16 20:46:39 +00:00
|
|
|
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-04-13 18:15:04 +00:00
|
|
|
s->free(this);
|
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-04-13 18:15:04 +00:00
|
|
|
s->free(this);
|
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-04-13 18:15:04 +00:00
|
|
|
s->free(this);
|
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_;
|
|
|
|
};
|
|
|
|
|
2008-11-21 23:20:35 +00:00
|
|
|
class Directory: public System::Directory {
|
|
|
|
public:
|
|
|
|
Directory(System* s, DIR* directory): s(s), directory(directory) { }
|
|
|
|
|
|
|
|
virtual const char* next() {
|
|
|
|
if (directory) {
|
|
|
|
dirent* e = readdir(directory);
|
|
|
|
if (e) {
|
|
|
|
return e->d_name;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual void dispose() {
|
|
|
|
if (directory) {
|
|
|
|
closedir(directory);
|
|
|
|
}
|
|
|
|
s->free(this);
|
|
|
|
}
|
|
|
|
|
|
|
|
System* s;
|
|
|
|
DIR* directory;
|
|
|
|
};
|
|
|
|
|
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,
|
2010-09-20 23:31:23 +00:00
|
|
|
bool isMain):
|
2007-07-20 14:36:31 +00:00
|
|
|
s(s),
|
|
|
|
p(p),
|
2008-02-20 16:41:30 +00:00
|
|
|
mainExecutable(isMain),
|
2007-09-18 23:30:09 +00:00
|
|
|
name_(name),
|
2008-01-10 01:20:36 +00:00
|
|
|
nameLength(nameLength),
|
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_;
|
|
|
|
}
|
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2010-09-20 23:31:23 +00:00
|
|
|
if (not mainExecutable) dlclose(p);
|
2007-07-20 14:36:31 +00:00
|
|
|
|
|
|
|
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-04-13 18:15:04 +00:00
|
|
|
s->free(name_);
|
2007-09-18 23:30:09 +00:00
|
|
|
}
|
|
|
|
|
2008-04-13 18:15:04 +00:00
|
|
|
s->free(this);
|
2007-07-20 14:36:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
System* s;
|
|
|
|
void* p;
|
2008-02-20 16:41:30 +00:00
|
|
|
bool mainExecutable;
|
2007-09-18 23:30:09 +00:00
|
|
|
const char* name_;
|
2008-01-10 01:20:36 +00:00
|
|
|
unsigned nameLength;
|
2007-07-20 14:36:31 +00:00
|
|
|
System::Library* next_;
|
|
|
|
};
|
|
|
|
|
2009-03-07 19:03:27 +00:00
|
|
|
MySystem():
|
|
|
|
threadVisitor(0),
|
2009-04-05 21:42:10 +00:00
|
|
|
visitTarget(0)
|
2009-03-07 19:03:27 +00:00
|
|
|
{
|
2008-04-09 19:08:13 +00:00
|
|
|
expect(this, system == 0);
|
|
|
|
system = this;
|
|
|
|
|
2010-12-20 00:47:21 +00:00
|
|
|
memset(handlers, 0, sizeof(handlers));
|
|
|
|
|
2008-04-09 19:08:13 +00:00
|
|
|
registerHandler(&nullHandler, InterruptSignalIndex);
|
2010-10-14 23:43:35 +00:00
|
|
|
registerHandler(&nullHandler, PipeSignalIndex);
|
2008-04-09 19:08:13 +00:00
|
|
|
registerHandler(&nullHandler, VisitSignalIndex);
|
|
|
|
|
|
|
|
expect(this, make(&visitLock) == 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
int registerHandler(System::SignalHandler* handler, int index) {
|
|
|
|
if (handler) {
|
|
|
|
handlers[index] = handler;
|
|
|
|
|
|
|
|
struct sigaction sa;
|
|
|
|
memset(&sa, 0, sizeof(struct sigaction));
|
|
|
|
sigemptyset(&(sa.sa_mask));
|
|
|
|
sa.sa_flags = SA_SIGINFO;
|
|
|
|
sa.sa_sigaction = handleSignal;
|
2007-07-28 21:28:25 +00:00
|
|
|
|
2008-04-09 19:08:13 +00:00
|
|
|
return sigaction(signals[index], &sa, oldHandlers + index);
|
|
|
|
} else if (handlers[index]) {
|
|
|
|
handlers[index] = 0;
|
|
|
|
return sigaction(signals[index], oldHandlers + index, 0);
|
|
|
|
} else {
|
|
|
|
return 1;
|
|
|
|
}
|
2007-07-20 14:36:31 +00:00
|
|
|
}
|
|
|
|
|
2008-04-13 18:15:04 +00:00
|
|
|
virtual void* tryAllocate(unsigned sizeInBytes) {
|
|
|
|
return malloc(sizeInBytes);
|
|
|
|
}
|
2007-07-20 14:36:31 +00:00
|
|
|
|
2008-04-13 18:15:04 +00:00
|
|
|
virtual void free(const void* p) {
|
|
|
|
if (p) ::free(const_cast<void*>(p));
|
|
|
|
}
|
2008-01-14 16:33:54 +00:00
|
|
|
|
2008-04-13 18:15:04 +00:00
|
|
|
virtual void* tryAllocateExecutable(unsigned sizeInBytes) {
|
2009-10-18 00:09:54 +00:00
|
|
|
#if (! defined __APPLE__) && (defined __x86_64__)
|
|
|
|
// map to the lower 32 bits of memory when possible so as to avoid
|
|
|
|
// expensive relative jumps
|
|
|
|
const unsigned Extra = MAP_32BIT;
|
|
|
|
#else
|
|
|
|
const unsigned Extra = 0;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
void* p = mmap(0, sizeInBytes, PROT_EXEC | PROT_READ | PROT_WRITE,
|
|
|
|
MAP_PRIVATE | MAP_ANON | Extra, -1, 0);
|
2009-03-07 19:03:27 +00:00
|
|
|
|
2009-04-05 21:42:10 +00:00
|
|
|
if (p == MAP_FAILED) {
|
2009-03-07 19:03:27 +00:00
|
|
|
return 0;
|
2009-04-05 21:42:10 +00:00
|
|
|
} else {
|
2009-10-20 15:06:52 +00:00
|
|
|
// fprintf(stderr, "executable from %p to %p\n", p,
|
|
|
|
// static_cast<uint8_t*>(p) + sizeInBytes);
|
2009-04-05 21:42:10 +00:00
|
|
|
return static_cast<uint8_t*>(p);
|
2007-07-20 14:36:31 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-04-05 21:42:10 +00:00
|
|
|
virtual void freeExecutable(const void* p, unsigned sizeInBytes) {
|
2009-04-07 00:34:12 +00:00
|
|
|
munmap(const_cast<void*>(p), sizeInBytes);
|
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) {
|
2009-10-14 16:01:37 +00:00
|
|
|
Status s = registerHandler(handler, SegFaultSignalIndex);
|
2009-10-19 16:31:34 +00:00
|
|
|
if (s == 0 and AltSegFaultSignal != InvalidSignal) {
|
2009-10-14 16:01:37 +00:00
|
|
|
return registerHandler(handler, AltSegFaultSignalIndex);
|
|
|
|
}
|
2009-10-18 00:09:54 +00:00
|
|
|
return s;
|
2008-04-09 19:08:13 +00:00
|
|
|
}
|
2007-12-30 22:24:48 +00:00
|
|
|
|
2010-12-20 00:47:21 +00:00
|
|
|
virtual Status handleDivideByZero(SignalHandler* handler) {
|
|
|
|
return registerHandler(handler, DivideByZeroSignalIndex);
|
|
|
|
}
|
|
|
|
|
2008-04-09 19:08:13 +00:00
|
|
|
virtual Status visit(System::Thread* st, System::Thread* sTarget,
|
|
|
|
ThreadVisitor* visitor)
|
|
|
|
{
|
|
|
|
assert(this, st != sTarget);
|
|
|
|
|
|
|
|
Thread* t = static_cast<Thread*>(st);
|
|
|
|
Thread* target = static_cast<Thread*>(sTarget);
|
|
|
|
|
|
|
|
ACQUIRE_MONITOR(t, visitLock);
|
|
|
|
|
|
|
|
while (threadVisitor) visitLock->wait(t, 0);
|
|
|
|
|
|
|
|
threadVisitor = visitor;
|
|
|
|
visitTarget = target;
|
|
|
|
|
|
|
|
int rv = pthread_kill(target->thread, VisitSignal);
|
|
|
|
|
2010-11-22 23:57:02 +00:00
|
|
|
int result;
|
2009-07-25 01:03:33 +00:00
|
|
|
if (rv == 0) {
|
|
|
|
while (visitTarget) visitLock->wait(t, 0);
|
2008-04-09 19:08:13 +00:00
|
|
|
|
2010-11-22 23:57:02 +00:00
|
|
|
result = 0;
|
2009-07-25 01:03:33 +00:00
|
|
|
} else {
|
2010-11-22 23:57:02 +00:00
|
|
|
visitTarget = 0;
|
|
|
|
|
|
|
|
result = -1;
|
2009-07-25 01:03:33 +00:00
|
|
|
}
|
2010-11-22 23:57:02 +00:00
|
|
|
|
|
|
|
threadVisitor = 0;
|
|
|
|
|
|
|
|
system->visitLock->notifyAll(t);
|
|
|
|
|
|
|
|
return result;
|
2007-12-30 22:24:48 +00:00
|
|
|
}
|
|
|
|
|
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;
|
|
|
|
|
2008-11-21 23:20:35 +00:00
|
|
|
int fd = ::open(name, O_RDONLY);
|
2007-09-17 00:13:36 +00:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2008-11-21 23:20:35 +00:00
|
|
|
virtual Status open(System::Directory** directory, const char* name) {
|
|
|
|
Status status = 1;
|
|
|
|
|
|
|
|
DIR* d = opendir(name);
|
|
|
|
if (d) {
|
|
|
|
*directory = new (allocate(this, sizeof(Directory))) Directory(this, d);
|
|
|
|
status = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
return status;
|
|
|
|
}
|
|
|
|
|
2010-11-05 19:18:28 +00:00
|
|
|
virtual FileType stat(const char* name, unsigned* length) {
|
2007-09-17 00:13:36 +00:00
|
|
|
struct stat s;
|
2010-11-05 19:18:28 +00:00
|
|
|
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)) {
|
2010-11-05 19:18:28 +00:00
|
|
|
*length = s.st_size;
|
2008-11-21 23:20:35 +00:00
|
|
|
return TypeFile;
|
2007-09-17 00:13:36 +00:00
|
|
|
} else if (S_ISDIR(s.st_mode)) {
|
2010-11-05 19:18:28 +00:00
|
|
|
*length = 0;
|
2008-11-21 23:20:35 +00:00
|
|
|
return TypeDirectory;
|
2007-09-17 00:13:36 +00:00
|
|
|
} else {
|
2010-11-05 19:18:28 +00:00
|
|
|
*length = 0;
|
2008-11-21 23:20:35 +00:00
|
|
|
return TypeUnknown;
|
2007-09-17 00:13:36 +00:00
|
|
|
}
|
|
|
|
} else {
|
2010-11-05 19:18:28 +00:00
|
|
|
*length = 0;
|
2008-11-21 23:20:35 +00:00
|
|
|
return TypeDoesNotExist;
|
2007-09-17 00:13:36 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-09-20 23:31:23 +00:00
|
|
|
virtual const char* libraryPrefix() {
|
2010-11-16 03:28:53 +00:00
|
|
|
return SO_PREFIX;
|
2010-09-20 23:31:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
virtual const char* librarySuffix() {
|
|
|
|
return SO_SUFFIX;
|
|
|
|
}
|
|
|
|
|
2007-07-20 14:36:31 +00:00
|
|
|
virtual Status load(System::Library** lib,
|
2010-09-20 23:31:23 +00:00
|
|
|
const char* name)
|
2007-07-20 14:36:31 +00:00
|
|
|
{
|
2007-09-18 23:30:09 +00:00
|
|
|
unsigned nameLength = (name ? strlen(name) : 0);
|
2010-09-20 23:31:23 +00:00
|
|
|
bool isMain = name == 0;
|
|
|
|
if (isMain) {
|
|
|
|
pathOfExecutable(this, &name, &nameLength);
|
2007-09-12 01:13:05 +00:00
|
|
|
}
|
2010-09-20 23:31:23 +00:00
|
|
|
void* p = dlopen(name, RTLD_LAZY | RTLD_LOCAL);
|
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);
|
2010-09-20 23:31:23 +00:00
|
|
|
if (isMain) {
|
2008-04-13 18:15:04 +00:00
|
|
|
free(name);
|
2008-01-28 23:17:22 +00:00
|
|
|
}
|
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)))
|
2010-09-20 23:31:23 +00:00
|
|
|
Library(this, p, n, nameLength, isMain);
|
2008-01-25 23:25:30 +00:00
|
|
|
|
2007-07-20 14:36:31 +00:00
|
|
|
return 0;
|
|
|
|
} else {
|
2010-09-20 23:31:23 +00:00
|
|
|
if (Verbose) {
|
2010-10-13 19:37:09 +00:00
|
|
|
fprintf(stderr, "dlerror opening %s: %s\n", name, dlerror());
|
2010-09-20 23:31:23 +00:00
|
|
|
}
|
2007-07-20 14:36:31 +00:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-10-24 15:46:09 +00:00
|
|
|
virtual char pathSeparator() {
|
|
|
|
return ':';
|
|
|
|
}
|
|
|
|
|
2010-09-20 23:31:23 +00:00
|
|
|
virtual char fileSeparator() {
|
|
|
|
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() {
|
2008-04-09 19:08:13 +00:00
|
|
|
visitLock->dispose();
|
|
|
|
|
|
|
|
registerHandler(0, InterruptSignalIndex);
|
|
|
|
registerHandler(0, VisitSignalIndex);
|
2010-10-14 23:43:35 +00:00
|
|
|
registerHandler(0, PipeSignalIndex);
|
2008-04-09 19:08:13 +00:00
|
|
|
system = 0;
|
|
|
|
|
2007-07-20 14:36:31 +00:00
|
|
|
::free(this);
|
|
|
|
}
|
2008-04-09 19:08:13 +00:00
|
|
|
|
|
|
|
class NullSignalHandler: public SignalHandler {
|
support stack unwinding without using a frame pointer
Previously, we unwound the stack by following the chain of frame
pointers for normal returns, stack trace creation, and exception
unwinding. On x86, this required reserving EBP/RBP for frame pointer
duties, making it unavailable for general computation and requiring
that it be explicitly saved and restored on entry and exit,
respectively.
On PowerPC, we use an ABI that makes the stack pointer double as a
frame pointer, so it doesn't cost us anything. We've been using the
same convention on ARM, but it doesn't match the native calling
convention, which makes it unusable when we want to call native code
from Java and pass arguments on the stack.
So far, the ARM calling convention mismatch hasn't been an issue
because we've never passed more arguments from Java to native code
than would fit in registers. However, we must now pass an extra
argument (the thread pointer) to e.g. divideLong so it can throw an
exception on divide by zero, which means the last argument must be
passed on the stack. This will clobber the linkage area we've been
using to hold the frame pointer, so we need to stop using it.
One solution would be to use the same convention on ARM as we do on
x86, but this would introduce the same overhead of making a register
unavailable for general use and extra code at method entry and exit.
Instead, this commit removes the need for a frame pointer. Unwinding
involves consulting a map of instruction offsets to frame sizes which
is generated at compile time. This is necessary because stack trace
creation can happen at any time due to Thread.getStackTrace being
called by another thread, and the frame size varies during the
execution of a method.
So far, only x86(_64) is working, and continuations and tail call
optimization are probably broken. More to come.
2011-01-17 02:05:05 +00:00
|
|
|
virtual bool handleSignal(void**, void**, void**) { return false; }
|
2008-04-09 19:08:13 +00:00
|
|
|
} nullHandler;
|
|
|
|
|
2009-10-19 16:31:34 +00:00
|
|
|
SignalHandler* handlers[SignalCount];
|
|
|
|
struct sigaction oldHandlers[SignalCount];
|
2008-04-09 19:08:13 +00:00
|
|
|
|
|
|
|
ThreadVisitor* threadVisitor;
|
|
|
|
Thread* visitTarget;
|
|
|
|
System::Monitor* visitLock;
|
2007-07-20 14:36:31 +00:00
|
|
|
};
|
|
|
|
|
2008-04-09 19:08:13 +00:00
|
|
|
void
|
|
|
|
handleSignal(int signal, siginfo_t* info, void* context)
|
|
|
|
{
|
|
|
|
ucontext_t* c = static_cast<ucontext_t*>(context);
|
|
|
|
|
|
|
|
void* ip = reinterpret_cast<void*>(IP_REGISTER(c));
|
|
|
|
void* stack = reinterpret_cast<void*>(STACK_REGISTER(c));
|
|
|
|
void* thread = reinterpret_cast<void*>(THREAD_REGISTER(c));
|
2011-01-26 00:22:43 +00:00
|
|
|
void* link = reinterpret_cast<void*>(LINK_REGISTER(c));
|
2008-04-09 19:08:13 +00:00
|
|
|
|
|
|
|
unsigned index;
|
|
|
|
|
|
|
|
switch (signal) {
|
|
|
|
case VisitSignal: {
|
|
|
|
index = VisitSignalIndex;
|
|
|
|
|
2011-01-26 00:22:43 +00:00
|
|
|
system->threadVisitor->visit(ip, stack, link);
|
2008-04-09 19:08:13 +00:00
|
|
|
|
|
|
|
System::Thread* t = system->visitTarget;
|
|
|
|
system->visitTarget = 0;
|
2008-04-21 22:36:13 +00:00
|
|
|
|
|
|
|
ACQUIRE_MONITOR(t, system->visitLock);
|
2008-04-09 19:08:13 +00:00
|
|
|
system->visitLock->notifyAll(t);
|
|
|
|
} break;
|
|
|
|
|
2009-10-14 16:01:37 +00:00
|
|
|
case SegFaultSignal:
|
2010-12-20 00:47:21 +00:00
|
|
|
case AltSegFaultSignal:
|
|
|
|
case DivideByZeroSignal: {
|
|
|
|
switch (signal) {
|
|
|
|
case SegFaultSignal:
|
2009-10-14 16:01:37 +00:00
|
|
|
index = SegFaultSignalIndex;
|
2010-12-20 00:47:21 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case AltSegFaultSignal:
|
2009-10-14 16:01:37 +00:00
|
|
|
index = AltSegFaultSignalIndex;
|
2010-12-20 00:47:21 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case DivideByZeroSignal:
|
|
|
|
index = DivideByZeroSignalIndex;
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
abort();
|
2009-10-14 16:01:37 +00:00
|
|
|
}
|
2010-12-20 00:47:21 +00:00
|
|
|
|
support stack unwinding without using a frame pointer
Previously, we unwound the stack by following the chain of frame
pointers for normal returns, stack trace creation, and exception
unwinding. On x86, this required reserving EBP/RBP for frame pointer
duties, making it unavailable for general computation and requiring
that it be explicitly saved and restored on entry and exit,
respectively.
On PowerPC, we use an ABI that makes the stack pointer double as a
frame pointer, so it doesn't cost us anything. We've been using the
same convention on ARM, but it doesn't match the native calling
convention, which makes it unusable when we want to call native code
from Java and pass arguments on the stack.
So far, the ARM calling convention mismatch hasn't been an issue
because we've never passed more arguments from Java to native code
than would fit in registers. However, we must now pass an extra
argument (the thread pointer) to e.g. divideLong so it can throw an
exception on divide by zero, which means the last argument must be
passed on the stack. This will clobber the linkage area we've been
using to hold the frame pointer, so we need to stop using it.
One solution would be to use the same convention on ARM as we do on
x86, but this would introduce the same overhead of making a register
unavailable for general use and extra code at method entry and exit.
Instead, this commit removes the need for a frame pointer. Unwinding
involves consulting a map of instruction offsets to frame sizes which
is generated at compile time. This is necessary because stack trace
creation can happen at any time due to Thread.getStackTrace being
called by another thread, and the frame size varies during the
execution of a method.
So far, only x86(_64) is working, and continuations and tail call
optimization are probably broken. More to come.
2011-01-17 02:05:05 +00:00
|
|
|
bool jump = system->handlers[index]->handleSignal(&ip, &stack, &thread);
|
2008-04-09 19:08:13 +00:00
|
|
|
|
2009-10-19 16:31:34 +00:00
|
|
|
if (jump) {
|
|
|
|
// I'd like to use setcontext here (and get rid of the
|
|
|
|
// 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.
|
2008-04-09 19:08:13 +00:00
|
|
|
|
2009-10-19 16:31:34 +00:00
|
|
|
sigset_t set;
|
2008-04-09 19:08:13 +00:00
|
|
|
|
2009-10-19 16:31:34 +00:00
|
|
|
sigemptyset(&set);
|
|
|
|
sigaddset(&set, signal);
|
|
|
|
sigprocmask(SIG_UNBLOCK, &set, 0);
|
2008-04-09 19:08:13 +00:00
|
|
|
|
support stack unwinding without using a frame pointer
Previously, we unwound the stack by following the chain of frame
pointers for normal returns, stack trace creation, and exception
unwinding. On x86, this required reserving EBP/RBP for frame pointer
duties, making it unavailable for general computation and requiring
that it be explicitly saved and restored on entry and exit,
respectively.
On PowerPC, we use an ABI that makes the stack pointer double as a
frame pointer, so it doesn't cost us anything. We've been using the
same convention on ARM, but it doesn't match the native calling
convention, which makes it unusable when we want to call native code
from Java and pass arguments on the stack.
So far, the ARM calling convention mismatch hasn't been an issue
because we've never passed more arguments from Java to native code
than would fit in registers. However, we must now pass an extra
argument (the thread pointer) to e.g. divideLong so it can throw an
exception on divide by zero, which means the last argument must be
passed on the stack. This will clobber the linkage area we've been
using to hold the frame pointer, so we need to stop using it.
One solution would be to use the same convention on ARM as we do on
x86, but this would introduce the same overhead of making a register
unavailable for general use and extra code at method entry and exit.
Instead, this commit removes the need for a frame pointer. Unwinding
involves consulting a map of instruction offsets to frame sizes which
is generated at compile time. This is necessary because stack trace
creation can happen at any time due to Thread.getStackTrace being
called by another thread, and the frame size varies during the
execution of a method.
So far, only x86(_64) is working, and continuations and tail call
optimization are probably broken. More to come.
2011-01-17 02:05:05 +00:00
|
|
|
vmJump(ip, stack, thread, 0, 0);
|
2009-10-19 16:31:34 +00:00
|
|
|
}
|
|
|
|
} break;
|
2008-04-09 19:08:13 +00:00
|
|
|
|
|
|
|
case InterruptSignal: {
|
|
|
|
index = InterruptSignalIndex;
|
|
|
|
} break;
|
|
|
|
|
2010-10-14 23:43:35 +00:00
|
|
|
case PipeSignal: {
|
|
|
|
index = PipeSignalIndex;
|
|
|
|
} break;
|
|
|
|
|
2008-04-09 19:08:13 +00:00
|
|
|
default: abort();
|
|
|
|
}
|
|
|
|
|
2010-11-18 17:24:58 +00:00
|
|
|
if (system->oldHandlers[index].sa_flags & SA_SIGINFO
|
|
|
|
and system->oldHandlers[index].sa_sigaction)
|
|
|
|
{
|
2008-04-09 19:08:13 +00:00
|
|
|
system->oldHandlers[index].sa_sigaction(signal, info, context);
|
|
|
|
} else if (system->oldHandlers[index].sa_handler) {
|
|
|
|
system->oldHandlers[index].sa_handler(signal);
|
|
|
|
} else {
|
2008-04-21 22:36:13 +00:00
|
|
|
switch (signal) {
|
|
|
|
case VisitSignal:
|
2009-07-23 22:17:52 +00:00
|
|
|
case InterruptSignal:
|
2010-10-14 23:43:35 +00:00
|
|
|
case PipeSignal:
|
2008-04-21 22:36:13 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
abort();
|
|
|
|
}
|
2008-04-09 19:08:13 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-07-20 14:36:31 +00:00
|
|
|
} // namespace
|
|
|
|
|
|
|
|
namespace vm {
|
|
|
|
|
|
|
|
System*
|
2008-11-11 15:20:49 +00:00
|
|
|
makeSystem(const char*)
|
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
|