mirror of
https://github.com/corda/corda.git
synced 2024-12-29 09:18:58 +00:00
implement Thread.interrupt()
This commit is contained in:
parent
abd9c2bc8d
commit
0e373727a2
@ -7,14 +7,18 @@ public class Thread implements Runnable {
|
|||||||
private long peer;
|
private long peer;
|
||||||
private final Runnable task;
|
private final Runnable task;
|
||||||
private Map<ThreadLocal, Object> locals;
|
private Map<ThreadLocal, Object> locals;
|
||||||
private Object sleepLock;
|
|
||||||
private boolean interrupted;
|
private boolean interrupted;
|
||||||
|
private Object sleepLock;
|
||||||
|
|
||||||
public Thread(Runnable task) {
|
public Thread(Runnable task) {
|
||||||
this.task = task;
|
this.task = task;
|
||||||
}
|
}
|
||||||
|
|
||||||
public synchronized void start() {
|
public synchronized void start() {
|
||||||
|
if (peer != 0) {
|
||||||
|
throw new IllegalStateException("thread already started");
|
||||||
|
}
|
||||||
|
|
||||||
Map<ThreadLocal, Object> map = currentThread().locals;
|
Map<ThreadLocal, Object> map = currentThread().locals;
|
||||||
if (map != null) {
|
if (map != null) {
|
||||||
for (Map.Entry<ThreadLocal, Object> e: map.entrySet()) {
|
for (Map.Entry<ThreadLocal, Object> e: map.entrySet()) {
|
||||||
@ -45,6 +49,26 @@ public class Thread implements Runnable {
|
|||||||
|
|
||||||
public static native Thread currentThread();
|
public static native Thread currentThread();
|
||||||
|
|
||||||
|
private static native void interrupt(long peer);
|
||||||
|
|
||||||
|
public synchronized void interrupt() {
|
||||||
|
if (peer != 0) {
|
||||||
|
interrupt(peer);
|
||||||
|
} else {
|
||||||
|
interrupted = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean interrupted() {
|
||||||
|
Thread t = currentThread();
|
||||||
|
|
||||||
|
synchronized (t) {
|
||||||
|
boolean v = t.interrupted;
|
||||||
|
t.interrupted = false;
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static void sleep(long milliseconds) throws InterruptedException {
|
public static void sleep(long milliseconds) throws InterruptedException {
|
||||||
Thread t = currentThread();
|
Thread t = currentThread();
|
||||||
if (t.sleepLock == null) {
|
if (t.sleepLock == null) {
|
||||||
|
@ -598,51 +598,31 @@ Thread_currentThread(Thread* t, jclass)
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
Thread_start(Thread* t, jobject this_)
|
Thread_doStart(Thread* t, jobject this_)
|
||||||
{
|
{
|
||||||
Thread* p = reinterpret_cast<Thread*>(threadPeer(t, *this_));
|
Thread* p = new (t->vm->system->allocate(sizeof(Thread)))
|
||||||
if (p) {
|
Thread(t->vm, *this_, t);
|
||||||
object message = makeString(t, "thread already started");
|
|
||||||
t->exception = makeIllegalStateException(t, message);
|
|
||||||
} else {
|
|
||||||
p = new (t->vm->system->allocate(sizeof(Thread))) Thread(t->vm, *this_, t);
|
|
||||||
|
|
||||||
enter(p, Thread::ActiveState);
|
enter(p, Thread::ActiveState);
|
||||||
|
|
||||||
class Runnable: public System::Runnable {
|
threadPeer(t, *this_) = reinterpret_cast<jlong>(p);
|
||||||
public:
|
|
||||||
Runnable(System* s, Thread* t): s(s), t(t) { }
|
|
||||||
|
|
||||||
virtual void run(System::Thread* st) {
|
if (not t->vm->system->success(t->vm->system->start(&(p->runnable)))) {
|
||||||
t->systemThread = st;
|
threadPeer(t, *this_) = -1;
|
||||||
|
|
||||||
vm::run(t, "java/lang/Thread", "run", "()V", t->javaThread);
|
p->exit();
|
||||||
|
|
||||||
if (t->exception) {
|
object message = makeString(t, "unable to start native thread");
|
||||||
printTrace(t, t->exception);
|
t->exception = makeRuntimeException(t, message);
|
||||||
}
|
|
||||||
|
|
||||||
t->exit();
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual void dispose() {
|
|
||||||
s->free(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
System* s;
|
|
||||||
Thread* t;
|
|
||||||
}* r = new (t->vm->system->allocate(sizeof(Runnable)))
|
|
||||||
Runnable(t->vm->system, p);
|
|
||||||
|
|
||||||
if (not t->vm->system->success(t->vm->system->start(r))) {
|
|
||||||
p->exit();
|
|
||||||
|
|
||||||
object message = makeString(t, "unable to start native thread");
|
|
||||||
t->exception = makeRuntimeException(t, message);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Thread_interrupt(Thread* t, jclass, jlong peer)
|
||||||
|
{
|
||||||
|
interrupt(t, reinterpret_cast<Thread*>(peer));
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
namespace vm {
|
namespace vm {
|
||||||
@ -670,7 +650,9 @@ populateBuiltinMap(Thread* t, object map)
|
|||||||
reinterpret_cast<void*>(::Runtime_exit) },
|
reinterpret_cast<void*>(::Runtime_exit) },
|
||||||
|
|
||||||
{ "Java_java_lang_Thread_doStart",
|
{ "Java_java_lang_Thread_doStart",
|
||||||
reinterpret_cast<void*>(::Thread_start) },
|
reinterpret_cast<void*>(::Thread_doStart) },
|
||||||
|
{ "Java_java_lang_Thread_interrupt",
|
||||||
|
reinterpret_cast<void*>(::Thread_interrupt) },
|
||||||
{ "Java_java_lang_Thread_currentThread",
|
{ "Java_java_lang_Thread_currentThread",
|
||||||
reinterpret_cast<void*>(::Thread_currentThread) },
|
reinterpret_cast<void*>(::Thread_currentThread) },
|
||||||
|
|
||||||
|
@ -1322,7 +1322,8 @@ Thread::Thread(Machine* m, object javaThread, Thread* parent):
|
|||||||
sp(0),
|
sp(0),
|
||||||
frame(-1),
|
frame(-1),
|
||||||
heapIndex(0),
|
heapIndex(0),
|
||||||
protector(0)
|
protector(0),
|
||||||
|
runnable(this)
|
||||||
#ifdef VM_STRESS
|
#ifdef VM_STRESS
|
||||||
, stress(false),
|
, stress(false),
|
||||||
heap(static_cast<object*>(m->system->allocate(HeapSizeInBytes)))
|
heap(static_cast<object*>(m->system->allocate(HeapSizeInBytes)))
|
||||||
@ -1335,7 +1336,7 @@ Thread::Thread(Machine* m, object javaThread, Thread* parent):
|
|||||||
m->rootThread = this;
|
m->rootThread = this;
|
||||||
m->unsafe = true;
|
m->unsafe = true;
|
||||||
|
|
||||||
if (not m->system->success(m->system->attach(&systemThread))) {
|
if (not m->system->success(m->system->attach(&runnable))) {
|
||||||
abort(this);
|
abort(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1472,7 +1473,7 @@ enter(Thread* t, Thread::State s)
|
|||||||
t->vm->exclusive = t;
|
t->vm->exclusive = t;
|
||||||
|
|
||||||
while (t->vm->activeCount > 1) {
|
while (t->vm->activeCount > 1) {
|
||||||
t->vm->stateLock->wait(t, 0);
|
t->vm->stateLock->wait(t->systemThread, 0);
|
||||||
}
|
}
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
@ -1498,7 +1499,7 @@ enter(Thread* t, Thread::State s)
|
|||||||
}
|
}
|
||||||
t->state = s;
|
t->state = s;
|
||||||
|
|
||||||
t->vm->stateLock->notifyAll(t);
|
t->vm->stateLock->notifyAll(t->systemThread);
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case Thread::ActiveState: {
|
case Thread::ActiveState: {
|
||||||
@ -1509,13 +1510,13 @@ enter(Thread* t, Thread::State s)
|
|||||||
t->state = s;
|
t->state = s;
|
||||||
t->vm->exclusive = 0;
|
t->vm->exclusive = 0;
|
||||||
|
|
||||||
t->vm->stateLock->notifyAll(t);
|
t->vm->stateLock->notifyAll(t->systemThread);
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case Thread::NoState:
|
case Thread::NoState:
|
||||||
case Thread::IdleState: {
|
case Thread::IdleState: {
|
||||||
while (t->vm->exclusive) {
|
while (t->vm->exclusive) {
|
||||||
t->vm->stateLock->wait(t, 0);
|
t->vm->stateLock->wait(t->systemThread, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
++ t->vm->activeCount;
|
++ t->vm->activeCount;
|
||||||
@ -1547,7 +1548,7 @@ enter(Thread* t, Thread::State s)
|
|||||||
t->state = s;
|
t->state = s;
|
||||||
|
|
||||||
while (t->vm->liveCount > 1) {
|
while (t->vm->liveCount > 1) {
|
||||||
t->vm->stateLock->wait(t, 0);
|
t->vm->stateLock->wait(t->systemThread, 0);
|
||||||
}
|
}
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
|
@ -22,7 +22,7 @@ namespace vm {
|
|||||||
const bool Verbose = false;
|
const bool Verbose = false;
|
||||||
const bool DebugRun = false;
|
const bool DebugRun = false;
|
||||||
const bool DebugStack = false;
|
const bool DebugStack = false;
|
||||||
const bool DebugMonitors = true;
|
const bool DebugMonitors = false;
|
||||||
|
|
||||||
const uintptr_t HashTakenMark = 1;
|
const uintptr_t HashTakenMark = 1;
|
||||||
const uintptr_t ExtendedMark = 2;
|
const uintptr_t ExtendedMark = 2;
|
||||||
@ -1124,6 +1124,16 @@ class Machine {
|
|||||||
JNIEnvVTable jniEnvVTable;
|
JNIEnvVTable jniEnvVTable;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
object
|
||||||
|
run(Thread* t, const char* className, const char* methodName,
|
||||||
|
const char* methodSpec, object this_, ...);
|
||||||
|
|
||||||
|
void
|
||||||
|
printTrace(Thread* t, object exception);
|
||||||
|
|
||||||
|
uint8_t&
|
||||||
|
threadInterrupted(Thread* t, object thread);
|
||||||
|
|
||||||
class Thread {
|
class Thread {
|
||||||
public:
|
public:
|
||||||
enum State {
|
enum State {
|
||||||
@ -1151,6 +1161,35 @@ class Thread {
|
|||||||
Protector* next;
|
Protector* next;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class Runnable: public System::Runnable {
|
||||||
|
public:
|
||||||
|
Runnable(Thread* t): t(t) { }
|
||||||
|
|
||||||
|
virtual void attach(System::Thread* st) {
|
||||||
|
t->systemThread = st;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void run() {
|
||||||
|
vm::run(t, "java/lang/Thread", "run", "()V", t->javaThread);
|
||||||
|
|
||||||
|
if (t->exception) {
|
||||||
|
printTrace(t, t->exception);
|
||||||
|
}
|
||||||
|
|
||||||
|
t->exit();
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual bool interrupted() {
|
||||||
|
return threadInterrupted(t, t->javaThread);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void setInterrupted(bool v) {
|
||||||
|
threadInterrupted(t, t->javaThread) = v;
|
||||||
|
}
|
||||||
|
|
||||||
|
Thread* t;
|
||||||
|
};
|
||||||
|
|
||||||
static const unsigned HeapSizeInBytes = 64 * 1024;
|
static const unsigned HeapSizeInBytes = 64 * 1024;
|
||||||
static const unsigned StackSizeInBytes = 64 * 1024;
|
static const unsigned StackSizeInBytes = 64 * 1024;
|
||||||
|
|
||||||
@ -1178,6 +1217,7 @@ class Thread {
|
|||||||
int frame;
|
int frame;
|
||||||
unsigned heapIndex;
|
unsigned heapIndex;
|
||||||
Protector* protector;
|
Protector* protector;
|
||||||
|
Runnable runnable;
|
||||||
#ifdef VM_STRESS
|
#ifdef VM_STRESS
|
||||||
bool stress;
|
bool stress;
|
||||||
object* heap;
|
object* heap;
|
||||||
@ -1248,13 +1288,13 @@ class MonitorResource {
|
|||||||
MonitorResource(Thread* t, System::Monitor* m): t(t), m(m) {
|
MonitorResource(Thread* t, System::Monitor* m): t(t), m(m) {
|
||||||
stress(t);
|
stress(t);
|
||||||
|
|
||||||
if (not m->tryAcquire(t)) {
|
if (not m->tryAcquire(t->systemThread)) {
|
||||||
ENTER(t, Thread::IdleState);
|
ENTER(t, Thread::IdleState);
|
||||||
m->acquire(t);
|
m->acquire(t->systemThread);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
~MonitorResource() { m->release(t); }
|
~MonitorResource() { m->release(t->systemThread); }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Thread* t;
|
Thread* t;
|
||||||
@ -1264,10 +1304,10 @@ class MonitorResource {
|
|||||||
class RawMonitorResource {
|
class RawMonitorResource {
|
||||||
public:
|
public:
|
||||||
RawMonitorResource(Thread* t, System::Monitor* m): t(t), m(m) {
|
RawMonitorResource(Thread* t, System::Monitor* m): t(t), m(m) {
|
||||||
m->acquire(t);
|
m->acquire(t->systemThread);
|
||||||
}
|
}
|
||||||
|
|
||||||
~RawMonitorResource() { m->release(t); }
|
~RawMonitorResource() { m->release(t->systemThread); }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Thread* t;
|
Thread* t;
|
||||||
@ -1440,6 +1480,12 @@ makeInvocationTargetException(Thread* t, object targetException)
|
|||||||
return makeRuntimeException(t, 0, trace, targetException);
|
return makeRuntimeException(t, 0, trace, targetException);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline object
|
||||||
|
makeInterruptedException(Thread* t)
|
||||||
|
{
|
||||||
|
return makeInterruptedException(t, 0, makeTrace(t), 0);
|
||||||
|
}
|
||||||
|
|
||||||
inline object
|
inline object
|
||||||
makeStackOverflowError(Thread* t)
|
makeStackOverflowError(Thread* t)
|
||||||
{
|
{
|
||||||
@ -1986,9 +2032,9 @@ acquire(Thread* t, object o)
|
|||||||
t, m, objectHash(t, o));
|
t, m, objectHash(t, o));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (not m->tryAcquire(t)) {
|
if (not m->tryAcquire(t->systemThread)) {
|
||||||
ENTER(t, Thread::IdleState);
|
ENTER(t, Thread::IdleState);
|
||||||
m->acquire(t);
|
m->acquire(t->systemThread);
|
||||||
}
|
}
|
||||||
|
|
||||||
stress(t);
|
stress(t);
|
||||||
@ -2004,7 +2050,7 @@ release(Thread* t, object o)
|
|||||||
t, m, objectHash(t, o));
|
t, m, objectHash(t, o));
|
||||||
}
|
}
|
||||||
|
|
||||||
m->release(t);
|
m->release(t->systemThread);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void
|
inline void
|
||||||
@ -2017,9 +2063,13 @@ wait(Thread* t, object o, int64_t milliseconds)
|
|||||||
t, milliseconds, m, objectHash(t, o));
|
t, milliseconds, m, objectHash(t, o));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m->owner() == t) {
|
if (m->owner() == t->systemThread) {
|
||||||
ENTER(t, Thread::IdleState);
|
ENTER(t, Thread::IdleState);
|
||||||
m->wait(t, milliseconds);
|
|
||||||
|
bool interrupted = m->wait(t->systemThread, milliseconds);
|
||||||
|
if (interrupted) {
|
||||||
|
t->exception = makeInterruptedException(t);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
t->exception = makeIllegalMonitorStateException(t);
|
t->exception = makeIllegalMonitorStateException(t);
|
||||||
}
|
}
|
||||||
@ -2032,12 +2082,6 @@ wait(Thread* t, object o, int64_t milliseconds)
|
|||||||
stress(t);
|
stress(t);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void
|
|
||||||
vmWait(Thread* t, object o, int64_t milliseconds)
|
|
||||||
{
|
|
||||||
wait(t, o, milliseconds);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void
|
inline void
|
||||||
notify(Thread* t, object o)
|
notify(Thread* t, object o)
|
||||||
{
|
{
|
||||||
@ -2048,19 +2092,13 @@ notify(Thread* t, object o)
|
|||||||
t, m, objectHash(t, o));
|
t, m, objectHash(t, o));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m->owner() == t) {
|
if (m->owner() == t->systemThread) {
|
||||||
m->notify(t);
|
m->notify(t->systemThread);
|
||||||
} else {
|
} else {
|
||||||
t->exception = makeIllegalMonitorStateException(t);
|
t->exception = makeIllegalMonitorStateException(t);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void
|
|
||||||
vmNotify(Thread* t, object o)
|
|
||||||
{
|
|
||||||
notify(t, o);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void
|
inline void
|
||||||
notifyAll(Thread* t, object o)
|
notifyAll(Thread* t, object o)
|
||||||
{
|
{
|
||||||
@ -2071,22 +2109,19 @@ notifyAll(Thread* t, object o)
|
|||||||
t, m, objectHash(t, o));
|
t, m, objectHash(t, o));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m->owner() == t) {
|
if (m->owner() == t->systemThread) {
|
||||||
m->notifyAll(t);
|
m->notifyAll(t->systemThread);
|
||||||
} else {
|
} else {
|
||||||
t->exception = makeIllegalMonitorStateException(t);
|
t->exception = makeIllegalMonitorStateException(t);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void
|
inline void
|
||||||
vmNotifyAll(Thread* t, object o)
|
interrupt(Thread*, Thread* target)
|
||||||
{
|
{
|
||||||
notifyAll(t, o);
|
target->systemThread->interrupt();
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
|
||||||
printTrace(Thread* t, object exception);
|
|
||||||
|
|
||||||
void
|
void
|
||||||
exit(Thread* t);
|
exit(Thread* t);
|
||||||
|
|
||||||
|
231
src/system.cpp
231
src/system.cpp
@ -7,10 +7,14 @@
|
|||||||
#include "dlfcn.h"
|
#include "dlfcn.h"
|
||||||
#include "errno.h"
|
#include "errno.h"
|
||||||
#include "pthread.h"
|
#include "pthread.h"
|
||||||
|
#include "signal.h"
|
||||||
#include "stdint.h"
|
#include "stdint.h"
|
||||||
|
|
||||||
#include "system.h"
|
#include "system.h"
|
||||||
|
|
||||||
|
#define ACQUIRE(x) MutexResource MAKE_NAME(mutexResource_) (x)
|
||||||
|
|
||||||
|
|
||||||
#ifdef __i386__
|
#ifdef __i386__
|
||||||
|
|
||||||
extern "C" uint64_t
|
extern "C" uint64_t
|
||||||
@ -86,6 +90,28 @@ using namespace vm;
|
|||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
void
|
||||||
|
handleSignal(int)
|
||||||
|
{
|
||||||
|
// ignore
|
||||||
|
}
|
||||||
|
|
||||||
int64_t
|
int64_t
|
||||||
now()
|
now()
|
||||||
{
|
{
|
||||||
@ -96,22 +122,39 @@ now()
|
|||||||
}
|
}
|
||||||
|
|
||||||
void*
|
void*
|
||||||
run(void* t)
|
run(void* r)
|
||||||
{
|
{
|
||||||
static_cast<System::Thread*>(t)->run();
|
static_cast<System::Runnable*>(r)->run();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
const bool Verbose = false;
|
const bool Verbose = false;
|
||||||
|
|
||||||
|
const unsigned Waiting = 1 << 0;
|
||||||
|
const unsigned Notified = 1 << 1;
|
||||||
|
|
||||||
class MySystem: public System {
|
class MySystem: public System {
|
||||||
public:
|
public:
|
||||||
class Thread: public System::Thread {
|
class Thread: public System::Thread {
|
||||||
public:
|
public:
|
||||||
Thread(System* s, System::Runnable* r): s(s), r(r) { }
|
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 run() {
|
virtual void interrupt() {
|
||||||
r->run(this);
|
ACQUIRE(mutex);
|
||||||
|
|
||||||
|
r->setInterrupted(true);
|
||||||
|
|
||||||
|
if (flags & Waiting) {
|
||||||
|
pthread_kill(thread, InterruptSignal);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void join() {
|
virtual void join() {
|
||||||
@ -120,26 +163,28 @@ class MySystem: public System {
|
|||||||
}
|
}
|
||||||
|
|
||||||
virtual void dispose() {
|
virtual void dispose() {
|
||||||
if (r) {
|
|
||||||
r->dispose();
|
|
||||||
}
|
|
||||||
s->free(this);
|
s->free(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pthread_t thread;
|
||||||
|
pthread_mutex_t mutex;
|
||||||
|
pthread_cond_t condition;
|
||||||
System* s;
|
System* s;
|
||||||
System::Runnable* r;
|
System::Runnable* r;
|
||||||
pthread_t thread;
|
Thread* next;
|
||||||
|
unsigned flags;
|
||||||
};
|
};
|
||||||
|
|
||||||
class Monitor: public System::Monitor {
|
class Monitor: public System::Monitor {
|
||||||
public:
|
public:
|
||||||
Monitor(System* s): s(s), context(0), depth(0) {
|
Monitor(System* s): s(s), owner_(0), first(0), last(0), depth(0) {
|
||||||
pthread_mutex_init(&mutex, 0);
|
pthread_mutex_init(&mutex, 0);
|
||||||
pthread_cond_init(&condition, 0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual bool tryAcquire(void* context) {
|
virtual bool tryAcquire(System::Thread* context) {
|
||||||
if (this->context == context) {
|
Thread* t = static_cast<Thread*>(context);
|
||||||
|
|
||||||
|
if (owner_ == t) {
|
||||||
++ depth;
|
++ depth;
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
@ -148,7 +193,7 @@ class MySystem: public System {
|
|||||||
return false;
|
return false;
|
||||||
|
|
||||||
case 0:
|
case 0:
|
||||||
this->context = context;
|
owner_ = t;
|
||||||
++ depth;
|
++ depth;
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
@ -158,18 +203,22 @@ class MySystem: public System {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void acquire(void* context) {
|
virtual void acquire(System::Thread* context) {
|
||||||
if (this->context != context) {
|
Thread* t = static_cast<Thread*>(context);
|
||||||
|
|
||||||
|
if (owner_ != t) {
|
||||||
pthread_mutex_lock(&mutex);
|
pthread_mutex_lock(&mutex);
|
||||||
this->context = context;
|
owner_ = t;
|
||||||
}
|
}
|
||||||
++ depth;
|
++ depth;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void release(void* context) {
|
virtual void release(System::Thread* context) {
|
||||||
if (this->context == context) {
|
Thread* t = static_cast<Thread*>(context);
|
||||||
|
|
||||||
|
if (owner_ == t) {
|
||||||
if (-- depth == 0) {
|
if (-- depth == 0) {
|
||||||
this->context = 0;
|
owner_ = 0;
|
||||||
pthread_mutex_unlock(&mutex);
|
pthread_mutex_unlock(&mutex);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -177,60 +226,139 @@ class MySystem: public System {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void wait(void* context, int64_t time) {
|
void append(Thread* t) {
|
||||||
if (this->context == context) {
|
if (last) {
|
||||||
|
last->next = t;
|
||||||
|
} else {
|
||||||
|
first = last = t;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void remove(Thread* t) {
|
||||||
|
for (Thread** p = &first; *p;) {
|
||||||
|
if (t == *p) {
|
||||||
|
*p = t->next;
|
||||||
|
if (last == t) {
|
||||||
|
last = 0;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
p = &((*p)->next);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual bool wait(System::Thread* context, int64_t time) {
|
||||||
|
Thread* t = static_cast<Thread*>(context);
|
||||||
|
|
||||||
|
if (owner_ == t) {
|
||||||
|
ACQUIRE(t->mutex);
|
||||||
|
|
||||||
|
if (t->r->interrupted()) {
|
||||||
|
t->r->setInterrupted(false);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
t->flags |= Waiting;
|
||||||
|
|
||||||
|
append(t);
|
||||||
|
|
||||||
unsigned depth = this->depth;
|
unsigned depth = this->depth;
|
||||||
this->depth = 0;
|
this->depth = 0;
|
||||||
this->context = 0;
|
owner_ = 0;
|
||||||
|
pthread_mutex_unlock(&mutex);
|
||||||
|
|
||||||
if (time) {
|
if (time) {
|
||||||
int64_t then = now() + time;
|
int64_t then = now() + time;
|
||||||
timespec ts = { then / 1000, (then % 1000) * 1000 * 1000 };
|
timespec ts = { then / 1000, (then % 1000) * 1000 * 1000 };
|
||||||
int rv = pthread_cond_timedwait(&condition, &mutex, &ts);
|
int rv = pthread_cond_timedwait
|
||||||
assert(s, rv == 0 or rv == ETIMEDOUT);
|
(&(t->condition), &(t->mutex), &ts);
|
||||||
|
assert(s, rv == 0 or rv == ETIMEDOUT or rv == EINTR);
|
||||||
} else {
|
} else {
|
||||||
int rv = pthread_cond_wait(&condition, &mutex);
|
int rv = pthread_cond_wait(&(t->condition), &(t->mutex));
|
||||||
assert(s, rv == 0);
|
assert(s, rv == 0 or rv == EINTR);
|
||||||
}
|
}
|
||||||
this->context = context;
|
|
||||||
|
pthread_mutex_lock(&mutex);
|
||||||
|
owner_ = t;
|
||||||
this->depth = depth;
|
this->depth = depth;
|
||||||
|
|
||||||
|
if ((t->flags & Notified) == 0) {
|
||||||
|
remove(t);
|
||||||
|
}
|
||||||
|
|
||||||
|
t->flags = 0;
|
||||||
|
|
||||||
|
if (t->r->interrupted()) {
|
||||||
|
t->r->setInterrupted(false);
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
sysAbort(s);
|
sysAbort(s);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void notify(void* context) {
|
void doNotify(Thread* t) {
|
||||||
if (this->context == context) {
|
ACQUIRE(t->mutex);
|
||||||
int rv = pthread_cond_signal(&condition);
|
|
||||||
assert(s, rv == 0);
|
t->flags |= Notified;
|
||||||
|
int rv = pthread_cond_signal(&(t->condition));
|
||||||
|
assert(s, rv == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
sysAbort(s);
|
sysAbort(s);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void notifyAll(void* context) {
|
virtual void notifyAll(System::Thread* context) {
|
||||||
if (this->context == context) {
|
Thread* t = static_cast<Thread*>(context);
|
||||||
int rv = pthread_cond_broadcast(&condition);
|
|
||||||
assert(s, rv == 0);
|
if (owner_ == t) {
|
||||||
|
for (Thread** p = &first; *p;) {
|
||||||
|
Thread* t = *p;
|
||||||
|
p = &(t->next);
|
||||||
|
if (t == last) {
|
||||||
|
last = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
doNotify(t);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
sysAbort(s);
|
sysAbort(s);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void* owner() {
|
virtual System::Thread* owner() {
|
||||||
return context;
|
return owner_;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void dispose() {
|
virtual void dispose() {
|
||||||
assert(s, context == 0);
|
assert(s, owner_ == 0);
|
||||||
pthread_mutex_destroy(&mutex);
|
pthread_mutex_destroy(&mutex);
|
||||||
pthread_cond_destroy(&condition);
|
|
||||||
s->free(this);
|
s->free(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
System* s;
|
System* s;
|
||||||
pthread_mutex_t mutex;
|
pthread_mutex_t mutex;
|
||||||
pthread_cond_t condition;
|
Thread* owner_;
|
||||||
void* context;
|
Thread* first;
|
||||||
|
Thread* last;
|
||||||
unsigned depth;
|
unsigned depth;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -278,6 +406,14 @@ class MySystem: public System {
|
|||||||
|
|
||||||
MySystem(unsigned limit): limit(limit), count(0) {
|
MySystem(unsigned limit): limit(limit), count(0) {
|
||||||
pthread_mutex_init(&mutex, 0);
|
pthread_mutex_init(&mutex, 0);
|
||||||
|
|
||||||
|
struct sigaction sa;
|
||||||
|
memset(&sa, 0, sizeof(struct sigaction));
|
||||||
|
sigemptyset(&(sa.sa_mask));
|
||||||
|
sa.sa_handler = handleSignal;
|
||||||
|
|
||||||
|
int rv = sigaction(InterruptSignal, &sa, 0);
|
||||||
|
assert(this, rv == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual bool success(Status s) {
|
virtual bool success(Status s) {
|
||||||
@ -332,16 +468,17 @@ class MySystem: public System {
|
|||||||
pthread_mutex_unlock(&mutex);
|
pthread_mutex_unlock(&mutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual Status attach(System::Thread** tp) {
|
virtual Status attach(Runnable* r) {
|
||||||
Thread* t = new (System::allocate(sizeof(Thread))) Thread(this, 0);
|
Thread* t = new (System::allocate(sizeof(Thread))) Thread(this, r);
|
||||||
t->thread = pthread_self();
|
t->thread = pthread_self();
|
||||||
*tp = t;
|
r->attach(t);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual Status start(Runnable* r) {
|
virtual Status start(Runnable* r) {
|
||||||
Thread* t = new (System::allocate(sizeof(Thread))) Thread(this, r);
|
Thread* t = new (System::allocate(sizeof(Thread))) Thread(this, r);
|
||||||
int rv = pthread_create(&(t->thread), 0, run, t);
|
r->attach(t);
|
||||||
|
int rv = pthread_create(&(t->thread), 0, run, r);
|
||||||
assert(this, rv == 0);
|
assert(this, rv == 0);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
32
src/system.h
32
src/system.h
@ -20,7 +20,7 @@ class System: public Allocator {
|
|||||||
class Thread {
|
class Thread {
|
||||||
public:
|
public:
|
||||||
virtual ~Thread() { }
|
virtual ~Thread() { }
|
||||||
virtual void run() = 0;
|
virtual void interrupt() = 0;
|
||||||
virtual void join() = 0;
|
virtual void join() = 0;
|
||||||
virtual void dispose() = 0;
|
virtual void dispose() = 0;
|
||||||
};
|
};
|
||||||
@ -28,20 +28,22 @@ class System: public Allocator {
|
|||||||
class Runnable {
|
class Runnable {
|
||||||
public:
|
public:
|
||||||
virtual ~Runnable() { }
|
virtual ~Runnable() { }
|
||||||
virtual void run(Thread*) = 0;
|
virtual void attach(Thread*) = 0;
|
||||||
virtual void dispose() = 0;
|
virtual void run() = 0;
|
||||||
|
virtual bool interrupted() = 0;
|
||||||
|
virtual void setInterrupted(bool v) = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
class Monitor {
|
class Monitor {
|
||||||
public:
|
public:
|
||||||
virtual ~Monitor() { }
|
virtual ~Monitor() { }
|
||||||
virtual bool tryAcquire(void* context) = 0;
|
virtual bool tryAcquire(Thread* context) = 0;
|
||||||
virtual void acquire(void* context) = 0;
|
virtual void acquire(Thread* context) = 0;
|
||||||
virtual void release(void* context) = 0;
|
virtual void release(Thread* context) = 0;
|
||||||
virtual void wait(void* context, int64_t time) = 0;
|
virtual bool wait(Thread* context, int64_t time) = 0;
|
||||||
virtual void notify(void* context) = 0;
|
virtual void notify(Thread* context) = 0;
|
||||||
virtual void notifyAll(void* context) = 0;
|
virtual void notifyAll(Thread* context) = 0;
|
||||||
virtual void* owner() = 0;
|
virtual Thread* owner() = 0;
|
||||||
virtual void dispose() = 0;
|
virtual void dispose() = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -57,7 +59,7 @@ class System: public Allocator {
|
|||||||
virtual ~System() { }
|
virtual ~System() { }
|
||||||
|
|
||||||
virtual bool success(Status) = 0;
|
virtual bool success(Status) = 0;
|
||||||
virtual Status attach(Thread**) = 0;
|
virtual Status attach(Runnable*) = 0;
|
||||||
virtual Status start(Runnable*) = 0;
|
virtual Status start(Runnable*) = 0;
|
||||||
virtual Status make(Monitor**) = 0;
|
virtual Status make(Monitor**) = 0;
|
||||||
virtual uint64_t call(void* function, uintptr_t* arguments, uint8_t* types,
|
virtual uint64_t call(void* function, uintptr_t* arguments, uint8_t* types,
|
||||||
@ -97,16 +99,20 @@ expect(System* s, bool v)
|
|||||||
}
|
}
|
||||||
|
|
||||||
#ifdef NDEBUG
|
#ifdef NDEBUG
|
||||||
|
|
||||||
inline void
|
inline void
|
||||||
assert(System*, bool)
|
assert(System*, bool)
|
||||||
{ }
|
{ }
|
||||||
#else
|
|
||||||
|
#else // not NDEBUG
|
||||||
|
|
||||||
inline void
|
inline void
|
||||||
assert(System* s, bool v)
|
assert(System* s, bool v)
|
||||||
{
|
{
|
||||||
expect(s, v);
|
expect(s, v);
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
#endif // not NDEBUG
|
||||||
|
|
||||||
System*
|
System*
|
||||||
makeSystem(unsigned heapSize);
|
makeSystem(unsigned heapSize);
|
||||||
|
@ -128,8 +128,8 @@
|
|||||||
(int64_t peer)
|
(int64_t peer)
|
||||||
(object task)
|
(object task)
|
||||||
(object locals)
|
(object locals)
|
||||||
(object sleepLock)
|
(uint8_t interrupted)
|
||||||
(uint8_t interrupted))
|
(object sleepLock))
|
||||||
|
|
||||||
(type stackTraceElement java/lang/StackTraceElement
|
(type stackTraceElement java/lang/StackTraceElement
|
||||||
(extends jobject)
|
(extends jobject)
|
||||||
@ -181,6 +181,9 @@
|
|||||||
(type invocationTargetException java/lang/InvocationTargetException
|
(type invocationTargetException java/lang/InvocationTargetException
|
||||||
(extends exception))
|
(extends exception))
|
||||||
|
|
||||||
|
(type interruptedException java/lang/InterruptedException
|
||||||
|
(extends exception))
|
||||||
|
|
||||||
(type error java/lang/Error
|
(type error java/lang/Error
|
||||||
(extends throwable))
|
(extends throwable))
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user