Received: from [128.135.164.22] (vanna.cs.uchicago.edu [128.135.164.22]) by cs.uchicago.edu (8.6.12/8.6.12) with SMTP id OAA09670 for <odonnell>; Thu, 12 Oct 1995 14:26:03 -0500
Message-Id: <v01510105aca2f8ac781e@[128.135.164.22]>
Mime-Version: 1.0
Content-Type: text/plain; charset="us-ascii"
Date: Thu, 12 Oct 1995 14:28:12 -0500
To: odonnell
From: "R. James Firby" <firby@cs.uchicago.edu>
Subject: Nachos Stuff

Mike,

Here are a few comments on your NACHOS guide.  It looks very good.

Jim

- Thread::Sleep and Thread::Yield have quite different behavior and they
can't really call each other.  Sleep is used to block a thread so the
thread MUST stop and cannot be run immediately.  Yield is used to give up
control if another thread is waiting and, if not, the same thread can be
run again.  Sleep contains the only call to Interrupt::Idle and is the only
place a thread status is ever changed to BLOCKED.  The paths in these
functions for what to do if a waiting thread is not found are very
different so one can't really call the other.

- The reason that Interrupt::YieldOnReturn is necessary is subtle.

On any given instruction cycle, interrupts can occur.  In fact, several
interrupts can occur.  A typical real  CPU will disable interrupts and jump
to the interrupt code for the highest priority interrupt.  The way that
interrupts work in NACHOS is similar to, but not quite like, the way they
work on a real machine.  To simulate a hardware interrupt, an interrupt is
scheduled by telling the simulator when the interrupt should occur, and
what code to run when it does.  When the time arrives, the machine
simulator runs the function scheduled for the interrupt.  This is analogous
to real hardware generating an interrupt and the CPU jumping to the
interrupt handling routine.  When the interrupt function returns, NACHOS
looks for further pending interrupts, and if it finds any it will execute
them immediately.

Here is the rub.  In the NACHOS interrupt code, the call to run the
interrupt handlers for all pending interrupts is CheckIfDue(...).  If one
of the interrupt functions were to do a Yield, this function call would be
suspended in the middle and another thread might run.  If this other thread
is an OS thread, then pending interrupts will remain pending while it runs
because OS threads don't run on the simulated machine.  Pending interrupts
will only be executed after jumping to a user thread running on the MIPS
simulator and by then things could be badly out of sync.

To prevent this, no new thread must be allowed to run until all pending
interrupts have been handled.  YieldOnReturn() sets a flag to yield the
current thread only after any other pending interrupts have run.

On a real machine this would not be a problem as long as OS code did not
keep interrupts disabled too long because OS threads would be interrupted
by pending interrupts also.  Slightly different problems with writing
reentrant interrupt handlers occur on real machines instead.

Jim




