/*
* 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.mmtk.plan.concurrent;
import org.mmtk.plan.Phase;
import org.mmtk.plan.Plan;
import org.mmtk.plan.SimpleCollector;
import org.mmtk.plan.TraceLocal;
import org.mmtk.utility.Log;
import org.mmtk.utility.options.Options;
import org.mmtk.vm.VM;
import org.vmmagic.pragma.*;
/**
* This class implements <i>per-collector thread</i> behavior
* and state for a concurrent collector.
*/
@Uninterruptible
public abstract class ConcurrentCollector extends SimpleCollector {
/****************************************************************************
* Instance fields
*/
/****************************************************************************
* Initialization
*/
/****************************************************************************
*
* Collection
*/
/**
* {@inheritDoc}
*/
@Override
@Unpreemptible
public void run() {
while (true) {
park();
if (Plan.concurrentWorkers.isMember(this)) {
concurrentCollect();
} else {
collect();
}
}
}
private static volatile boolean continueCollecting;
/** Perform some concurrent garbage collection */
@Unpreemptible
public final void concurrentCollect() {
if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(!Plan.gcInProgress());
do {
short phaseId = Phase.getConcurrentPhaseId();
concurrentCollectionPhase(phaseId);
} while (continueCollecting);
}
@Override
public void collect() {
if (!Phase.isPhaseStackEmpty()) {
Phase.continuePhaseStack();
} else {
Phase.beginNewPhaseStack(Phase.scheduleComplex(global().collection));
}
}
@Override
@Inline
public void collectionPhase(short phaseId, boolean primary) {
if (phaseId == Concurrent.FLUSH_COLLECTOR) {
getCurrentTrace().processRoots();
getCurrentTrace().flush();
return;
}
super.collectionPhase(phaseId, primary);
}
/**
* Perform some concurrent collection work.
*
* @param phaseId The unique phase identifier
*/
@Unpreemptible
public void concurrentCollectionPhase(short phaseId) {
if (phaseId == Concurrent.CONCURRENT_CLOSURE) {
if (VM.VERIFY_ASSERTIONS) {
VM.assertions._assert(!Plan.gcInProgress());
}
TraceLocal trace = getCurrentTrace();
while (!trace.incrementalTrace(100)) {
if (group.isAborted()) {
trace.flush();
break;
}
}
if (rendezvous() == 0) {
continueCollecting = false;
if (!group.isAborted()) {
/* We are responsible for ensuring termination. */
if (Options.verbose.getValue() >= 2) Log.writeln("< requesting mutator flush >");
VM.collection.requestMutatorFlush();
if (Options.verbose.getValue() >= 2) Log.writeln("< mutators flushed >");
if (concurrentTraceComplete()) {
continueCollecting = Phase.notifyConcurrentPhaseComplete();
} else {
continueCollecting = true;
Phase.notifyConcurrentPhaseIncomplete();
}
}
}
rendezvous();
return;
}
Log.write("Concurrent phase ");
Log.write(Phase.getName(phaseId));
Log.writeln(" not handled.");
VM.assertions.fail("Concurrent phase not handled!");
}
/**
* @return whether all work has been completed
*/
protected abstract boolean concurrentTraceComplete();
/****************************************************************************
*
* Miscellaneous.
*/
/** @return The active global plan as a <code>Concurrent</code> instance. */
@Inline
private static Concurrent global() {
return (Concurrent) VM.activePlan.global();
}
}