/*
* 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;
import org.mmtk.utility.Log;
import org.mmtk.utility.heap.HeapGrowthManager;
import org.mmtk.utility.options.Options;
import org.mmtk.vm.Monitor;
import org.mmtk.vm.VM;
import org.vmmagic.pragma.*;
@Uninterruptible
public class ControllerCollectorContext extends CollectorContext {
/** The lock to use to manage collection */
private Monitor lock;
/** The set of worker threads to use */
private final ParallelCollectorGroup workers;
/** Flag used to control the 'race to request' */
private boolean requestFlag;
/** The current request index */
private int requestCount;
/** The request index that was last completed */
private int lastRequestCount = -1;
/** Is there concurrent collection activity */
private boolean concurrentCollection = false;
/**
* Create a controller context.
*
* @param workers The worker group to use for collection.
*/
public ControllerCollectorContext(ParallelCollectorGroup workers) {
this.workers = workers;
}
@Override
@Interruptible
public void initCollector(int id) {
super.initCollector(id);
lock = VM.newHeavyCondLock("CollectorControlLock");
}
/**
* Main execution loop.
*/
@Override
@Unpreemptible
public void run() {
while (true) {
// Wait for a collection request.
if (Options.verbose.getValue() >= 5) Log.writeln("[STWController: Waiting for request...]");
waitForRequest();
if (Options.verbose.getValue() >= 5) Log.writeln("[STWController: Request recieved.]");
// The start time.
long startTime = VM.statistics.nanoTime();
if (concurrentCollection) {
if (Options.verbose.getValue() >= 5) Log.writeln("[STWController: Stopping concurrent collectors...]");
Plan.concurrentWorkers.abortCycle();
Plan.concurrentWorkers.waitForCycle();
Phase.clearConcurrentPhase();
// Collector must re-request concurrent collection in this case.
concurrentCollection = false;
}
// Stop all mutator threads
if (Options.verbose.getValue() >= 5) Log.writeln("[STWController: Stopping the world...]");
VM.collection.stopAllMutators();
// Was this user triggered?
boolean userTriggeredCollection = Plan.isUserTriggeredCollection();
boolean internalTriggeredCollection = Plan.isInternalTriggeredCollection();
// Clear the request
clearRequest();
// Trigger GC.
if (Options.verbose.getValue() >= 5) Log.writeln("[STWController: Triggering worker threads...]");
workers.triggerCycle();
// Wait for GC threads to complete.
workers.waitForCycle();
if (Options.verbose.getValue() >= 5) Log.writeln("[STWController: Worker threads complete!]");
// Heap growth logic
long elapsedTime = VM.statistics.nanoTime() - startTime;
HeapGrowthManager.recordGCTime(VM.statistics.nanosToMillis(elapsedTime));
if (VM.activePlan.global().lastCollectionFullHeap() && !internalTriggeredCollection) {
if (Options.variableSizeHeap.getValue() && !userTriggeredCollection) {
// Don't consider changing the heap size if the application triggered the collection
if (Options.verbose.getValue() >= 5) Log.writeln("[STWController: Considering heap size.]");
HeapGrowthManager.considerHeapSize();
}
HeapGrowthManager.reset();
}
// Reset the triggering information.
Plan.resetCollectionTrigger();
// Resume all mutators
if (Options.verbose.getValue() >= 5) Log.writeln("[STWController: Resuming mutators...]");
VM.collection.resumeAllMutators();
// Start threads that will perform concurrent collection work alongside mutators.
if (concurrentCollection) {
if (Options.verbose.getValue() >= 5) Log.writeln("[STWController: Triggering concurrent collectors...]");
Plan.concurrentWorkers.triggerCycle();
}
}
}
/**
* Request that concurrent collection is performed after this stop-the-world increment.
*/
public void requestConcurrentCollection() {
concurrentCollection = true;
}
/**
* Request a collection.
*/
public void request() {
if (requestFlag) {
return;
}
lock.lock();
if (!requestFlag) {
requestFlag = true;
requestCount++;
lock.broadcast();
}
lock.unlock();
}
/**
* Clear the collection request, making future requests incur an
* additional collection cycle.
*/
private void clearRequest() {
lock.lock();
requestFlag = false;
lock.unlock();
}
/**
* Wait until a request is received.
*/
private void waitForRequest() {
lock.lock();
lastRequestCount++;
while (lastRequestCount == requestCount) {
lock.await();
}
lock.unlock();
}
}