private void extractArguments(String[] args) {
    String testArgsString = Config.getString("AutoGrader.testArgs");
    if (testArgsString == null) {
      testArgsString = "";
    }

    for (int i = 0; i < args.length; ) {
      String arg = args[i++];
      if (arg.length() > 0 && arg.charAt(0) == '-') {
        if (arg.equals("-#")) {
          Lib.assertTrue(i < args.length, "-# switch missing argument");
          testArgsString = args[i++];
        }
      }
    }

    StringTokenizer st = new StringTokenizer(testArgsString, ",\n\t\f\r");

    while (st.hasMoreTokens()) {
      StringTokenizer pair = new StringTokenizer(st.nextToken(), "=");

      Lib.assertTrue(pair.hasMoreTokens(), "test argument missing key");
      String key = pair.nextToken();

      Lib.assertTrue(pair.hasMoreTokens(), "test argument missing value");
      String value = pair.nextToken();

      testArgs.put(key, value);
    }
  }
Exemple #2
0
  /**
   * 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() {
    /* Probably unnecessary sanity check: we make sure that the current
     * thread is bound to the current TCB. This check can only fail if
     * non-Nachos threads invoke start().
     */
    Lib.assertTrue(currentTCB.javaThread == Thread.currentThread());

    // make sure AutoGrader.runningThread() called associateThread()
    Lib.assertTrue(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();
  }
Exemple #3
0
  private void associateThread(KThread thread) {
    // make sure AutoGrader.runningThread() gets called only once per
    // context switch
    Lib.assertTrue(!associated);
    associated = true;

    Lib.assertTrue(thread != null);

    if (nachosThread != null) Lib.assertTrue(thread == nachosThread);
    else nachosThread = thread;
  }
  /**
   * Nachos main entry point.
   *
   * @param args the command line arguments.
   */
  public static void main(final String[] args) {
    System.out.print("nachos 5.0j initializing...");

    Lib.assertTrue(Machine.args == null);
    Machine.args = args;

    processArgs();

    Config.load(configFileName);

    // get the current directory (.)
    baseDirectory = new File(new File("").getAbsolutePath());
    // get the nachos directory (./nachos)
    nachosDirectory = new File(baseDirectory, "nachos");

    String testDirectoryName = Config.getString("FileSystem.testDirectory");

    // get the test directory
    if (testDirectoryName != null) {
      testDirectory = new File(testDirectoryName);
    } else {
      // use ../test
      testDirectory = new File(baseDirectory.getParentFile(), "test");
    }

    securityManager = new NachosSecurityManager(testDirectory);
    privilege = securityManager.getPrivilege();

    privilege.machine = new MachinePrivilege();

    TCB.givePrivilege(privilege);
    privilege.stats = stats;

    securityManager.enable();
    createDevices();
    checkUserClasses();

    autoGrader = (AutoGrader) Lib.constructObject(autoGraderClassName);

    new TCB()
        .start(
            new Runnable() {
              public void run() {
                autoGrader.start(privilege);
              }
            });
  }
 int getIntegerArgument(String key) {
   try {
     return Integer.parseInt(getStringArgument(key));
   } catch (NumberFormatException e) {
     Lib.assertNotReached("getIntegerArgument(" + key + ") failed: " + "value is not an integer");
     return 0;
   }
 }
Exemple #6
0
  private void threadroot() {
    // this should be running the current thread
    Lib.assertTrue(javaThread == Thread.currentThread());

    if (!isFirstTCB) {
      /* start() is waiting for us to wake it up, signalling that it's OK
       * to context switch to us. We leave the running flag false so that
       * we'll still run if a context switch happens before we go to
       * sleep. All we have to do is wake up the current TCB and then
       * wait to get woken up by contextSwitch() or destroy().
       */

      currentTCB.interrupt();
      this.yield();
    } else {
      /* start() called us directly, so we just need to initialize
       * a couple things.
       */

      currentTCB = this;
      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.out.print("\nTCB terminated improperly!\n");
        privilege.exit(1);
      }

      runningThreads.removeElement(this);
      if (runningThreads.isEmpty()) privilege.exit(0);
    } catch (Throwable e) {
      System.out.print("\n");
      e.printStackTrace();

      runningThreads.removeElement(this);
      if (runningThreads.isEmpty()) privilege.exit(1);
      else die();
    }
  }
  private static void processArgs() {
    for (int i = 0; i < args.length; ) {
      String arg = args[i++];
      if (arg.length() > 0 && arg.charAt(0) == '-') {
        if (arg.equals("-d")) {
          Lib.assertTrue(i < args.length, "switch without argument");
          Lib.enableDebugFlags(args[i++]);
        } else if (arg.equals("-h")) {
          System.out.print(help);
          System.exit(1);
        } else if (arg.equals("-m")) {
          Lib.assertTrue(i < args.length, "switch without argument");
          try {
            numPhysPages = Integer.parseInt(args[i++]);
          } catch (NumberFormatException e) {
            Lib.assertNotReached("bad value for -m switch");
          }
        } else if (arg.equals("-s")) {
          Lib.assertTrue(i < args.length, "switch without argument");
          try {
            randomSeed = Long.parseLong(args[i++]);
          } catch (NumberFormatException e) {
            Lib.assertNotReached("bad value for -s switch");
          }
        } else if (arg.equals("-x")) {
          Lib.assertTrue(i < args.length, "switch without argument");
          shellProgramName = args[i++];
        } else if (arg.equals("-z")) {
          System.out.print(copyright);
          System.exit(1);
        }
        // these switches are reserved for the autograder
        else if (arg.equals("-[]")) {
          Lib.assertTrue(i < args.length, "switch without argument");
          configFileName = args[i++];
        } else if (arg.equals("--")) {
          Lib.assertTrue(i < args.length, "switch without argument");
          autoGraderClassName = args[i++];
        }
      }
    }

    Lib.seedRandom(randomSeed);
  }
  /**
   * Start this autograder. Extract the <tt>-#</tt> arguments, call <tt>init()</tt>, load and
   * initialize the kernel, and call <tt>run()</tt>.
   *
   * @param privilege encapsulates privileged access to the Nachos machine.
   */
  public void start(Privilege privilege) {
    Lib.assertTrue(this.privilege == null, "start() called multiple times");
    this.privilege = privilege;

    String[] args = Machine.getCommandLineArguments();

    extractArguments(args);

    System.out.print(" grader");

    init();

    System.out.print("\n");

    kernel = (Kernel) Lib.constructObject(Config.getString("Kernel.kernel"));
    kernel.initialize(args);

    run();
  }
Exemple #9
0
  /**
   * 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.assertTrue(currentTCB != null && currentTCB.javaThread == Thread.currentThread());
    // can't destroy current thread
    Lib.assertTrue(this != currentTCB);
    // thread must have started but not be destroyed yet
    Lib.assertTrue(javaThread != null && !done);

    // ensure AutoGrader.finishingCurrentThread() called authorizeDestroy()
    Lib.assertTrue(nachosThread == toBeDestroyed);
    toBeDestroyed = null;

    this.done = true;
    currentTCB.running = false;

    this.interrupt();
    currentTCB.waitForInterrupt();

    this.javaThread = null;
  }
  boolean getBooleanArgument(String key) {
    String value = getStringArgument(key);

    if (value.equals("1") || value.toLowerCase().equals("true")) {
      return true;
    } else if (value.equals("0") || value.toLowerCase().equals("false")) {
      return false;
    } else {
      Lib.assertNotReached("getBooleanArgument(" + key + ") failed: " + "value is not a boolean");
      return false;
    }
  }
  /**
   * Return the name of the process class that the kernel should use. In the multi-programming
   * project, returns <tt>nachos.userprog.UserProcess</tt>. In the VM project, returns
   * <tt>nachos.vm.VMProcess</tt>. In the networking project, returns
   * <tt>nachos.network.NetProcess</tt>.
   *
   * @return the name of the process class that the kernel should use.
   * @see nachos.userprog.UserKernel#run
   * @see nachos.userprog.UserProcess
   * @see nachos.vm.VMProcess
   * @see nachos.network.NetProcess
   */
  public static String getProcessClassName() {
    if (processClassName == null) processClassName = Config.getString("Kernel.processClassName");

    Lib.assertTrue(processClassName != null);
    return processClassName;
  }
  /**
   * Return the name of the shell program that a user-programming kernel must run. Make sure
   * <tt>UserKernel.run()</tt> <i>always</i> uses this method to decide which program to run.
   *
   * @return the name of the shell program to run.
   */
  public static String getShellProgramName() {
    if (shellProgramName == null) shellProgramName = Config.getString("Kernel.shellProgram");

    Lib.assertTrue(shellProgramName != null);
    return shellProgramName;
  }
Exemple #13
0
 private static void authorizeDestroy(KThread thread) {
   // make sure AutoGrader.finishingThread() gets called only once per
   // destroy
   Lib.assertTrue(toBeDestroyed == null);
   toBeDestroyed = thread;
 }
  private static void checkUserClasses() {
    System.out.print(" user-check");

    Class aclsInt = (new int[0]).getClass();
    Class clsObject = Lib.loadClass("java.lang.Object");
    Class clsRunnable = Lib.loadClass("java.lang.Runnable");
    Class clsString = Lib.loadClass("java.lang.String");

    Class clsKernel = Lib.loadClass("nachos.machine.Kernel");
    Class clsFileSystem = Lib.loadClass("nachos.machine.FileSystem");
    Class clsRiderControls = Lib.loadClass("nachos.machine.RiderControls");
    Class clsElevatorControls = Lib.loadClass("nachos.machine.ElevatorControls");
    Class clsRiderInterface = Lib.loadClass("nachos.machine.RiderInterface");
    Class clsElevatorControllerInterface =
        Lib.loadClass("nachos.machine.ElevatorControllerInterface");

    Class clsAlarm = Lib.loadClass("nachos.threads.Alarm");
    Class clsThreadedKernel = Lib.loadClass("nachos.threads.ThreadedKernel");
    Class clsKThread = Lib.loadClass("nachos.threads.KThread");
    Class clsCommunicator = Lib.loadClass("nachos.threads.Communicator");
    Class clsSemaphore = Lib.loadClass("nachos.threads.Semaphore");
    Class clsLock = Lib.loadClass("nachos.threads.Lock");
    Class clsCondition = Lib.loadClass("nachos.threads.Condition");
    Class clsCondition2 = Lib.loadClass("nachos.threads.Condition2");
    Class clsRider = Lib.loadClass("nachos.threads.Rider");
    Class clsElevatorController = Lib.loadClass("nachos.threads.ElevatorController");

    Lib.checkDerivation(clsThreadedKernel, clsKernel);

    Lib.checkStaticField(clsThreadedKernel, "alarm", clsAlarm);
    Lib.checkStaticField(clsThreadedKernel, "fileSystem", clsFileSystem);

    Lib.checkMethod(clsAlarm, "waitUntil", new Class[] {long.class}, void.class);

    Lib.checkConstructor(clsKThread, new Class[] {});
    Lib.checkConstructor(clsKThread, new Class[] {clsRunnable});

    Lib.checkStaticMethod(clsKThread, "currentThread", new Class[] {}, clsKThread);
    Lib.checkStaticMethod(clsKThread, "finish", new Class[] {}, void.class);
    Lib.checkStaticMethod(clsKThread, "yield", new Class[] {}, void.class);
    Lib.checkStaticMethod(clsKThread, "sleep", new Class[] {}, void.class);

    Lib.checkMethod(clsKThread, "setTarget", new Class[] {clsRunnable}, clsKThread);
    Lib.checkMethod(clsKThread, "setName", new Class[] {clsString}, clsKThread);
    Lib.checkMethod(clsKThread, "getName", new Class[] {}, clsString);
    Lib.checkMethod(clsKThread, "fork", new Class[] {}, void.class);
    Lib.checkMethod(clsKThread, "ready", new Class[] {}, void.class);
    Lib.checkMethod(clsKThread, "join", new Class[] {}, void.class);

    Lib.checkField(clsKThread, "schedulingState", clsObject);

    Lib.checkConstructor(clsCommunicator, new Class[] {});
    Lib.checkMethod(clsCommunicator, "speak", new Class[] {int.class}, void.class);
    Lib.checkMethod(clsCommunicator, "listen", new Class[] {}, int.class);

    Lib.checkConstructor(clsSemaphore, new Class[] {int.class});
    Lib.checkMethod(clsSemaphore, "P", new Class[] {}, void.class);
    Lib.checkMethod(clsSemaphore, "V", new Class[] {}, void.class);

    Lib.checkConstructor(clsLock, new Class[] {});
    Lib.checkMethod(clsLock, "acquire", new Class[] {}, void.class);
    Lib.checkMethod(clsLock, "release", new Class[] {}, void.class);
    Lib.checkMethod(clsLock, "isHeldByCurrentThread", new Class[] {}, boolean.class);

    Lib.checkConstructor(clsCondition, new Class[] {clsLock});
    Lib.checkConstructor(clsCondition2, new Class[] {clsLock});

    Lib.checkMethod(clsCondition, "sleep", new Class[] {}, void.class);
    Lib.checkMethod(clsCondition, "wake", new Class[] {}, void.class);
    Lib.checkMethod(clsCondition, "wakeAll", new Class[] {}, void.class);
    Lib.checkMethod(clsCondition2, "sleep", new Class[] {}, void.class);
    Lib.checkMethod(clsCondition2, "wake", new Class[] {}, void.class);
    Lib.checkMethod(clsCondition2, "wakeAll", new Class[] {}, void.class);

    Lib.checkDerivation(clsRider, clsRiderInterface);

    Lib.checkConstructor(clsRider, new Class[] {});
    Lib.checkMethod(clsRider, "initialize", new Class[] {clsRiderControls, aclsInt}, void.class);

    Lib.checkDerivation(clsElevatorController, clsElevatorControllerInterface);

    Lib.checkConstructor(clsElevatorController, new Class[] {});
    Lib.checkMethod(
        clsElevatorController, "initialize", new Class[] {clsElevatorControls}, void.class);
  }
Exemple #15
0
 public void associateThread(KThread thread) {
   Lib.assertTrue(currentTCB != null);
   currentTCB.associateThread(thread);
 }
 private void delay() {
   long time = Machine.timer().getTime();
   int amount = 1000;
   ThreadedKernel.alarm.waitUntil(amount);
   Lib.my_assert(Machine.timer().getTime() >= time + amount);
 }
Exemple #17
0
  /**
   * Causes the thread represented by this TCB to begin execution. The specified target is run in
   * the thread.
   */
  public void start(Runnable target) {
    /* We will not use synchronization here, because we're assuming that
     * either this is the first call to start(), or we're being called in
     * the context of another TCB. Since we only allow one TCB to run at a
     * time, no synchronization is necessary.
     *
     * The only way this assumption could be broken is if one of our
     * non-Nachos threads used the TCB code.
     */

    /* Make sure this TCB has not already been started. If done is false,
     * then destroy() has not yet set javaThread back to null, so we can
     * use javaThread as a reliable indicator of whether or not start() has
     * already been invoked.
     */
    Lib.assertTrue(javaThread == null && !done);

    /* Make sure there aren't too many running TCBs already. This
     * limitation exists in an effort to prevent wild thread usage.
     */
    Lib.assertTrue(runningThreads.size() < maxThreads);

    isFirstTCB = (currentTCB == null);

    /* Probably unnecessary sanity check: if this is not the first TCB, we
     * make sure that the current thread is bound to the current TCB. This
     * check can only fail if non-Nachos threads invoke start().
     */
    if (!isFirstTCB) Lib.assertTrue(currentTCB.javaThread == Thread.currentThread());

    /* At this point all checks are complete, so we go ahead and start the
     * TCB. Whether or not this is the first TCB, it gets added to
     * runningThreads, and we save the target closure.
     */
    runningThreads.add(this);

    this.target = target;

    if (!isFirstTCB) {
      /* If this is not the first TCB, we have to make a new Java thread
       * to run it. Creating Java threads is a privileged operation.
       */
      tcbTarget =
          new Runnable() {
            public void run() {
              threadroot();
            }
          };

      privilege.doPrivileged(
          new Runnable() {
            public void run() {
              javaThread = new Thread(tcbTarget);
            }
          });

      /* The Java thread hasn't yet started, but we need to get it
       * blocking in yield(). We do this by temporarily turning off the
       * current TCB, starting the new Java thread, and waiting for it
       * to wake us up from threadroot(). Once the new TCB wakes us up,
       * it's safe to context switch to the new TCB.
       */
      currentTCB.running = false;

      this.javaThread.start();
      currentTCB.waitForInterrupt();
    } else {
      /* This is the first TCB, so we don't need to make a new Java
       * thread to run it; we just steal the current Java thread.
       */
      javaThread = Thread.currentThread();

      /* All we have to do now is invoke threadroot() directly. */
      threadroot();
    }
  }
 String getStringArgument(String key) {
   String value = (String) testArgs.get(key);
   Lib.assertTrue(value != null, "getStringArgument(" + key + ") failed to find key");
   return value;
 }
  void level(int level) {
    this.level++;
    Lib.assertTrue(level == this.level, "level() advanced more than one step: test jumped ahead");

    if (level == targetLevel) done();
  }
 /**
  * Request permission to receive a packet. The autograder can use this to drop packets very
  * selectively.
  *
  * @param privilege proves the authenticity of this call.
  * @return <tt>true</tt> if the packet should be delivered to the kernel.
  */
 public boolean canReceivePacket(Privilege privilege) {
   Lib.assertTrue(privilege == this.privilege, "security violation");
   return true;
 }
 /**
  * Notify the autograder that <tt>Processor.run()</tt> was invoked. This can be used to simulate
  * user programs.
  *
  * @param privilege proves the authenticity of this call.
  */
 public void runProcessor(Privilege privilege) {
   Lib.assertTrue(privilege == this.privilege, "security violation");
 }
 /**
  * Notify the autograder that a user program executed a syscall instruction.
  *
  * @param privilege proves the authenticity of this call.
  * @return <tt>true</tt> if the kernel exception handler should be called.
  */
 public boolean exceptionHandler(Privilege privilege) {
   Lib.assertTrue(privilege == this.privilege, "security violation");
   return true;
 }
 /**
  * Notify the autograder that a timer interrupt occurred and was handled by software if a timer
  * interrupt handler was installed. Called by the hardware timer.
  *
  * @param privilege proves the authenticity of this call.
  * @param time the actual time at which the timer interrupt was issued.
  */
 public void timerInterrupt(Privilege privilege, long time) {
   Lib.assertTrue(privilege == this.privilege, "security violation");
 }