/*
* This file is part of the Jikes RVM project (http://jikesrvm.org).
*
* This file is licensed to You under the Common Public License (CPL);
* 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/cpl1.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
*/
/** Perform some concurrent garbage collection */
public final void concurrentCollect() {
if (VM.VERIFY_ASSERTIONS) VM.assertions._assert(!Plan.gcInProgress());
if (Phase.startConcurrentPhase()) {
/* Can't change while we are 'in' the concurrent phase */
short phaseId = Phase.getConcurrentPhaseId();
concurrentCollectionPhase(phaseId);
}
}
public void collect() {
if (!Phase.isPhaseStackEmpty()) {
Phase.continuePhaseStack();
} else {
Phase.beginNewPhaseStack(Phase.scheduleComplex(global().collection));
}
}
/**
* Perform a per-collector collection phase.
*
* @param phaseId The collection phase to perform
* @param primary Perform any single-threaded activities using this thread.
*/
@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
*/
public void concurrentCollectionPhase(short phaseId) {
if (phaseId == Concurrent.CONCURRENT_CLOSURE) {
if (VM.VERIFY_ASSERTIONS) {
VM.assertions._assert(!Plan.gcInProgress());
for(int i=0; i < VM.activePlan.mutatorCount(); i++) {
VM.assertions._assert(((ConcurrentMutator)VM.activePlan.mutator(i)).barrierActive);
}
}
TraceLocal trace = getCurrentTrace();
while(!trace.incrementalTrace(100)) {
/* Check if we should yield */
if (VM.collection.yieldpoint()) {
if (resetConcurrentWork) {
/* We have been preempted by a full collection */
return;
}
}
}
if (Phase.completeConcurrentPhase()) {
/* We are responsible for ensuring termination. */
if (Options.verbose.getValue() >= 2) Log.writeln("< requesting mutator flush >");
VM.collection.requestMutatorFlush();
if (resetConcurrentWork) {
/* We have been preempted by a full collection */
return;
}
if (Options.verbose.getValue() >= 2) Log.writeln("< mutators flushed >");
if (concurrentTraceComplete()) {
Phase.notifyConcurrentPhaseComplete();
} else {
Phase.notifyConcurrentPhaseIncomplete();
}
}
return;
}
Log.write("Concurrent phase "); Log.write(Phase.getName(phaseId));
Log.writeln(" not handled.");
VM.assertions.fail("Concurrent phase not handled!");
}
/**
* Has all work 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();
}
}