static char arrays
OpenFile (again)
Console I/O
Nachos (C++) Semaphore class
Virtual Memory
BitMap
Adding a C++ class to Nachos
CoreMap
Exceptions: machine/machine.h
PageFaultException
C compilers sometimes place restrictions on declarations of character arrays which also include initialization:
char msg[] = "Hello, World!\n";
The restriction is that such a declaration with initialization, must either be (1) a global declaration or (2) must be declared static if local to a function:
#include "syscall.h"
int main()
{
static char msg[] = "Hello, World!\n";
Write(msg, 13, 1);
...
}
The destructor for OpenFile closes the associated file.
This is a problem if two nachos threads are sharing the file.
When nachos begins (executing main), it is set up as a nachos thread. This allows context switches between the initial thread executing main and any other threads that are created.
This means that a Thread object is created even for the execution of nachos main function.
See the function Initialize(...) which is called from main and is implemented in threads/system.cc.
stats = new Statistics(); // collect statistics
interrupt = new Interrupt; // start up interrupt handling
scheduler = new Scheduler(); // initialize the ready queue
if (randomYield) // start the timer (if needed)
timer = new Timer(TimerInterruptHandler, 0, randomYield);
threadToBeDestroyed = NULL;
// We didn't explicitly allocate the current thread we are running in.
// But if it ever tries to give up the CPU, we better have a Thread
// object to save its state.
currentThread = new Thread("main");
currentThread->setStatus(RUNNING);
interrupt->Enable();
CallOnUserAbort(Cleanup); // if user hits ctl-C
#ifdef USER_PROGRAM
machine = new Machine(debugUserProg); // this must come first
#endif
All nachos threads (including the initial nachos kernel thread executing main) share standard input/output.
Normal output and debugging messages from Nachos will not appear if some nachos user thread closes standard output.
Alternatives?
The userprog/nachos implements the -c option. This option tests the Console class whic represents keyboard input, terminal output.
The console test (with the -c option) is run by:
hawk% cd nachos-3.4/code/userprog hawk% nachos -c Hello (Type in this input.) Hello (Result printed to terminal screen.) q ( or anything that begins with q ) qMachine halting! Ticks: total 5195530, idle 5195380, system 150, user 0 Disk I/O: reads 0, writes 0 Console I/O: reads 8, writes 7 Paging: faults 0 Network I/O: packets received 0, sent 0 Cleaning up... hawk%
The Console simulation is based on semaphores.
static Console *console;
static Semaphore *readAvail;
static Semaphore *writeDone;
static void ReadAvail(int arg) { readAvail->V(); }
static void WriteDone(int arg) { writeDone->V(); }
ConsoleTest (char *in, char *out)
{
char ch;
console = new Console(in, out, ReadAvail, WriteDone, 0);
readAvail = new Semaphore("read avail", 0);
writeDone = new Semaphore("write done", 0);
for (;;) {
readAvail->P(); // wait for character to arrive
ch = console->GetChar();
console->PutChar(ch); // echo it!
writeDone->P() ; // wait for write to finish
if (ch == 'q') return; // if q, quit
}
}
Note that readAvail and writeDone are "Semaphore" objects each with initial value 0. The Semaphore::P() and Semaphore::V() operations are provided by the nachos kernel in the C++ Semaphore class.
P is for "decrement" and V is for "increment".
The semaphore value is not allowed to be < 0. And so the Semaphore::P operation will block the calling nachos thread if the integer value of the Semaphore is already 0.
void
Semaphore::P()
{
IntStatus oldLevel = interrupt->SetLevel(IntOff); // disable interrupts
while (value == 0) { // semaphore not available
queue->Append((void *)currentThread); // so go to sleep
currentThread->Sleep();
}
value--; // semaphore available,
// consume its value
(void) interrupt->SetLevel(oldLevel); // re-enable interrupts
}
void
Semaphore::V()
{
Thread *thread;
IntStatus oldLevel = interrupt->SetLevel(IntOff);
thread = (Thread *)queue->Remove();
if (thread != NULL) // make thread ready, consuming the V immediately
scheduler->ReadyToRun(thread);
value++;
(void) interrupt->SetLevel(oldLevel);
}
We need at least to be able to load two programs into Mips memory in order to have any implementation of the Nachos Exec system call.
From syscall.h:
/* Run the executable, stored in the Nachos file "name", and return the * address space identifier */ SpaceId Exec(char *name);
The BitMap class is defined in userprog/bitmap.h:
class BitMap {
public:
BitMap(int nitems); // Initialize a bitmap, with "nitems" bits
// initially, all bits are cleared.
~BitMap(); // De-allocate bitmap
void Mark(int which); // Set the "nth" bit
void Clear(int which); // Clear the "nth" bit
bool Test(int which); // Is the "nth" bit set?
int Find(); // Return the # of a clear bit, and as a side
// effect, set the bit.
// If no bits are clear, return -1.
int NumClear(); // Return the number of clear bits
void Print(); // Print contents of bitmap
// These aren't needed until FILESYS, when we will need to read and
// write the bitmap to a file
void FetchFrom(OpenFile *file); // fetch contents from disk
void WriteBack(OpenFile *file); // write contents to disk
private:
int numBits; // number of bits in the bitmap
int numWords; // number of words of bitmap storage
// (rounded up if numBits is not a
// multiple of the number of bits in
// a word)
unsigned int *map; // bit storage
};
The nachos routine, StartProcess in userprog/progtest.cc, loads a user program in memory. It could be modified to use BitMap as follows:
numPages = divRoundUp(size, PageSize);
// ASSERT(numPages <= NumPhysPages); // check we're not trying
// allocate more than
// physical memory at this
// point with partial loading
// of pages not yet
// implemented.
// Are there enough free frames for the initial load?
DEBUG('b', "free frames = %d, need %d for %s\n",
frameMap->NumClear(), numPages, filename);
if ( frameMap->NumClear() < numPages )
{
printf("Not enough physical memory to start user program!\n");
However, suppose the BitMap class doesn't quite provide enough functionality. You could create a derived class, say CoreMap.
How do we add a new class to Nachos and still have the makefiles work?
Suppose we decide to create a new class CoreMap, derived from BitMap.
Steps:
USERPROG_H = ../userprog/addrspace.h\
../userprog/bitmap.h\
../userprog/coremap.h\
../filesys/filesys.h\
../filesys/openfile.h\
../machine/console.h\
../machine/machine.h\
../machine/mipssim.h\
../machine/translate.h
USERPROG_C = ../userprog/addrspace.cc\
../userprog/bitmap.cc\
../userprog/coremap.cc\
../userprog/exception.cc\
../userprog/progtest.cc\
../machine/console.cc\
../machine/machine.cc\
../machine/mipssim.cc\
../machine/translate.cc
../userprog/coremap.cc\
../userprog/exception.cc\
../userprog/progtest.cc\
../machine/console.cc\
../machine/machine.cc\
../machine/mipssim.cc\
../machine/translate.cc
USERPROG_O = addrspace.o bitmap.o coremap.o exception.o progtest.o console.o \
machine.o mipssim.o translate.o
make all
Note the \ escapes the newline and is very important.
Remember, all the exceptions have symbolic names and are listed in machine/machine.h
One particular such exception is PageFaultException.
Look at the page table again.