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.jikesrvm.mm.mminterface;
014    
015    import org.jikesrvm.VM;
016    import org.jikesrvm.mm.mmtk.Collection;
017    import org.jikesrvm.scheduler.RVMThread;
018    import org.jikesrvm.scheduler.Monitor;
019    import org.vmmagic.pragma.Unpreemptible;
020    import org.mmtk.plan.Plan;
021    
022    /**
023     * Handshake handles mutator requests to initiate a collection, and
024     * wait for a collection to complete.  It implements the process of
025     * suspending all mutator threads executing in Java and starting all
026     * the GC threads (CollectorThreads) for the processors that will
027     * be participating in a collection.  This may not be all processors,
028     * if we exclude those executing in native code.
029     *
030     * Because the threading strategy within RVM is currently under
031     * revision, the logic here is also changing and somewhat "messy".
032     *
033     * @see CollectorThread
034     */
035    public class Handshake {
036    
037      /***********************************************************************
038       *
039       * Class variables
040       */
041      public static final int verbose = 0;
042    
043      /***********************************************************************
044       *
045       * Instance variables
046       */
047      private Monitor lock;
048      protected boolean requestFlag;
049      public int gcTrigger;  // reason for this GC
050      private int collectorThreadsParked;
051    
052      public Handshake() {
053        reset();
054      }
055      public void boot() {
056        lock = new Monitor();
057      }
058    
059      /**
060       * Call this if you know that a GC request has already been made and you'd like
061       * to wait on that GC to finish - presumably because you're trying to allocate
062       * and cannot reasonably do so before GC is done.  Note, there CANNOT be a
063       * GC safe point between when you realize that there is already a GC request and
064       * when you call this method!
065       */
066      @Unpreemptible
067      public void waitForGCToFinish() {
068        if (verbose >= 1) VM.sysWriteln("GC Message: Handshake.requestAndAwaitCompletion - yielding");
069        /* allow a gc thread to run */
070        RVMThread t=RVMThread.getCurrentThread();
071        t.assertAcceptableStates(RVMThread.IN_JAVA,
072                                 RVMThread.IN_JAVA_TO_BLOCK);
073        RVMThread.observeExecStatusAtSTW(t.getExecStatus());
074        t.block(RVMThread.gcBlockAdapter);
075        if (verbose >= 1) VM.sysWriteln("GC Message: Handshake.requestAndAwaitCompletion - mutator running");
076      }
077    
078      /**
079       * Called by mutators to request a garbage collection and wait for
080       * it to complete.
081       *
082       * Waiting is actually just yielding the processor to schedule the
083       * collector thread, which will disable further thread switching on
084       * the processor until it has completed the collection.
085       */
086      @Unpreemptible
087      public void requestAndAwaitCompletion(int why) {
088        request(why);
089        waitForGCToFinish();
090      }
091    
092      /**
093       * Called by mutators to request an asynchronous garbage collection.
094       * After initiating a GC (if one is not already initiated), the
095       * caller continues until it yields to the GC.  It may thus make
096       * this call at an otherwise unsafe point.
097       */
098      @Unpreemptible("Change state of thread possibly context switching if generating exception")
099      public void requestAndContinue(int why) {
100        request(why);
101      }
102    
103      @Unpreemptible
104      public void reset() {
105        if (lock!=null) {
106          lock.lockNoHandshake();
107        }
108        gcTrigger = Collection.UNKNOWN_GC_TRIGGER;
109        requestFlag = false;
110        if (lock!=null) {
111          lock.unlock();
112        }
113      }
114      @Unpreemptible
115      void parkCollectorThread() {
116        lock.lockNoHandshake();
117        collectorThreadsParked++;
118        lock.broadcast();
119        if (verbose>=1) VM.sysWriteln("GC Thread #",RVMThread.getCurrentThreadSlot()," parked.");
120        while (!requestFlag) {
121          if (verbose>=1) VM.sysWriteln("GC Thread #",RVMThread.getCurrentThreadSlot()," waiting for request.");
122          lock.waitWithHandshake();
123        }
124        if (verbose>=1) VM.sysWriteln("GC Thread #",RVMThread.getCurrentThreadSlot()," got request, unparking.");
125        collectorThreadsParked--;
126        lock.unlock();
127      }
128    
129      /**
130       * Called by mutators to request a garbage collection.
131       *
132       * @return true if the completion flag is not already set.
133       */
134      @Unpreemptible("Becoming another thread interrupts the current thread, avoid preemption in the process")
135      private boolean request(int why) {
136        if (verbose>=1) VM.sysWriteln("Thread #",RVMThread.getCurrentThreadSlot()," is trying to make a GC request");
137        lock.lockNoHandshake();
138        if (verbose>=1) VM.sysWriteln("Thread #",RVMThread.getCurrentThreadSlot()," acquired the lock for making a GC request");
139        if (why > gcTrigger) gcTrigger = why;
140        if (requestFlag) {
141          if (verbose >= 1) {
142            VM.sysWriteln("GC Message: mutator: already in progress");
143          }
144        } else {
145          // first mutator initiates collection by making all gc threads
146          // runnable at high priority
147          if (verbose >= 1) VM.sysWriteln("GC Message: Handshake - mutator: initiating collection");
148    
149          if (!RVMThread.threadingInitialized) {
150            VM.sysWrite("GC required before system fully initialized");
151            VM.sysWriteln("Specify larger than default heapsize on command line");
152            RVMThread.dumpStack();
153            VM.shutdown(VM.EXIT_STATUS_MISC_TROUBLE);
154          }
155    
156          requestFlag = true;
157          Plan.setCollectionTriggered();
158          lock.broadcast();
159        }
160        lock.unlock();
161        return true;
162      }
163    }
164