Untitled

mail@pastecode.io avatar
unknown
plain_text
2 years ago
4.3 kB
2
Indexable
Never
package nachos.threads;

import nachos.machine.*;

// import priority queue 
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() {

        // KThread.currentThread().yield1();

        // disable interrupt
        boolean intStatus = Machine.interrupt().disable();

        while (!waitQueue.isEmpty() && waitQueue.peek().wakeTime <= Machine.timer().getTime()) {
            // Retrieves and removes the head of the queue, or return null if this queue is empty.
            // then set the current thread from waiting state in waitQueue to ready state in ready queue.
            // waitQueue.poll().thread.ready();
            WaitingThread test = waitQueue.poll();
            test.wakeWaitingThread();
        }

        // Preempt current thread as normal
        // KThread.yield1();

        // enable interrupt
        Machine.interrupt().restore(intStatus);

    }

    /**
     * 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)

        // disable interrupt
        boolean intStatus = Machine.interrupt().disable();

        long wakeTime = Machine.timer().getTime() + x;
        // while (wakeTime > Machine.timer().getTime()) {
        //     KThread.yield1();
        // }

        // to check if the wakeTime >=  WaitUntil called time + x
        // System.out.println(wakeTime + ":" + Machine.timer().getTime() + ":" + x);

        KThread currentThread = KThread.currentThread();

        // create a waitingThread object
        WaitingThread waitingThread = new WaitingThread(currentThread, wakeTime);
        
        // place the waitingThread in the waitQueue
        waitQueue.add(waitingThread);

        // put the current thread to sleep using condition2
        // alarmCondition.sleep();
        lock.acquire();
        alarmCondition.sleep();
        lock.release();
        
        // Not using Kthread to put thread to sleep instead using condition2 
        // KThread.sleep();

        // enable interrupt
        Machine.interrupt().restore(intStatus);

    }


    // added WaitingThread
    private class WaitingThread implements Comparable<WaitingThread> {
        KThread thread;
        long wakeTime;

        public WaitingThread(KThread thread, long wakeTime) {
            this.thread = thread;
            this.wakeTime = wakeTime;
        }

        public void wakeWaitingThread(){
            alarmCondition.wake();
        }

        public int compareTo(WaitingThread thread) {
            if (this.wakeTime < thread.wakeTime) {
                return -1;
            } else if (this.wakeTime > thread.wakeTime) {
                return 1;
            } else {
                return 0;
            }
        }

    }

    // created waitQueue
    private PriorityQueue<WaitingThread> waitQueue = new PriorityQueue<WaitingThread>();
    
    // create a private Lock called lock.
    private Lock lock = new Lock();

    // create a private Condition2 called alarmCondition.
    private Condition2 alarmCondition = new Condition2(lock);
}