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 */
013package org.mmtk.plan.concurrent;
014
015import org.mmtk.plan.Phase;
016import org.mmtk.plan.Plan;
017import org.mmtk.plan.SimpleCollector;
018import org.mmtk.plan.TraceLocal;
019import org.mmtk.utility.Log;
020import org.mmtk.utility.options.Options;
021import org.mmtk.vm.VM;
022
023import 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
030public 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   * @return whether all work has 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}