Пример #1
0
  /**
   * 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+
  }
Пример #2
0
 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);
 }
Пример #3
0
  /**
   * 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);
  }
Пример #4
0
  /**
   * 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);
  }
Пример #5
0
  /**
   * 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);
  }
Пример #6
0
  /**
   * 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);
  }
Пример #7
0
  /**
   * 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);
  }
Пример #8
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();
  }
Пример #9
0
  private void begin() {
    Lib.debug(dbgThread, "Beginning thread: " + toString());

    Lib.assertTrue(this == currentThread);

    restoreState();

    Machine.interrupt().enable();
  }
Пример #10
0
  /**
   * 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);
  }
Пример #11
0
  /**
   * 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);
  }
Пример #12
0
  /**
   * 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);
  }
Пример #13
0
  /**
   * 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());

    // Precondition: this thread must not be the current thread. Moreover,
    // return if this thread is already finished.
    Lib.assertTrue(this != currentThread);
    if (this.status == this.statusFinished) return;

    // Calling sleep on a KThread requires interrupts to be disabled. We
    // will restore the status after we put the current thread to sleep.
    boolean intStatus = Machine.interrupt().disable();

    // Add the current thread into the buffer to indicate that it's blocked
    // before this thread is finished.
    this.waitedThreadList.add(this.currentThread);

    // Put the current thread to sleep, and restore the interrupt.
    currentThread.sleep();
    Machine.interrupt().restore(intStatus);
  }
Пример #14
0
  /** 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);
  }
Пример #15
0
  /**
   * 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();
  }
Пример #16
0
  /**
   * 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;
  }
Пример #17
0
  /**
   * 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();
  }
Пример #18
0
  /**
   * 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;
    }
  }
Пример #19
0
  /**
   * 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();
  }
Пример #20
0
  /**
   * 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;

    // When this thread is finished, we need to reset the status of all
    // waited/blocked thread to ready state.
    while (!currentThread.waitedThreadList.isEmpty()) {
      KThread threadToRestore = currentThread.waitedThreadList.remove(0);
      threadToRestore.ready();
    }

    sleep();
  }
Пример #21
0
 /**
  * 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() {
   // disable interrupts (maybe not necessary)
   Machine.interrupt().disable(); // let's see if this works?
   // get current time
   long currentTime = Machine.timer().getTime();
   // go through waitQueue and put each thread that is "less than" current wait time on ready queue
   AlarmBucket placeholder = null;
   int count = waitQueue.size();
   while (count > 0) {
     placeholder = waitQueue.peek();
     if (placeholder.getTime() <= currentTime) {
       placeholder = waitQueue.poll();
       placeholder.getKThread().ready();
       count = waitQueue.size();
     } else {
       count = 0;
     }
   }
   // yield current thread
   KThread.currentThread().yield();
   // Machine.interrupt().enable(); //let's see if this works? DAC DEBUG
 }
Пример #22
0
  /**
   * 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;

    KThread aux = null;
    if (joinList.size() > 0) {
      aux = joinList.getFirst();
    }
    if (aux != null) {
      aux.ready();
      joinList.removeFirst();
    }
    sleep();
  }
Пример #23
0
 /**
  * Prepare this thread to give up the processor. Kernel threads do not need to do anything here.
  */
 protected void saveState() {
   Lib.assertTrue(Machine.interrupt().disabled());
   Lib.assertTrue(this == currentThread);
 }