Index: rvm/src/org/jikesrvm/memorymanagers/mminterface/SynchronizationBarrier.java =================================================================== --- rvm/src/org/jikesrvm/memorymanagers/mminterface/SynchronizationBarrier.java (.../withBuildFixes) (revision 11770) +++ rvm/src/org/jikesrvm/memorymanagers/mminterface/SynchronizationBarrier.java (.../fixJNIEntry) (revision 11770) @@ -14,6 +14,7 @@ import org.jikesrvm.VM; import org.jikesrvm.runtime.VM_Magic; +import org.jikesrvm.mm.mmtk.SynchronizedCounter; import static org.jikesrvm.runtime.VM_SysCall.sysCall; import org.jikesrvm.scheduler.VM_Processor; import org.jikesrvm.scheduler.VM_Scheduler; @@ -38,6 +39,9 @@ private int numRealProcessors; final Barrier barrier = new Barrier(); + + final SynchronizedCounter initReached = new SynchronizedCounter(); + boolean initGoAhead = false; /** * Constructor @@ -73,6 +77,7 @@ @Uninterruptible public void startupRendezvous() { + int myProcessorId = VM_Processor.getCurrentProcessorId(); VM_CollectorThread th = VM_Magic.threadAsCollectorThread(VM_Scheduler.getCurrentThread()); int myNumber = th.getGCOrdinal(); @@ -83,39 +88,61 @@ " ordinal ", myNumber); } - - if (myNumber > 1) { // non-designated guys just wait for designated guy to finish - barrier.arrive(8888); // wait for designated guy to do his job - VM_Magic.isync(); // so subsequent instructions won't see stale values + + if (myNumber > 1) { + initReached.increment(); + if (verbose > 0) VM.sysWriteln("GC Message: startupRendezvous has incremented for ", myNumber); + VM_Magic.sync(); + while (!initGoAhead) waitABit(5); + VM_Magic.sync(); + if (verbose > 0) VM.sysWriteln("GC Message: startupRendezvous ack received by ", myNumber); + barrier.arrive(8888); if (verbose > 0) VM.sysWriteln("GC Message: startupRendezvous leaving as ", myNumber); - return; // leave barrier + return; } - - // Thread with gcOrdinal==1 must detect processors whose active threads are - // stuck in Native C, block them there, and make them non-participants - // - waitABit(5); // give missing threads a chance to show up - int numParticipating = 0; - for (int i = 1; i <= VM_GreenScheduler.numProcessors; i++) { - if (VM_GreenScheduler.getProcessor(i).lockInCIfInC()) { // can't be true for self - if (verbose > 0) VM.sysWriteln("GC Message: excluding processor ", i); - removeProcessor(i); - } else { - numParticipating++; + + // wait for threads to show up while also ensuring that none of them + // disappear. + + initReached.increment(); + int numParticipating=VM_GreenScheduler.numProcessors; + while (initReached.peek() 0) VM.sysWriteln("GC Message: excluding processor ", i); + removeProcessor(i); + initReached.increment(); + numParticipating--; + } } } + + if (verbose > 0) VM.sysWriteln("GC Message: everyone has arrived"); - if (verbose > 0) { - VM.sysWriteln("GC Message: startupRendezvous numParticipating = ", numParticipating); - } + // we blocked out some threads that got stuck in C, and all other threads + // are now waiting for me to give them the go-ahead. + + VM_Magic.sync(); + initGoAhead=true; + VM_Magic.sync(); + + // now we set the target for the Barrier and perform an 'arrive', as a + // silly hack to make it easy to reset our counters. + + if (verbose > 0) VM.sysWriteln("GC Message: waiting for barrier arrival to allow reset"); + barrier.setTarget(numParticipating); - barrier.arrive(8888); // all setup now complete and we can proceed + barrier.arrive(8888); + + initReached.reset(); + initGoAhead=false; + VM_Magic.sync(); // update main memory so other processors will see it in "while" loop VM_Magic.isync(); // so subsequent instructions won't see stale values if (verbose > 0) { VM.sysWriteln("GC Message: startupRendezvous designated proc leaving"); } - } // startupRendezvous /** @@ -164,14 +191,29 @@ VM_GreenProcessor vp = VM_GreenScheduler.getProcessor(id); - // get processors collector thread off its transfer queue - vp.collectorThreadMutex.lock("removing a processor from gc"); - VM_GreenThread ct = vp.collectorThread; - vp.collectorThread = null; - vp.collectorThreadMutex.unlock(); - if (VM.VerifyAssertions) { - VM._assert(ct != null && ct.isGCThread()); + VM_GreenThread ct=null; + + // get processor's collector thread off its transfer queue, waiting if + // necessary for it to show up + int spinCnt=0; + for (;;) { + boolean done=false; + vp.collectorThreadMutex.lock("removing a processor from gc"); + ct = vp.collectorThread; + if (ct!=null) { + if (verbose>0) VM.sysWriteln("setting collectorThread to null in SB.removeProcessor for ",id); + vp.collectorThread = null; + done=true; + } else { + if (spinCnt++==100) { + if (verbose>0) VM.sysWriteln("it's taking a while in SB.removeProcessor for ",id); + } + } + vp.collectorThreadMutex.unlock(); + if (done) break; + waitABit(5); } + // put it back on the global collector thread queue VM_GreenScheduler.collectorMutex.lock("collector mutex for processor removal"); VM_GreenScheduler.collectorQueue.enqueue(ct); Index: rvm/src/org/jikesrvm/scheduler/greenthreads/VM_GreenThreadQueue.java =================================================================== --- rvm/src/org/jikesrvm/scheduler/greenthreads/VM_GreenThreadQueue.java (.../withBuildFixes) (revision 11770) +++ rvm/src/org/jikesrvm/scheduler/greenthreads/VM_GreenThreadQueue.java (.../fixJNIEntry) (revision 11770) @@ -26,6 +26,13 @@ public class VM_GreenThreadQueue extends VM_AbstractThreadQueue { /** + * Name to use if debug mode is on. If this is null, then don't print + * debug messages. If it is non-null, then print debug messages with + * this string attached. + */ + protected String debugName; + + /** * First thread on list. */ protected VM_GreenThread head; @@ -36,6 +43,19 @@ protected VM_GreenThread tail; /** + * Initialize the queue without debugging. + */ + public VM_GreenThreadQueue() {} + + /** + * Initialize the queue with debugging turned on, using the given + * name. + */ + public VM_GreenThreadQueue(String debugName) { + this.debugName = debugName; + } + + /** * Are any threads on the queue? */ @Override @@ -70,6 +90,13 @@ @Override @UninterruptibleNoWarn public void enqueue(VM_GreenThread t) { + if (debugName != null) { + if (t==null) { + VM.sysWriteln(debugName,": enqueueing null thread"); + } else { + VM.sysWriteln(debugName,": enqueueing thread with index ",t.getIndex()); + } + } // not currently on any other queue if (VM.VerifyAssertions && t.getNext() != null) { VM.sysWrite("Thread sitting on >1 queue: "); @@ -104,6 +131,9 @@ public VM_GreenThread dequeue() { VM_GreenThread t = head; if (t == null) { + if (debugName != null) { + VM.sysWriteln(debugName,": dequeueing null"); + } return null; } head = t.getNext(); @@ -111,9 +141,26 @@ if (head == null) { tail = null; } + if (debugName != null) { + VM.sysWriteln(debugName,": dequeueing thread with index ",t.getIndex()); + } if (VM.VerifyAssertions) VM._assert(t.isQueueable()); return t; } + + /** Debug helper for dequeueGCThread (this is a bit hackish) */ + private VM_GreenThread dequeueGCThreadDebugRet(VM_GreenThread t) { + if (debugName != null) { + if (t==null) { + VM.sysWriteln(debugName,": dequeueing null GC thread"); + } else { + if (debugName != null) { + VM.sysWriteln(debugName,": dequeueing GC thread with index ",t.getIndex()); + } + } + } + return t; + } /** * Dequeue the CollectorThread, if any, from this queue. If qlock != null @@ -125,7 +172,7 @@ VM_GreenThread currentThread = head; if (head == null) { if (qlock != null) qlock.unlock(); - return null; + return dequeueGCThreadDebugRet(null); } VM_GreenThread nextThread = head.getNext(); @@ -136,7 +183,7 @@ } currentThread.setNext(null); if (qlock != null) qlock.unlock(); - return currentThread; + return dequeueGCThreadDebugRet(currentThread); } while (nextThread != null) { @@ -147,13 +194,13 @@ } nextThread.setNext(null); if (qlock != null) qlock.unlock(); - return nextThread; + return dequeueGCThreadDebugRet(nextThread); } currentThread = nextThread; nextThread = nextThread.getNext(); } - return null; + return dequeueGCThreadDebugRet(null); } /** Index: rvm/src/org/jikesrvm/scheduler/greenthreads/VM_GreenProcessor.java =================================================================== --- rvm/src/org/jikesrvm/scheduler/greenthreads/VM_GreenProcessor.java (.../withBuildFixes) (revision 11770) +++ rvm/src/org/jikesrvm/scheduler/greenthreads/VM_GreenProcessor.java (.../fixJNIEntry) (revision 11770) @@ -36,6 +36,9 @@ @Uninterruptible @NonMoving public final class VM_GreenProcessor extends VM_Processor { + + private static final int verbose = 0; + /** * thread previously running on this processor */ @@ -353,6 +356,7 @@ if (VM.TraceThreadScheduling > 1) { VM_Scheduler.trace("VM_Processor", "getRunnableThread: collector thread", ct.getIndex()); } + if (verbose>0) VM.sysWriteln("setting collectorThread to null in GP.getRunnableThread for ",id,", returning thread ",ct.getIndex()); collectorThread = null; collectorThreadMutex.unlock(); return ct; @@ -467,6 +471,7 @@ private void transferThread(VM_GreenThread t) { if (t.isGCThread()) { collectorThreadMutex.lock("gc thread transfer"); + if (verbose>0) VM.sysWriteln("setting collectorThread to ",t.getIndex()," in GP.transferThread for ",id); collectorThread = t; /* Implied by transferring a gc thread */ requestYieldToGC(); @@ -554,7 +559,8 @@ /** * sets the VP status to BLOCKED_IN_NATIVE if it is currently IN_NATIVE (ie C) - * returns true if BLOCKED_IN_NATIVE + * returns true if BLOCKED_IN_NATIVE by us, false if it was either already + * BLOCKED_IN_NATIVE, or if it was IN_JAVA. */ @Override public boolean lockInCIfInC() { @@ -562,9 +568,7 @@ Offset offset = VM_Entrypoints.vpStatusField.getOffset(); do { oldState = VM_Magic.prepareInt(this, offset); - if (VM.VerifyAssertions) VM._assert(oldState != BLOCKED_IN_NATIVE); if (oldState != IN_NATIVE) { - if (VM.VerifyAssertions) VM._assert(oldState == IN_JAVA); return false; } } while (!(VM_Magic.attemptInt(this, offset, oldState, BLOCKED_IN_NATIVE)));