package nachos.threads; import nachos.machine.*; import java.util.PriorityQueue; /** * Uses the hardware timer to provide preemption, and to allow threads to sleep * until a certain time. */ public class Alarm { /** * Allocate a new Alarm. Set the machine's timer interrupt handler to this * alarm's callback. * * <p><b>Note</b>: Nachos will not function correctly with more than one * alarm. */ public Alarm() { Machine.timer().setInterruptHandler(new Runnable() { public void run() { timerInterrupt(); } }); } /** * The timer interrupt handler. This is called by the machine's timer * periodically (approximately every 500 clock ticks). Causes the current * thread to yield, forcing a context switch if there is another thread * that should be run. */ public void timerInterrupt() { Machine.interrupt().disable(); while(waitQueue.peek() != null && ((BlockedThread)waitQueue.peek()).x < Machine.timer().getTime()) { waitQueue.poll().t.ready(); } KThread.currentThread().yield(); } /** * Put the current thread to sleep for at least <i>x</i> ticks, * waking it up in the timer interrupt handler. The thread must be * woken up (placed in the scheduler ready set) during the first timer * interrupt where * * <p><blockquote> * (current time) >= (WaitUntil called time)+(x) * </blockquote> * * @param x the minimum number of clock ticks to wait. * * @see nachos.machine.Timer#getTime() */ public void waitUntil(long x) { // for now, cheat just to get something working (busy waiting is bad) // long wakeTime = Machine.timer().getTime() + x; // while (wakeTime > Machine.timer().getTime()) // KThread.yield(); Machine.interrupt().disable(); BlockedThread t = new BlockedThread(); t.t = KThread.currentThread(); t.x = x + Machine.timer().getTime(); waitQueue.offer(t); KThread.sleep(); } public class BlockedThread implements Comparable { public KThread t; public long x; public int compareTo(Object t) { if(x == ((BlockedThread)t).x) return 0; else if(x < ((BlockedThread)t).x) return 1; else return -1; } } PriorityQueue<BlockedThread> waitQueue = new PriorityQueue<BlockedThread>(); }