Nachos Thread Internals

Tom Kelliher, CS 318

Feb. 2, 1998


From last time:

  1. Nachos: groups, accounts, code, and compiling.


  1. Internals of Nachos thread code.

  2. Critical sections and cooperating processes.


Nachos Thread Internals

  1. Note the command line switches to Nachos. Demonstrate.

  2. The first DEBUG message in main() won't ever print anything. Why?

  3. Once we leave Initialize, main() is running as a thread. Complication: main() cannot exit while other threads are active.

  4. The Makefile in the threads directory sets-up the compiler command line to define THREADS. Demonstrate.

  5. Note call to currentThread->Finish() .

  1. Called from main() .

  2. It forks a thread, which executes SimpleThread() with a parameter of 1.

  3. it executes SimpleThread() with a parameter of 0.

  4. Using Thread::Yield(), the threads ping pong back and forth.

  5. Threads are being scheduled, somehow. How can we construct a test here to determine the scheduling algorithm?


Declaration of the thread class.

  1. Note the comments regarding thread stack overflows.

  2. Try to find defn. of ThreadStackSize.

  3. Why can't stackTop and machineState be moved?

  4. Parameters to Thread::Fork() .

  5. Don't rely on Thread::CheckOverflow() .

  6. Interface to switch.s .

  1. Thread::Fork(): Use of interrupt ``mask'' to achieve mutually exclusive access (atomicity) to shared data:
    Thread::Fork(VoidFunctionPtr func, int arg)
        DEBUG('t', "Forking thread \"%s\" with func = 0x%x, arg = %d\n",
         name, (int) func, arg);
        StackAllocate(func, arg);
        IntStatus oldLevel = interrupt->SetLevel(IntOff);
        scheduler->ReadyToRun(this); // ReadyToRun assumes that interrupts 
                   // are disabled!
        (void) interrupt->SetLevel(oldLevel);
    Initializes thread and puts on ready queue.

  2. Thread::Finish(): note that the thread can't be destroyed here.

    Another reason why a thread/process can't immediately be removed: zombies in Unix.

    Note use of Sleep() .

  3. What's the difference between Yield() and Sleep() ?


We need to discuss the critical section problem.

Critical Sections and Cooperating Processes

What is a critical section?

The overlapping portion of cooperating processes, where shared variables are being accessed.
Not all processes share variables: independent processes.

Cooperating/independent processes.

Necessary conditions for a solution to the c.s. problem:

  1. Mutual Exclusion --- if is executing in one of its critical sections, no , , is executing in its critical sections.

  2. Progress --- a process operating outside of its critical section cannot prevent other processes from entering theirs; processes attempting to enter their critical sections simultaneously must decide which process enters eventually.

  3. Bounded Waiting --- a process attempting to enter its critical region will be able to do so eventually.


  1. No assumptions made about relative speed of processes

  2. No process may remain in its critical section indefinitely (may not terminate in its critical section)

  3. A memory operation (read or write) is atomic --- cannot be interrupted. For now, we do not assume indivisible RMW cycles.

Classic example: the producer/consumer problem (aka bounded buffer):

Global data:

const int N = 10;

int buffer[N];
int in = 0;
int out = 0;
int full = 0;
int empty = N;


while (1)
   while (empty == 0)

   buffer[in] = inData;
   in = ++in % N;


while (1)
   while (full == 0)

   outData = buffer[out];
   out = ++out % N;
Is there potential for trouble here?

Critical Section Usage Model

(for n processes, )

do {
   mutexbegin();       /* CS entry */
   mutexend();         /* CS exit  */
} while (!done);

A Simple, Primitive Hardware Solution

  1. Just disable interrupts.

  2. Umm, what about user processes?

  3. Why this doesn't work with multiprocessors.

  4. This is dangerous.

Thomas P. Kelliher
Fri Jan 30 11:03:29 EST 1998
Tom Kelliher