ensure Thread::flags is always updated atomically

Since this field is sometimes updated from other threads, it is
essential that we always update it atomically.
This commit is contained in:
Joel Dice 2014-08-20 09:49:00 -06:00
parent e1074c026c
commit 32aefaf421
6 changed files with 69 additions and 53 deletions

View File

@ -1111,15 +1111,17 @@ class Thread {
ExitState ExitState
}; };
static const unsigned UseBackupHeapFlag = 1 << 0; enum Flag {
static const unsigned WaitingFlag = 1 << 1; UseBackupHeapFlag = 1 << 0,
static const unsigned TracingFlag = 1 << 2; WaitingFlag = 1 << 1,
static const unsigned DaemonFlag = 1 << 3; TracingFlag = 1 << 2,
static const unsigned StressFlag = 1 << 4; DaemonFlag = 1 << 3,
static const unsigned ActiveFlag = 1 << 5; StressFlag = 1 << 4,
static const unsigned SystemFlag = 1 << 6; ActiveFlag = 1 << 5,
static const unsigned JoinFlag = 1 << 7; SystemFlag = 1 << 6,
static const unsigned TryNativeFlag = 1 << 8; JoinFlag = 1 << 7,
TryNativeFlag = 1 << 8
};
class Protector { class Protector {
public: public:
@ -1301,6 +1303,18 @@ class Thread {
void exit(); void exit();
void dispose(); void dispose();
void setFlag(Flag flag) {
atomicOr(&flags, flag);
}
void clearFlag(Flag flag) {
atomicAnd(&flags, ~flag);
}
unsigned getFlags() {
return flags;
}
JNIEnvVTable* vtable; JNIEnvVTable* vtable;
Machine* m; Machine* m;
Thread* parent; Thread* parent;
@ -1325,6 +1339,8 @@ class Thread {
uintptr_t* heap; uintptr_t* heap;
uintptr_t backupHeap[ThreadBackupHeapSizeInWords]; uintptr_t backupHeap[ThreadBackupHeapSizeInWords];
unsigned backupHeapIndex; unsigned backupHeapIndex;
private:
unsigned flags; unsigned flags;
}; };
@ -1496,9 +1512,9 @@ void shutDown(Thread* t);
inline void stress(Thread* t) inline void stress(Thread* t)
{ {
if ((not t->m->unsafe) if ((not t->m->unsafe)
and (t->flags & (Thread::StressFlag | Thread::TracingFlag)) == 0 and (t->getFlags() & (Thread::StressFlag | Thread::TracingFlag)) == 0
and t->state != Thread::NoState and t->state != Thread::IdleState) { and t->state != Thread::NoState and t->state != Thread::IdleState) {
atomicOr(&(t->flags), Thread::StressFlag); t->setFlag(Thread::StressFlag);
#ifdef VM_STRESS_MAJOR #ifdef VM_STRESS_MAJOR
collect(t, Heap::MajorCollection); collect(t, Heap::MajorCollection);
@ -1506,7 +1522,7 @@ inline void stress(Thread* t)
collect(t, Heap::MinorCollection); collect(t, Heap::MinorCollection);
#endif // not VM_STRESS_MAJOR #endif // not VM_STRESS_MAJOR
atomicAnd(&(t->flags), ~Thread::StressFlag); t->clearFlag(Thread::StressFlag);
} }
} }
@ -1581,9 +1597,9 @@ inline bool ensure(Thread* t, unsigned sizeInBytes)
if (t->heapIndex + ceilingDivide(sizeInBytes, BytesPerWord) if (t->heapIndex + ceilingDivide(sizeInBytes, BytesPerWord)
> ThreadHeapSizeInWords) { > ThreadHeapSizeInWords) {
if (sizeInBytes <= ThreadBackupHeapSizeInBytes) { if (sizeInBytes <= ThreadBackupHeapSizeInBytes) {
expect(t, (t->flags & Thread::UseBackupHeapFlag) == 0); expect(t, (t->getFlags() & Thread::UseBackupHeapFlag) == 0);
atomicOr(&(t->flags), Thread::UseBackupHeapFlag); t->setFlag(Thread::UseBackupHeapFlag);
return true; return true;
} else { } else {
@ -1790,7 +1806,7 @@ inline uint64_t runThread(Thread* t, uintptr_t*)
inline bool startThread(Thread* t, Thread* p) inline bool startThread(Thread* t, Thread* p)
{ {
p->flags |= Thread::JoinFlag; p->setFlag(Thread::JoinFlag);
return t->m->system->success(t->m->system->start(&(p->runnable))); return t->m->system->success(t->m->system->start(&(p->runnable)));
} }
@ -1865,7 +1881,7 @@ inline void registerDaemon(Thread* t)
{ {
ACQUIRE_RAW(t, t->m->stateLock); ACQUIRE_RAW(t, t->m->stateLock);
atomicOr(&(t->flags), Thread::DaemonFlag); t->setFlag(Thread::DaemonFlag);
++t->m->daemonCount; ++t->m->daemonCount;
@ -2698,7 +2714,7 @@ inline bool acquireSystem(Thread* t, Thread* target)
ACQUIRE_RAW(t, t->m->stateLock); ACQUIRE_RAW(t, t->m->stateLock);
if (t->state != Thread::JoinedState) { if (t->state != Thread::JoinedState) {
atomicOr(&(target->flags), Thread::SystemFlag); target->setFlag(Thread::SystemFlag);
return true; return true;
} else { } else {
return false; return false;
@ -2711,7 +2727,7 @@ inline void releaseSystem(Thread* t, Thread* target)
assertT(t, t->state != Thread::JoinedState); assertT(t, t->state != Thread::JoinedState);
atomicAnd(&(target->flags), ~Thread::SystemFlag); target->clearFlag(Thread::SystemFlag);
} }
inline bool atomicCompareAndSwapObject(Thread* t, inline bool atomicCompareAndSwapObject(Thread* t,
@ -2875,10 +2891,10 @@ inline void monitorAppendWait(Thread* t, GcMonitor* monitor)
{ {
assertT(t, monitor->owner() == t); assertT(t, monitor->owner() == t);
expect(t, (t->flags & Thread::WaitingFlag) == 0); expect(t, (t->getFlags() & Thread::WaitingFlag) == 0);
expect(t, t->waitNext == 0); expect(t, t->waitNext == 0);
atomicOr(&(t->flags), Thread::WaitingFlag); t->setFlag(Thread::WaitingFlag);
if (monitor->waitTail()) { if (monitor->waitTail()) {
static_cast<Thread*>(monitor->waitTail())->waitNext = t; static_cast<Thread*>(monitor->waitTail())->waitNext = t;
@ -2909,7 +2925,7 @@ inline void monitorRemoveWait(Thread* t, GcMonitor* monitor)
} }
t->waitNext = 0; t->waitNext = 0;
atomicAnd(&(t->flags), ~Thread::WaitingFlag); t->clearFlag(Thread::WaitingFlag);
return; return;
} else { } else {
@ -2967,7 +2983,7 @@ inline bool monitorWait(Thread* t, GcMonitor* monitor, int64_t time)
monitor->depth() = depth; monitor->depth() = depth;
if (t->flags & Thread::WaitingFlag) { if (t->getFlags() & Thread::WaitingFlag) {
monitorRemoveWait(t, monitor); monitorRemoveWait(t, monitor);
} else { } else {
expect(t, not monitorFindWait(t, monitor)); expect(t, not monitorFindWait(t, monitor));
@ -2986,7 +3002,7 @@ inline Thread* monitorPollWait(Thread* t UNUSED, GcMonitor* monitor)
if (next) { if (next) {
monitor->waitHead() = next->waitNext; monitor->waitHead() = next->waitNext;
atomicAnd(&(next->flags), ~Thread::WaitingFlag); next->clearFlag(Thread::WaitingFlag);
next->waitNext = 0; next->waitNext = 0;
if (next == monitor->waitTail()) { if (next == monitor->waitTail()) {
monitor->waitTail() = 0; monitor->waitTail() = 0;
@ -3099,7 +3115,7 @@ inline void wait(Thread* t, object o, int64_t milliseconds)
bool interrupted = monitorWait(t, m, milliseconds); bool interrupted = monitorWait(t, m, milliseconds);
if (interrupted) { if (interrupted) {
if (t->m->alive or (t->flags & Thread::DaemonFlag) == 0) { if (t->m->alive or (t->getFlags() & Thread::DaemonFlag) == 0) {
t->m->classpath->clearInterrupted(t); t->m->classpath->clearInterrupted(t);
throwNew(t, GcInterruptedException::Type); throwNew(t, GcInterruptedException::Type);
} else { } else {

View File

@ -317,8 +317,8 @@ extern "C" AVIAN_EXPORT int64_t JNICALL
int64_t argument; int64_t argument;
memcpy(&argument, arguments + 2, 8); memcpy(&argument, arguments + 2, 8);
t->flags |= Thread::TryNativeFlag; t->setFlag(Thread::TryNativeFlag);
THREAD_RESOURCE0(t, t->flags &= ~Thread::TryNativeFlag); THREAD_RESOURCE0(t, t->clearFlag(Thread::TryNativeFlag));
return reinterpret_cast<int64_t (*)(int64_t)>(function)(argument); return reinterpret_cast<int64_t (*)(int64_t)>(function)(argument);
} }

View File

@ -391,7 +391,7 @@ class MyClasspath : public Classpath {
} }
vm::acquire(t, t->javaThread); vm::acquire(t, t->javaThread);
t->flags &= ~Thread::ActiveFlag; t->clearFlag(Thread::ActiveFlag);
vm::notifyAll(t, t->javaThread); vm::notifyAll(t, t->javaThread);
vm::release(t, t->javaThread); vm::release(t, t->javaThread);
}); });

View File

@ -582,7 +582,7 @@ class MyClasspath : public Classpath {
THREAD_RESOURCE0(t, { THREAD_RESOURCE0(t, {
vm::acquire(t, t->javaThread); vm::acquire(t, t->javaThread);
t->flags &= ~Thread::ActiveFlag; t->clearFlag(Thread::ActiveFlag);
vm::notifyAll(t, t->javaThread); vm::notifyAll(t, t->javaThread);
vm::release(t, t->javaThread); vm::release(t, t->javaThread);
@ -3624,7 +3624,7 @@ extern "C" AVIAN_EXPORT jboolean JNICALL
ENTER(t, Thread::ActiveState); ENTER(t, Thread::ActiveState);
Thread* p = reinterpret_cast<Thread*>(cast<GcThread>(t, *thread)->peer()); Thread* p = reinterpret_cast<Thread*>(cast<GcThread>(t, *thread)->peer());
return p and (p->flags & Thread::ActiveFlag) != 0; return p and (p->getFlags() & Thread::ActiveFlag) != 0;
} }
extern "C" AVIAN_EXPORT void JNICALL EXPORT(JVM_SuspendThread)(Thread*, jobject) extern "C" AVIAN_EXPORT void JNICALL EXPORT(JVM_SuspendThread)(Thread*, jobject)

View File

@ -2494,8 +2494,8 @@ unsigned traceSize(Thread* t)
void NO_RETURN throwArithmetic(MyThread* t) void NO_RETURN throwArithmetic(MyThread* t)
{ {
if (ensure(t, GcArithmeticException::FixedSize + traceSize(t))) { if (ensure(t, GcArithmeticException::FixedSize + traceSize(t))) {
atomicOr(&(t->flags), Thread::TracingFlag); t->setFlag(Thread::TracingFlag);
THREAD_RESOURCE0(t, atomicAnd(&(t->flags), ~Thread::TracingFlag)); THREAD_RESOURCE0(t, t->clearFlag(Thread::TracingFlag));
throwNew(t, GcArithmeticException::Type); throwNew(t, GcArithmeticException::Type);
} else { } else {
@ -2706,8 +2706,8 @@ uint64_t makeMultidimensionalArrayFromReference(MyThread* t,
void NO_RETURN throwArrayIndexOutOfBounds(MyThread* t) void NO_RETURN throwArrayIndexOutOfBounds(MyThread* t)
{ {
if (ensure(t, GcArrayIndexOutOfBoundsException::FixedSize + traceSize(t))) { if (ensure(t, GcArrayIndexOutOfBoundsException::FixedSize + traceSize(t))) {
atomicOr(&(t->flags), Thread::TracingFlag); t->setFlag(Thread::TracingFlag);
THREAD_RESOURCE0(t, atomicAnd(&(t->flags), ~Thread::TracingFlag)); THREAD_RESOURCE0(t, t->clearFlag(Thread::TracingFlag));
throwNew(t, GcArrayIndexOutOfBoundsException::Type); throwNew(t, GcArrayIndexOutOfBoundsException::Type);
} else { } else {
@ -3006,7 +3006,7 @@ void gcIfNecessary(MyThread* t)
{ {
stress(t); stress(t);
if (UNLIKELY(t->flags & Thread::UseBackupHeapFlag)) { if (UNLIKELY(t->getFlags() & Thread::UseBackupHeapFlag)) {
collect(t, Heap::MinorCollection); collect(t, Heap::MinorCollection);
} }
} }
@ -8116,7 +8116,7 @@ object invoke(Thread* thread, GcMethod* method, ArgumentList* arguments)
} }
if (t->exception) { if (t->exception) {
if (UNLIKELY(t->flags & Thread::UseBackupHeapFlag)) { if (UNLIKELY(t->getFlags() & Thread::UseBackupHeapFlag)) {
collect(t, Heap::MinorCollection); collect(t, Heap::MinorCollection);
} }
@ -8166,9 +8166,9 @@ class SignalHandler : public SignalRegistrar::Handler {
void setException(MyThread* t) { void setException(MyThread* t) {
if (ensure(t, pad(fixedSize) + traceSize(t))) { if (ensure(t, pad(fixedSize) + traceSize(t))) {
atomicOr(&(t->flags), Thread::TracingFlag); t->setFlag(Thread::TracingFlag);
t->exception = makeThrowable(t, type); t->exception = makeThrowable(t, type);
atomicAnd(&(t->flags), ~Thread::TracingFlag); t->clearFlag(Thread::TracingFlag);
} else { } else {
// not enough memory available for a new exception and stack // not enough memory available for a new exception and stack
// trace -- use a preallocated instance instead // trace -- use a preallocated instance instead
@ -8183,7 +8183,7 @@ class SignalHandler : public SignalRegistrar::Handler {
{ {
MyThread* t = static_cast<MyThread*>(m->localThread->get()); MyThread* t = static_cast<MyThread*>(m->localThread->get());
if (t and t->state == Thread::ActiveState) { if (t and t->state == Thread::ActiveState) {
if (t->flags & Thread::TryNativeFlag) { if (t->getFlags() & Thread::TryNativeFlag) {
setException(t); setException(t);
popResources(t); popResources(t);
@ -8873,9 +8873,9 @@ class MyProcessor : public Processor {
} }
if (ensure(t, traceSize(target))) { if (ensure(t, traceSize(target))) {
atomicOr(&(t->flags), Thread::TracingFlag); t->setFlag(Thread::TracingFlag);
trace = makeTrace(t, target); trace = makeTrace(t, target);
atomicAnd(&(t->flags), ~Thread::TracingFlag); t->clearFlag(Thread::TracingFlag);
} }
} }
@ -8887,7 +8887,7 @@ class MyProcessor : public Processor {
t->m->system->visit(t->systemThread, target->systemThread, &visitor); t->m->system->visit(t->systemThread, target->systemThread, &visitor);
if (UNLIKELY(t->flags & Thread::UseBackupHeapFlag)) { if (UNLIKELY(t->getFlags() & Thread::UseBackupHeapFlag)) {
PROTECT(t, visitor.trace); PROTECT(t, visitor.trace);
collect(t, Heap::MinorCollection); collect(t, Heap::MinorCollection);

View File

@ -47,8 +47,8 @@ void join(Thread* t, Thread* o)
{ {
if (t != o) { if (t != o) {
assertT(t, o->state != Thread::JoinedState); assertT(t, o->state != Thread::JoinedState);
assertT(t, (o->flags & Thread::SystemFlag) == 0); assertT(t, (o->getFlags() & Thread::SystemFlag) == 0);
if (o->flags & Thread::JoinFlag) { if (o->getFlags() & Thread::JoinFlag) {
o->systemThread->join(); o->systemThread->join();
} }
o->state = Thread::JoinedState; o->state = Thread::JoinedState;
@ -170,7 +170,7 @@ void disposeNoRemove(Thread* m, Thread* o)
void interruptDaemon(Thread* m, Thread* o) void interruptDaemon(Thread* m, Thread* o)
{ {
if (o->flags & Thread::DaemonFlag) { if (o->getFlags() & Thread::DaemonFlag) {
interrupt(m, o); interrupt(m, o);
} }
} }
@ -257,7 +257,7 @@ void killZombies(Thread* t, Thread* o)
killZombies(t, child); killZombies(t, child);
} }
if ((o->flags & Thread::SystemFlag) == 0) { if ((o->getFlags() & Thread::SystemFlag) == 0) {
switch (o->state) { switch (o->state) {
case Thread::ZombieState: case Thread::ZombieState:
join(t, o); join(t, o);
@ -689,10 +689,10 @@ void postCollect(Thread* t)
t->heapIndex = 0; t->heapIndex = 0;
} }
if (t->flags & Thread::UseBackupHeapFlag) { if (t->getFlags() & Thread::UseBackupHeapFlag) {
memset(t->backupHeap, 0, ThreadBackupHeapSizeInBytes); memset(t->backupHeap, 0, ThreadBackupHeapSizeInBytes);
t->flags &= ~Thread::UseBackupHeapFlag; t->clearFlag(Thread::UseBackupHeapFlag);
t->backupHeapIndex = 0; t->backupHeapIndex = 0;
} }
@ -3441,9 +3441,9 @@ void doCollect(Thread* t, Heap::CollectionType type, int pendingAllocation)
THREAD_RESOURCE0(t, t->m->collecting = false); THREAD_RESOURCE0(t, t->m->collecting = false);
#ifdef VM_STRESS #ifdef VM_STRESS
bool stress = (t->flags & Thread::StressFlag) != 0; bool stress = (t->getFlags() & Thread::StressFlag) != 0;
if (not stress) if (not stress)
atomicOr(&(t->flags), Thread::StressFlag); t->setFlag(Thread::StressFlag);
#endif #endif
Machine* m = t->m; Machine* m = t->m;
@ -3474,7 +3474,7 @@ void doCollect(Thread* t, Heap::CollectionType type, int pendingAllocation)
#ifdef VM_STRESS #ifdef VM_STRESS
if (not stress) if (not stress)
atomicAnd(&(t->flags), ~Thread::StressFlag); t->clearFlag(Thread::StressFlag);
#endif #endif
GcFinalizer* finalizeQueue = t->m->finalizeQueue; GcFinalizer* finalizeQueue = t->m->finalizeQueue;
@ -4070,7 +4070,7 @@ void enter(Thread* t, Thread::State s)
assertT(t, t->m->liveCount > 0); assertT(t, t->m->liveCount > 0);
--t->m->liveCount; --t->m->liveCount;
if (t->flags & Thread::DaemonFlag) { if (t->getFlags() & Thread::DaemonFlag) {
--t->m->daemonCount; --t->m->daemonCount;
} }
} }
@ -4182,7 +4182,7 @@ object allocate3(Thread* t,
{ {
expect(t, t->criticalLevel == 0); expect(t, t->criticalLevel == 0);
if (UNLIKELY(t->flags & Thread::UseBackupHeapFlag)) { if (UNLIKELY(t->getFlags() & Thread::UseBackupHeapFlag)) {
expect(t, expect(t,
t->backupHeapIndex + ceilingDivide(sizeInBytes, BytesPerWord) t->backupHeapIndex + ceilingDivide(sizeInBytes, BytesPerWord)
<= ThreadBackupHeapSizeInWords); <= ThreadBackupHeapSizeInWords);
@ -4191,7 +4191,7 @@ object allocate3(Thread* t,
t->backupHeapIndex += ceilingDivide(sizeInBytes, BytesPerWord); t->backupHeapIndex += ceilingDivide(sizeInBytes, BytesPerWord);
fieldAtOffset<object>(o, 0) = 0; fieldAtOffset<object>(o, 0) = 0;
return o; return o;
} else if (UNLIKELY(t->flags & Thread::TracingFlag)) { } else if (UNLIKELY(t->getFlags() & Thread::TracingFlag)) {
expect(t, expect(t,
t->heapIndex + ceilingDivide(sizeInBytes, BytesPerWord) t->heapIndex + ceilingDivide(sizeInBytes, BytesPerWord)
<= ThreadHeapSizeInWords); <= ThreadHeapSizeInWords);