/* * This file is part of the Jikes RVM project (http://jikesrvm.org). * * This file is licensed to You under the Common Public License (CPL); * You may not use this file except in compliance with the License. You * may obtain a copy of the License at * * http://www.opensource.org/licenses/cpl1.0.php * * See the COPYRIGHT.txt file distributed with this work for information * regarding copyright ownership. */ package org.jikesrvm.scheduler.greenthreads; import org.jikesrvm.VM; import org.jikesrvm.runtime.VM_Magic; import static org.jikesrvm.runtime.VM_SysCall.sysCall; import org.jikesrvm.runtime.VM_Time; import org.jikesrvm.scheduler.VM_Scheduler; import org.vmmagic.pragma.Uninterruptible; /** * Low priority thread to run when there's nothing else to do. * This thread also handles initializing the virtual processor * for execution. * * This follows the Singleton pattern. */ final class VM_IdleThread extends VM_GreenThread { /** * Should we call VM_Processor.initializeProcessor as the first action * of run? True for every idle thread except the one that runs on the * primordial processor. */ private boolean runInitProc; /** * A thread to run if there is no other work for a virtual processor. */ VM_IdleThread(VM_GreenProcessor processorAffinity, boolean runInitProcessor) { super("VM_IdleThread"); makeDaemon(true); super.processorAffinity = processorAffinity; runInitProc = runInitProcessor; setPriority(Thread.MIN_PRIORITY); } /** * Is this the idle thread? * @return true */ @Uninterruptible @Override public boolean isIdleThread() { return true; } @Override public void run() { // overrides VM_Thread if (state != State.RUNNABLE) changeThreadState(State.NEW, State.RUNNABLE); VM_GreenProcessor myProcessor = VM_GreenProcessor.getCurrentProcessor(); if (VM.ExtremeAssertions) VM._assert(myProcessor == processorAffinity); if (runInitProc) myProcessor.initializeProcessor(); // Only perform load balancing if there is more than one processor. final boolean loadBalancing = VM_GreenScheduler.numProcessors > 1; long spinNano = loadBalancing ? ((long)1e6) : 0; main: while (true) { if (VM_Scheduler.terminated) terminate(); // FIXME: if (VM.VerifyAssertions) VM._assert(processorAffinity.idleQueue.isEmpty()); long t = VM_Time.nanoTime() + spinNano; if (VM_Scheduler.debugRequested) { VM.sysWriteln("debug requested in idle thread"); VM_Scheduler.debugRequested = false; } do { VM_GreenProcessor.idleProcessor = myProcessor; if (availableWork(myProcessor)) { if (VM.ExtremeAssertions) { VM._assert(myProcessor == VM_GreenProcessor.getCurrentProcessor()); } VM_GreenThread.yield(VM_GreenProcessor.getCurrentProcessor().idleQueue); continue main; } } while (VM_Time.nanoTime() < t); /* Now go into the long-term sleep/check-for-work loop. */ for (; ;) { sysCall.sysVirtualProcessorYield(); if (availableWork(myProcessor)) { continue main; } VM_GreenThread.yield(VM_GreenProcessor.getCurrentProcessor().idleQueue); /* Doze a millisecond (well, Linux rounds it up to a centisecond) */ sysCall.sysNanosleep((long)1e6); } } } /** * @return true, if there appears to be a runnable thread for the processor to execute */ private static boolean availableWork(VM_GreenProcessor p) { if (!p.readyQueue.isEmpty()) return true; VM_Magic.isync(); if (!p.transferQueue.isEmpty()) return true; if (p.ioQueue.isReady()) return true; if (p.subArchQueue.isReady()) return true; if (VM_GreenScheduler.wakeupQueue.isReady()) { VM_GreenScheduler.wakeupMutex.lock("wakeup mutex"); VM_GreenThread t = VM_GreenScheduler.wakeupQueue.dequeue(); VM_GreenScheduler.wakeupMutex.unlock(); if (t != null) { t.schedule(); return true; } } return false; } }