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.scheduler;
014
015import org.jikesrvm.VM;
016import static org.jikesrvm.runtime.SysCall.sysCall;
017import org.vmmagic.pragma.NonMoving;
018import org.vmmagic.pragma.Uninterruptible;
019import 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
036public 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