use of org.vmmagic.pragma.Unpreemptible in project JikesRVM by JikesRVM.
the class ThinLock method inlineUnlock.
@Inline
@NoNullCheck
@Unpreemptible
@Entrypoint
public static void inlineUnlock(Object o, Offset lockOffset) {
// FIXME: bad for PPC?
Word old = Magic.prepareWord(o, lockOffset);
Word id = old.and(TL_THREAD_ID_MASK.or(TL_STAT_MASK));
Word tid = Word.fromIntSignExtend(RVMThread.getCurrentThread().getLockingId());
if (id.EQ(tid)) {
if (!old.and(TL_LOCK_COUNT_MASK).isZero()) {
setDedicatedU16(o, lockOffset, old.minus(TL_LOCK_COUNT_UNIT));
Magic.fence();
return;
}
} else if (old.xor(tid).rshl(TL_LOCK_COUNT_SHIFT).EQ(TL_STAT_THIN.rshl(TL_LOCK_COUNT_SHIFT))) {
Magic.combinedLoadBarrier();
if (Magic.attemptWord(o, lockOffset, old, old.and(TL_UNLOCK_MASK).or(TL_STAT_THIN))) {
if (!VM.MagicAttemptImpliesStoreLoadBarrier)
Magic.fence();
return;
}
}
unlock(o, lockOffset);
}
use of org.vmmagic.pragma.Unpreemptible in project JikesRVM by JikesRVM.
the class ThinLock method casFromBiased.
@NoInline
@Unpreemptible
public static boolean casFromBiased(Object o, Offset lockOffset, Word oldLockWord, Word changed, int cnt) {
RVMThread me = RVMThread.getCurrentThread();
Word id = oldLockWord.and(TL_THREAD_ID_MASK);
if (id.isZero()) {
if (false)
VM.sysWriteln("id is zero - easy case.");
return Synchronization.tryCompareAndSwap(o, lockOffset, oldLockWord, changed);
} else {
if (false)
VM.sysWriteln("id = ", id);
int slot = id.toInt() >> TL_THREAD_ID_SHIFT;
if (false)
VM.sysWriteln("slot = ", slot);
RVMThread owner = RVMThread.threadBySlot[slot];
if (owner == me || /* I own it, so I can unbias it trivially. This occurs
when we are inflating due to, for example, wait() */
owner == null) /* the thread that owned it is dead, so it's safe to
unbias. */
{
// be unbiasing.
return Synchronization.tryCompareAndSwap(o, lockOffset, oldLockWord, changed);
} else {
boolean result = false;
// goofy.
if (false)
VM.sysWriteln("entering pair handshake");
owner.beginPairHandshake();
if (false)
VM.sysWriteln("done with that");
Word newLockWord = Magic.getWordAtOffset(o, lockOffset);
result = Synchronization.tryCompareAndSwap(o, lockOffset, oldLockWord, changed);
owner.endPairHandshake();
if (false)
VM.sysWriteln("that worked.");
return result;
}
}
}
use of org.vmmagic.pragma.Unpreemptible in project JikesRVM by JikesRVM.
the class ThinLock method attemptToInflate.
/**
* Promotes a light-weight lock to a heavy-weight lock. If this returns the lock
* that you gave it, its mutex will be locked; otherwise, its mutex will be unlocked.
* Hence, calls to this method should always be followed by a condition lock() or
* unlock() call.
*
* @param o the object to get a heavy-weight lock
* @param lockOffset the offset of the thin lock word in the object.
* @param l the lock to attempt to inflate
* @return the inflated lock; either the one you gave, or another one, if the lock
* was inflated by some other thread.
*/
@NoNullCheck
@Unpreemptible
protected static Lock attemptToInflate(Object o, Offset lockOffset, Lock l) {
if (false)
VM.sysWriteln("l = ", Magic.objectAsAddress(l));
l.mutex.lock();
for (int cnt = 0; ; ++cnt) {
Word bits = Magic.getWordAtOffset(o, lockOffset);
// check to see if another thread has already created a fat lock
if (isFat(bits)) {
if (trace) {
VM.sysWriteln("Thread #", RVMThread.getCurrentThreadSlot(), ": freeing lock ", Magic.objectAsAddress(l), " because we had a double-inflate");
}
Lock result = Lock.getLock(getLockIndex(bits));
if (result == null || result.lockedObject != o) {
continue;
/* this is nasty. this will happen when a lock
is deflated. */
}
Lock.free(l);
l.mutex.unlock();
return result;
}
if (VM.VerifyAssertions)
VM._assert(l != null);
if (attemptToMarkInflated(o, lockOffset, bits, l.index, cnt)) {
l.setLockedObject(o);
l.setOwnerId(getLockOwner(bits));
if (l.getOwnerId() != 0) {
l.setRecursionCount(getRecCount(bits));
} else {
if (VM.VerifyAssertions)
VM._assert(l.getRecursionCount() == 0);
}
return l;
}
// contention detected, try again
}
}
use of org.vmmagic.pragma.Unpreemptible in project JikesRVM by JikesRVM.
the class RVMThread method blockAllMutatorsForGC.
/**
* Stop all mutator threads. This is current intended to be run by a single thread.
*
* Fixpoint until there are no threads that we haven't blocked. Fixpoint is needed to
* catch the (unlikely) case that a thread spawns another thread while we are waiting.
*/
@NoCheckStore
@Unpreemptible
public static void blockAllMutatorsForGC() {
RVMThread.handshakeLock.lockNoHandshake();
while (true) {
// (1) Find all the threads that need to be blocked for GC
RVMThread.acctLock.lockNoHandshake();
int numToHandshake = 0;
for (int i = 0; i < RVMThread.numThreads; i++) {
RVMThread t = RVMThread.threads[i];
if (!t.isCollectorThread() && !t.ignoreHandshakesAndGC()) {
RVMThread.handshakeThreads[numToHandshake++] = t;
}
}
RVMThread.acctLock.unlock();
// (2) Remove any threads that have already been blocked from the list.
for (int i = 0; i < numToHandshake; i++) {
RVMThread t = RVMThread.handshakeThreads[i];
t.monitor().lockNoHandshake();
if (t.blockedFor(RVMThread.gcBlockAdapter) || RVMThread.notRunning(t.asyncBlock(RVMThread.gcBlockAdapter))) {
// Already blocked or not running, remove.
RVMThread.handshakeThreads[i--] = RVMThread.handshakeThreads[--numToHandshake];
// help GC
RVMThread.handshakeThreads[numToHandshake] = null;
}
t.monitor().unlock();
}
// terminating).
if (numToHandshake == 0)
break;
// (4) Request a block for GC from all other threads.
for (int i = 0; i < numToHandshake; i++) {
if (false)
VM.sysWriteln("Waiting for ", RVMThread.handshakeThreads[i].getThreadSlot(), " to block.");
RVMThread t = RVMThread.handshakeThreads[i];
RVMThread.observeExecStatusAtSTW(t.block(RVMThread.gcBlockAdapter));
// help GC
RVMThread.handshakeThreads[i] = null;
}
}
RVMThread.handshakeLock.unlock();
// Deal with terminating threads to ensure that all threads are either dead to MMTk or stopped above.
RVMThread.processAboutToTerminate();
}
use of org.vmmagic.pragma.Unpreemptible in project JikesRVM by JikesRVM.
the class RVMThread method block.
/**
* Attempts to block the thread, and return the state it is in after the
* attempt. If we're blocking ourselves, this will always return IN_JAVA. If
* the thread signals to us the intention to die as we are trying to block it,
* this will return TERMINATED. NOTE: the thread's execStatus will not
* actually be TERMINATED at that point yet.
* <p>
* Note that this method is ridiculously dangerous, especially if you pass
* asynchronous==false. Waiting for another thread to stop is not in itself
* interruptible - so if you ask another thread to block and they ask you
* to block, you might deadlock.
*
* @param ba the adapter to block on
* @param asynchronous {@code true} if the request is asynchronous (i.e. the
* receiver is only notified), {@code false} if the caller waits for the
* receiver to block
* @return the new state of the thread
*/
@Unpreemptible("Only blocks if the receiver is the current thread, or if asynchronous is set to false and the thread is not already blocked")
int block(BlockAdapter ba, boolean asynchronous) {
int result;
if (traceBlock)
VM.sysWriteln("Thread #", getCurrentThread().threadSlot, " is requesting that thread #", threadSlot, " blocks.");
monitor().lockNoHandshake();
int token = ba.requestBlock(this);
if (getCurrentThread() == this) {
if (traceBlock)
VM.sysWriteln("Thread #", threadSlot, " is blocking.");
checkBlock();
result = getExecStatus();
} else {
if (traceBlock)
VM.sysWriteln("Thread #", threadSlot, " is being told to block.");
if (isAboutToTerminate) {
if (traceBlock)
VM.sysWriteln("Thread #", threadSlot, " is terminating, returning as if blocked in TERMINATED state.");
result = TERMINATED;
} else {
takeYieldpoint = 1;
// CAS the execStatus field
int newState = setBlockedExecStatus();
result = newState;
if (traceReallyBlock)
VM.sysWriteln("Thread #", getCurrentThreadSlot(), " is blocking thread #", threadSlot, " which is in state ", newState);
// this broadcast serves two purposes: notifies threads that are
// IN_JAVA but waiting on monitor() that they should awake and
// acknowledge the block request; or notifies anyone
// waiting for this thread to block that the thread is
// BLOCKED_IN_NATIVE or BLOCKED_IN_JNI. in the latter case the
// broadcast() happens _before_ the setting of the flags that the
// other threads would be awaiting, but that is fine, since we're
// still holding the lock anyway.
monitor().broadcast();
if (newState == IN_JAVA_TO_BLOCK) {
if (!asynchronous) {
if (traceBlock)
VM.sysWriteln("Thread #", getCurrentThread().threadSlot, " is waiting for thread #", threadSlot, " to block.");
while (ba.hasBlockRequest(this, token) && !ba.isBlocked(this) && !isAboutToTerminate) {
if (traceBlock)
VM.sysWriteln("Thread #", getCurrentThread().threadSlot, " is calling wait until thread #", threadSlot, " blocks.");
// will this deadlock when the thread dies?
if (VM.VerifyAssertions) {
// do a timed wait, and assert that the thread did not disappear
// into native in the meantime
// 1 sec
monitor().timedWaitRelativeNoHandshake(1000L * 1000L * 1000L);
if (traceReallyBlock) {
VM.sysWriteln("Thread #", threadSlot, "'s status is ", READABLE_EXEC_STATUS[getExecStatus()]);
}
assertUnacceptableStates(IN_NATIVE);
} else {
monitor().waitNoHandshake();
}
if (traceBlock)
VM.sysWriteln("Thread #", getCurrentThread().threadSlot, " has returned from the wait call.");
}
if (isAboutToTerminate) {
result = TERMINATED;
} else {
result = getExecStatus();
}
}
} else if (newState == BLOCKED_IN_NATIVE || newState == BLOCKED_IN_JNI) {
// state accordingly and tell anyone who is waiting.
if (traceBlock)
VM.sysWriteln("Thread #", getCurrentThread().threadSlot, " has seen thread #", threadSlot, " in native; changing its status accordingly.");
ba.clearBlockRequest(this);
ba.setBlocked(this, true);
}
}
}
monitor().unlock();
if (traceReallyBlock)
VM.sysWriteln("Thread #", getCurrentThread().threadSlot, " is done telling thread #", threadSlot, " to block.");
return result;
}
Aggregations