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;
014    
015    import org.mmtk.utility.Log;
016    import org.mmtk.utility.heap.HeapGrowthManager;
017    import org.mmtk.utility.options.Options;
018    import org.mmtk.vm.Monitor;
019    import org.mmtk.vm.VM;
020    
021    import org.vmmagic.pragma.*;
022    
023    @Uninterruptible
024    public class ControllerCollectorContext extends CollectorContext {
025    
026      /** The lock to use to manage collection */
027      private Monitor lock;
028    
029      /** The set of worker threads to use */
030      private ParallelCollectorGroup workers;
031    
032      /** Flag used to control the 'race to request' */
033      private boolean requestFlag;
034    
035      /** The current request index */
036      private int requestCount;
037    
038      /** The request index that was last completed */
039      private int lastRequestCount = -1;
040    
041      /** Is there concurrent collection activity */
042      private boolean concurrentCollection = false;
043    
044      /**
045       * Create a controller context.
046       *
047       * @param workers The worker group to use for collection.
048       */
049      public ControllerCollectorContext(ParallelCollectorGroup workers) {
050        this.workers = workers;
051      }
052    
053      @Override
054      @Interruptible
055      public void initCollector(int id) {
056        super.initCollector(id);
057        lock = VM.newHeavyCondLock("CollectorControlLock");
058      }
059    
060      /**
061       * Main execution loop.
062       */
063      @Override
064      @Unpreemptible
065      public void run() {
066        while(true) {
067          // Wait for a collection request.
068          if (Options.verbose.getValue() >= 5) Log.writeln("[STWController: Waiting for request...]");
069          waitForRequest();
070          if (Options.verbose.getValue() >= 5) Log.writeln("[STWController: Request recieved.]");
071    
072          // The start time.
073          long startTime = VM.statistics.nanoTime();
074    
075          if (concurrentCollection) {
076            if (Options.verbose.getValue() >= 5) Log.writeln("[STWController: Stopping concurrent collectors...]");
077            Plan.concurrentWorkers.abortCycle();
078            Plan.concurrentWorkers.waitForCycle();
079            Phase.clearConcurrentPhase();
080            // Collector must re-request concurrent collection in this case.
081            concurrentCollection = false;
082          }
083    
084          // Stop all mutator threads
085          if (Options.verbose.getValue() >= 5) Log.writeln("[STWController: Stopping the world...]");
086          VM.collection.stopAllMutators();
087    
088          // Was this user triggered?
089          boolean userTriggeredCollection = Plan.isUserTriggeredCollection();
090          boolean internalTriggeredCollection = Plan.isInternalTriggeredCollection();
091    
092          // Clear the request
093          clearRequest();
094    
095          // Trigger GC.
096          if (Options.verbose.getValue() >= 5) Log.writeln("[STWController: Triggering worker threads...]");
097          workers.triggerCycle();
098    
099          // Wait for GC threads to complete.
100          workers.waitForCycle();
101          if (Options.verbose.getValue() >= 5) Log.writeln("[STWController: Worker threads complete!]");
102    
103          // Heap growth logic
104          long elapsedTime = VM.statistics.nanoTime() - startTime;
105          HeapGrowthManager.recordGCTime(VM.statistics.nanosToMillis(elapsedTime));
106          if (VM.activePlan.global().lastCollectionFullHeap() && !internalTriggeredCollection) {
107            if (Options.variableSizeHeap.getValue() && !userTriggeredCollection) {
108              // Don't consider changing the heap size if the application triggered the collection
109              if (Options.verbose.getValue() >= 5) Log.writeln("[STWController: Considering heap size.]");
110              HeapGrowthManager.considerHeapSize();
111            }
112            HeapGrowthManager.reset();
113          }
114    
115          // Reset the triggering information.
116          Plan.resetCollectionTrigger();
117    
118          // Resume all mutators
119          if (Options.verbose.getValue() >= 5) Log.writeln("[STWController: Resuming mutators...]");
120          VM.collection.resumeAllMutators();
121    
122          // Start threads that will perform concurrent collection work alongside mutators.
123          if (concurrentCollection) {
124            if (Options.verbose.getValue() >= 5) Log.writeln("[STWController: Triggering concurrent collectors...]");
125            Plan.concurrentWorkers.triggerCycle();
126          }
127        }
128      }
129    
130      /**
131       * Request that concurrent collection is performed after this stop-the-world increment.
132       */
133      public void requestConcurrentCollection() {
134        concurrentCollection = true;
135      }
136    
137      /**
138       * Request a collection.
139       */
140      public void request() {
141        if (requestFlag) {
142          return;
143        }
144        lock.lock();
145        if (!requestFlag) {
146          requestFlag = true;
147          requestCount++;
148          lock.broadcast();
149        }
150        lock.unlock();
151      }
152    
153      /**
154       * Clear the collection request, making future requests incur an
155       * additional collection cycle.
156       */
157      private void clearRequest() {
158        lock.lock();
159        requestFlag = false;
160        lock.unlock();
161      }
162    
163      /**
164       * Wait until a request is received.
165       */
166      private void waitForRequest() {
167        lock.lock();
168        lastRequestCount++;
169        while (lastRequestCount == requestCount) {
170          lock.await();
171        }
172        lock.unlock();
173      }
174    }