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.concurrent;
014
015 import org.mmtk.plan.Phase;
016 import org.mmtk.plan.Plan;
017 import org.mmtk.plan.SimpleCollector;
018 import org.mmtk.plan.TraceLocal;
019 import org.mmtk.utility.Log;
020 import org.mmtk.utility.options.Options;
021 import org.mmtk.vm.VM;
022
023 import org.vmmagic.pragma.*;
024
025 /**
026 * This class implements <i>per-collector thread</i> behavior
027 * and state for a concurrent collector.
028 */
029 @Uninterruptible
030 public abstract class ConcurrentCollector extends SimpleCollector {
031
032 /****************************************************************************
033 * Instance fields
034 */
035
036 /****************************************************************************
037 * Initialization
038 */
039
040 /****************************************************************************
041 *
042 * Collection
043 */
044
045 /**
046 * {@inheritDoc}
047 */
048 @Override
049 @Unpreemptible
050 public void run() {
051 while(true) {
052 park();
053 if (Plan.concurrentWorkers.isMember(this)) {
054 concurrentCollect();
055 } else {
056 collect();
057 }
058 }
059 }
060
061 private static volatile boolean continueCollecting;
062
063 /** Perform some concurrent garbage collection */
064 @Unpreemptible
065 public final void concurrentCollect() {
066 if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(!Plan.gcInProgress());
067 do {
068 short phaseId = Phase.getConcurrentPhaseId();
069 concurrentCollectionPhase(phaseId);
070 } while (continueCollecting);
071 }
072
073 @Override
074 public void collect() {
075 if (!Phase.isPhaseStackEmpty()) {
076 Phase.continuePhaseStack();
077 } else {
078 Phase.beginNewPhaseStack(Phase.scheduleComplex(global().collection));
079 }
080 }
081
082 @Override
083 @Inline
084 public void collectionPhase(short phaseId, boolean primary) {
085 if (phaseId == Concurrent.FLUSH_COLLECTOR) {
086 getCurrentTrace().processRoots();
087 getCurrentTrace().flush();
088 return;
089 }
090
091 super.collectionPhase(phaseId, primary);
092 }
093
094 /**
095 * Perform some concurrent collection work.
096 *
097 * @param phaseId The unique phase identifier
098 */
099 @Unpreemptible
100 public void concurrentCollectionPhase(short phaseId) {
101 if (phaseId == Concurrent.CONCURRENT_CLOSURE) {
102 if (VM.VERIFY_ASSERTIONS) {
103 VM.assertions._assert(!Plan.gcInProgress());
104 }
105 TraceLocal trace = getCurrentTrace();
106 while(!trace.incrementalTrace(100)) {
107 if (group.isAborted()) {
108 trace.flush();
109 break;
110 }
111 }
112 if (rendezvous() == 0) {
113 continueCollecting = false;
114 if (!group.isAborted()) {
115 /* We are responsible for ensuring termination. */
116 if (Options.verbose.getValue() >= 2) Log.writeln("< requesting mutator flush >");
117 VM.collection.requestMutatorFlush();
118
119 if (Options.verbose.getValue() >= 2) Log.writeln("< mutators flushed >");
120
121 if (concurrentTraceComplete()) {
122 continueCollecting = Phase.notifyConcurrentPhaseComplete();
123 } else {
124 continueCollecting = true;
125 Phase.notifyConcurrentPhaseIncomplete();
126 }
127 }
128 }
129 rendezvous();
130 return;
131 }
132
133 Log.write("Concurrent phase "); Log.write(Phase.getName(phaseId));
134 Log.writeln(" not handled.");
135 VM.assertions.fail("Concurrent phase not handled!");
136 }
137
138 /**
139 * Has all work been completed?
140 */
141 protected abstract boolean concurrentTraceComplete();
142
143
144 /****************************************************************************
145 *
146 * Miscellaneous.
147 */
148
149 /** @return The active global plan as a <code>Concurrent</code> instance. */
150 @Inline
151 private static Concurrent global() {
152 return (Concurrent) VM.activePlan.global();
153 }
154 }