tcb.java
来自「Nachos 5 java version」· Java 代码 · 共 309 行
JAVA
309 行
// PART OF THE MACHINE SIMULATION. DO NOT CHANGE.package nachos.machine;import nachos.security.*;import nachos.threads.KThread;import java.util.Vector;import java.security.PrivilegedAction;/** * A TCB simulates the low-level details necessary to create, context-switch, * and destroy Nachos threads. Each TCB controls an underlying JVM Thread * object. * * <p> * Do not use any methods in <tt>java.lang.Thread</tt>, as they are not * compatible with the TCB API. Most <tt>Thread</tt> methods will either crash * Nachos or have no useful effect. * * <p> * Do not use the <i>synchronized</i> keyword <b>anywhere</b> in your code. * It's against the rules, <i>and</i> it can easily deadlock nachos. */public final class TCB { /** * Allocate a new TCB. */ public TCB() { } /** * Give the TCB class the necessary privilege to create threads. This is * necessary, because unlike other machine classes that need privilege, we * want the kernel to be able to create TCB objects on its own. * * @param privilege encapsulates privileged access to the Nachos * machine. */ public static void givePrivilege(Privilege privilege) { TCB.privilege = privilege; privilege.tcb = new TCBPrivilege(); } /** * Causes the thread represented by this TCB to begin execution. The * specified target is run in the thread. */ public void start(Runnable target) { // make sure this TCB has not already been started Lib.assert(javaThread == null && !done); // make sure there aren't too many threads already Lib.assert(runningThreads.size() < maxThreads); isFirstTCB = runningThreads.isEmpty(); if (!isFirstTCB) { // make sure the current TCB is correct Lib.assert(currentTCB != null && currentTCB.javaThread == Thread.currentThread()); } // TCB start has been approved. add to collection of running threads. runningThreads.add(this); this.target = target; // if not the first, have to make a thread to run if (!isFirstTCB) { tcbTarget = new Runnable() { public void run() { threadroot(); } }; // creating threads is a privileged operation privilege.doPrivileged(new Runnable() { public void run() { javaThread = new Thread(tcbTarget); } }); // now start thread and wait for it to notify us from threadroot currentTCB.running = false; this.javaThread.start(); currentTCB.waitForInterrupt(); } // otherwise, just call threadroot directly... else { currentTCB = this; javaThread = Thread.currentThread(); threadroot(); } } /** * Return the TCB of the currently running thread. */ public static TCB currentTCB() { return currentTCB; } /** * Context switch between the current TCB and this TCB. This TCB will * become the new current TCB. It is acceptable for this TCB to be the * current TCB. */ public void contextSwitch() { // make sure the current TCB is correct Lib.assert(currentTCB != null && currentTCB.javaThread == Thread.currentThread()); // make sure AutoGrader.runningThread() called associateThread() Lib.assert(currentTCB.associated); currentTCB.associated = false; // can't switch from a TCB to itself if (this == currentTCB) return; /* There are some synchronization concerns here. As soon as we wake up * the next thread, we cannot assume anything about static variables, * or about any TCB's state. Therefore, before waking up the next * thread, we must latch the value of currentTCB, and set its running * flag to false (so that, in case we get interrupted before we call * yield(), the interrupt will set the running flag and yield() won't * block). */ TCB previous = currentTCB; previous.running = false; this.interrupt(); previous.yield(); } /** * Destroy this TCB. This TCB must not be in use by the current thread. * This TCB must also have been authorized to be destroyed by the * autograder. */ public void destroy() { // make sure the current TCB is correct Lib.assert(currentTCB != null && currentTCB.javaThread == Thread.currentThread()); // can't destroy current thread Lib.assert(this != currentTCB); // thread must have started but not be destroyed yet Lib.assert(javaThread != null && !done); // ensure AutoGrader.finishingCurrentThread() called authorizeDestroy() Lib.assert(nachosThread == toBeDestroyed); toBeDestroyed = null; this.done = true; currentTCB.running = false; this.interrupt(); currentTCB.waitForInterrupt(); this.javaThread = null; } /** * Destroy all TCBs and exit Nachos. Same as <tt>Machine.terminate()</tt>. */ public static void die() { privilege.exit(0); } /** * Test if the current JVM thread belongs to a Nachos TCB. The AWT event * dispatcher is an example of a non-Nachos thread. * * @return <tt>true</tt> if the current JVM thread is a Nachos thread. */ public static boolean isNachosThread() { return (currentTCB != null && Thread.currentThread() == currentTCB.javaThread); } private void threadroot() { // this should be running the current thread Lib.assert(javaThread == Thread.currentThread()); if (!isFirstTCB) { // make sure currentTCB is some other thread Lib.assert(currentTCB != null && this != currentTCB); // let currentTCB get out of start() currentTCB.interrupt(); // wait to be scheduled to run this.yield(); } else { // make sure currentTCB is us Lib.assert(currentTCB != null && this == currentTCB); // we get to run immediately running = true; } try { target.run(); // no way out of here without going throw one of the catch blocks Lib.assertNotReached(); } catch (ThreadDeath e) { // make sure this TCB is being destroyed properly if (!done) { System.err.print("\nTCB terminated improperly!\n"); privilege.exit(1); } runningThreads.removeElement(this); if (runningThreads.isEmpty()) privilege.exit(0); } catch (Throwable e) { e.printStackTrace(); runningThreads.removeElement(this); if (runningThreads.isEmpty()) privilege.exit(1); else die(); } } private void yield() { waitForInterrupt(); if (done) { currentTCB.interrupt(); throw new ThreadDeath(); } currentTCB = this; } private synchronized void waitForInterrupt() { while (!running) { try { wait(); } catch (InterruptedException e) { } if (currentTCB == null) throw new ThreadDeath(); } } private synchronized void interrupt() { running = true; notify(); } private void associateThread(KThread thread) { // make sure AutoGrader.runningThread() gets called only once per // context switch Lib.assert(!associated); associated = true; Lib.assert(thread != null); if (nachosThread != null) Lib.assert(thread == nachosThread); else nachosThread = thread; } private static void authorizeDestroy(KThread thread) { // make sure AutoGrader.finishingThread() gets called only once per // destroy Lib.assert(toBeDestroyed == null); toBeDestroyed = thread; } /** * The maximum number of started, non-destroyed TCB's that can be in * existence. */ public static final int maxThreads = 250; private static TCB currentTCB = null; private static int numThreads = 0; private static Privilege privilege; private static KThread toBeDestroyed = null; private static Vector runningThreads = new Vector(); private Thread javaThread = null; private KThread nachosThread = null; private boolean associated = false; private boolean running = false; private boolean done = false; private Runnable target; private Runnable tcbTarget; private boolean isFirstTCB; private static class TCBPrivilege implements Privilege.TCBPrivilege { public void associateThread(KThread thread) { Lib.assert(currentTCB != null); currentTCB.associateThread(thread); } public void authorizeDestroy(KThread thread) { TCB.authorizeDestroy(thread); } }}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?