/* * This file is part of the Jikes RVM project (http://jikesrvm.org). * * This file is licensed to You under the Eclipse Public License (EPL); * You may not use this file except in compliance with the License. You * may obtain a copy of the License at * * http://www.opensource.org/licenses/eclipse-1.0.php * * See the COPYRIGHT.txt file distributed with this work for information * regarding copyright ownership. */ package org.jikesrvm.mm.mminterface; import org.jikesrvm.VM; import org.jikesrvm.runtime.Magic; import org.jikesrvm.scheduler.Monitor; import org.jikesrvm.scheduler.RVMThread; import org.vmmagic.pragma.Uninterruptible; /** * A synchronization barrier used to synchronize collector threads, * and the processors they are running on, during parallel collections. * * The core barrier functionality is implemented by a barrier object. * The code in this class was in charge of VM-related idiosyncrasies like * computing how many processors are participating in a particular collection, * but that is all obsolete now that we're using native threads. Hence this * class is somewhat vestigial. */ public class SynchronizationBarrier { private static final int verbose = 0; private Monitor lock; private int target; private int[] counters = new int[2]; private int[] modes = new int[2]; private int countIdx; /** * Constructor */ public SynchronizationBarrier() { } public void boot() { lock=new Monitor(); this.target=RVMThread.numProcessors; countIdx=0; } /** * Wait for all other collectorThreads/processors to arrive at this barrier. */ @Uninterruptible public int rendezvous(int where) { if (false) { VM.sysWriteln("thread ",RVMThread.getCurrentThreadSlot()," rendezvousing at ",where); } arrive(where); Magic.isync(); // so subsequent instructions won't see stale values // XXX This should be changed to return ordinal of current rendezvous rather than the one at the beginning return Magic.threadAsCollectorThread(RVMThread.getCurrentThread()).getGCOrdinal(); } /** * First rendezvous for a collection, called by all CollectorThreads that arrive * to participate in a collection. Thread with gcOrdinal==1 is responsible for * detecting detecting the number of processors (which is retarded since we already * know how many there are). */ @Uninterruptible public void startupRendezvous() { // PNT: FIXME: this is more complicated than it needs to be. CollectorThread th = Magic.threadAsCollectorThread(RVMThread.getCurrentThread()); int myNumber = th.getGCOrdinal(); if (verbose > 0) { VM.sysWriteln("GC Message: SynchronizationBarrier.startupRendezvous: thr ", th.getThreadSlot(), " ordinal ", myNumber); } if (myNumber > 1) { arrive(100); // wait for designated guy to do his job Magic.isync(); // so subsequent instructions won't see stale values if (verbose > 0) VM.sysWriteln("GC Message: startupRendezvous leaving as ", myNumber); return; // leave barrier } int numParticipating = RVMThread.numProcessors; if (verbose > 0) { VM.sysWriteln("GC Message: startupRendezvous numParticipating = ", numParticipating); } arrive(100); // all setup now complete and we can proceed Magic.sync(); // update main memory so other processors will see it in "while" loop Magic.isync(); // so subsequent instructions won't see stale values if (verbose > 0) { VM.sysWriteln("GC Message: startupRendezvous designated proc leaving"); } } // startupRendezvous @Uninterruptible private boolean arrive(int mode) { if (false) { VM.sysWriteln("thread ",RVMThread.getCurrentThreadSlot(), " entered ",RVMThread.getCurrentThread().barriersEntered++, " barriers"); } lock.lockNoHandshake(); int myCountIdx=countIdx; boolean result; if (VM.VerifyAssertions) { if (counters[myCountIdx]==0) { modes[myCountIdx]=mode; } else { int oldMode=modes[myCountIdx]; if (oldMode!=mode) { VM.sysWriteln("Thread ",RVMThread.getCurrentThreadSlot()," encountered "+ "incorrect mode entering barrier."); VM.sysWriteln("Thread ",RVMThread.getCurrentThreadSlot(),"'s mode: ",mode); VM.sysWriteln("Thread ",RVMThread.getCurrentThreadSlot()," saw others in mode: ",oldMode); VM._assert(modes[myCountIdx]==mode); VM._assert(oldMode==mode); } } } counters[myCountIdx]++; if (counters[myCountIdx]==target) { counters[myCountIdx]=0; countIdx^=1; lock.broadcast(); if (false) { VM.sysWriteln("waking everyone"); } result=true; } else { while (counters[myCountIdx]!=0) { lock.waitNoHandshake(); } result=false; } lock.unlock(); if (false) { VM.sysWriteln("thread ",RVMThread.getCurrentThreadSlot(), " exited ",RVMThread.getCurrentThread().barriersExited++, " barriers"); } return result; } }