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    }