/** * Initialize this kernel. Creates a synchronized console and sets the * processor's exception handler. */ public void initialize(String[] args) { super.initialize(args); console = new SynchConsole(Machine.console()); Machine.processor().setExceptionHandler(new Runnable() { public void run() { exceptionHandler(); } }); }
public class SwapFile { public static OpenFile swapFile; private static String swapName; private static int PAGESIZE = Machine.processor().pageSize; public static List<Integer> freePages; public static List<Integer> allocatedPages; private static Lock swapLock; private static byte[] memory = Machine.processor().getMemory(); public static void initialize(String filename) { swapFile = ThreadedKernel.fileSystem.open(filename, true); swapName = filename; freePages = new LinkedList<Integer>(); allocatedPages = new LinkedList<Integer>(); swapLock = new Lock(); } public static void close() { swapFile.close(); ThreadedKernel.fileSystem.remove(swapName); } public static int insertPage(int spn, int ppn) { swapLock.acquire(); int numBits = swapFile.write(spn * PAGESIZE, memory, ppn * PAGESIZE, PAGESIZE); // assert that numBits == PAGESIZE allocatedPages.add(spn); swapLock.release(); return spn; } /* we will try to allocate a free page from the freepages*/ public static int insertPage(int ppn) { int numBits = 0; int spn = swapFile.length() / PAGESIZE; if (freePages.size() > 0) { spn = freePages.remove(0); } return insertPage(spn, ppn); } public static void readPage(int spn, int ppn) { if (allocatedPages.contains(spn)) { swapLock.acquire(); swapFile.read(spn * PAGESIZE, memory, ppn * PAGESIZE, PAGESIZE); swapLock.release(); } else { } } public static void free(int page) { swapLock.acquire(); freePages.add(page); swapLock.release(); } }
/** * Wake up at most one thread sleeping on this condition variable. The current thread must hold * the associated lock. */ public void wake() { Lib.assertTrue(conditionLock.isHeldByCurrentThread()); boolean intStatus = Machine.interrupt().disable(); // +hy+ ((KThread) waitQueue.removeFirst()).ready(); // +hy+ Machine.interrupt().restore(intStatus); // +hy+ }
private void syncTLB() { for (int i = 0; i < Machine.processor().getTLBSize(); i++) { TranslationEntry tE = Machine.processor().readTLBEntry(i); if (tE.valid) { pageTable[tE.vpn].dirty = tE.dirty; pageTable[tE.vpn].used = tE.used; } } }
public void wakeJoinedThreads() { boolean oldInterruptStatus = Machine.interrupt().disable(); KThread thread = null; do { thread = waitingKThreadListToJoin.nextThread(); if (thread != null) { thread.ready(); } } while (thread != null); Machine.interrupt().restore(oldInterruptStatus); }
/** Moves this thread to the ready state and adds this to the scheduler's ready queue. */ public void ready() { Lib.debug(dbgThread, "Ready thread: " + toString()); Lib.assertTrue(Machine.interrupt().disabled()); Lib.assertTrue(status != statusReady); status = statusReady; if (this != idleThread) readyQueue.waitForAccess(this); Machine.autoGrader().readyThread(this); }
/** * Atomically release the associated lock and go to sleep on this condition variable until another * thread wakes it using <tt>wake()</tt>. The current thread must hold the associated lock. The * thread will automatically reacquire the lock before <tt>sleep()</tt> returns. */ public void sleep() { Lib.assertTrue(conditionLock.isHeldByCurrentThread()); boolean intStatus = Machine.interrupt().disable(); conditionLock.release(); waitQueue.waitForAccess(KThread.currentThread()); KThread.sleep(); conditionLock.acquire(); Machine.interrupt().restore(intStatus); }
/** * Wake up at most one thread sleeping on this condition variable. The current thread must hold * the associated lock. */ public void wake() { Lib.assertTrue(conditionLock.isHeldByCurrentThread()); boolean intStatus = Machine.interrupt().disable(); KThread thread = waitQueue.nextThread(); if (thread != null) { thread.ready(); } Machine.interrupt().restore(intStatus); }
/** * Save the state of this process in preparation for a context switch. Called by * <tt>UThread.saveState()</tt>. */ public void saveState() { for (int i = 0; i < Machine.processor().getTLBSize(); i++) { TranslationEntry tE = Machine.processor().readTLBEntry(i); if (tE.valid) { pageTable[tE.vpn].dirty = tE.dirty; pageTable[tE.vpn].used = tE.used; } tE.valid = false; Machine.processor().writeTLBEntry(i, tE); // savedState[i] = tE.vpn; } }
/** * Relinquish the CPU if any other thread is ready to run. If so, put the current thread on the * ready queue, so that it will eventually be rescheuled. * * <p>Returns immediately if no other thread is ready to run. Otherwise returns when the current * thread is chosen to run again by <tt>readyQueue.nextThread()</tt>. * * <p>Interrupts are disabled, so that the current thread can atomically add itself to the ready * queue and switch to the next thread. On return, restores interrupts to the previous state, in * case <tt>yield()</tt> was called with interrupts disabled. */ public static void yield() { Lib.debug(dbgThread, "Yielding thread: " + currentThread.toString()); Lib.assertTrue(currentThread.status == statusRunning); boolean intStatus = Machine.interrupt().disable(); currentThread.ready(); runNextThread(); Machine.interrupt().restore(intStatus); }
public void run() { long wakeTime = randomDelay(); System.out.println( "** " + name + ": Sleeping for " + wakeTime + " (i.e., until time=" + (wakeTime + Machine.timer().getTime()) + ")"); ThreadedKernel.alarm.waitUntil(wakeTime); System.out.println(name + " is Done Sleeping (time=" + Machine.timer().getTime() + ")"); }
/** * 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) { // disable interrupts Machine.interrupt().disable(); // let's see if this works? DAC DEBUG // calculate wakeTime long wakeTime = Machine.timer().getTime() + x; // create AlarmBucket AlarmBucket Abuck = new AlarmBucket(wakeTime, KThread.currentThread()); // add current thread (alarm bucket) to waitQueue waitQueue.add(Abuck); // put current thread to sleep KThread.currentThread().sleep(); return; }
/** * Finish the current thread and schedule it to be destroyed when it is safe to do so. This method * is automatically called when a thread's <tt>run</tt> method returns, but it may also be called * directly. * * <p>The current thread cannot be immediately destroyed because its stack and other execution * state are still in use. Instead, this thread will be destroyed automatically by the next thread * to run, when it is safe to delete this thread. */ public static void finish() { Lib.debug(dbgThread, "Finishing thread: " + currentThread.toString()); Machine.interrupt().disable(); Machine.autoGrader().finishingCurrentThread(); Lib.assertTrue(toBeDestroyed == null); toBeDestroyed = currentThread; currentThread.status = statusFinished; sleep(); }
/** * Dispatch the CPU to this thread. Save the state of the current thread, switch to the new thread * by calling <tt>TCB.contextSwitch()</tt>, and load the state of the new thread. The new thread * becomes the current thread. * * <p>If the new thread and the old thread are the same, this method must still call * <tt>saveState()</tt>, <tt>contextSwitch()</tt>, and <tt>restoreState()</tt>. * * <p>The state of the previously running thread must already have been changed from running to * blocked or ready (depending on whether the thread is sleeping or yielding). * * @param finishing <tt>true</tt> if the current thread is finished, and should be destroyed by * the new thread. */ private void run() { Lib.assertTrue(Machine.interrupt().disabled()); Machine.yield(); currentThread.saveState(); Lib.debug(dbgThread, "Switching from: " + currentThread.toString() + " to: " + toString()); currentThread = this; tcb.contextSwitch(); currentThread.restoreState(); }
/** * Waits for this thread to finish. If this thread is already finished, return immediately. This * method must only be called once; the second call is not guaranteed to return. This thread must * not be the current thread. */ public void join() { Lib.debug(dbgThread, "Joining to thread: " + toString()); // FIXME Touhid :: join() edit starts boolean intStatus = Machine.interrupt().setStatus(false); if (status != statusFinished) { // Joinee is not finished yet waitingKThreadListToJoin.waitForAccess(currentThread()); KThread.sleep(); } Machine.interrupt().restore(intStatus); // join() edit ends Lib.assertTrue(this != currentThread); }
/** * The exception handler. This handler is called by the processor whenever * a user instruction causes a processor exception. * * <p> * When the exception handler is invoked, interrupts are enabled, and the * processor's cause register contains an integer identifying the cause of * the exception (see the <tt>exceptionZZZ</tt> constants in the * <tt>Processor</tt> class). If the exception involves a bad virtual * address (e.g. page fault, TLB miss, read-only, bus error, or address * error), the processor's BadVAddr register identifies the virtual address * that caused the exception. */ public void exceptionHandler() { Lib.assert(KThread.currentThread() instanceof UThread); UserProcess process = ((UThread) KThread.currentThread()).process; int cause = Machine.processor().readRegister(Processor.regCause); process.handleException(cause); }
/** * Transfer data from the specified array to this process's virtual memory. This method handles * address translation details. This method must <i>not</i> destroy the current process if an * error occurs, but instead should return the number of bytes successfully copied (or zero if no * data could be copied). * * @param vaddr the first byte of virtual memory to write. * @param data the array containing the data to transfer. * @param offset the first byte to transfer from the array. * @param length the number of bytes to transfer from the array to virtual memory. * @return the number of bytes successfully transferred. */ public int writeVirtualMemory(int vaddr, byte[] data, int offset, int length) { Lib.assertTrue(offset >= 0 && length >= 0 && offset + length <= data.length); byte[] memory = Machine.processor().getMemory(); int transferred = 0; while (length > 0 && offset < data.length) { int addrOffset = vaddr % 1024; int virtualPage = vaddr / 1024; if (virtualPage >= pageTable.length || virtualPage < 0) { break; } TranslationEntry pte = pageTable[virtualPage]; if (!pte.valid || pte.readOnly) { break; } pte.used = true; pte.dirty = true; int physPage = pte.ppn; int physAddr = physPage * 1024 + addrOffset; int transferLength = Math.min(data.length - offset, Math.min(length, 1024 - addrOffset)); System.arraycopy(data, offset, memory, physAddr, transferLength); vaddr += transferLength; offset += transferLength; length -= transferLength; transferred += transferLength; } return transferred; }
/** * Waits for this thread to finish. If this thread is already finished, return immediately. This * method must only be called once; the second call is not guaranteed to return. This thread must * not be the current thread. */ public void join() { boolean intStatus = Machine.interrupt().disable(); Lib.debug(dbgThread, "Joining to thread: " + toString()); Lib.assertTrue(this != currentThread); if (cont == 0) { cont = 1; if (this.status == statusFinished) { return; } else { this.joinList.add(currentThread); currentThread.sleep(); } } Machine.interrupt().restore(intStatus); }
/** * Prepare this thread to be run. Set <tt>status</tt> to <tt>statusRunning</tt> and check * <tt>toBeDestroyed</tt>. */ protected void restoreState() { Lib.debug(dbgThread, "Running thread: " + currentThread.toString()); Lib.assertTrue(Machine.interrupt().disabled()); Lib.assertTrue(this == currentThread); Lib.assertTrue(tcb == TCB.currentTCB()); Machine.autoGrader().runningThread(this); status = statusRunning; if (toBeDestroyed != null) { toBeDestroyed.tcb.destroy(); toBeDestroyed.tcb = null; toBeDestroyed = null; } }
@Override protected void init() { super.init(); System.out.println("\ninitializing VMGrader.."); System.out.println("physical pages = " + Machine.processor().getNumPhysPages()); if (hasArgument(SwapFile)) swapFile = getStringArgument(SwapFile); }
/** * Finish the current thread and schedule it to be destroyed when it is safe to do so. This method * is automatically called when a thread's <tt>run</tt> method returns, but it may also be called * directly. * * <p>The current thread cannot be immediately destroyed because its stack and other execution * state are still in use. Instead, this thread will be destroyed automatically by the next thread * to run, when it is safe to delete this thread. */ public static void finish() { Lib.debug(dbgThread, "Finishing thread: " + currentThread.toString()); // FIXME Touhid :: Wake threads that have joined the currently running // thread currentThread.wakeJoinedThreads(); Machine.interrupt().disable(); Machine.autoGrader().finishingCurrentThread(); Lib.assertTrue(toBeDestroyed == null); toBeDestroyed = currentThread; currentThread.status = statusFinished; sleep(); }
/** * 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(); } }); }
/** * Wait for a thread to speak through this communicator, and then return the <i>word</i> that * thread passed to <tt>speak()</tt>. * * @return the integer transferred. */ public int listen() { boolean intStatus = Machine.interrupt().disable(); condLock.acquire(); listenCount++; speakCond.wake(); if (msgList.isEmpty()) listenCond.sleep(); condLock.release(); Machine.interrupt().restore(intStatus); // Must have msg if reach here. return msgList.remove(0); }
/** * Relinquish the CPU, because the current thread has either finished or it is blocked. This * thread must be the current thread. * * <p>If the current thread is blocked (on a synchronization primitive, i.e. a <tt>Semaphore</tt>, * <tt>Lock</tt>, or <tt>Condition</tt>), eventually some thread will wake this thread up, putting * it back on the ready queue so that it can be rescheduled. Otherwise, <tt>finish()</tt> should * have scheduled this thread to be destroyed by the next thread to run. */ public static void sleep() { Lib.debug(dbgThread, "Sleeping thread: " + currentThread.toString()); Lib.assertTrue(Machine.interrupt().disabled()); if (currentThread.status != statusFinished) currentThread.status = statusBlocked; runNextThread(); }
/** Handle the halt() system call. */ private int handleHalt() { if (this.process_id != ROOT) { return 0; } Machine.halt(); Lib.assertNotReached("Machine.halt() did not halt machine!"); return 0; }
private void begin() { Lib.debug(dbgThread, "Beginning thread: " + toString()); Lib.assertTrue(this == currentThread); restoreState(); Machine.interrupt().enable(); }
/** * Start running user programs, by creating a process and running a shell * program in it. The name of the shell program it must run is returned by * <tt>Machine.getShellProgramName()</tt>. * * @see nachos.machine.Machine#getShellProgramName */ public void run() { super.run(); UserProcess process = UserProcess.newUserProcess(); String shellProgram = Machine.getShellProgramName(); Lib.assert(process.execute(shellProgram, new String[] { })); KThread.currentThread().finish(); }
/** * Wait for a thread to listen through this communicator, and then transfer <i>word</i> to the * listener. * * <p>Does not return until this thread is paired up with a listening thread. Exactly one listener * should receive <i>word</i>. * * @param word the integer to transfer. */ public void speak(int word) { boolean intStatus = Machine.interrupt().disable(); condLock.acquire(); if (listenCount == 0) { speakCond.sleep(); } listenCount--; msgList.add(word); listenCond.wake(); condLock.release(); Machine.interrupt().restore(intStatus); }
/** * Causes this thread to begin execution. The result is that two threads are running concurrently: * the current thread (which returns from the call to the <tt>fork</tt> method) and the other * thread (which executes its target's <tt>run</tt> method). */ public void fork() { Lib.assertTrue(status == statusNew); Lib.assertTrue(target != null); Lib.debug(dbgThread, "Forking thread: " + toString() + " Runnable: " + target); boolean intStatus = Machine.interrupt().disable(); tcb.start( new Runnable() { public void run() { runThread(); } }); ready(); Machine.interrupt().restore(intStatus); }
@Override protected int handleTestSystemCall(int type, int a0, int a1, int a2) { switch (type) { case ActionPhyPages: return Machine.processor().getNumPhysPages(); case ActionGetSwapSize: return getSwapSize(); default: return super.handleTestSystemCall(type, a0, a1, a2); } }