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 }