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);
    }
  }
Exemplo n.º 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();
  }
Exemplo n.º 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;
  }
Exemplo n.º 4
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;
  }
  /**
   * 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);
              }
            });
  }
Exemplo n.º 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();
    }
  }
  /**
   * 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();
  }
  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);
  }
 /**
  * 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;
 }
Exemplo n.º 10
0
 private void delay() {
   long time = Machine.timer().getTime();
   int amount = 1000;
   ThreadedKernel.alarm.waitUntil(amount);
   Lib.assertTrue(Machine.timer().getTime() >= time + amount);
 }
 String getStringArgument(String key) {
   String value = (String) testArgs.get(key);
   Lib.assertTrue(value != null, "getStringArgument(" + key + ") failed to find key");
   return value;
 }
 /**
  * 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;
 }
Exemplo n.º 13
0
 private static void authorizeDestroy(KThread thread) {
   // make sure AutoGrader.finishingThread() gets called only once per
   // destroy
   Lib.assertTrue(toBeDestroyed == null);
   toBeDestroyed = thread;
 }
  /**
   * 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;
  }
 /**
  * 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");
 }
  void level(int level) {
    this.level++;
    Lib.assertTrue(level == this.level, "level() advanced more than one step: test jumped ahead");

    if (level == targetLevel) done();
  }
Exemplo n.º 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();
    }
  }
Exemplo n.º 18
0
 public void associateThread(KThread thread) {
   Lib.assertTrue(currentTCB != null);
   currentTCB.associateThread(thread);
 }
  /**
   * 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;
  }
 /**
  * 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");
 }