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.scheduler;
014    
015    import org.jikesrvm.VM;
016    import static org.jikesrvm.runtime.SysCall.sysCall;
017    import org.vmmagic.pragma.NonMoving;
018    import org.vmmagic.pragma.Uninterruptible;
019    import org.vmmagic.pragma.UninterruptibleNoWarn;
020    
021    /**
022     * The timer thread.  Although we are using purely native threading, threads
023     * need to occasionally be poked for the purposes of sampling and OSR.
024     * <p>
025     * It should be noted that the implementation of this class prioritizes
026     * unobtrusiveness and lock-freedom over precision.  For example, on any given
027     * timer release some threads may be missed or poked more than once, with the
028     * understanding that if they are missed on one release then they will (with
029     * high probability) not be missed on a future release.
030     * <p>
031     * It may be that to make the system scale, more than one timer thread will
032     * be needed.  But for now, this should suffice.
033     */
034    @Uninterruptible
035    @NonMoving
036    public class TimerThread extends SystemThread {
037      private static final int verbose = 0;
038      public TimerThread() {
039        super("TimerThread");
040      }
041      // NOTE: this runs concurrently with stop-the-world GC
042      // TODO: consider allowing GC to be sampled to enable profile-directed optimization of MMTk.
043      @Override
044      public void run() {
045        VM.disableYieldpoints();
046        if (verbose>=1) VM.sysWriteln("TimerThread run routine entered");
047        try {
048          for (;;) {
049            sysCall.sysNanoSleep(1000L*1000L*VM.interruptQuantum);
050    
051            if (VM.BuildForAdaptiveSystem) {
052              // grab the lock to prevent threads from getting GC'd while we are
053              // iterating (since this thread doesn't stop for GC)
054              RVMThread.acctLock.lockNoHandshake();
055              RVMThread.timerTicks++;
056              for (int i=0;i<RVMThread.numThreads;++i) {
057                RVMThread candidate=RVMThread.threads[i];
058                if (candidate!=null && candidate.shouldBeSampled()) {
059                  candidate.timeSliceExpired++;
060                  candidate.takeYieldpoint=1;
061                }
062              }
063              RVMThread.acctLock.unlock();
064            }
065    
066            RVMThread.checkDebugRequest();
067          }
068        } catch (Throwable e) {
069          printExceptionAndDie(e);
070        }
071      }
072      @UninterruptibleNoWarn
073      private static void printExceptionAndDie(Throwable e) {
074        VM.sysWriteln("Unexpected exception thrown in timer thread: ",e.toString());
075        e.printStackTrace();
076        VM.sysFail("Died in timer thread.");
077      }
078    }
079