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.mmtk.plan; 014 015 import org.mmtk.utility.Constants; 016 017 import org.mmtk.vm.Monitor; 018 import org.mmtk.vm.VM; 019 020 import org.vmmagic.pragma.*; 021 022 /** 023 * This class represents a pool of collector contexts that can be triggered 024 * to perform collection activity. 025 */ 026 @Uninterruptible 027 public class ParallelCollectorGroup implements Constants { 028 029 /**************************************************************************** 030 * Instance fields 031 */ 032 033 /** The name of this collector context group. */ 034 private final String name; 035 036 /** The collector context instances operating within this group */ 037 private ParallelCollector[] contexts; 038 039 /** Lock used to manage group state. */ 040 private Monitor lock; 041 042 /** The number of cycles triggered */ 043 private volatile int triggerCount; 044 045 /** The number of threads that are currently parked */ 046 private volatile int contextsParked; 047 048 /** Is there an abort request outstanding? */ 049 private volatile boolean aborted; 050 051 /** Used to count threads during calls to rendezvous() */ 052 private int[] rendezvousCounter = new int[2]; 053 054 /** Which rendezvous counter is currently in use */ 055 private volatile int currentRendezvousCounter; 056 057 /**************************************************************************** 058 * 059 * Initialization 060 */ 061 public ParallelCollectorGroup(String name) { 062 this.name = name; 063 } 064 065 /** 066 * @return The number of active collector contexts. 067 */ 068 public int activeWorkerCount() { 069 return contexts.length; 070 } 071 072 /** 073 * Initialize the collector context group. 074 * 075 * @param size The number of collector contexts within the group. 076 * @param klass The type of collector context to create. 077 */ 078 @Interruptible 079 public void initGroup(int size, Class<? extends ParallelCollector> klass) { 080 this.lock = VM.newHeavyCondLock("CollectorContextGroup"); 081 this.triggerCount = 1; 082 this.contexts = new ParallelCollector[size]; 083 for(int i = 0; i < size; i++) { 084 try { 085 contexts[i] = klass.newInstance(); 086 contexts[i].group = this; 087 contexts[i].workerOrdinal = i; 088 VM.collection.spawnCollectorContext(contexts[i]); 089 } catch (Throwable t) { 090 VM.assertions.fail("Error creating collector context '" + klass.getName() + "' for group '" + name + "': " + t.toString()); 091 } 092 } 093 } 094 095 /** 096 * Wake up the parked threads in this group. 097 */ 098 public void triggerCycle() { 099 lock.lock(); 100 triggerCount++; 101 contextsParked = 0; 102 lock.broadcast(); 103 lock.unlock(); 104 } 105 106 /** 107 * Signal that you would like the threads to park abruptly. Has no effect if no cycle is active. 108 */ 109 public void abortCycle() { 110 lock.lock(); 111 if (contextsParked < contexts.length) { 112 aborted = true; 113 } 114 lock.unlock(); 115 } 116 117 /** 118 * Has the cycle been aborted? 119 */ 120 public boolean isAborted() { 121 return aborted; 122 } 123 124 /** 125 * Wait until the group is idle. 126 */ 127 public void waitForCycle() { 128 lock.lock(); 129 while (contextsParked < contexts.length) { 130 lock.await(); 131 } 132 lock.unlock(); 133 } 134 135 /** 136 * Park the given collector in the group. The given context must be a member of this group. 137 * 138 * @param context The context to park. 139 */ 140 public void park(ParallelCollector context) { 141 if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(isMember(context)); 142 lock.lock(); 143 context.lastTriggerCount++; 144 if (context.lastTriggerCount == triggerCount) { 145 contextsParked++; 146 if (contextsParked == contexts.length) { 147 aborted = false; 148 } 149 lock.broadcast(); 150 while (context.lastTriggerCount == triggerCount) { 151 lock.await(); 152 } 153 } 154 lock.unlock(); 155 } 156 157 /** 158 * Is the given context and member of this group. 159 * 160 * @param context The context to pass. 161 * @return {@code true} if the context is a member. 162 */ 163 public boolean isMember(CollectorContext context) { 164 for(CollectorContext c: contexts) { 165 if (c == context) { 166 return true; 167 } 168 } 169 return false; 170 } 171 172 /** 173 * Rendezvous with other active threads in this group. 174 * 175 * @return The order in which you entered the rendezvous. 176 */ 177 public int rendezvous() { 178 lock.lock(); 179 int i = currentRendezvousCounter; 180 int me = rendezvousCounter[i]++; 181 if (me == contexts.length-1) { 182 currentRendezvousCounter ^= 1; 183 rendezvousCounter[currentRendezvousCounter] = 0; 184 lock.broadcast(); 185 } else { 186 while(rendezvousCounter[i] < contexts.length) { 187 lock.await(); 188 } 189 } 190 lock.unlock(); 191 return me; 192 } 193 }