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.jikesrvm.mm.mmtk;
014
015import org.mmtk.plan.CollectorContext;
016import org.mmtk.plan.MutatorContext;
017
018import org.jikesrvm.VM;
019import org.jikesrvm.architecture.StackFrameLayout;
020import org.jikesrvm.mm.mminterface.MemoryManager;
021import org.jikesrvm.mm.mminterface.Selected;
022import org.jikesrvm.mm.mminterface.CollectorThread;
023import org.jikesrvm.runtime.SysCall;
024import org.jikesrvm.scheduler.RVMThread;
025import org.jikesrvm.scheduler.FinalizerThread;
026
027import org.vmmagic.pragma.Interruptible;
028import org.vmmagic.pragma.Uninterruptible;
029import org.vmmagic.pragma.UninterruptibleNoWarn;
030import org.vmmagic.pragma.Unpreemptible;
031import org.vmmagic.unboxed.Address;
032
033@Uninterruptible
034public class Collection extends org.mmtk.vm.Collection {
035
036  /****************************************************************************
037   *
038   * Class variables
039   */
040
041  /**
042   * {@inheritDoc}
043   */
044  @Override
045  @Interruptible
046  public void spawnCollectorContext(CollectorContext context) {
047    byte[] stack = MemoryManager.newStack(StackFrameLayout.getStackSizeCollector());
048    CollectorThread t = new CollectorThread(stack, context);
049    t.start();
050  }
051
052  @Override
053  public int getDefaultThreads() {
054    return SysCall.sysCall.sysNumProcessors();
055  }
056
057  @Override
058  public int getActiveThreads() {
059    return RVMThread.getNumActiveThreads() - RVMThread.getNumActiveDaemons();
060  }
061
062  @Override
063  @Unpreemptible
064  public void blockForGC() {
065    RVMThread t = RVMThread.getCurrentThread();
066    t.assertAcceptableStates(RVMThread.IN_JAVA, RVMThread.IN_JAVA_TO_BLOCK);
067    RVMThread.observeExecStatusAtSTW(t.getExecStatus());
068    RVMThread.getCurrentThread().block(RVMThread.gcBlockAdapter);
069  }
070
071  /***********************************************************************
072   *
073   * Initialization
074   */
075
076  /**
077   * {@inheritDoc}
078   */
079  @Override
080  @UninterruptibleNoWarn
081  public void outOfMemory() {
082    throw RVMThread.getOutOfMemoryError();
083  }
084
085  @Override
086  public final void prepareMutator(MutatorContext m) {
087    /*
088     * The collector threads of processors currently running threads
089     * off in JNI-land cannot run.
090     */
091    RVMThread t = ((Selected.Mutator) m).getThread();
092    t.monitor().lockNoHandshake();
093    // are these the only unexpected states?
094    t.assertUnacceptableStates(RVMThread.IN_JNI,RVMThread.IN_NATIVE);
095    int execStatus = t.getExecStatus();
096    // these next assertions are not redundant given the ability of the
097    // states to change asynchronously, even when we're holding the lock, since
098    // the thread may change its own state.  of course that shouldn't happen,
099    // but having more assertions never hurts...
100    if (VM.VerifyAssertions) VM._assert(execStatus != RVMThread.IN_JNI);
101    if (VM.VerifyAssertions) VM._assert(execStatus != RVMThread.IN_NATIVE);
102    if (execStatus == RVMThread.BLOCKED_IN_JNI) {
103      if (false) {
104        VM.sysWriteln("for thread #",t.getThreadSlot()," setting up JNI stack scan");
105        VM.sysWriteln("thread #",t.getThreadSlot()," has top java fp = ",t.getJNIEnv().topJavaFP());
106      }
107
108      /* thread is blocked in C for this GC.
109       Its stack needs to be scanned, starting from the "top" java
110       frame, which has been saved in the running threads JNIEnv.  Put
111       the saved frame pointer into the threads saved context regs,
112       which is where the stack scan starts. */
113      t.contextRegisters.setInnermost(Address.zero(), t.getJNIEnv().topJavaFP());
114    }
115    t.monitor().unlock();
116  }
117
118  @Override
119  @Unpreemptible
120  public void stopAllMutators() {
121    RVMThread.blockAllMutatorsForGC();
122  }
123
124  @Override
125  @Unpreemptible
126  public void resumeAllMutators() {
127    RVMThread.unblockAllMutatorsForGC();
128  }
129
130  private static RVMThread.SoftHandshakeVisitor mutatorFlushVisitor =
131    new RVMThread.SoftHandshakeVisitor() {
132      @Override
133      @Uninterruptible
134      public boolean checkAndSignal(RVMThread t) {
135        t.flushRequested = true;
136        return true;
137      }
138      @Override
139      @Uninterruptible
140      public void notifyStuckInNative(RVMThread t) {
141        t.flush();
142        t.flushRequested = false;
143      }
144    };
145
146  @Override
147  @UninterruptibleNoWarn("This method is really unpreemptible, since it involves blocking")
148  public void requestMutatorFlush() {
149    Selected.Mutator.get().flush();
150    RVMThread.softHandshake(mutatorFlushVisitor);
151  }
152
153  /***********************************************************************
154   *
155   * Finalizers
156   */
157
158  /**
159   * Schedule the finalizerThread, if there are objects to be
160   * finalized and the finalizerThread is on its queue (ie. currently
161   * idle).  Should be called at the end of GC after moveToFinalizable
162   * has been called, and before mutators are allowed to run.
163   */
164  @Uninterruptible
165  public static void scheduleFinalizerThread() {
166    int finalizedCount = FinalizableProcessor.countReadyForFinalize();
167    if (finalizedCount > 0) {
168      FinalizerThread.schedule();
169    }
170  }
171}
172