001    /*
002     *  This file is part of the Jikes RVM project (http://jikesrvm.org).
003     *
004     *  This file is licensed to You under the Eclipse Public License (EPL);
005     *  You may not use this file except in compliance with the License. You
006     *  may obtain a copy of the License at
007     *
008     *      http://www.opensource.org/licenses/eclipse-1.0.php
009     *
010     *  See the COPYRIGHT.txt file distributed with this work for information
011     *  regarding copyright ownership.
012     */
013    package org.jikesrvm.mm.mminterface;
014    
015    import org.jikesrvm.VM;
016    import org.jikesrvm.runtime.Magic;
017    import org.jikesrvm.scheduler.Monitor;
018    import org.jikesrvm.scheduler.RVMThread;
019    import org.vmmagic.pragma.Uninterruptible;
020    
021    /**
022     * A synchronization barrier used to synchronize collector threads,
023     * and the processors they are running on, during parallel collections.
024     *
025     * The core barrier functionality is implemented by a barrier object.
026     * The code in this class was in charge of VM-related idiosyncrasies like
027     * computing how many processors are participating in a particular collection,
028     * but that is all obsolete now that we're using native threads.  Hence this
029     * class is somewhat vestigial.
030     */
031    public class SynchronizationBarrier {
032    
033      private static final int verbose = 0;
034    
035      private Monitor lock;
036      private int target;
037      private int[] counters = new int[2];
038      private int[] modes = new int[2];
039      private int countIdx;
040    
041      /**
042       * Constructor
043       */
044      public SynchronizationBarrier() {
045      }
046    
047      public void boot() {
048        lock=new Monitor();
049        this.target=RVMThread.numProcessors;
050        countIdx=0;
051      }
052    
053      /**
054       * Wait for all other collectorThreads/processors to arrive at this barrier.
055       */
056      @Uninterruptible
057      public int rendezvous(int where) {
058    
059        if (false) {
060          VM.sysWriteln("thread ",RVMThread.getCurrentThreadSlot()," rendezvousing at ",where);
061        }
062        arrive(where);
063    
064        Magic.isync(); // so subsequent instructions won't see stale values
065    
066        // XXX This should be changed to return ordinal of current rendezvous rather than the one at the beginning
067        return Magic.threadAsCollectorThread(RVMThread.getCurrentThread()).getGCOrdinal();
068      }
069    
070      /**
071       * First rendezvous for a collection, called by all CollectorThreads that arrive
072       * to participate in a collection.  Thread with gcOrdinal==1 is responsible for
073       * detecting detecting the number of processors (which is retarded since we already
074       * know how many there are).
075       */
076      @Uninterruptible
077      public void startupRendezvous() {
078    
079        // PNT: FIXME: this is more complicated than it needs to be.
080    
081        CollectorThread th = Magic.threadAsCollectorThread(RVMThread.getCurrentThread());
082        int myNumber = th.getGCOrdinal();
083    
084        if (verbose > 0) {
085          VM.sysWriteln("GC Message: SynchronizationBarrier.startupRendezvous: thr ",
086                        th.getThreadSlot(),
087                        " ordinal ",
088                        myNumber);
089        }
090    
091        if (myNumber > 1) {
092          arrive(100); // wait for designated guy to do his job
093          Magic.isync();     // so subsequent instructions won't see stale values
094          if (verbose > 0) VM.sysWriteln("GC Message: startupRendezvous  leaving as ", myNumber);
095          return;               // leave barrier
096        }
097    
098        int numParticipating = RVMThread.numProcessors;
099    
100        if (verbose > 0) {
101          VM.sysWriteln("GC Message: startupRendezvous  numParticipating = ", numParticipating);
102        }
103        arrive(100);    // all setup now complete and we can proceed
104        Magic.sync();   // update main memory so other processors will see it in "while" loop
105        Magic.isync();  // so subsequent instructions won't see stale values
106        if (verbose > 0) {
107          VM.sysWriteln("GC Message: startupRendezvous  designated proc leaving");
108        }
109      }  // startupRendezvous
110    
111      @Uninterruptible
112      private boolean arrive(int mode) {
113        if (false) {
114          VM.sysWriteln("thread ",RVMThread.getCurrentThreadSlot(),
115                        " entered ",RVMThread.getCurrentThread().barriersEntered++,
116                        " barriers");
117        }
118        lock.lockNoHandshake();
119        int myCountIdx=countIdx;
120        boolean result;
121        if (VM.VerifyAssertions) {
122          if (counters[myCountIdx]==0) {
123            modes[myCountIdx]=mode;
124          } else {
125            int oldMode=modes[myCountIdx];
126            if (oldMode!=mode) {
127              VM.sysWriteln("Thread ",RVMThread.getCurrentThreadSlot()," encountered "+
128                            "incorrect mode entering barrier.");
129              VM.sysWriteln("Thread ",RVMThread.getCurrentThreadSlot(),"'s mode: ",mode);
130              VM.sysWriteln("Thread ",RVMThread.getCurrentThreadSlot()," saw others in mode: ",oldMode);
131              VM._assert(modes[myCountIdx]==mode);
132              VM._assert(oldMode==mode);
133            }
134          }
135        }
136        counters[myCountIdx]++;
137        if (counters[myCountIdx]==target) {
138          counters[myCountIdx]=0;
139          countIdx^=1;
140          lock.broadcast();
141          if (false) {
142            VM.sysWriteln("waking everyone");
143          }
144          result=true;
145        } else {
146          while (counters[myCountIdx]!=0) {
147            lock.waitNoHandshake();
148          }
149          result=false;
150        }
151        lock.unlock();
152        if (false) {
153          VM.sysWriteln("thread ",RVMThread.getCurrentThreadSlot(),
154                        " exited ",RVMThread.getCurrentThread().barriersExited++,
155                        " barriers");
156        }
157        return result;
158      }
159    }