This commit is contained in:
2024-12-30 05:59:42 +08:00
parent bf78b95c9d
commit 06a29f7677
42 changed files with 1758 additions and 1556 deletions

View File

@@ -200,18 +200,18 @@ DEFINES = -DFILESYS_STUB -DRDATA -DSIM_FIX
# break the thread system. You might want to use -fno-inline if # break the thread system. You might want to use -fno-inline if
# you need to call some inline functions from the debugger. # you need to call some inline functions from the debugger.
CFLAGS = -g -Wall -Wextra $(INCPATH) $(DEFINES) $(HOSTCFLAGS) -DCHANGED -m32 # -fsanitize=address,undefined CFLAGS = -g -Wall $(INCPATH) $(DEFINES) $(HOSTCFLAGS) -DCHANGED -m32 -w
LDFLAGS = -m32 # -fsanitize=address,undefined LDFLAGS = -m32
CPP_AS_FLAGS= -m32 CPP_AS_FLAGS= -m32
##################################################################### #####################################################################
CPP=/lib/cpp CPP=/lib/cpp
CC = g++ -m32 -Wno-deprecated CC = g++ -m32
LD = g++ -m32 -Wno-deprecated LD = g++ -m32
AS = as --32 AS = as --32
RM = /bin/rm RM = /bin/rm
INCPATH = -I../network -I../filesys -I../userprog -I../threads -I../machine -I../lib -I- INCPATH = -iquote../network -iquote../filesys -iquote../userprog -iquote../threads -iquote../machine -iquote../lib
PROGRAM = nachos PROGRAM = nachos
@@ -332,7 +332,6 @@ S_OFILES = switch.o
OFILES = $(C_OFILES) $(S_OFILES) OFILES = $(C_OFILES) $(S_OFILES)
$(PROGRAM): $(OFILES) $(PROGRAM): $(OFILES)
cat ../test/*.sh ../test/Makefile ../test/*.c
$(LD) $(OFILES) $(LDFLAGS) -o $(PROGRAM) $(LD) $(OFILES) $(LDFLAGS) -o $(PROGRAM)
$(C_OFILES): %.o: $(C_OFILES): %.o:

View File

@@ -40,56 +40,108 @@
#ifdef FILESYS_STUB // Temporarily implement file system calls as #ifdef FILESYS_STUB // Temporarily implement file system calls as
// calls to UNIX, until the real file system // calls to UNIX, until the real file system
// implementation is available // implementation is available
typedef int OpenFileId;
class FileSystem { class FileSystem {
public: public:
FileSystem() { for (int i = 0; i < 20; i++) fileDescriptorTable[i] = NULL; } FileSystem() { for (int i = 0; i < 20; i++) fileDescriptorTable[i] = NULL; }
bool Create(char *name) { bool Create(char* name) {
int fileDescriptor = OpenForWrite(name); int fileDescriptor = OpenForWrite(name);
if (fileDescriptor == -1) return FALSE;
Close(fileDescriptor);
return TRUE;
}
if (fileDescriptor == -1) return FALSE; OpenFile* Open(char* name) {
Close(fileDescriptor); int fileDescriptor = OpenForReadWrite(name, FALSE);
return TRUE; if (fileDescriptor == -1) return NULL;
} return new OpenFile(fileDescriptor);
}
OpenFile* Open(char *name) { OpenFileId OpenFiles(char* name) {
int fileDescriptor = OpenForReadWrite(name, FALSE); OpenFile* file = Open(name);
if (!file) return -1;
int freeIndex = -1;
if (fileDescriptor == -1) return NULL; for (int i = 0; i < 20; i++)
return new OpenFile(fileDescriptor); if (!fileDescriptorTable[i])
} freeIndex = i;
bool Remove(char *name) { return Unlink(name) == 0; } if (freeIndex == -1)
return -1;
OpenFileId fileDescriptor = file->GetFileDescriptor();
fileDescriptorTable[freeIndex] = file;
return fileDescriptor;
}
int WriteFile(char* buffer, int size, OpenFileId fd) {
for (int i = 0; i < 20; i++) {
if (!fileDescriptorTable[i])
continue;
if (fileDescriptorTable[i]->GetFileDescriptor() == fd) {
return fileDescriptorTable[i]->Write(buffer, size);
}
}
return -1;
}
int ReadFile(char* buffer, int size, OpenFileId fd) {
for (int i = 0; i < 20; i++) {
if (!fileDescriptorTable[i])
continue;
if (fileDescriptorTable[i]->GetFileDescriptor() == fd)
return fileDescriptorTable[i]->Read(buffer, size);
}
return -1;
}
int CloseFile(OpenFileId fd) {
for (int i = 0; i < 20; i++) {
if (!fileDescriptorTable[i])
continue;
if (fileDescriptorTable[i]->GetFileDescriptor() == fd) {
delete fileDescriptorTable[i];
fileDescriptorTable[i] = NULL;
return 1;
}
}
return 0;
}
bool Remove(char* name) { return Unlink(name) == 0; }
OpenFile* fileDescriptorTable[20];
OpenFile *fileDescriptorTable[20];
}; };
#else // FILESYS #else // FILESYS
class FileSystem { class FileSystem {
public: public:
FileSystem(bool format); // Initialize the file system. FileSystem(bool format); // Initialize the file system.
// Must be called *after* "synchDisk" // Must be called *after* "synchDisk"
// has been initialized. // has been initialized.
// If "format", there is nothing on // If "format", there is nothing on
// the disk, so initialize the directory // the disk, so initialize the directory
// and the bitmap of free blocks. // and the bitmap of free blocks.
bool Create(char *name, int initialSize); bool Create(char* name, int initialSize);
// Create a file (UNIX creat) // Create a file (UNIX creat)
OpenFile* Open(char *name); // Open a file (UNIX open) OpenFile* Open(char* name); // Open a file (UNIX open)
bool Remove(char *name); // Delete a file (UNIX unlink) bool Remove(char* name); // Delete a file (UNIX unlink)
void List(); // List all the files in the file system void List(); // List all the files in the file system
void Print(); // List all the files and their contents void Print(); // List all the files and their contents
private: private:
OpenFile* freeMapFile; // Bit map of free disk blocks, OpenFile* freeMapFile; // Bit map of free disk blocks,
// represented as a file // represented as a file
OpenFile* directoryFile; // "Root" directory -- list of OpenFile* directoryFile; // "Root" directory -- list of
// file names, represented as a file // file names, represented as a file
}; };
#endif // FILESYS #endif // FILESYS

View File

@@ -27,33 +27,39 @@
#ifdef FILESYS_STUB // Temporarily implement calls to #ifdef FILESYS_STUB // Temporarily implement calls to
// Nachos file system as calls to UNIX! // Nachos file system as calls to UNIX!
// See definitions listed under #else // See definitions listed under #else
typedef int OpenFileId;
class OpenFile { class OpenFile {
public: public:
OpenFile(int f) { file = f; currentOffset = 0; } // open the file OpenFile(int f) { file = f; currentOffset = 0; } // open the file
~OpenFile() { Close(file); } // close the file ~OpenFile() { Close(file); } // close the file
int ReadAt(char *into, int numBytes, int position) { int ReadAt(char *into, int numBytes, int position) {
Lseek(file, position, 0); Lseek(file, position, 0);
return ReadPartial(file, into, numBytes); return ReadPartial(file, into, numBytes);
} }
int WriteAt(char *from, int numBytes, int position) { int WriteAt(char *from, int numBytes, int position) {
Lseek(file, position, 0); Lseek(file, position, 0);
WriteFile(file, from, numBytes); WriteFile(file, from, numBytes);
return numBytes; return numBytes;
} }
int Read(char *into, int numBytes) { int Read(char *into, int numBytes) {
int numRead = ReadAt(into, numBytes, currentOffset); int numRead = ReadAt(into, numBytes, currentOffset);
currentOffset += numRead; currentOffset += numRead;
return numRead; return numRead;
} }
int Write(char *from, int numBytes) { int Write(char *from, int numBytes) {
int numWritten = WriteAt(from, numBytes, currentOffset); int numWritten = WriteAt(from, numBytes, currentOffset);
currentOffset += numWritten; currentOffset += numWritten;
return numWritten; return numWritten;
} }
int Length() { Lseek(file, 0, 2); return Tell(file); } int Length() { Lseek(file, 0, 2); return Tell(file); }
OpenFileId GetFileDescriptor() {
return file;
}
private: private:
int file; int file;
int currentOffset; int currentOffset;

View File

@@ -29,6 +29,7 @@ const char dbgFile = 'f'; // file system
const char dbgAddr = 'a'; // address spaces const char dbgAddr = 'a'; // address spaces
const char dbgNet = 'n'; // network emulation const char dbgNet = 'n'; // network emulation
const char dbgSys = 'u'; // systemcall const char dbgSys = 'u'; // systemcall
const char dbgSche = 'z';
class Debug { class Debug {
public: public:

View File

@@ -308,7 +308,6 @@ int
OpenForWrite(char *name) OpenForWrite(char *name)
{ {
int fd = open(name, O_RDWR|O_CREAT|O_TRUNC, 0666); int fd = open(name, O_RDWR|O_CREAT|O_TRUNC, 0666);
// cerr << "OpenForWrite name, fd: " << (int)name << ", " << fd << endl;
ASSERT(fd >= 0); ASSERT(fd >= 0);
return fd; return fd;
@@ -326,7 +325,6 @@ int
OpenForReadWrite(char *name, bool crashOnError) OpenForReadWrite(char *name, bool crashOnError)
{ {
int fd = open(name, O_RDWR, 0); int fd = open(name, O_RDWR, 0);
// cerr << "OpenForReadWrite name, fd: " << (int)name << ", " << fd << endl;
ASSERT(!crashOnError || fd >= 0); ASSERT(!crashOnError || fd >= 0);
return fd; return fd;

View File

@@ -172,13 +172,19 @@ ConsoleOutput::PutChar(char ch)
kernel->interrupt->Schedule(this, ConsoleTime, ConsoleWriteInt); kernel->interrupt->Schedule(this, ConsoleTime, ConsoleWriteInt);
} }
//----------------------------------------------------------------------
// ConsoleOutput::PutInt()
// Write a int to the simulated display, schedule an interrupt
// to occur in the future, and return.
//----------------------------------------------------------------------
void void
ConsoleOutput::PutInt(int value) ConsoleOutput::PutInt(int value)
{ {
ASSERT(putBusy == FALSE); ASSERT(putBusy == FALSE);
char *printStr = (char*)malloc(sizeof(char)*15); char * printStr = (char*)malloc(sizeof(char) * 15);
sprintf(printStr, "%d\n", value); sprintf(printStr, "%d\n", value);
WriteFile(writeFileNo, printStr, strlen(printStr)*sizeof(char)); WriteFile(writeFileNo, printStr, strlen(printStr) * sizeof(char));
putBusy = TRUE; putBusy = TRUE;
kernel->interrupt->Schedule(this, ConsoleTime, ConsoleWriteInt); kernel->interrupt->Schedule(this, ConsoleTime, ConsoleWriteInt);
} }

View File

@@ -76,7 +76,9 @@ class ConsoleOutput : public CallBackObj {
void PutChar(char ch); // Write "ch" to the console display, void PutChar(char ch); // Write "ch" to the console display,
// and return immediately. "callWhenDone" // and return immediately. "callWhenDone"
// will called when the I/O completes. // will called when the I/O completes.
void PutInt(int n);
void PutInt(int value);
void CallBack(); // Invoked when next character can be put void CallBack(); // Invoked when next character can be put
// out to the display. // out to the display.

View File

@@ -22,8 +22,8 @@
#include "copyright.h" #include "copyright.h"
#include "interrupt.h" #include "interrupt.h"
#include "main.h"
#include "synchconsole.h" #include "synchconsole.h"
#include "main.h"
// String definitions for debugging messages // String definitions for debugging messages
@@ -341,7 +341,7 @@ static void
PrintPending (PendingInterrupt *pending) PrintPending (PendingInterrupt *pending)
{ {
cout << "Interrupt handler "<< intTypeNames[pending->type]; cout << "Interrupt handler "<< intTypeNames[pending->type];
cout << ", scheduled at " << pending->when << endl; cout << ", scheduled at " << pending->when;
} }
//---------------------------------------------------------------------- //----------------------------------------------------------------------
@@ -360,8 +360,31 @@ Interrupt::DumpState()
cout << "\nEnd of pending interrupts\n"; cout << "\nEnd of pending interrupts\n";
} }
void void Interrupt::PrintInt(int value)
Interrupt::PrintInt(int value)
{ {
kernel->synchConsoleOut->PutInt(value); kernel->synchConsoleOut->PutInt(value);
} }
OpenFileId
Interrupt::OpenFile(char *filename)
{
return kernel->fileSystem->OpenFiles(filename);
}
int
Interrupt::WriteFile(char *buffer, int size, OpenFileId fd)
{
return kernel->fileSystem->WriteFile(buffer, size, fd);
}
int
Interrupt::CloseFile(OpenFileId fd)
{
return kernel->fileSystem->CloseFile(fd);
}
int
Interrupt::ReadFile(char *buffer, int size, OpenFileId fd)
{
return kernel->fileSystem->ReadFile(buffer, size, fd);
}

View File

@@ -37,35 +37,41 @@
#include "list.h" #include "list.h"
#include "callback.h" #include "callback.h"
#include "filesys.h"
typedef int OpenFileId;
// Interrupts can be disabled (IntOff) or enabled (IntOn) // Interrupts can be disabled (IntOff) or enabled (IntOn)
enum IntStatus { IntOff, IntOn }; enum IntStatus { IntOff, IntOn };
// Nachos can be running kernel code (SystemMode), user code (UserMode), // Nachos can be running kernel code (SystemMode), user code (UserMode),
// or there can be no runnable thread, because the ready list // or there can be no runnable thread, because the ready list
// is empty (IdleMode). // is empty (IdleMode).
enum MachineStatus {IdleMode, SystemMode, UserMode}; enum MachineStatus { IdleMode, SystemMode, UserMode };
// IntType records which hardware device generated an interrupt. // IntType records which hardware device generated an interrupt.
// In Nachos, we support a hardware timer device, a disk, a console // In Nachos, we support a hardware timer device, a disk, a console
// display and keyboard, and a network. // display and keyboard, and a network.
enum IntType { TimerInt, DiskInt, ConsoleWriteInt, ConsoleReadInt, enum IntType {
NetworkSendInt, NetworkRecvInt}; TimerInt, DiskInt, ConsoleWriteInt, ConsoleReadInt,
NetworkSendInt, NetworkRecvInt
};
// The following class defines an interrupt that is scheduled // The following class defines an interrupt that is scheduled
// to occur in the future. The internal data structures are // to occur in the future. The internal data structures are
// left public to make it simpler to manipulate. // left public to make it simpler to manipulate.
class PendingInterrupt { class PendingInterrupt {
public: public:
PendingInterrupt(CallBackObj *callOnInt, int time, IntType kind); PendingInterrupt(CallBackObj* callOnInt, int time, IntType kind);
// initialize an interrupt that will // initialize an interrupt that will
// occur in the future // occur in the future
CallBackObj *callOnInterrupt;// The object (in the hardware device CallBackObj* callOnInterrupt;// The object (in the hardware device
// emulator) to call when the interrupt occurs // emulator) to call when the interrupt occurs
int when; // When the interrupt is supposed to fire int when; // When the interrupt is supposed to fire
IntType type; // for debugging IntType type; // for debugging
}; };
// The following class defines the data structures for the simulation // The following class defines the data structures for the simulation
@@ -74,72 +80,76 @@ class PendingInterrupt {
// in the future. // in the future.
class Interrupt { class Interrupt {
public: public:
Interrupt(); // initialize the interrupt simulation Interrupt(); // initialize the interrupt simulation
~Interrupt(); // de-allocate data structures ~Interrupt(); // de-allocate data structures
IntStatus SetLevel(IntStatus level); IntStatus SetLevel(IntStatus level);
// Disable or enable interrupts // Disable or enable interrupts
// and return previous setting. // and return previous setting.
void Enable() { (void) SetLevel(IntOn); } void Enable() { (void)SetLevel(IntOn); }
// Enable interrupts. // Enable interrupts.
IntStatus getLevel() {return level;} IntStatus getLevel() { return level; }
// Return whether interrupts // Return whether interrupts
// are enabled or disabled // are enabled or disabled
void Idle(); // The ready queue is empty, roll void Idle(); // The ready queue is empty, roll
// simulated time forward until the // simulated time forward until the
// next interrupt // next interrupt
void Halt(); // quit and print out stats void Halt(); // quit and print out stats
void PrintInt(int number); void PrintInt(int number);
int CreateFile(char *filename); int CreateFile(char* filename);
OpenFileId OpenFile(char* filename);
int WriteFile(char* buffer, int size, OpenFileId fd);
int CloseFile(OpenFileId fd);
int ReadFile(char* buffer, int size, OpenFileId fd);
void YieldOnReturn(); // cause a context switch on return void YieldOnReturn(); // cause a context switch on return
// from an interrupt handler // from an interrupt handler
MachineStatus getStatus() { return status; } MachineStatus getStatus() { return status; }
void setStatus(MachineStatus st) { status = st; } void setStatus(MachineStatus st) { status = st; }
// idle, kernel, user // idle, kernel, user
void DumpState(); // Print interrupt state void DumpState(); // Print interrupt state
// NOTE: the following are internal to the hardware simulation code. // NOTE: the following are internal to the hardware simulation code.
// DO NOT call these directly. I should make them "private", // DO NOT call these directly. I should make them "private",
// but they need to be public since they are called by the // but they need to be public since they are called by the
// hardware device simulators. // hardware device simulators.
void Schedule(CallBackObj *callTo, int when, IntType type); void Schedule(CallBackObj* callTo, int when, IntType type);
// Schedule an interrupt to occur // Schedule an interrupt to occur
// at time "when". This is called // at time "when". This is called
// by the hardware device simulators. // by the hardware device simulators.
void OneTick(); // Advance simulated time void OneTick(); // Advance simulated time
private: private:
IntStatus level; // are interrupts enabled or disabled? IntStatus level; // are interrupts enabled or disabled?
SortedList<PendingInterrupt *> *pending; SortedList<PendingInterrupt*>* pending;
// the list of interrupts scheduled // the list of interrupts scheduled
// to occur in the future // to occur in the future
//int writeFileNo; //UNIX file emulating the display //int writeFileNo; //UNIX file emulating the display
bool inHandler; // TRUE if we are running an interrupt handler bool inHandler; // TRUE if we are running an interrupt handler
//bool putBusy; // Is a PrintInt operation in progress //bool putBusy; // Is a PrintInt operation in progress
//If so, you cannoot do another one //If so, you cannoot do another one
bool yieldOnReturn; // TRUE if we are to context switch bool yieldOnReturn; // TRUE if we are to context switch
// on return from the interrupt handler // on return from the interrupt handler
MachineStatus status; // idle, kernel mode, user mode MachineStatus status; // idle, kernel mode, user mode
// these functions are internal to the interrupt simulation code // these functions are internal to the interrupt simulation code
bool CheckIfDue(bool advanceClock); bool CheckIfDue(bool advanceClock);
// Check if any interrupts are supposed // Check if any interrupts are supposed
// to occur now, and if so, do them // to occur now, and if so, do them
void ChangeLevel(IntStatus old, // SetLevel, without advancing the void ChangeLevel(IntStatus old, // SetLevel, without advancing the
IntStatus now); // simulated time IntStatus now); // simulated time
}; };
#endif // INTERRRUPT_H #endif // INTERRRUPT_H

View File

@@ -13,17 +13,10 @@
// Textual names of the exceptions that can be generated by user program // Textual names of the exceptions that can be generated by user program
// execution, for debugging. // execution, for debugging.
static char* exceptionNames[] = { static char* exceptionNames[] = { "no exception", "syscall",
"no exception", "page fault/no TLB entry", "page read only",
"syscall", "bus error", "address error", "overflow",
"page fault/no TLB entry", "illegal instruction" };
"page read only",
"bus error",
"address error",
"overflow",
"illegal instruction",
"bad memory allocation"
};
//---------------------------------------------------------------------- //----------------------------------------------------------------------
// CheckEndian // CheckEndian

View File

@@ -28,34 +28,34 @@
// Definitions related to the size, and format of user memory // Definitions related to the size, and format of user memory
const int PageSize = 128; // set the page size equal to const int PageSize = 128; // set the page size equal to
// the disk sector size, for simplicity // the disk sector size, for simplicity
// //
// You are allowed to change this value. // You are allowed to change this value.
// Doing so will change the number of pages of physical memory // Doing so will change the number of pages of physical memory
// available on the simulated machine. // available on the simulated machine.
// //
const int NumPhysPages = 128; const int NumPhysPages = 128;
const int MemorySize = (NumPhysPages * PageSize); const int MemorySize = (NumPhysPages * PageSize);
const int TLBSize = 4; // if there is a TLB, make it small const int TLBSize = 4; // if there is a TLB, make it small
enum ExceptionType { enum ExceptionType { NoException, // Everything ok!
NoException, // Everything ok! SyscallException, // A program executed a system call.
SyscallException, // A program executed a system call. PageFaultException, // No valid translation found
PageFaultException, // No valid translation found ReadOnlyException, // Write attempted to page marked
ReadOnlyException, // Write attempted to page marked // "read-only"
// "read-only" BusErrorException, // Translation resulted in an
BusErrorException, // Translation resulted in an // invalid physical address
// invalid physical address AddressErrorException, // Unaligned reference or one that
AddressErrorException, // Unaligned reference or one that // was beyond the end of the
// was beyond the end of the // address space
// address space OverflowException, // Integer overflow in add or sub.
OverflowException, // Integer overflow in add or sub. IllegalInstrException, // Unimplemented or reserved instr.
IllegalInstrException, // Unimplemented or reserved instr.
MemoryLimitException, // Bad allocation
NumExceptionTypes MemoryLimitException, // Insufficient memory
NumExceptionTypes
}; };
// User program CPU state. The full set of MIPS registers, plus a few // User program CPU state. The full set of MIPS registers, plus a few
@@ -96,97 +96,97 @@ class Interrupt;
class Machine { class Machine {
public: public:
Machine(bool debug); // Initialize the simulation of the hardware Machine(bool debug); // Initialize the simulation of the hardware
// for running user programs // for running user programs
~Machine(); // De-allocate the data structures ~Machine(); // De-allocate the data structures
// Routines callable by the Nachos kernel // Routines callable by the Nachos kernel
void Run(); // Run a user program void Run(); // Run a user program
int ReadRegister(int num); // read the contents of a CPU register int ReadRegister(int num); // read the contents of a CPU register
void WriteRegister(int num, int value); void WriteRegister(int num, int value);
// store a value into a CPU register // store a value into a CPU register
// Data structures accessible to the Nachos kernel -- main memory and the // Data structures accessible to the Nachos kernel -- main memory and the
// page table/TLB. // page table/TLB.
// //
// Note that *all* communication between the user program and the kernel // Note that *all* communication between the user program and the kernel
// are in terms of these data structures (plus the CPU registers). // are in terms of these data structures (plus the CPU registers).
char *mainMemory; // physical memory to store user program, char *mainMemory; // physical memory to store user program,
// code and data, while executing // code and data, while executing
// NOTE: the hardware translation of virtual addresses in the user program // NOTE: the hardware translation of virtual addresses in the user program
// to physical addresses (relative to the beginning of "mainMemory") // to physical addresses (relative to the beginning of "mainMemory")
// can be controlled by one of: // can be controlled by one of:
// a traditional linear page table // a traditional linear page table
// a software-loaded translation lookaside buffer (tlb) -- a cache of // a software-loaded translation lookaside buffer (tlb) -- a cache of
// mappings of virtual page #'s to physical page #'s // mappings of virtual page #'s to physical page #'s
// //
// If "tlb" is NULL, the linear page table is used // If "tlb" is NULL, the linear page table is used
// If "tlb" is non-NULL, the Nachos kernel is responsible for managing // If "tlb" is non-NULL, the Nachos kernel is responsible for managing
// the contents of the TLB. But the kernel can use any data structure // the contents of the TLB. But the kernel can use any data structure
// it wants (eg, segmented paging) for handling TLB cache misses. // it wants (eg, segmented paging) for handling TLB cache misses.
// //
// For simplicity, both the page table pointer and the TLB pointer are // For simplicity, both the page table pointer and the TLB pointer are
// public. However, while there can be multiple page tables (one per address // public. However, while there can be multiple page tables (one per address
// space, stored in memory), there is only one TLB (implemented in hardware). // space, stored in memory), there is only one TLB (implemented in hardware).
// Thus the TLB pointer should be considered as *read-only*, although // Thus the TLB pointer should be considered as *read-only*, although
// the contents of the TLB are free to be modified by the kernel software. // the contents of the TLB are free to be modified by the kernel software.
TranslationEntry *tlb; // this pointer should be considered TranslationEntry *tlb; // this pointer should be considered
// "read-only" to Nachos kernel code // "read-only" to Nachos kernel code
TranslationEntry *pageTable; TranslationEntry *pageTable;
unsigned int pageTableSize; unsigned int pageTableSize;
bool ReadMem(int addr, int size, int* value); bool ReadMem(int addr, int size, int* value);
bool WriteMem(int addr, int size, int value); bool WriteMem(int addr, int size, int value);
// Read or write 1, 2, or 4 bytes of virtual // Read or write 1, 2, or 4 bytes of virtual
// memory (at addr). Return FALSE if a // memory (at addr). Return FALSE if a
// correct translation couldn't be found. // correct translation couldn't be found.
private: private:
// Routines internal to the machine simulation -- DO NOT call these directly // Routines internal to the machine simulation -- DO NOT call these directly
void DelayedLoad(int nextReg, int nextVal); void DelayedLoad(int nextReg, int nextVal);
// Do a pending delayed load (modifying a reg) // Do a pending delayed load (modifying a reg)
void OneInstruction(Instruction *instr); void OneInstruction(Instruction *instr);
// Run one instruction of a user program. // Run one instruction of a user program.
ExceptionType Translate(int virtAddr, int* physAddr, int size,bool writing); ExceptionType Translate(int virtAddr, int* physAddr, int size,bool writing);
// Translate an address, and check for // Translate an address, and check for
// alignment. Set the use and dirty bits in // alignment. Set the use and dirty bits in
// the translation entry appropriately, // the translation entry appropriately,
// and return an exception code if the // and return an exception code if the
// translation couldn't be completed. // translation couldn't be completed.
void RaiseException(ExceptionType which, int badVAddr); void RaiseException(ExceptionType which, int badVAddr);
// Trap to the Nachos kernel, because of a // Trap to the Nachos kernel, because of a
// system call or other exception. // system call or other exception.
void Debugger(); // invoke the user program debugger void Debugger(); // invoke the user program debugger
void DumpState(); // print the user CPU and memory state void DumpState(); // print the user CPU and memory state
// Internal data structures // Internal data structures
int registers[NumTotalRegs]; // CPU registers, for executing user programs int registers[NumTotalRegs]; // CPU registers, for executing user programs
bool singleStep; // drop back into the debugger after each bool singleStep; // drop back into the debugger after each
// simulated instruction // simulated instruction
int runUntilTime; // drop back into the debugger when simulated int runUntilTime; // drop back into the debugger when simulated
// time reaches this value // time reaches this value
friend class Interrupt; // calls DelayedLoad() friend class Interrupt; // calls DelayedLoad()
}; };
extern void ExceptionHandler(ExceptionType which); extern void ExceptionHandler(ExceptionType which);
// Entry point into Nachos for handling // Entry point into Nachos for handling
// user system calls and exceptions // user system calls and exceptions
// Defined in exception.cc // Defined in exception.cc
// Routines for converting Words and Short Words to and from the // Routines for converting Words and Short Words to and from the

View File

@@ -20,25 +20,25 @@
// The fields in this class are public to make it easier to update. // The fields in this class are public to make it easier to update.
class Statistics { class Statistics {
public: public:
int totalTicks; // Total time running Nachos int totalTicks; // Total time running Nachos
int idleTicks; // Time spent idle (no threads to run) int idleTicks; // Time spent idle (no threads to run)
int systemTicks; // Time spent executing system code int systemTicks; // Time spent executing system code
int userTicks; // Time spent executing user code int userTicks; // Time spent executing user code
// (this is also equal to # of // (this is also equal to # of
// user instructions executed) // user instructions executed)
int numDiskReads; // number of disk read requests int numDiskReads; // number of disk read requests
int numDiskWrites; // number of disk write requests int numDiskWrites; // number of disk write requests
int numConsoleCharsRead; // number of characters read from the keyboard int numConsoleCharsRead; // number of characters read from the keyboard
int numConsoleCharsWritten; // number of characters written to the display int numConsoleCharsWritten; // number of characters written to the display
int numPageFaults; // number of virtual memory page faults int numPageFaults; // number of virtual memory page faults
int numPacketsSent; // number of packets sent over the network int numPacketsSent; // number of packets sent over the network
int numPacketsRecvd; // number of packets received over the network int numPacketsRecvd; // number of packets received over the network
Statistics(); // initialize everything to zero Statistics(); // initialize everything to zero
void Print(); // print collected statistics void Print(); // print collected statistics
}; };
// Constants used to reflect the relative time an operation would // Constants used to reflect the relative time an operation would
@@ -49,12 +49,15 @@ class Statistics {
// in the kernel measured by the number of calls to enable interrupts, // in the kernel measured by the number of calls to enable interrupts,
// these time constants are none too exact. // these time constants are none too exact.
const int UserTick = 1; // advance for each user-level instruction const int UserTick = 1; // advance for each user-level instruction
const int SystemTick = 10; // advance each time interrupts are enabled const int SystemTick = 10; // advance each time interrupts are enabled
const int RotationTime = 500; // time disk takes to rotate one sector const int RotationTime = 500; // time disk takes to rotate one sector
const int SeekTime = 500; // time disk takes to seek past one track const int SeekTime = 500; // time disk takes to seek past one track
const int ConsoleTime = 100; // time to read or write one character
const int NetworkTime = 100; // time to send or receive one packet // MP4 MODIFIED
const int TimerTicks = 100; // (average) time between timer interrupts const int ConsoleTime = 1; // time to read or write one character
const int NetworkTime = 100; // time to send or receive one packet
const int TimerTicks = 100; // (average) time between timer interrupts
#endif // STATS_H #endif // STATS_H

View File

@@ -85,38 +85,38 @@ ShortToMachine(unsigned short shortword) { return ShortToHost(shortword); }
bool bool
Machine::ReadMem(int addr, int size, int *value) Machine::ReadMem(int addr, int size, int *value)
{ {
int data; int data;
ExceptionType exception; ExceptionType exception;
int physicalAddress; int physicalAddress;
DEBUG(dbgAddr, "Reading VA " << addr << ", size " << size); DEBUG(dbgAddr, "Reading VA " << addr << ", size " << size);
exception = Translate(addr, &physicalAddress, size, FALSE); exception = Translate(addr, &physicalAddress, size, FALSE);
if (exception != NoException) { if (exception != NoException) {
RaiseException(exception, addr); RaiseException(exception, addr);
return FALSE; return FALSE;
} }
switch (size) { switch (size) {
case 1: case 1:
data = mainMemory[physicalAddress]; data = mainMemory[physicalAddress];
*value = data; *value = data;
break; break;
case 2: case 2:
data = *(unsigned short *) &mainMemory[physicalAddress]; data = *(unsigned short *) &mainMemory[physicalAddress];
*value = ShortToHost(data); *value = ShortToHost(data);
break; break;
case 4: case 4:
data = *(unsigned int *) &mainMemory[physicalAddress]; data = *(unsigned int *) &mainMemory[physicalAddress];
*value = WordToHost(data); *value = WordToHost(data);
break; break;
default: ASSERT(FALSE); default: ASSERT(FALSE);
} }
DEBUG(dbgAddr, "\tvalue read = " << *value); DEBUG(dbgAddr, "\tvalue read = " << *value);
return (TRUE); return (TRUE);
} }
//---------------------------------------------------------------------- //----------------------------------------------------------------------
@@ -135,35 +135,35 @@ Machine::ReadMem(int addr, int size, int *value)
bool bool
Machine::WriteMem(int addr, int size, int value) Machine::WriteMem(int addr, int size, int value)
{ {
ExceptionType exception; ExceptionType exception;
int physicalAddress; int physicalAddress;
DEBUG(dbgAddr, "Writing VA " << addr << ", size " << size << ", value " << value); DEBUG(dbgAddr, "Writing VA " << addr << ", size " << size << ", value " << value);
exception = Translate(addr, &physicalAddress, size, TRUE); exception = Translate(addr, &physicalAddress, size, TRUE);
if (exception != NoException) { if (exception != NoException) {
RaiseException(exception, addr); RaiseException(exception, addr);
return FALSE; return FALSE;
} }
switch (size) { switch (size) {
case 1: case 1:
mainMemory[physicalAddress] = (unsigned char) (value & 0xff); mainMemory[physicalAddress] = (unsigned char) (value & 0xff);
break; break;
case 2: case 2:
*(unsigned short *) &mainMemory[physicalAddress] *(unsigned short *) &mainMemory[physicalAddress]
= ShortToMachine((unsigned short) (value & 0xffff)); = ShortToMachine((unsigned short) (value & 0xffff));
break; break;
case 4: case 4:
*(unsigned int *) &mainMemory[physicalAddress] *(unsigned int *) &mainMemory[physicalAddress]
= WordToMachine((unsigned int) value); = WordToMachine((unsigned int) value);
break; break;
default: ASSERT(FALSE); default: ASSERT(FALSE);
} }
return TRUE; return TRUE;
} }
//---------------------------------------------------------------------- //----------------------------------------------------------------------
@@ -184,75 +184,67 @@ Machine::WriteMem(int addr, int size, int value)
ExceptionType ExceptionType
Machine::Translate(int virtAddr, int* physAddr, int size, bool writing) Machine::Translate(int virtAddr, int* physAddr, int size, bool writing)
{ {
int i; int i;
unsigned int vpn, offset; unsigned int vpn, offset;
TranslationEntry *entry; TranslationEntry *entry;
unsigned int pageFrame; unsigned int pageFrame;
DEBUG(dbgAddr, "\tTranslate " << virtAddr << (writing ? " , write" : " , read")); DEBUG(dbgAddr, "\tTranslate " << virtAddr << (writing ? " , write" : " , read"));
// check for alignment errors // check for alignment errors
if (((size == 4) && (virtAddr & 0x3)) || ((size == 2) && (virtAddr & 0x1))){ if (((size == 4) && (virtAddr & 0x3)) || ((size == 2) && (virtAddr & 0x1))){
DEBUG(dbgAddr, "Alignment problem at " << virtAddr << ", size " << size); DEBUG(dbgAddr, "Alignment problem at " << virtAddr << ", size " << size);
return AddressErrorException; return AddressErrorException;
}
// we must have either a TLB or a page table, but not both!
ASSERT(tlb == NULL || pageTable == NULL);
ASSERT(tlb != NULL || pageTable != NULL);
// calculate the virtual page number, and offset within the page,
// from the virtual address
vpn = (unsigned) virtAddr / PageSize;
offset = (unsigned) virtAddr % PageSize;
if (tlb == NULL) { // => page table => vpn is index into table
if (vpn >= pageTableSize) {
DEBUG(dbgAddr, "Illegal virtual page # " << virtAddr);
DEBUG(dbgAddr, "vpn, pageTableSize, NumPhysPages: " << vpn << ' ' << pageTableSize << ' ' << NumPhysPages);
return AddressErrorException;
} else if (!pageTable[vpn].valid) {
DEBUG(dbgAddr, "Invalid virtual page # " << virtAddr);
return PageFaultException;
} }
entry = &pageTable[vpn]; // we must have either a TLB or a page table, but not both!
} else { ASSERT(tlb == NULL || pageTable == NULL);
for (entry = NULL, i = 0; i < TLBSize; i++) ASSERT(tlb != NULL || pageTable != NULL);
if (tlb[i].valid && (tlb[i].virtualPage == ((int)vpn))) {
entry = &tlb[i]; // FOUND!
break;
}
if (entry == NULL) { // not found
DEBUG(dbgAddr, "Invalid TLB entry for this virtual page!");
return PageFaultException; // really, this is a TLB fault,
// the page may be in memory,
// but not in the TLB
}
}
if (entry->readOnly && writing) { // trying to write to a read-only page // calculate the virtual page number, and offset within the page,
DEBUG(dbgAddr, "Write to read-only page at " << virtAddr); // from the virtual address
return ReadOnlyException; vpn = (unsigned) virtAddr / PageSize;
} offset = (unsigned) virtAddr % PageSize;
pageFrame = entry->physicalPage;
if (pageFrame == -1) {
pageFrame = entry->physicalPage = kernel->frameTable->Allocate();
if (pageFrame == -1) {
DEBUG(dbgAddr, "Memory Limit exceeded");
return MemoryLimitException;
}
}
// if the pageFrame is too big, there is something really wrong! if (tlb == NULL) { // => page table => vpn is index into table
// An invalid translation was loaded into the page table or TLB. if (vpn >= pageTableSize) {
if (pageFrame >= NumPhysPages) { DEBUG(dbgAddr, "Illegal virtual page # " << virtAddr);
DEBUG(dbgAddr, "Illegal pageframe " << pageFrame); return AddressErrorException;
return BusErrorException; } else if (!pageTable[vpn].valid) {
} DEBUG(dbgAddr, "Invalid virtual page # " << virtAddr);
entry->use = TRUE; // set the use, dirty bits return PageFaultException;
if (writing) }
entry->dirty = TRUE; entry = &pageTable[vpn];
*physAddr = pageFrame * PageSize + offset; } else {
ASSERT((*physAddr >= 0) && ((*physAddr + size) <= MemorySize)); for (entry = NULL, i = 0; i < TLBSize; i++)
DEBUG(dbgAddr, "phys addr = " << *physAddr); if (tlb[i].valid && (tlb[i].virtualPage == ((int)vpn))) {
return NoException; entry = &tlb[i]; // FOUND!
break;
}
if (entry == NULL) { // not found
DEBUG(dbgAddr, "Invalid TLB entry for this virtual page!");
return PageFaultException; // really, this is a TLB fault,
// the page may be in memory,
// but not in the TLB
}
}
if (entry->readOnly && writing) { // trying to write to a read-only page
DEBUG(dbgAddr, "Write to read-only page at " << virtAddr);
return ReadOnlyException;
}
pageFrame = entry->physicalPage;
// if the pageFrame is too big, there is something really wrong!
// An invalid translation was loaded into the page table or TLB.
if (pageFrame >= NumPhysPages) {
DEBUG(dbgAddr, "Illegal pageframe " << pageFrame);
return BusErrorException;
}
entry->use = TRUE; // set the use, dirty bits
if (writing)
entry->dirty = TRUE;
*physAddr = pageFrame * PageSize + offset;
ASSERT((*physAddr >= 0) && ((*physAddr + size) <= MemorySize));
DEBUG(dbgAddr, "phys addr = " << *physAddr);
return NoException;
} }

View File

@@ -113,8 +113,7 @@ ifeq ($(hosttype),unknown)
PROGRAMS = unknownhost PROGRAMS = unknownhost
else else
# change this if you create a new test program! # change this if you create a new test program!
PROGRAMS = add halt consoleIO_test1 consoleIO_test2 fileIO_test1 fileIO_test2 test PROGRAMS = mp4_consoleIO_1 mp4_consoleIO_2 mp4_consoleIO_3 mp4_consoleIO_4
# PROGRAMS = halt
endif endif
all: $(PROGRAMS) all: $(PROGRAMS)
@@ -122,78 +121,35 @@ all: $(PROGRAMS)
start.o: start.S ../userprog/syscall.h start.o: start.S ../userprog/syscall.h
$(CC) $(CFLAGS) $(ASFLAGS) -c start.S $(CC) $(CFLAGS) $(ASFLAGS) -c start.S
halt.o: halt.c mp4_consoleIO_1.o: mp4_consoleIO_1.c
$(CC) $(CFLAGS) -c halt.c $(CC) $(CFLAGS) -c mp4_consoleIO_1.c
halt: halt.o start.o
$(LD) $(LDFLAGS) start.o halt.o -o halt.coff
$(COFF2NOFF) halt.coff halt
add.o: add.c mp4_consoleIO_1: mp4_consoleIO_1.o start.o
$(CC) $(CFLAGS) -c add.c $(LD) $(LDFLAGS) start.o mp4_consoleIO_1.o -o mp4_consoleIO_1.coff
$(COFF2NOFF) mp4_consoleIO_1.coff mp4_consoleIO_1
add: add.o start.o
$(LD) $(LDFLAGS) start.o add.o -o add.coff
$(COFF2NOFF) add.coff add
shell.o: shell.c mp4_consoleIO_2.o: mp4_consoleIO_2.c
$(CC) $(CFLAGS) -c shell.c $(CC) $(CFLAGS) -c mp4_consoleIO_2.c
shell: shell.o start.o
$(LD) $(LDFLAGS) start.o shell.o -o shell.coff
$(COFF2NOFF) shell.coff shell
sort.o: sort.c mp4_consoleIO_2: mp4_consoleIO_2.o start.o
$(CC) $(CFLAGS) -c sort.c $(LD) $(LDFLAGS) start.o mp4_consoleIO_2.o -o mp4_consoleIO_2.coff
sort: sort.o start.o $(COFF2NOFF) mp4_consoleIO_2.coff mp4_consoleIO_2
$(LD) $(LDFLAGS) start.o sort.o -o sort.coff
$(COFF2NOFF) sort.coff sort
segments.o: segments.c mp4_consoleIO_3.o: mp4_consoleIO_3.c
$(CC) $(CFLAGS) -c segments.c $(CC) $(CFLAGS) -c mp4_consoleIO_3.c
segments: segments.o start.o
$(LD) $(LDFLAGS) start.o segments.o -o segments.coff
$(COFF2NOFF) segments.coff segments
matmult.o: matmult.c mp4_consoleIO_3: mp4_consoleIO_3.o start.o
$(CC) $(CFLAGS) -c matmult.c $(LD) $(LDFLAGS) start.o mp4_consoleIO_3.o -o mp4_consoleIO_3.coff
matmult: matmult.o start.o $(COFF2NOFF) mp4_consoleIO_3.coff mp4_consoleIO_3
$(LD) $(LDFLAGS) start.o matmult.o -o matmult.coff
$(COFF2NOFF) matmult.coff matmult
consoleIO_test1.o: consoleIO_test1.c mp4_consoleIO_4.o: mp4_consoleIO_4.c
$(CC) $(CFLAGS) -c consoleIO_test1.c $(CC) $(CFLAGS) -c mp4_consoleIO_4.c
consoleIO_test1: consoleIO_test1.o start.o
$(LD) $(LDFLAGS) start.o consoleIO_test1.o -o consoleIO_test1.coff
$(COFF2NOFF) consoleIO_test1.coff consoleIO_test1
consoleIO_test2.o: consoleIO_test2.c mp4_consoleIO_4: mp4_consoleIO_4.o start.o
$(CC) $(CFLAGS) -c consoleIO_test2.c $(LD) $(LDFLAGS) start.o mp4_consoleIO_4.o -o mp4_consoleIO_4.coff
consoleIO_test2: consoleIO_test2.o start.o $(COFF2NOFF) mp4_consoleIO_4.coff mp4_consoleIO_4
$(LD) $(LDFLAGS) start.o consoleIO_test2.o -o consoleIO_test2.coff
$(COFF2NOFF) consoleIO_test2.coff consoleIO_test2
fileIO_test1.o: fileIO_test1.c
$(CC) $(CFLAGS) -c fileIO_test1.c
fileIO_test1: fileIO_test1.o start.o
$(LD) $(LDFLAGS) start.o fileIO_test1.o -o fileIO_test1.coff
$(COFF2NOFF) fileIO_test1.coff fileIO_test1
fileIO_test2.o: fileIO_test2.c
$(CC) $(CFLAGS) -c fileIO_test2.c
fileIO_test2: fileIO_test2.o start.o
$(LD) $(LDFLAGS) start.o fileIO_test2.o -o fileIO_test2.coff
$(COFF2NOFF) fileIO_test2.coff fileIO_test2
fileIO_test3.o: fileIO_test3.c
$(CC) $(CFLAGS) -c fileIO_test3.c
fileIO_test3: fileIO_test3.o start.o
$(LD) $(LDFLAGS) start.o fileIO_test3.o -o fileIO_test3.coff
$(COFF2NOFF) fileIO_test3.coff fileIO_test3
test.o: test.c
$(CC) $(CFLAGS) -c test.c
test: test.o start.o
$(LD) $(LDFLAGS) start.o test.o -o test.coff
$(COFF2NOFF) test.coff test
clean: clean:
$(RM) -f *.o *.ii $(RM) -f *.o *.ii
@@ -203,12 +159,11 @@ distclean: clean
$(RM) -f $(PROGRAMS) $(RM) -f $(PROGRAMS)
run: $(PROGRAMS) run: $(PROGRAMS)
timeout 1 $(NACHOS) -e consoleIO_test1 -e consoleIO_test2 timeout 1 $(NACHOS) -ep mp4_consoleIO_1 70 -ep mp4_consoleIO_3 80 -ep mp4_consoleIO_2 50
echo 'done' echo 'done'
debug: $(PROGRAMS) debug: $(PROGRAMS)
timeout 1 $(NACHOS) -e consoleIO_test1 -e consoleIO_test2 -d + timeout 1 $(NACHOS) -d z -ep mp4_consoleIO_1 60 -ep mp4_consoleIO_2 70
unknownhost: unknownhost:
@echo Host type could not be determined. @echo Host type could not be determined.

View File

@@ -0,0 +1,10 @@
#include "syscall.h"
int main()
{
int n;
for (n = 0; n < 4; n++) {
PrintInt(1);
}
return 0;
}

View File

@@ -0,0 +1,9 @@
#include "syscall.h"
int main()
{
int n;
for (n = 0; n < 5; n++) {
PrintInt(2);
}
return 0;
}

View File

@@ -0,0 +1,10 @@
#include "syscall.h"
int
main()
{
int n;
for (n = 0; n < 12; n++) {
PrintInt(3);
}
return 0;
}

View File

@@ -0,0 +1,9 @@
#include "syscall.h"
int main()
{
int n;
for (n = 0; n < 11; n++) {
PrintInt(4);
}
return 0;
}

View File

@@ -1,4 +1,9 @@
make distclean make distclean
make make
timeout 1 ../build.linux/nachos -e consoleIO_test1 -e consoleIO_test2 rm -f *.o *.ii
echo 'done' rm -f *.coff
echo "=========================="
timeout 1 ../build.linux/nachos -e mp4_consoleIO_1 -e mp4_consoleIO_2
echo "=========================="
timeout 1 ../build.linux/nachos -e mp4_consoleIO_3 -e mp4_consoleIO_4
echo "done"

View File

@@ -58,6 +58,14 @@ MSG:
j $31 j $31
.end MSG .end MSG
.globl PrintInt
.ent PrintInt
PrintInt:
addiu $2,$0,SC_PrintInt
syscall
j $31
.end PrintInt
.globl Add .globl Add
.ent Add .ent Add
Add: Add:
@@ -186,14 +194,6 @@ ThreadJoin:
j $31 j $31
.end ThreadJoin .end ThreadJoin
.globl PrintInt
.ent PrintInt
PrintInt:
addiu $2,$0,SC_PrintInt
syscall
j $31
.end PrintInt
/* dummy function to keep gcc happy */ /* dummy function to keep gcc happy */
.globl __main .globl __main

View File

@@ -46,10 +46,12 @@ Alarm::Alarm(bool doRandom)
void void
Alarm::CallBack() Alarm::CallBack()
{ {
Interrupt *interrupt = kernel->interrupt; Interrupt* interrupt = kernel->interrupt;
MachineStatus status = interrupt->getStatus(); MachineStatus status = interrupt->getStatus();
// Todo ----
if (status != IdleMode) { if (status != IdleMode) {
interrupt->YieldOnReturn(); // interrupt->YieldOnReturn();
} }
// ---------
} }

View File

@@ -24,10 +24,8 @@
// for the initialization (see also comments in main.cc) // for the initialization (see also comments in main.cc)
//---------------------------------------------------------------------- //----------------------------------------------------------------------
Kernel::Kernel(int argc, char **argv) Kernel::Kernel(int argc, char** argv)
{ {
execfileNum = 0;
threadNum = 0;
randomSlice = FALSE; randomSlice = FALSE;
debugUserProg = FALSE; debugUserProg = FALSE;
consoleIn = NULL; // default is stdin consoleIn = NULL; // default is stdin
@@ -45,32 +43,48 @@ Kernel::Kernel(int argc, char **argv)
// number generator // number generator
randomSlice = TRUE; randomSlice = TRUE;
i++; i++;
} else if (strcmp(argv[i], "-s") == 0) { }
else if (strcmp(argv[i], "-s") == 0) {
debugUserProg = TRUE; debugUserProg = TRUE;
} else if (strcmp(argv[i], "-e") == 0) { }
execfile[++execfileNum]= argv[++i]; // Todo ----
else if (strcmp(argv[i], "-e") == 0) {
execfile[++execfileNum] = argv[++i];
cout << execfile[execfileNum] << "\n"; cout << execfile[execfileNum] << "\n";
} else if (strcmp(argv[i], "-ci") == 0) { }
else if (strcmp(argv[i], "-ep") == 0) {
execfile[++execfileNum] = argv[++i];
execPriority[execfileNum] = atoi(argv[++i]);
cout << execfile[execfileNum] << " with priority "
<< execPriority[execfileNum] << "\n";
}
// ---------
else if (strcmp(argv[i], "-ci") == 0) {
ASSERT(i + 1 < argc); ASSERT(i + 1 < argc);
consoleIn = argv[i + 1]; consoleIn = argv[i + 1];
i++; i++;
} else if (strcmp(argv[i], "-co") == 0) { }
else if (strcmp(argv[i], "-co") == 0) {
ASSERT(i + 1 < argc); ASSERT(i + 1 < argc);
consoleOut = argv[i + 1]; consoleOut = argv[i + 1];
i++; i++;
#ifndef FILESYS_STUB #ifndef FILESYS_STUB
} else if (strcmp(argv[i], "-f") == 0) { }
else if (strcmp(argv[i], "-f") == 0) {
formatFlag = TRUE; formatFlag = TRUE;
#endif #endif
} else if (strcmp(argv[i], "-n") == 0) { }
else if (strcmp(argv[i], "-n") == 0) {
ASSERT(i + 1 < argc); // next argument is float ASSERT(i + 1 < argc); // next argument is float
reliability = atof(argv[i + 1]); reliability = atof(argv[i + 1]);
i++; i++;
} else if (strcmp(argv[i], "-m") == 0) { }
else if (strcmp(argv[i], "-m") == 0) {
ASSERT(i + 1 < argc); // next argument is int ASSERT(i + 1 < argc); // next argument is int
hostName = atoi(argv[i + 1]); hostName = atoi(argv[i + 1]);
i++; i++;
} else if (strcmp(argv[i], "-u") == 0) { }
else if (strcmp(argv[i], "-u") == 0) {
cout << "Partial usage: nachos [-rs randomSeed]\n"; cout << "Partial usage: nachos [-rs randomSeed]\n";
cout << "Partial usage: nachos [-s]\n"; cout << "Partial usage: nachos [-s]\n";
cout << "Partial usage: nachos [-ci consoleIn] [-co consoleOut]\n"; cout << "Partial usage: nachos [-ci consoleIn] [-co consoleOut]\n";
@@ -92,32 +106,34 @@ Kernel::Kernel(int argc, char **argv)
void void
Kernel::Initialize() Kernel::Initialize()
{ {
// We didn't explicitly allocate the current thread we are running in. // 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 // But if it ever tries to give up the CPU, we better have a Thread
// object to save its state. // object to save its state.
currentThread = new Thread("main", threadNum++); currentThread = new Thread("main", threadNum++);
currentThread->setStatus(RUNNING); currentThread->setStatus(RUNNING);
stats = new Statistics(); // collect statistics stats = new Statistics(); // collect statistics
interrupt = new Interrupt; // start up interrupt handling interrupt = new Interrupt; // start up interrupt handling
scheduler = new Scheduler(); // initialize the ready queue scheduler = new Scheduler(); // initialize the ready queue
alarm = new Alarm(randomSlice); // start up time slicing alarm = new Alarm(randomSlice); // start up time slicing
machine = new Machine(debugUserProg); machine = new Machine(debugUserProg);
synchConsoleIn = new SynchConsoleInput(consoleIn); // input from stdin synchConsoleIn = new SynchConsoleInput(consoleIn); // input from stdin
synchConsoleOut = new SynchConsoleOutput(consoleOut); // output to stdout synchConsoleOut = new SynchConsoleOutput(consoleOut); // output to stdout
synchDisk = new SynchDisk(); // synchDisk = new SynchDisk(); //
#ifdef FILESYS_STUB #ifdef FILESYS_STUB
fileSystem = new FileSystem(); fileSystem = new FileSystem();
#else #else
fileSystem = new FileSystem(formatFlag); fileSystem = new FileSystem(formatFlag);
#endif // FILESYS_STUB #endif // FILESYS_STUB
postOfficeIn = new PostOfficeInput(10);
postOfficeOut = new PostOfficeOutput(reliability);
frameTable = new FrameTable;
interrupt->Enable(); // MP4 MODIFIED
// postOfficeIn = new PostOfficeInput(10);
// postOfficeOut = new PostOfficeOutput(reliability);
frameTable = new FrameTable();
interrupt->Enable();
} }
//---------------------------------------------------------------------- //----------------------------------------------------------------------
@@ -127,20 +143,23 @@ Kernel::Initialize()
Kernel::~Kernel() Kernel::~Kernel()
{ {
delete stats; delete stats;
delete interrupt; delete interrupt;
delete scheduler; delete scheduler;
delete alarm; delete alarm;
delete machine; delete machine;
delete synchConsoleIn; delete synchConsoleIn;
delete synchConsoleOut; delete synchConsoleOut;
delete synchDisk; delete synchDisk;
delete fileSystem; delete fileSystem;
delete postOfficeIn;
delete postOfficeOut;
delete frameTable;
Exit(0); // MP4 MODIFIED
// delete postOfficeIn;
// delete postOfficeOut;
delete frameTable;
Exit(0);
} }
//---------------------------------------------------------------------- //----------------------------------------------------------------------
@@ -150,23 +169,23 @@ Kernel::~Kernel()
void void
Kernel::ThreadSelfTest() { Kernel::ThreadSelfTest() {
Semaphore *semaphore; Semaphore* semaphore;
SynchList<int> *synchList; SynchList<int>* synchList;
LibSelfTest(); // test library routines LibSelfTest(); // test library routines
currentThread->SelfTest(); // test thread switching currentThread->SelfTest(); // test thread switching
// test semaphore operation // test semaphore operation
semaphore = new Semaphore("test", 0); semaphore = new Semaphore("test", 0);
semaphore->SelfTest(); semaphore->SelfTest();
delete semaphore; delete semaphore;
// test locks, condition variables // test locks, condition variables
// using synchronized lists // using synchronized lists
synchList = new SynchList<int>; synchList = new SynchList<int>;
synchList->SelfTest(9); synchList->SelfTest(9);
delete synchList; delete synchList;
} }
@@ -186,7 +205,7 @@ Kernel::ConsoleTest() {
do { do {
ch = synchConsoleIn->GetChar(); ch = synchConsoleIn->GetChar();
if(ch != EOF) synchConsoleOut->PutChar(ch); // echo it! if (ch != EOF) synchConsoleOut->PutChar(ch); // echo it!
} while (ch != EOF); } while (ch != EOF);
cout << "\n"; cout << "\n";
@@ -214,8 +233,8 @@ Kernel::NetworkTest() {
int farHost = (hostName == 0 ? 1 : 0); int farHost = (hostName == 0 ? 1 : 0);
PacketHeader outPktHdr, inPktHdr; PacketHeader outPktHdr, inPktHdr;
MailHeader outMailHdr, inMailHdr; MailHeader outMailHdr, inMailHdr;
char *data = "Hello there!"; char* data = "Hello there!";
char *ack = "Got it!"; char* ack = "Got it!";
char buffer[MaxMailSize]; char buffer[MaxMailSize];
// construct packet, mail header for original message // construct packet, mail header for original message
@@ -232,7 +251,7 @@ Kernel::NetworkTest() {
// Wait for the first message from the other machine // Wait for the first message from the other machine
postOfficeIn->Receive(0, &inPktHdr, &inMailHdr, buffer); postOfficeIn->Receive(0, &inPktHdr, &inMailHdr, buffer);
cout << "Got: " << buffer << " : from " << inPktHdr.from << ", box " cout << "Got: " << buffer << " : from " << inPktHdr.from << ", box "
<< inMailHdr.from << "\n"; << inMailHdr.from << "\n";
cout.flush(); cout.flush();
// Send acknowledgement to the other machine (using "reply to" mailbox // Send acknowledgement to the other machine (using "reply to" mailbox
@@ -245,71 +264,73 @@ Kernel::NetworkTest() {
// Wait for the ack from the other machine to the first message we sent // Wait for the ack from the other machine to the first message we sent
postOfficeIn->Receive(1, &inPktHdr, &inMailHdr, buffer); postOfficeIn->Receive(1, &inPktHdr, &inMailHdr, buffer);
cout << "Got: " << buffer << " : from " << inPktHdr.from << ", box " cout << "Got: " << buffer << " : from " << inPktHdr.from << ", box "
<< inMailHdr.from << "\n"; << inMailHdr.from << "\n";
cout.flush(); cout.flush();
} }
// Then we're done! // Then we're done!
} }
void ForkExecute(Thread *t) void ForkExecute(Thread* t)
{ {
if (!t->space->Load(t->getName())) if (!t->space->Load(t->getName())) {
return; // executable not found return; // executable not found
}
t->space->Execute(t->getName());
t->space->Execute(t->getName());
} }
void Kernel::ExecAll() void Kernel::ExecAll()
{ {
for (int i=1;i<=execfileNum;i++) { for (int i = 1;i <= execfileNum;i++) {
int a = Exec(execfile[i]); int a = Exec(execfile[i], execPriority[i]);
} }
currentThread->Finish(); currentThread->Finish();
//Kernel::Exec(); //Kernel::Exec();
} }
// Todo ----
int Kernel::Exec(char* name) int Kernel::Exec(char* name, int priority)
{ {
t[threadNum] = new Thread(name, threadNum); t[threadNum] = new Thread(name, threadNum);
t[threadNum]->space = new AddrSpace(); t[threadNum]->setPriority(priority);
t[threadNum]->Fork((VoidFunctionPtr) &ForkExecute, (void *)t[threadNum]); // ---------
t[threadNum]->space = new AddrSpace();
t[threadNum]->Fork((VoidFunctionPtr)&ForkExecute, (void*)t[threadNum]);
threadNum++;
return threadNum++; return threadNum - 1;
/* /*
cout << "Total threads number is " << execfileNum << endl; cout << "Total threads number is " << execfileNum << endl;
for (int n=1;n<=execfileNum;n++) { for (int n=1;n<=execfileNum;n++) {
t[n] = new Thread(execfile[n]); t[n] = new Thread(execfile[n]);
t[n]->space = new AddrSpace(); t[n]->space = new AddrSpace();
t[n]->Fork((VoidFunctionPtr) &ForkExecute, (void *)t[n]); t[n]->Fork((VoidFunctionPtr) &ForkExecute, (void *)t[n]);
cout << "Thread " << execfile[n] << " is executing." << endl; cout << "Thread " << execfile[n] << " is executing." << endl;
} }
cout << "debug Kernel::Run finished.\n"; cout << "debug Kernel::Run finished.\n";
*/ */
// Thread *t1 = new Thread(execfile[1]); // Thread *t1 = new Thread(execfile[1]);
// Thread *t1 = new Thread("../test/test1"); // Thread *t1 = new Thread("../test/test1");
// Thread *t2 = new Thread("../test/test2"); // Thread *t2 = new Thread("../test/test2");
// AddrSpace *halt = new AddrSpace(); // AddrSpace *halt = new AddrSpace();
// t1->space = new AddrSpace(); // t1->space = new AddrSpace();
// t2->space = new AddrSpace(); // t2->space = new AddrSpace();
// halt->Execute("../test/halt"); // halt->Execute("../test/halt");
// t1->Fork((VoidFunctionPtr) &ForkExecute, (void *)t1); // t1->Fork((VoidFunctionPtr) &ForkExecute, (void *)t1);
// t2->Fork((VoidFunctionPtr) &ForkExecute, (void *)t2); // t2->Fork((VoidFunctionPtr) &ForkExecute, (void *)t2);
// currentThread->Finish(); // currentThread->Finish();
// Kernel::Run(); // Kernel::Run();
// cout << "after ThreadedKernel:Run();" << endl; // unreachable // cout << "after ThreadedKernel:Run();" << endl; // unreachable
} }
int Kernel::CreateFile(char *filename) int Kernel::CreateFile(char* filename)
{ {
return fileSystem->Create(filename); return fileSystem->Create(filename);
} }
void Kernel::PrintInt(int value)
{
return synchConsoleOut->PutInt(value);
}

View File

@@ -25,31 +25,34 @@ class SynchConsoleInput;
class SynchConsoleOutput; class SynchConsoleOutput;
class SynchDisk; class SynchDisk;
// Todo ----
// ---------
class Kernel { class Kernel {
public: public:
Kernel(int argc, char **argv); Kernel(int argc, char **argv);
// Interpret command line arguments // Interpret command line arguments
~Kernel(); // deallocate the kernel ~Kernel(); // deallocate the kernel
void Initialize(); // initialize the kernel -- separated void Initialize(); // initialize the kernel -- separated
// from constructor because // from constructor because
// refers to "kernel" as a global // refers to "kernel" as a global
void ExecAll(); void ExecAll();
int Exec(char* name);
// Todo ----
int Exec(char* name, int priority);
// ---------
void ThreadSelfTest(); // self test of threads and synchronization void ThreadSelfTest(); // self test of threads and synchronization
void ConsoleTest(); // interactive console self test void ConsoleTest(); // interactive console self test
void NetworkTest(); // interactive 2-machine network test void NetworkTest(); // interactive 2-machine network test
Thread* getThread(int threadID){return t[threadID];} Thread* getThread(int threadID){return t[threadID];}
void PrintInt(int n);
int CreateFile(char* filename); // fileSystem call int CreateFile(char* filename); // fileSystem call
// These are public for notational convenience; really, // These are public for notational convenience; really,
// they're global variables used everywhere. // they're global variables used everywhere.
Thread *currentThread; // the thread holding the CPU Thread *currentThread; // the thread holding the CPU
Scheduler *scheduler; // the ready list Scheduler *scheduler; // the ready list
@@ -64,13 +67,17 @@ class Kernel {
PostOfficeInput *postOfficeIn; PostOfficeInput *postOfficeIn;
PostOfficeOutput *postOfficeOut; PostOfficeOutput *postOfficeOut;
FrameTable *frameTable; FrameTable *frameTable;
int hostName; // machine identifier int hostName; // machine identifier
private: private:
Thread* t[10]; Thread* t[10];
// Todo ----
char* execfile[10]; char* execfile[10];
int execPriority[10];
// ---------
int execfileNum; int execfileNum;
int threadNum; int threadNum;
bool randomSlice; // enable pseudo-random time slicing bool randomSlice; // enable pseudo-random time slicing
@@ -85,5 +92,3 @@ class Kernel {
#endif // KERNEL_H #endif // KERNEL_H

View File

@@ -47,8 +47,8 @@
#include "sysdep.h" #include "sysdep.h"
// global variables // global variables
Kernel *kernel; Kernel* kernel;
Debug *debug; Debug* debug;
//---------------------------------------------------------------------- //----------------------------------------------------------------------
@@ -78,26 +78,26 @@ static const int TransferSize = 128;
//---------------------------------------------------------------------- //----------------------------------------------------------------------
static void static void
Copy(char *from, char *to) Copy(char* from, char* to)
{ {
int fd; int fd;
OpenFile* openFile; OpenFile* openFile;
int amountRead, fileLength; int amountRead, fileLength;
char *buffer; char* buffer;
// Open UNIX file // Open UNIX file
if ((fd = OpenForReadWrite(from,FALSE)) < 0) { if ((fd = OpenForReadWrite(from, FALSE)) < 0) {
printf("Copy: couldn't open input file %s\n", from); printf("Copy: couldn't open input file %s\n", from);
return; return;
} }
// Figure out length of UNIX file // Figure out length of UNIX file
Lseek(fd, 0, 2); Lseek(fd, 0, 2);
fileLength = Tell(fd); fileLength = Tell(fd);
Lseek(fd, 0, 0); Lseek(fd, 0, 0);
// Create a Nachos file of the same length // Create a Nachos file of the same length
DEBUG('f', "Copying file " << from << " of size " << fileLength << " to file " << to); DEBUG('f', "Copying file " << from << " of size " << fileLength << " to file " << to);
if (!kernel->fileSystem->Create(to, fileLength)) { // Create Nachos file if (!kernel->fileSystem->Create(to, fileLength)) { // Create Nachos file
printf("Copy: couldn't create output file %s\n", to); printf("Copy: couldn't create output file %s\n", to);
Close(fd); Close(fd);
@@ -107,13 +107,13 @@ Copy(char *from, char *to)
openFile = kernel->fileSystem->Open(to); openFile = kernel->fileSystem->Open(to);
ASSERT(openFile != NULL); ASSERT(openFile != NULL);
// Copy the data in TransferSize chunks // Copy the data in TransferSize chunks
buffer = new char[TransferSize]; buffer = new char[TransferSize];
while ((amountRead=ReadPartial(fd, buffer, sizeof(char)*TransferSize)) > 0) while ((amountRead = ReadPartial(fd, buffer, sizeof(char) * TransferSize)) > 0)
openFile->Write(buffer, amountRead); openFile->Write(buffer, amountRead);
delete [] buffer; delete[] buffer;
// Close the UNIX and the Nachos files // Close the UNIX and the Nachos files
delete openFile; delete openFile;
Close(fd); Close(fd);
} }
@@ -126,11 +126,11 @@ Copy(char *from, char *to)
//---------------------------------------------------------------------- //----------------------------------------------------------------------
void void
Print(char *name) Print(char* name)
{ {
OpenFile *openFile; OpenFile* openFile;
int i, amountRead; int i, amountRead;
char *buffer; char* buffer;
if ((openFile = kernel->fileSystem->Open(name)) == NULL) { if ((openFile = kernel->fileSystem->Open(name)) == NULL) {
printf("Print: unable to open file %s\n", name); printf("Print: unable to open file %s\n", name);
@@ -141,7 +141,7 @@ Print(char *name)
while ((amountRead = openFile->Read(buffer, TransferSize)) > 0) while ((amountRead = openFile->Read(buffer, TransferSize)) > 0)
for (i = 0; i < amountRead; i++) for (i = 0; i < amountRead; i++)
printf("%c", buffer[i]); printf("%c", buffer[i]);
delete [] buffer; delete[] buffer;
delete openFile; // close the Nachos file delete openFile; // close the Nachos file
return; return;
@@ -164,19 +164,19 @@ Print(char *name)
//---------------------------------------------------------------------- //----------------------------------------------------------------------
int int
main(int argc, char **argv) main(int argc, char** argv)
{ {
int i; int i;
char *debugArg = ""; char* debugArg = "";
char *userProgName = NULL; // default is not to execute a user prog char* userProgName = NULL; // default is not to execute a user prog
bool threadTestFlag = false; bool threadTestFlag = false;
bool consoleTestFlag = false; bool consoleTestFlag = false;
bool networkTestFlag = false; bool networkTestFlag = false;
#ifndef FILESYS_STUB #ifndef FILESYS_STUB
char *copyUnixFileName = NULL; // UNIX file to be copied into Nachos char* copyUnixFileName = NULL; // UNIX file to be copied into Nachos
char *copyNachosFileName = NULL; // name of copied file in Nachos char* copyNachosFileName = NULL; // name of copied file in Nachos
char *printFileName = NULL; char* printFileName = NULL;
char *removeFileName = NULL; char* removeFileName = NULL;
bool dirListFlag = false; bool dirListFlag = false;
bool dumpFlag = false; bool dumpFlag = false;
#endif //FILESYS_STUB #endif //FILESYS_STUB
@@ -186,61 +186,61 @@ main(int argc, char **argv)
// the Kernel constructor // the Kernel constructor
for (i = 1; i < argc; i++) { for (i = 1; i < argc; i++) {
if (strcmp(argv[i], "-d") == 0) { if (strcmp(argv[i], "-d") == 0) {
ASSERT(i + 1 < argc); // next argument is debug string ASSERT(i + 1 < argc); // next argument is debug string
debugArg = argv[i + 1]; debugArg = argv[i + 1];
i++; i++;
} }
else if (strcmp(argv[i], "-z") == 0) { else if (strcmp(argv[i], "-z") == 0) {
cout << copyright << "\n"; cout << copyright << "\n";
} }
else if (strcmp(argv[i], "-x") == 0) { else if (strcmp(argv[i], "-x") == 0) {
ASSERT(i + 1 < argc); ASSERT(i + 1 < argc);
userProgName = argv[i + 1]; userProgName = argv[i + 1];
i++; i++;
} }
else if (strcmp(argv[i], "-K") == 0) { else if (strcmp(argv[i], "-K") == 0) {
threadTestFlag = TRUE; threadTestFlag = TRUE;
} }
else if (strcmp(argv[i], "-C") == 0) { else if (strcmp(argv[i], "-C") == 0) {
consoleTestFlag = TRUE; consoleTestFlag = TRUE;
} }
else if (strcmp(argv[i], "-N") == 0) { else if (strcmp(argv[i], "-N") == 0) {
networkTestFlag = TRUE; networkTestFlag = TRUE;
} }
#ifndef FILESYS_STUB #ifndef FILESYS_STUB
else if (strcmp(argv[i], "-cp") == 0) { else if (strcmp(argv[i], "-cp") == 0) {
ASSERT(i + 2 < argc); ASSERT(i + 2 < argc);
copyUnixFileName = argv[i + 1]; copyUnixFileName = argv[i + 1];
copyNachosFileName = argv[i + 2]; copyNachosFileName = argv[i + 2];
i += 2; i += 2;
} }
else if (strcmp(argv[i], "-p") == 0) { else if (strcmp(argv[i], "-p") == 0) {
ASSERT(i + 1 < argc); ASSERT(i + 1 < argc);
printFileName = argv[i + 1]; printFileName = argv[i + 1];
i++; i++;
} }
else if (strcmp(argv[i], "-r") == 0) { else if (strcmp(argv[i], "-r") == 0) {
ASSERT(i + 1 < argc); ASSERT(i + 1 < argc);
removeFileName = argv[i + 1]; removeFileName = argv[i + 1];
i++; i++;
} }
else if (strcmp(argv[i], "-l") == 0) { else if (strcmp(argv[i], "-l") == 0) {
dirListFlag = true; dirListFlag = true;
} }
else if (strcmp(argv[i], "-D") == 0) { else if (strcmp(argv[i], "-D") == 0) {
dumpFlag = true; dumpFlag = true;
} }
#endif //FILESYS_STUB #endif //FILESYS_STUB
else if (strcmp(argv[i], "-u") == 0) { else if (strcmp(argv[i], "-u") == 0) {
cout << "Partial usage: nachos [-z -d debugFlags]\n"; cout << "Partial usage: nachos [-z -d debugFlags]\n";
cout << "Partial usage: nachos [-x programName]\n"; cout << "Partial usage: nachos [-x programName]\n";
cout << "Partial usage: nachos [-K] [-C] [-N]\n"; cout << "Partial usage: nachos [-K] [-C] [-N]\n";
#ifndef FILESYS_STUB #ifndef FILESYS_STUB
cout << "Partial usage: nachos [-cp UnixFile NachosFile]\n"; cout << "Partial usage: nachos [-cp UnixFile NachosFile]\n";
cout << "Partial usage: nachos [-p fileName] [-r fileName]\n"; cout << "Partial usage: nachos [-p fileName] [-r fileName]\n";
cout << "Partial usage: nachos [-l] [-D]\n"; cout << "Partial usage: nachos [-l] [-D]\n";
#endif //FILESYS_STUB #endif //FILESYS_STUB
} }
} }
debug = new Debug(debugArg); debug = new Debug(debugArg);
@@ -256,36 +256,36 @@ main(int argc, char **argv)
// at this point, the kernel is ready to do something // at this point, the kernel is ready to do something
// run some tests, if requested // run some tests, if requested
if (threadTestFlag) { if (threadTestFlag) {
kernel->ThreadSelfTest(); // test threads and synchronization kernel->ThreadSelfTest(); // test threads and synchronization
} }
if (consoleTestFlag) { if (consoleTestFlag) {
kernel->ConsoleTest(); // interactive test of the synchronized console kernel->ConsoleTest(); // interactive test of the synchronized console
} }
if (networkTestFlag) { if (networkTestFlag) {
kernel->NetworkTest(); // two-machine test of the network kernel->NetworkTest(); // two-machine test of the network
} }
#ifndef FILESYS_STUB #ifndef FILESYS_STUB
if (removeFileName != NULL) { if (removeFileName != NULL) {
kernel->fileSystem->Remove(removeFileName); kernel->fileSystem->Remove(removeFileName);
} }
if (copyUnixFileName != NULL && copyNachosFileName != NULL) { if (copyUnixFileName != NULL && copyNachosFileName != NULL) {
Copy(copyUnixFileName,copyNachosFileName); Copy(copyUnixFileName, copyNachosFileName);
} }
if (dumpFlag) { if (dumpFlag) {
kernel->fileSystem->Print(); kernel->fileSystem->Print();
} }
if (dirListFlag) { if (dirListFlag) {
kernel->fileSystem->List(); kernel->fileSystem->List();
} }
if (printFileName != NULL) { if (printFileName != NULL) {
Print(printFileName); Print(printFileName);
} }
#endif // FILESYS_STUB #endif // FILESYS_STUB
// finally, run an initial user program if requested to do so // finally, run an initial user program if requested to do so
kernel->ExecAll(); kernel->ExecAll();
// If we don't run a user program, we may get here. // If we don't run a user program, we may get here.
// Calling "return" would terminate the program. // Calling "return" would terminate the program.
// Instead, call Halt, which will first clean up, then // Instead, call Halt, which will first clean up, then

View File

@@ -22,6 +22,7 @@
#include "debug.h" #include "debug.h"
#include "scheduler.h" #include "scheduler.h"
#include "main.h" #include "main.h"
#include <functional>
//---------------------------------------------------------------------- //----------------------------------------------------------------------
// Scheduler::Scheduler // Scheduler::Scheduler
@@ -29,10 +30,21 @@
// Initially, no ready threads. // Initially, no ready threads.
//---------------------------------------------------------------------- //----------------------------------------------------------------------
// Todo ----
int cmp(Thread *a, Thread *b)
{
int ap = a->getPriority();
int bp = b->getPriority();
return (ap < bp) - (ap > bp);
}
Scheduler::Scheduler() Scheduler::Scheduler()
{ {
readyList = new List<Thread *>; readyList = new SortedList(cmp);
toBeDestroyed = NULL; // ---------
toBeDestroyed = NULL;
} }
//---------------------------------------------------------------------- //----------------------------------------------------------------------
@@ -42,7 +54,7 @@ Scheduler::Scheduler()
Scheduler::~Scheduler() Scheduler::~Scheduler()
{ {
delete readyList; delete readyList;
} }
//---------------------------------------------------------------------- //----------------------------------------------------------------------
@@ -54,13 +66,15 @@ Scheduler::~Scheduler()
//---------------------------------------------------------------------- //----------------------------------------------------------------------
void void
Scheduler::ReadyToRun (Thread *thread) Scheduler::ReadyToRun(Thread* thread)
{ {
ASSERT(kernel->interrupt->getLevel() == IntOff); ASSERT(kernel->interrupt->getLevel() == IntOff);
DEBUG(dbgThread, "Putting thread on ready list: " << thread->getName()); DEBUG(dbgThread, "Putting thread on ready list: " << thread->getName());
//cout << "Putting thread on ready list: " << thread->getName() << endl ; //cout << "Putting thread on ready list: " << thread->getName() << endl ;
thread->setStatus(READY); thread->setStatus(READY);
readyList->Append(thread);
DEBUG(dbgSche, "[A] Tick [" << kernel->stats->totalTicks << "]: Process [" << thread->getName() << "] is inserted into queue.");
readyList->Insert(thread);
} }
//---------------------------------------------------------------------- //----------------------------------------------------------------------
@@ -71,14 +85,16 @@ Scheduler::ReadyToRun (Thread *thread)
// Thread is removed from the ready list. // Thread is removed from the ready list.
//---------------------------------------------------------------------- //----------------------------------------------------------------------
Thread * Thread*
Scheduler::FindNextToRun () Scheduler::FindNextToRun()
{ {
ASSERT(kernel->interrupt->getLevel() == IntOff); ASSERT(kernel->interrupt->getLevel() == IntOff);
if (readyList->IsEmpty()) { if (readyList->IsEmpty()) {
return NULL; return NULL;
} else { }
else {
DEBUG(dbgSche, "[B] Tick [" << kernel->stats->totalTicks << "]: Process [" << readyList->Front()->getName() << "] is removed from queue.");
return readyList->RemoveFront(); return readyList->RemoveFront();
} }
} }
@@ -101,9 +117,9 @@ Scheduler::FindNextToRun ()
//---------------------------------------------------------------------- //----------------------------------------------------------------------
void void
Scheduler::Run (Thread *nextThread, bool finishing) Scheduler::Run(Thread* nextThread, bool finishing)
{ {
Thread *oldThread = kernel->currentThread; Thread* oldThread = kernel->currentThread;
ASSERT(kernel->interrupt->getLevel() == IntOff); ASSERT(kernel->interrupt->getLevel() == IntOff);
@@ -124,6 +140,7 @@ Scheduler::Run (Thread *nextThread, bool finishing)
nextThread->setStatus(RUNNING); // nextThread is now running nextThread->setStatus(RUNNING); // nextThread is now running
DEBUG(dbgThread, "Switching from: " << oldThread->getName() << " to: " << nextThread->getName()); DEBUG(dbgThread, "Switching from: " << oldThread->getName() << " to: " << nextThread->getName());
DEBUG(dbgSche, "[C] Tick [" << kernel->stats->totalTicks << "]: Process [" << nextThread->getName() << "] is now selected for execution, thread [" << oldThread->getName() << "] is replaced.");
// This is a machine-dependent assembly language routine defined // This is a machine-dependent assembly language routine defined
// in switch.s. You may have to think // in switch.s. You may have to think
@@ -174,6 +191,6 @@ Scheduler::CheckToBeDestroyed()
void void
Scheduler::Print() Scheduler::Print()
{ {
cout << "Ready list contents:\n"; cout << "Ready list contents:\n";
readyList->Apply(ThreadPrint); readyList->Apply(ThreadPrint);
} }

View File

@@ -23,22 +23,25 @@ class Scheduler {
~Scheduler(); // De-allocate ready list ~Scheduler(); // De-allocate ready list
void ReadyToRun(Thread* thread); void ReadyToRun(Thread* thread);
// Thread can be dispatched. // Thread can be dispatched.
Thread* FindNextToRun(); // Dequeue first thread on the ready Thread* FindNextToRun(); // Dequeue first thread on the ready
// list, if any, and return thread. // list, if any, and return thread.
void Run(Thread* nextThread, bool finishing); void Run(Thread* nextThread, bool finishing);
// Cause nextThread to start running // Cause nextThread to start running
void CheckToBeDestroyed();// Check if thread that had been void CheckToBeDestroyed();// Check if thread that had been
// running needs to be deleted // running needs to be deleted
void Print(); // Print contents of ready list void Print(); // Print contents of ready list
// SelfTest for scheduler is implemented in class Thread // SelfTest for scheduler is implemented in class Thread
private: private:
List<Thread *> *readyList; // queue of threads that are ready to run, // Todo ----
// but not running SortedList<Thread *> *readyList; // queue of threads that are ready to run,
// but not running
// ---------
Thread *toBeDestroyed; // finishing thread to be destroyed Thread *toBeDestroyed; // finishing thread to be destroyed
// by the next thread that runs // by the next thread that runs
}; };
#endif // SCHEDULER_H #endif // SCHEDULER_H

View File

@@ -48,7 +48,7 @@ Semaphore::Semaphore(char* debugName, int initialValue)
{ {
name = debugName; name = debugName;
value = initialValue; value = initialValue;
queue = new List<Thread *>; queue = new List<Thread*>;
} }
//---------------------------------------------------------------------- //----------------------------------------------------------------------
@@ -75,20 +75,20 @@ Semaphore::~Semaphore()
void void
Semaphore::P() Semaphore::P()
{ {
Interrupt *interrupt = kernel->interrupt; Interrupt* interrupt = kernel->interrupt;
Thread *currentThread = kernel->currentThread; Thread* currentThread = kernel->currentThread;
// disable interrupts // disable interrupts
IntStatus oldLevel = interrupt->SetLevel(IntOff); IntStatus oldLevel = interrupt->SetLevel(IntOff);
while (value == 0) { // semaphore not available while (value == 0) { // semaphore not available
queue->Append(currentThread); // so go to sleep queue->Append(currentThread); // so go to sleep
currentThread->Sleep(FALSE); currentThread->Sleep(FALSE);
} }
value--; // semaphore available, consume its value value--; // semaphore available, consume its value
// re-enable interrupts // re-enable interrupts
(void) interrupt->SetLevel(oldLevel); (void)interrupt->SetLevel(oldLevel);
} }
//---------------------------------------------------------------------- //----------------------------------------------------------------------
@@ -102,18 +102,18 @@ Semaphore::P()
void void
Semaphore::V() Semaphore::V()
{ {
Interrupt *interrupt = kernel->interrupt; Interrupt* interrupt = kernel->interrupt;
// disable interrupts // disable interrupts
IntStatus oldLevel = interrupt->SetLevel(IntOff); IntStatus oldLevel = interrupt->SetLevel(IntOff);
if (!queue->IsEmpty()) { // make thread ready. if (!queue->IsEmpty()) { // make thread ready.
kernel->scheduler->ReadyToRun(queue->RemoveFront()); kernel->scheduler->ReadyToRun(queue->RemoveFront());
} }
value++; value++;
// re-enable interrupts // re-enable interrupts
(void) interrupt->SetLevel(oldLevel); (void)interrupt->SetLevel(oldLevel);
} }
//---------------------------------------------------------------------- //----------------------------------------------------------------------
@@ -122,27 +122,27 @@ Semaphore::V()
// to control two threads ping-ponging back and forth. // to control two threads ping-ponging back and forth.
//---------------------------------------------------------------------- //----------------------------------------------------------------------
static Semaphore *ping; static Semaphore* ping;
static void static void
SelfTestHelper (Semaphore *pong) SelfTestHelper(Semaphore* pong)
{ {
for (int i = 0; i < 10; i++) { for (int i = 0; i < 10; i++) {
ping->P(); ping->P();
pong->V(); pong->V();
} }
} }
void void
Semaphore::SelfTest() Semaphore::SelfTest()
{ {
Thread *helper = new Thread("ping", 1); Thread* helper = new Thread("ping", 1);
ASSERT(value == 0); // otherwise test won't work! ASSERT(value == 0); // otherwise test won't work!
ping = new Semaphore("ping", 0); ping = new Semaphore("ping", 0);
helper->Fork((VoidFunctionPtr) SelfTestHelper, this); helper->Fork((VoidFunctionPtr)SelfTestHelper, this);
for (int i = 0; i < 10; i++) { for (int i = 0; i < 10; i++) {
ping->V(); ping->V();
this->P(); this->P();
} }
delete ping; delete ping;
} }
@@ -213,7 +213,7 @@ void Lock::Release()
Condition::Condition(char* debugName) Condition::Condition(char* debugName)
{ {
name = debugName; name = debugName;
waitQueue = new List<Semaphore *>; waitQueue = new List<Semaphore*>;
} }
//---------------------------------------------------------------------- //----------------------------------------------------------------------
@@ -243,16 +243,16 @@ Condition::~Condition()
void Condition::Wait(Lock* conditionLock) void Condition::Wait(Lock* conditionLock)
{ {
Semaphore *waiter; Semaphore* waiter;
ASSERT(conditionLock->IsHeldByCurrentThread()); ASSERT(conditionLock->IsHeldByCurrentThread());
waiter = new Semaphore("condition", 0); waiter = new Semaphore("condition", 0);
waitQueue->Append(waiter); waitQueue->Append(waiter);
conditionLock->Release(); conditionLock->Release();
waiter->P(); waiter->P();
conditionLock->Acquire(); conditionLock->Acquire();
delete waiter; delete waiter;
} }
//---------------------------------------------------------------------- //----------------------------------------------------------------------
@@ -272,13 +272,13 @@ void Condition::Wait(Lock* conditionLock)
void Condition::Signal(Lock* conditionLock) void Condition::Signal(Lock* conditionLock)
{ {
Semaphore *waiter; Semaphore* waiter;
ASSERT(conditionLock->IsHeldByCurrentThread()); ASSERT(conditionLock->IsHeldByCurrentThread());
if (!waitQueue->IsEmpty()) { if (!waitQueue->IsEmpty()) {
waiter = waitQueue->RemoveFront(); waiter = waitQueue->RemoveFront();
waiter->V(); waiter->V();
} }
} }

View File

@@ -33,19 +33,20 @@ const int STACK_FENCEPOST = 0xdedbeef;
// "threadName" is an arbitrary string, useful for debugging. // "threadName" is an arbitrary string, useful for debugging.
//---------------------------------------------------------------------- //----------------------------------------------------------------------
Thread::Thread(char* threadName, int threadID) Thread::Thread(char *threadName, int threadID)
{ {
ID = threadID; ID = threadID;
name = threadName; name = threadName;
stackTop = NULL; stackTop = NULL;
stack = NULL; stack = NULL;
status = JUST_CREATED; status = JUST_CREATED;
for (int i = 0; i < MachineStateSize; i++) { for (int i = 0; i < MachineStateSize; i++)
machineState[i] = NULL; // not strictly necessary, since {
// new thread ignores contents machineState[i] = NULL; // not strictly necessary, since
// of machine registers // new thread ignores contents
} // of machine registers
space = NULL; }
space = NULL;
} }
//---------------------------------------------------------------------- //----------------------------------------------------------------------
@@ -62,10 +63,10 @@ Thread::Thread(char* threadName, int threadID)
Thread::~Thread() Thread::~Thread()
{ {
DEBUG(dbgThread, "Deleting thread: " << name); DEBUG(dbgThread, "Deleting thread: " << name);
ASSERT(this != kernel->currentThread); ASSERT(this != kernel->currentThread);
if (stack != NULL) if (stack != NULL)
DeallocBoundedArray((char *) stack, StackSize * sizeof(int)); DeallocBoundedArray((char *)stack, StackSize * sizeof(int));
} }
//---------------------------------------------------------------------- //----------------------------------------------------------------------
@@ -88,20 +89,19 @@ Thread::~Thread()
// "arg" is a single argument to be passed to the procedure. // "arg" is a single argument to be passed to the procedure.
//---------------------------------------------------------------------- //----------------------------------------------------------------------
void void Thread::Fork(VoidFunctionPtr func, void *arg)
Thread::Fork(VoidFunctionPtr func, void *arg)
{ {
Interrupt *interrupt = kernel->interrupt; Interrupt *interrupt = kernel->interrupt;
Scheduler *scheduler = kernel->scheduler; Scheduler *scheduler = kernel->scheduler;
IntStatus oldLevel; IntStatus oldLevel;
DEBUG(dbgThread, "Forking thread: " << name << " f(a): " << (int) func << " " << arg); DEBUG(dbgThread, "Forking thread: " << name << " f(a): " << (int)func << " " << arg);
StackAllocate(func, arg); StackAllocate(func, arg);
oldLevel = interrupt->SetLevel(IntOff); oldLevel = interrupt->SetLevel(IntOff);
scheduler->ReadyToRun(this); // ReadyToRun assumes that interrupts scheduler->ReadyToRun(this); // ReadyToRun assumes that interrupts
// are disabled! // are disabled!
(void) interrupt->SetLevel(oldLevel); (void)interrupt->SetLevel(oldLevel);
} }
//---------------------------------------------------------------------- //----------------------------------------------------------------------
@@ -119,16 +119,16 @@ Thread::Fork(VoidFunctionPtr func, void *arg)
// Don't do this: void foo() { int bigArray[10000]; ... } // Don't do this: void foo() { int bigArray[10000]; ... }
//---------------------------------------------------------------------- //----------------------------------------------------------------------
void void Thread::CheckOverflow()
Thread::CheckOverflow()
{ {
if (stack != NULL) { if (stack != NULL)
#ifdef HPUX // Stacks grow upward on the Snakes {
ASSERT(stack[StackSize - 1] == STACK_FENCEPOST); #ifdef HPUX // Stacks grow upward on the Snakes
ASSERT(stack[StackSize - 1] == STACK_FENCEPOST);
#else #else
ASSERT(*stack == STACK_FENCEPOST); ASSERT(*stack == STACK_FENCEPOST);
#endif #endif
} }
} }
//---------------------------------------------------------------------- //----------------------------------------------------------------------
@@ -142,8 +142,7 @@ Thread::CheckOverflow()
// 2. enable interrupts (so we can get time-sliced) // 2. enable interrupts (so we can get time-sliced)
//---------------------------------------------------------------------- //----------------------------------------------------------------------
void void Thread::Begin()
Thread::Begin ()
{ {
ASSERT(this == kernel->currentThread); ASSERT(this == kernel->currentThread);
DEBUG(dbgThread, "Beginning thread: " << name); DEBUG(dbgThread, "Beginning thread: " << name);
@@ -167,18 +166,16 @@ Thread::Begin ()
//---------------------------------------------------------------------- //----------------------------------------------------------------------
// //
void void Thread::Finish()
Thread::Finish ()
{ {
(void) kernel->interrupt->SetLevel(IntOff); (void)kernel->interrupt->SetLevel(IntOff);
ASSERT(this == kernel->currentThread); ASSERT(this == kernel->currentThread);
DEBUG(dbgThread, "Finishing thread: " << name); DEBUG(dbgThread, "Finishing thread: " << name);
Sleep(TRUE); // invokes SWITCH Sleep(TRUE); // invokes SWITCH
// not reached // not reached
} }
//---------------------------------------------------------------------- //----------------------------------------------------------------------
// Thread::Yield // Thread::Yield
// Relinquish the CPU if any other thread is ready to run. // Relinquish the CPU if any other thread is ready to run.
@@ -197,22 +194,22 @@ Thread::Finish ()
// Similar to Thread::Sleep(), but a little different. // Similar to Thread::Sleep(), but a little different.
//---------------------------------------------------------------------- //----------------------------------------------------------------------
void void Thread::Yield()
Thread::Yield ()
{ {
Thread *nextThread; Thread *nextThread;
IntStatus oldLevel = kernel->interrupt->SetLevel(IntOff); IntStatus oldLevel = kernel->interrupt->SetLevel(IntOff);
ASSERT(this == kernel->currentThread); ASSERT(this == kernel->currentThread);
DEBUG(dbgThread, "Yielding thread: " << name); DEBUG(dbgThread, "Yielding thread: " << name);
nextThread = kernel->scheduler->FindNextToRun(); nextThread = kernel->scheduler->FindNextToRun();
if (nextThread != NULL) { if (nextThread != NULL)
kernel->scheduler->ReadyToRun(this); {
kernel->scheduler->Run(nextThread, FALSE); kernel->scheduler->ReadyToRun(this);
} kernel->scheduler->Run(nextThread, FALSE);
(void) kernel->interrupt->SetLevel(oldLevel); }
(void)kernel->interrupt->SetLevel(oldLevel);
} }
//---------------------------------------------------------------------- //----------------------------------------------------------------------
@@ -235,23 +232,23 @@ Thread::Yield ()
// so that there can't be a time slice between pulling the first thread // so that there can't be a time slice between pulling the first thread
// off the ready list, and switching to it. // off the ready list, and switching to it.
//---------------------------------------------------------------------- //----------------------------------------------------------------------
void void Thread::Sleep(bool finishing)
Thread::Sleep (bool finishing)
{ {
Thread *nextThread; Thread *nextThread;
ASSERT(this == kernel->currentThread); ASSERT(this == kernel->currentThread);
ASSERT(kernel->interrupt->getLevel() == IntOff); ASSERT(kernel->interrupt->getLevel() == IntOff);
DEBUG(dbgThread, "Sleeping thread: " << name); DEBUG(dbgThread, "Sleeping thread: " << name);
status = BLOCKED; status = BLOCKED;
//cout << "debug Thread::Sleep " << name << "wait for Idle\n"; // cout << "debug Thread::Sleep " << name << "wait for Idle\n";
while ((nextThread = kernel->scheduler->FindNextToRun()) == NULL) { while ((nextThread = kernel->scheduler->FindNextToRun()) == NULL)
kernel->interrupt->Idle(); // no one to run, wait for an interrupt {
} kernel->interrupt->Idle(); // no one to run, wait for an interrupt
// returns when it's time for us to run }
kernel->scheduler->Run(nextThread, finishing); // returns when it's time for us to run
kernel->scheduler->Run(nextThread, finishing);
} }
//---------------------------------------------------------------------- //----------------------------------------------------------------------
@@ -277,16 +274,19 @@ void ThreadPrint(Thread *t) { t->Print(); }
static void * static void *
PLabelToAddr(void *plabel) PLabelToAddr(void *plabel)
{ {
int funcPtr = (int) plabel; int funcPtr = (int)plabel;
if (funcPtr & 0x02) { if (funcPtr & 0x02)
// L-Field is set. This is a PLT pointer {
funcPtr -= 2; // Get rid of the L bit // L-Field is set. This is a PLT pointer
return (*(void **)funcPtr); funcPtr -= 2; // Get rid of the L bit
} else { return (*(void **)funcPtr);
// L-field not set. }
return plabel; else
} {
// L-field not set.
return plabel;
}
} }
#endif #endif
@@ -302,62 +302,60 @@ PLabelToAddr(void *plabel)
// "arg" is the parameter to be passed to the procedure // "arg" is the parameter to be passed to the procedure
//---------------------------------------------------------------------- //----------------------------------------------------------------------
void void Thread::StackAllocate(VoidFunctionPtr func, void *arg)
Thread::StackAllocate (VoidFunctionPtr func, void *arg)
{ {
stack = (int *) AllocBoundedArray(StackSize * sizeof(int)); stack = (int *)AllocBoundedArray(StackSize * sizeof(int));
#ifdef PARISC #ifdef PARISC
// HP stack works from low addresses to high addresses // HP stack works from low addresses to high addresses
// everyone else works the other way: from high addresses to low addresses // everyone else works the other way: from high addresses to low addresses
stackTop = stack + 16; // HP requires 64-byte frame marker stackTop = stack + 16; // HP requires 64-byte frame marker
stack[StackSize - 1] = STACK_FENCEPOST; stack[StackSize - 1] = STACK_FENCEPOST;
#endif #endif
#ifdef SPARC #ifdef SPARC
stackTop = stack + StackSize - 96; // SPARC stack must contains at stackTop = stack + StackSize - 96; // SPARC stack must contains at
// least 1 activation record // least 1 activation record
// to start with. // to start with.
*stack = STACK_FENCEPOST; *stack = STACK_FENCEPOST;
#endif #endif
#ifdef PowerPC // RS6000 #ifdef PowerPC // RS6000
stackTop = stack + StackSize - 16; // RS6000 requires 64-byte frame marker stackTop = stack + StackSize - 16; // RS6000 requires 64-byte frame marker
*stack = STACK_FENCEPOST; *stack = STACK_FENCEPOST;
#endif #endif
#ifdef DECMIPS #ifdef DECMIPS
stackTop = stack + StackSize - 4; // -4 to be on the safe side! stackTop = stack + StackSize - 4; // -4 to be on the safe side!
*stack = STACK_FENCEPOST; *stack = STACK_FENCEPOST;
#endif #endif
#ifdef ALPHA #ifdef ALPHA
stackTop = stack + StackSize - 8; // -8 to be on the safe side! stackTop = stack + StackSize - 8; // -8 to be on the safe side!
*stack = STACK_FENCEPOST; *stack = STACK_FENCEPOST;
#endif #endif
#ifdef x86 #ifdef x86
// the x86 passes the return address on the stack. In order for SWITCH() // the x86 passes the return address on the stack. In order for SWITCH()
// to go to ThreadRoot when we switch to this thread, the return addres // to go to ThreadRoot when we switch to this thread, the return addres
// used in SWITCH() must be the starting address of ThreadRoot. // used in SWITCH() must be the starting address of ThreadRoot.
stackTop = stack + StackSize - 4; // -4 to be on the safe side! stackTop = stack + StackSize - 4; // -4 to be on the safe side!
*(--stackTop) = (int) ThreadRoot; *(--stackTop) = (int)ThreadRoot;
*stack = STACK_FENCEPOST; *stack = STACK_FENCEPOST;
#endif #endif
#ifdef PARISC #ifdef PARISC
machineState[PCState] = PLabelToAddr(ThreadRoot); machineState[PCState] = PLabelToAddr(ThreadRoot);
machineState[StartupPCState] = PLabelToAddr(ThreadBegin); machineState[StartupPCState] = PLabelToAddr(ThreadBegin);
machineState[InitialPCState] = PLabelToAddr(func); machineState[InitialPCState] = PLabelToAddr(func);
machineState[InitialArgState] = arg; machineState[InitialArgState] = arg;
machineState[WhenDonePCState] = PLabelToAddr(ThreadFinish); machineState[WhenDonePCState] = PLabelToAddr(ThreadFinish);
#else #else
machineState[PCState] = (void*)ThreadRoot; machineState[PCState] = (void *)ThreadRoot;
machineState[StartupPCState] = (void*)ThreadBegin; machineState[StartupPCState] = (void *)ThreadBegin;
machineState[InitialPCState] = (void*)func; machineState[InitialPCState] = (void *)func;
machineState[InitialArgState] = (void*)arg; machineState[InitialArgState] = (void *)arg;
machineState[WhenDonePCState] = (void*)ThreadFinish; machineState[WhenDonePCState] = (void *)ThreadFinish;
#endif #endif
} }
@@ -372,11 +370,10 @@ Thread::StackAllocate (VoidFunctionPtr func, void *arg)
// while executing kernel code. This routine saves the former. // while executing kernel code. This routine saves the former.
//---------------------------------------------------------------------- //----------------------------------------------------------------------
void void Thread::SaveUserState()
Thread::SaveUserState()
{ {
for (int i = 0; i < NumTotalRegs; i++) for (int i = 0; i < NumTotalRegs; i++)
userRegisters[i] = kernel->machine->ReadRegister(i); userRegisters[i] = kernel->machine->ReadRegister(i);
} }
//---------------------------------------------------------------------- //----------------------------------------------------------------------
@@ -388,14 +385,12 @@ Thread::SaveUserState()
// while executing kernel code. This routine restores the former. // while executing kernel code. This routine restores the former.
//---------------------------------------------------------------------- //----------------------------------------------------------------------
void void Thread::RestoreUserState()
Thread::RestoreUserState()
{ {
for (int i = 0; i < NumTotalRegs; i++) for (int i = 0; i < NumTotalRegs; i++)
kernel->machine->WriteRegister(i, userRegisters[i]); kernel->machine->WriteRegister(i, userRegisters[i]);
} }
//---------------------------------------------------------------------- //----------------------------------------------------------------------
// SimpleThread // SimpleThread
// Loop 5 times, yielding the CPU to another ready thread // Loop 5 times, yielding the CPU to another ready thread
@@ -410,8 +405,9 @@ SimpleThread(int which)
{ {
int num; int num;
for (num = 0; num < 5; num++) { for (num = 0; num < 5; num++)
cout << "*** thread " << which << " looped " << num << " times\n"; {
cout << "*** thread " << which << " looped " << num << " times\n";
kernel->currentThread->Yield(); kernel->currentThread->Yield();
} }
} }
@@ -422,14 +418,26 @@ SimpleThread(int which)
// to call SimpleThread, and then calling SimpleThread ourselves. // to call SimpleThread, and then calling SimpleThread ourselves.
//---------------------------------------------------------------------- //----------------------------------------------------------------------
void void Thread::SelfTest()
Thread::SelfTest()
{ {
DEBUG(dbgThread, "Entering Thread::SelfTest"); DEBUG(dbgThread, "Entering Thread::SelfTest");
Thread *t = new Thread("forked thread", 1); Thread *t = new Thread("forked thread", 1);
t->Fork((VoidFunctionPtr) SimpleThread, (void *) 1); t->Fork((VoidFunctionPtr)SimpleThread, (void *)1);
kernel->currentThread->Yield(); kernel->currentThread->Yield();
SimpleThread(0); SimpleThread(0);
} }
// Todo ----
int Thread::getPriority() const
{
return priority;
}
void Thread::setPriority(int p)
{
ASSERT(p >= 0 && p <= 149);
priority = p;
}
// ---------

View File

@@ -80,6 +80,10 @@ class Thread {
int *stackTop; // the current stack pointer int *stackTop; // the current stack pointer
void *machineState[MachineStateSize]; // all registers except for stackTop void *machineState[MachineStateSize]; // all registers except for stackTop
// Todo ----
int priority;
// ---------
public: public:
Thread(char* debugName, int threadID); // initialize a Thread Thread(char* debugName, int threadID); // initialize a Thread
~Thread(); // deallocate a Thread ~Thread(); // deallocate a Thread
@@ -89,6 +93,11 @@ class Thread {
// basic thread operations // basic thread operations
// Todo ----
int getPriority() const;
void setPriority(int p);
// ---------
void Fork(VoidFunctionPtr func, void *arg); void Fork(VoidFunctionPtr func, void *arg);
// Make thread run (*func)(arg) // Make thread run (*func)(arg)
void Yield(); // Relinquish the CPU if any void Yield(); // Relinquish the CPU if any
@@ -101,9 +110,9 @@ class Thread {
void CheckOverflow(); // Check if thread stack has overflowed void CheckOverflow(); // Check if thread stack has overflowed
void setStatus(ThreadStatus st) { status = st; } void setStatus(ThreadStatus st) { status = st; }
ThreadStatus getStatus() { return (status); } ThreadStatus getStatus() { return (status); }
char* getName() { return (name); } char* getName() { return (name); }
int getID() { return (ID); } int getID() { return (ID); }
void Print() { cout << name; } void Print() { cout << name; }
void SelfTest(); // test whether thread impl is working void SelfTest(); // test whether thread impl is working
@@ -111,18 +120,18 @@ class Thread {
// some of the private data for this class is listed above // some of the private data for this class is listed above
int *stack; // Bottom of the stack int *stack; // Bottom of the stack
// NULL if this is the main thread // NULL if this is the main thread
// (If NULL, don't deallocate stack) // (If NULL, don't deallocate stack)
ThreadStatus status; // ready, running or blocked ThreadStatus status; // ready, running or blocked
char* name; char* name;
int ID; int ID;
void StackAllocate(VoidFunctionPtr func, void *arg); void StackAllocate(VoidFunctionPtr func, void *arg);
// Allocate a stack for thread. // Allocate a stack for thread.
// Used internally by Fork() // Used internally by Fork()
// A thread running a user program actually has *two* sets of CPU registers -- // A thread running a user program actually has *two* sets of CPU registers --
// one for its state while executing user code, one for its state // one for its state while executing user code, one for its state
// while executing kernel code. // while executing kernel code.
int userRegisters[NumTotalRegs]; // user-level CPU register state int userRegisters[NumTotalRegs]; // user-level CPU register state

View File

@@ -27,101 +27,35 @@
// object file header, in case the file was generated on a little // object file header, in case the file was generated on a little
// endian machine, and we're now running on a big endian machine. // endian machine, and we're now running on a big endian machine.
//---------------------------------------------------------------------- //----------------------------------------------------------------------
static void static void
SwapHeader (NoffHeader *noffH) SwapHeader(NoffHeader* noffH)
{ {
noffH->noffMagic = WordToHost(noffH->noffMagic); noffH->noffMagic = WordToHost(noffH->noffMagic);
noffH->code.size = WordToHost(noffH->code.size); noffH->code.size = WordToHost(noffH->code.size);
noffH->code.virtualAddr = WordToHost(noffH->code.virtualAddr); noffH->code.virtualAddr = WordToHost(noffH->code.virtualAddr);
noffH->code.inFileAddr = WordToHost(noffH->code.inFileAddr); noffH->code.inFileAddr = WordToHost(noffH->code.inFileAddr);
#ifdef RDATA #ifdef RDATA
noffH->readonlyData.size = WordToHost(noffH->readonlyData.size); noffH->readonlyData.size = WordToHost(noffH->readonlyData.size);
noffH->readonlyData.virtualAddr = noffH->readonlyData.virtualAddr =
WordToHost(noffH->readonlyData.virtualAddr); WordToHost(noffH->readonlyData.virtualAddr);
noffH->readonlyData.inFileAddr = noffH->readonlyData.inFileAddr =
WordToHost(noffH->readonlyData.inFileAddr); WordToHost(noffH->readonlyData.inFileAddr);
#endif #endif
noffH->initData.size = WordToHost(noffH->initData.size); noffH->initData.size = WordToHost(noffH->initData.size);
noffH->initData.virtualAddr = WordToHost(noffH->initData.virtualAddr); noffH->initData.virtualAddr = WordToHost(noffH->initData.virtualAddr);
noffH->initData.inFileAddr = WordToHost(noffH->initData.inFileAddr); noffH->initData.inFileAddr = WordToHost(noffH->initData.inFileAddr);
noffH->uninitData.size = WordToHost(noffH->uninitData.size); noffH->uninitData.size = WordToHost(noffH->uninitData.size);
noffH->uninitData.virtualAddr = WordToHost(noffH->uninitData.virtualAddr); noffH->uninitData.virtualAddr = WordToHost(noffH->uninitData.virtualAddr);
noffH->uninitData.inFileAddr = WordToHost(noffH->uninitData.inFileAddr); noffH->uninitData.inFileAddr = WordToHost(noffH->uninitData.inFileAddr);
#ifdef RDATA #ifdef RDATA
DEBUG(dbgAddr, "code = " << noffH->code.size << DEBUG(dbgAddr, "code = " << noffH->code.size <<
" readonly = " << noffH->readonlyData.size << " readonly = " << noffH->readonlyData.size <<
" init = " << noffH->initData.size << " init = " << noffH->initData.size <<
" uninit = " << noffH->uninitData.size << "\n"); " uninit = " << noffH->uninitData.size << "\n");
#endif #endif
} }
FrameTable::Node::Node(int idx):
next(nullptr), idx(idx) {}
FrameTable::FrameTable()
{
available = NumPhysPages;
useCount = new int[NumPhysPages];
begin = end = new FrameTable::Node;
for (int i = 0; i < NumPhysPages; i++) {
useCount[i] = 0;
end->idx = i;
end->next = new FrameTable::Node;
end = end->next;
}
}
FrameTable::~FrameTable()
{
delete[] useCount;
while (begin != end) {
FrameTable::Node *tmpNode = begin;
begin = begin->next;
delete tmpNode;
}
delete begin;
}
int FrameTable::Allocate()
{
if (available == 0)
return -1;
int ret = begin->idx;
Node *tmp = begin;
begin = begin->next;
delete tmp;
--available;
useCount[ret]++;
bzero(kernel->machine->mainMemory + ret * PageSize, PageSize);
//cerr << "Allocated at page: " << ret << endl;
return ret;
}
void FrameTable::Release(int phyPageNum)
{
useCount[phyPageNum]--;
if (useCount[phyPageNum] > 0)
return;
++available;
//cerr << "Release page: " << end->idx << endl;
end->idx = phyPageNum;
end->next = new FrameTable::Node;
}
size_t FrameTable::RemainSize()
{
return available;
}
//---------------------------------------------------------------------- //----------------------------------------------------------------------
// AddrSpace::AddrSpace // AddrSpace::AddrSpace
// Create an address space to run a user program. // Create an address space to run a user program.
@@ -129,9 +63,24 @@ size_t FrameTable::RemainSize()
// memory. For now, this is really simple (1:1), since we are // memory. For now, this is really simple (1:1), since we are
// only uniprogramming, and we have a single unsegmented page table // only uniprogramming, and we have a single unsegmented page table
//---------------------------------------------------------------------- //----------------------------------------------------------------------
AddrSpace::AddrSpace() AddrSpace::AddrSpace()
{} {
pageTable = NULL; // initialize with NULL
/*
pageTable = new TranslationEntry[NumPhysPages];
for (int i = 0; i < NumPhysPages; i++) {
pageTable[i].virtualPage = i; // for now, virt page # = phys page #
pageTable[i].physicalPage = i;
pageTable[i].valid = TRUE;
pageTable[i].use = FALSE;
pageTable[i].dirty = FALSE;
pageTable[i].readOnly = FALSE;
}
// zero out the entire address space
bzero(kernel->machine->mainMemory, MemorySize);
*/
}
//---------------------------------------------------------------------- //----------------------------------------------------------------------
// AddrSpace::~AddrSpace // AddrSpace::~AddrSpace
@@ -140,10 +89,9 @@ AddrSpace::AddrSpace()
AddrSpace::~AddrSpace() AddrSpace::~AddrSpace()
{ {
for (int i = 0; i < NumPhysPages; i++) /* delete pageTable; */
if (pageTable[i].use == TRUE) // release frame table by page table
kernel->frameTable->Release(pageTable[i].physicalPage); kernel->frameTable->Release(pageTable, numPages);
delete[] pageTable;
} }
@@ -156,114 +104,140 @@ AddrSpace::~AddrSpace()
// //
// "fileName" is the file containing the object code to load into memory // "fileName" is the file containing the object code to load into memory
//---------------------------------------------------------------------- //----------------------------------------------------------------------
bool bool
AddrSpace::Load(char *fileName) AddrSpace::Load(char* fileName)
{ {
//cerr << "AddrSpace::Load" << endl; OpenFile* executable = kernel->fileSystem->Open(fileName);
OpenFile *executable = kernel->fileSystem->Open(fileName); NoffHeader noffH;
NoffHeader noffH; unsigned int size;
unsigned int size;
if (executable == NULL) { if (executable == NULL) {
cerr << "Unable to open file " << fileName << "\n"; cerr << "Unable to open file " << fileName << "\n";
return FALSE; return FALSE;
} }
executable->ReadAt((char *)&noffH, sizeof(noffH), 0); executable->ReadAt((char*)&noffH, sizeof(noffH), 0);
if ((noffH.noffMagic != NOFFMAGIC) && if ((noffH.noffMagic != NOFFMAGIC) &&
(WordToHost(noffH.noffMagic) == NOFFMAGIC)) (WordToHost(noffH.noffMagic) == NOFFMAGIC))
SwapHeader(&noffH); SwapHeader(&noffH);
ASSERT(noffH.noffMagic == NOFFMAGIC); ASSERT(noffH.noffMagic == NOFFMAGIC);
#ifdef RDATA #ifdef RDATA
// how big is address space? // how big is address space?
size = noffH.code.size + noffH.readonlyData.size + noffH.initData.size + size = noffH.code.size + noffH.readonlyData.size + noffH.initData.size +
noffH.uninitData.size + UserStackSize; noffH.uninitData.size + UserStackSize;
//cerr << noffH.code.size << ' ' // we need to increase the size
// << noffH.readonlyData.size << ' ' // to leave room for the stack
// << noffH.initData.size << ' '
// << noffH.uninitData.size << ' '
// << UserStackSize << endl;
// we need to increase the size
// to leave room for the stack
#else #else
// how big is address space? // how big is address space?
size = noffH.code.size + noffH.initData.size + noffH.uninitData.size size = noffH.code.size + noffH.initData.size + noffH.uninitData.size
+ UserStackSize; // we need to increase the size + UserStackSize; // we need to increase the size
// to leave room for the stack // to leave room for the stack
//cerr << noffH.code.size << ' '
// << noffH.initData.size << ' '
// << noffH.uninitData.size << ' '
// << UserStackSize << endl;
#endif #endif
numPages = divRoundUp(size, PageSize); numPages = divRoundUp(size, PageSize);
size = numPages * PageSize; size = numPages * PageSize;
ASSERT(numPages <= NumPhysPages); // check we're not trying pageTable = kernel->frameTable->Allocate(numPages);
// to run anything too big -- if (!pageTable) {
// at least until we have kernel->interrupt->setStatus(SystemMode);
// virtual memory ExceptionHandler(MemoryLimitException);
kernel->interrupt->setStatus(UserMode);
pageTable = new TranslationEntry[numPages];
for (int i = 0; i < numPages; i++) {
pageTable[i].virtualPage = i;
pageTable[i].physicalPage = -1;
pageTable[i].valid = TRUE;
pageTable[i].use = FALSE;
pageTable[i].dirty = FALSE;
pageTable[i].readOnly = FALSE;
}
DEBUG(dbgAddr, "Initializing address space: " << numPages << ", " << size);
// then, copy in the code and data segments into memory
if (noffH.code.size > 0) {
DEBUG(dbgAddr, "Initializing code segment.");
DEBUG(dbgAddr, noffH.code.virtualAddr << ", " << noffH.code.size);
for (size_t cur = 0; cur < (size_t)noffH.code.size; cur += PageSize) {
size_t physAddr, size = min((size_t)PageSize, noffH.code.size - cur);
Translate(noffH.code.virtualAddr + cur, &physAddr, 1);
//cerr << "physAddr, size: " << physAddr << ' ' << size << endl;
executable->ReadAt(
&(kernel->machine->mainMemory[physAddr]), size,
noffH.code.inFileAddr + cur);
} }
}
if (noffH.initData.size > 0) {
DEBUG(dbgAddr, "Initializing data segment.");
DEBUG(dbgAddr, noffH.initData.virtualAddr << ", " << noffH.initData.size);
for (size_t cur = 0; cur < (size_t)noffH.initData.size; cur += PageSize) { DEBUG(dbgAddr, "Initializing address space: " << numPages << ", " << size);
size_t physAddr, size = min((size_t)PageSize, noffH.initData.size - cur);
Translate(noffH.initData.virtualAddr + cur, &physAddr, 1);
executable->ReadAt( // then, copy in the code and data segments into memory
&(kernel->machine->mainMemory[physAddr]), size, uint paddr; // physical address
noffH.initData.inFileAddr + cur); ExceptionType ex; // occurring exception
int sz, // total size to load
vaddr, // base virtual address
fpos, // base file position
to_load; // size to load on each time
if (noffH.code.size > 0) {
DEBUG(dbgAddr, "Initializing code segment.");
DEBUG(dbgAddr, noffH.code.virtualAddr << ", " << noffH.code.size);
sz = noffH.code.size;
vaddr = noffH.code.virtualAddr;
fpos = noffH.code.inFileAddr;
for (uint offset = 0; offset < sz; offset += PageSize) {
ex = Translate(vaddr + offset, &paddr, 1);
if (ex != NoException) {
kernel->interrupt->setStatus(SystemMode);
ExceptionHandler(ex);
kernel->interrupt->setStatus(UserMode);
}
to_load = offset + PageSize < sz ? PageSize : sz - offset;
executable->ReadAt(
&(kernel->machine->mainMemory[paddr]),
to_load, fpos + offset);
}
}
if (noffH.initData.size > 0) {
DEBUG(dbgAddr, "Initializing data segment.");
DEBUG(dbgAddr, noffH.initData.virtualAddr << ", " << noffH.initData.size);
sz = noffH.initData.size;
vaddr = noffH.initData.virtualAddr;
fpos = noffH.initData.inFileAddr;
for (uint offset = 0; offset < sz; offset += PageSize) {
ex = Translate(vaddr + offset, &paddr, 1);
if (ex != NoException) {
kernel->interrupt->setStatus(SystemMode);
ExceptionHandler(ex);
kernel->interrupt->setStatus(UserMode);
}
to_load = offset + PageSize < sz ? PageSize : sz - offset;
executable->ReadAt(
&(kernel->machine->mainMemory[paddr]),
to_load, fpos + offset);
}
} }
}
#ifdef RDATA #ifdef RDATA
if (noffH.readonlyData.size > 0) { if (noffH.readonlyData.size > 0) {
DEBUG(dbgAddr, "Initializing read only data segment."); DEBUG(dbgAddr, "Initializing read only data segment.");
DEBUG(dbgAddr, noffH.readonlyData.virtualAddr << ", " << noffH.readonlyData.size); DEBUG(dbgAddr, noffH.readonlyData.virtualAddr << ", " << noffH.readonlyData.size);
for (size_t cur = 0; cur < (size_t)noffH.readonlyData.size; cur += PageSize) { sz = noffH.readonlyData.size;
size_t physAddr, size = min((size_t)PageSize, noffH.readonlyData.size - cur); vaddr = noffH.readonlyData.virtualAddr;
Translate(noffH.readonlyData.virtualAddr + cur, &physAddr, 1); fpos = noffH.readonlyData.inFileAddr;
executable->ReadAt( // read only flag for page table
&(kernel->machine->mainMemory[physAddr]), for (int i = 0, lim = divRoundUp(sz, PageSize),
size, noffH.readonlyData.inFileAddr + cur); from = vaddr / PageSize; i < lim; ++i)
pageTable[from + i].readOnly = TRUE;
for (uint offset = 0; offset < sz; offset += PageSize) {
ex = Translate(vaddr + offset, &paddr, 0); // read only
if (ex != NoException) {
kernel->interrupt->setStatus(SystemMode);
ExceptionHandler(ex);
kernel->interrupt->setStatus(UserMode);
}
to_load = offset + PageSize < sz ? PageSize : sz - offset;
executable->ReadAt(
&(kernel->machine->mainMemory[paddr]),
to_load, fpos + offset);
}
} }
}
#endif #endif
delete executable; // close file delete executable; // close file
return TRUE; // success return TRUE; // success
} }
//---------------------------------------------------------------------- //----------------------------------------------------------------------
@@ -274,21 +248,20 @@ AddrSpace::Load(char *fileName)
// the address space // the address space
// //
//---------------------------------------------------------------------- //----------------------------------------------------------------------
void void
AddrSpace::Execute(char* fileName) AddrSpace::Execute(char* fileName)
{ {
//cerr << "AddrSpace::Execute" << endl;
kernel->currentThread->space = this;
this->InitRegisters(); // set the initial register values kernel->currentThread->space = this;
this->RestoreState(); // load page table register
kernel->machine->Run(); // jump to the user progam this->InitRegisters(); // set the initial register values
this->RestoreState(); // load page table register
ASSERTNOTREACHED(); // machine->Run never returns; kernel->machine->Run(); // jump to the user program
// the address space exits
// by doing the syscall "exit" ASSERTNOTREACHED(); // machine->Run never returns;
// the address space exits
// by doing the syscall "exit"
} }
@@ -301,31 +274,30 @@ AddrSpace::Execute(char* fileName)
// will be saved/restored into the currentThread->userRegisters // will be saved/restored into the currentThread->userRegisters
// when this thread is context switched out. // when this thread is context switched out.
//---------------------------------------------------------------------- //----------------------------------------------------------------------
void void
AddrSpace::InitRegisters() AddrSpace::InitRegisters()
{ {
Machine *machine = kernel->machine; Machine* machine = kernel->machine;
int i; int i;
for (i = 0; i < NumTotalRegs; i++) for (i = 0; i < NumTotalRegs; i++)
machine->WriteRegister(i, 0); machine->WriteRegister(i, 0);
// Initial program counter -- must be location of "Start", which // Initial program counter -- must be location of "Start", which
// is assumed to be virtual address zero // is assumed to be virtual address zero
machine->WriteRegister(PCReg, 0); machine->WriteRegister(PCReg, 0);
// Need to also tell MIPS where next instruction is, because // Need to also tell MIPS where next instruction is, because
// of branch delay possibility // of branch delay possibility
// Since instructions occupy four bytes each, the next instruction // Since instructions occupy four bytes each, the next instruction
// after start will be at virtual address four. // after start will be at virtual address four.
machine->WriteRegister(NextPCReg, 4); machine->WriteRegister(NextPCReg, 4);
// Set the stack register to the end of the address space, where we // Set the stack register to the end of the address space, where we
// allocated the stack; but subtract off a bit, to make sure we don't // allocated the stack; but subtract off a bit, to make sure we don't
// accidentally reference off the end! // accidentally reference off the end!
machine->WriteRegister(StackReg, numPages * PageSize - 16); machine->WriteRegister(StackReg, numPages * PageSize - 16);
DEBUG(dbgAddr, "Initializing stack pointer: " << numPages * PageSize - 16); DEBUG(dbgAddr, "Initializing stack pointer: " << numPages * PageSize - 16);
} }
//---------------------------------------------------------------------- //----------------------------------------------------------------------
@@ -335,9 +307,9 @@ AddrSpace::InitRegisters()
// //
// For now, don't need to save anything! // For now, don't need to save anything!
//---------------------------------------------------------------------- //----------------------------------------------------------------------
void AddrSpace::SaveState() void AddrSpace::SaveState()
{} {
}
//---------------------------------------------------------------------- //----------------------------------------------------------------------
// AddrSpace::RestoreState // AddrSpace::RestoreState
@@ -346,11 +318,10 @@ void AddrSpace::SaveState()
// //
// For now, tell the machine where to find the page table. // For now, tell the machine where to find the page table.
//---------------------------------------------------------------------- //----------------------------------------------------------------------
void AddrSpace::RestoreState() void AddrSpace::RestoreState()
{ {
kernel->machine->pageTable = pageTable; kernel->machine->pageTable = pageTable;
kernel->machine->pageTableSize = numPages; kernel->machine->pageTableSize = numPages;
} }
@@ -363,50 +334,84 @@ void AddrSpace::RestoreState()
// Return any exceptions caused by the address translation. // Return any exceptions caused by the address translation.
//---------------------------------------------------------------------- //----------------------------------------------------------------------
ExceptionType ExceptionType
AddrSpace::Translate(unsigned int vaddr, unsigned int *paddr, int isReadWrite) AddrSpace::Translate(unsigned int vaddr, unsigned int* paddr, int isReadWrite)
{ {
TranslationEntry *pte; TranslationEntry* pte;
int pfn; int pfn;
unsigned int vpn = vaddr / PageSize; unsigned int vpn = vaddr / PageSize;
unsigned int offset = vaddr % PageSize; unsigned int offset = vaddr % PageSize;
if(vpn >= numPages) { if (vpn >= numPages) {
return AddressErrorException; return AddressErrorException;
}
pte = &pageTable[vpn];
if(isReadWrite && pte->readOnly) {
return ReadOnlyException;
}
pfn = pte->physicalPage;
if (pfn == -1) {
pfn = pte->physicalPage = kernel->frameTable->Allocate();
if (pfn == -1) {
DEBUG(dbgAddr, "Memory Limit exceeded");
return MemoryLimitException;
} }
}
// if the pageFrame is too big, there is something really wrong! pte = &pageTable[vpn];
// An invalid translation was loaded into the page table or TLB.
if (pfn >= NumPhysPages) {
DEBUG(dbgAddr, "Illegal physical page " << pfn);
return BusErrorException;
}
pte->use = TRUE; // set the use, dirty bits if (isReadWrite && pte->readOnly) {
return ReadOnlyException;
}
if(isReadWrite) pfn = pte->physicalPage;
pte->dirty = TRUE;
*paddr = pfn * PageSize + offset; // if the pageFrame is too big, there is something really wrong!
// An invalid translation was loaded into the page table or TLB.
if (pfn >= NumPhysPages) {
DEBUG(dbgAddr, "Illegal physical page " << pfn);
return BusErrorException;
}
ASSERT((*paddr < MemorySize)); pte->use = TRUE; // set the use, dirty bits
//cerr << " -- AddrSpace::Translate(): vaddr: " << vaddr << if (isReadWrite)
// ", paddr: " << *paddr << "\n"; pte->dirty = TRUE;
return NoException; *paddr = pfn * PageSize + offset;
ASSERT((*paddr < MemorySize));
//cerr << " -- AddrSpace::Translate(): vaddr: " << vaddr <<
// ", paddr: " << *paddr << "\n";
return NoException;
} }
FrameTable::FrameTable() {
for (int i = 0; i < NumPhysPages; ++i)
available.Append(i);
}
FrameTable::~FrameTable() {}
uint FrameTable::RemainSize() { return available.NumInList(); }
PageTable FrameTable::Allocate(uint pageNum) {
// if not enough memory
if (RemainSize() < pageNum)
return NULL;
PageTable ptb = new TranslationEntry[pageNum];
for (int i = 0; i < pageNum; ++i) {
ptb[i].virtualPage = i;
int f = available.RemoveFront(); // frame number
ptb[i].physicalPage = f;
// initialize flags
ptb[i].valid = TRUE;
ptb[i].use = FALSE;
ptb[i].dirty = FALSE;
ptb[i].readOnly = FALSE;
// zero out the entire address space
bzero(kernel->machine->mainMemory + f * PageSize, PageSize);
}
return ptb;
}
void FrameTable::Release(PageTable ptb, int pageNum) {
if (!ptb)
return; // nothing to release
for (int i = 0; i < pageNum; ++i)
available.Append(ptb[i].physicalPage);
delete[] ptb;
}

View File

@@ -18,57 +18,84 @@
#define UserStackSize 1024 // increase this as necessary! #define UserStackSize 1024 // increase this as necessary!
class FrameTable {
public:
FrameTable();
~FrameTable();
int Allocate();
void Release(int phyPageNum);
size_t RemainSize();
private:
struct Node {
Node *next;
int idx;
Node(int idx = -1);
};
Node *begin, *end;
size_t available;
int *useCount;
};
class AddrSpace { class AddrSpace {
public: public:
AddrSpace(); // Create an address space. AddrSpace(); // Create an address space.
~AddrSpace(); // De-allocate an address space ~AddrSpace(); // De-allocate an address space
bool Load(char *fileName); // Load a program into addr space from bool Load(char* fileName); // Load a program into addr space from
// a file // a file
// return false if not found // return false if not found
void Execute(char *fileName); // Run a program void Execute(char* fileName); // Run a program
// assumes the program has already // assumes the program has already
// been loaded // been loaded
void SaveState(); // Save/restore address space-specific void SaveState(); // Save/restore address space-specific
void RestoreState(); // info on a context switch void RestoreState(); // info on a context switch
// Translate virtual address _vaddr_ // Translate virtual address _vaddr_
// to physical address _paddr_. _mode_ // to physical address _paddr_. _mode_
// is 0 for Read, 1 for Write. // is 0 for Read, 1 for Write.
ExceptionType Translate(unsigned int vaddr, unsigned int *paddr, int mode); ExceptionType Translate(unsigned int vaddr, unsigned int* paddr, int mode);
private: private:
TranslationEntry *pageTable; TranslationEntry* pageTable; // Assume linear page table translation
unsigned int numPages; // Number of pages in the virtual // for now!
// address space unsigned int numPages; // Number of pages in the virtual
// address space
void InitRegisters(); // Initialize user-level CPU registers, void InitRegisters(); // Initialize user-level CPU registers,
// before jumping to user code // before jumping to user code
}; };
#endif // ADDRSPACE_H #endif // ADDRSPACE_H
#ifndef FRAME_TABLE_H
#define FRAME_TABLE_H
#include "machine.h"
#include "list.h"
/**
* Data structure of Virtual Memory
*/
typedef TranslationEntry* PageTable;
/**
* Data structure of Physical Memory
*/
class FrameTable {
public:
/**
* Initialize a frame table
*/
FrameTable();
~FrameTable();
/**
* Allocate pageNum of frames (pages) and collect
* corresponding translation information into a page table.
*
* @param pageNum numbers of pages
* @return a new Page table, NULL if not enough memory space
*/
PageTable Allocate(uint pageNum);
/**
* Release the physical memory frame
* which the info stored in PageTable
*/
void Release(PageTable ptb, int pageNum);
/**
* @return the remaining numbers of entry of the frame table
*/
uint RemainSize();
private:
List<int> available;
};
#endif /* FRAME_TABLE_H */

View File

@@ -1,18 +1,18 @@
// exception.cc // exception.cc
// Entry point into the Nachos kernel from user programs. // Entry point into the Nachos kernel from user programs.
// There are two kinds of things that can cause control to // There are two kinds of things that can cause control to
// transfer back to here from user code: // transfer back to here from user code:
// //
// syscall -- The user code explicitly requests to call a procedure // syscall -- The user code explicitly requests to call a procedure
// in the Nachos kernel. Right now, the only function we support is // in the Nachos kernel. Right now, the only function we support is
// "Halt". // "Halt".
// //
// exceptions -- The user code does something that the CPU can't handle. // exceptions -- The user code does something that the CPU can't handle.
// For instance, accessing memory that doesn't exist, arithmetic errors, // For instance, accessing memory that doesn't exist, arithmetic errors,
// etc. // etc.
// //
// Interrupts (which can also cause control to transfer from user // Interrupts (which can also cause control to transfer from user
// code into the Nachos kernel) are handled elsewhere. // code into the Nachos kernel) are handled elsewhere.
// //
// For now, this only handles the Halt() system call. // For now, this only handles the Halt() system call.
// Everything else core dumps. // Everything else core dumps.
@@ -27,192 +27,170 @@
#include "ksyscall.h" #include "ksyscall.h"
//---------------------------------------------------------------------- //----------------------------------------------------------------------
// ExceptionHandler // ExceptionHandler
// Entry point into the Nachos kernel. Called when a user program // Entry point into the Nachos kernel. Called when a user program
// is executing, and either does a syscall, or generates an addressing // is executing, and either does a syscall, or generates an addressing
// or arithmetic exception. // or arithmetic exception.
// //
// For system calls, the following is the calling convention: // For system calls, the following is the calling convention:
// //
// system call code -- r2 // system call code -- r2
// arg1 -- r4 // arg1 -- r4
// arg2 -- r5 // arg2 -- r5
// arg3 -- r6 // arg3 -- r6
// arg4 -- r7 // arg4 -- r7
// //
// The result of the system call, if any, must be put back into r2. // The result of the system call, if any, must be put back into r2.
// //
// If you are handling a system call, don't forget to increment the pc // If you are handling a system call, don't forget to increment the pc
// before returning. (Or else you'll loop making the same system call forever!) // before returning. (Or else you'll loop making the same system call forever!)
// //
// "which" is the kind of exception. The list of possible exceptions // "which" is the kind of exception. The list of possible exceptions
// is in machine.h. // is in machine.h.
//---------------------------------------------------------------------- //----------------------------------------------------------------------
void void
ExceptionHandler(ExceptionType which) ExceptionHandler(ExceptionType which)
{ {
int type = kernel->machine->ReadRegister(2); int type = kernel->machine->ReadRegister(2);
int val; int val;
int status, exit, threadID, programID; int status, exit, threadID, programID;
DEBUG(dbgSys, "Received Exception " << which << " type: " << type << "\n"); int fd, size;
switch (which) { DEBUG(dbgSys, "Received Exception " << which << " type: " << type << "\n");
case SyscallException: switch (which) {
switch(type) { case SyscallException:
case SC_Halt: switch (type) {
DEBUG(dbgSys, "Shutdown, initiated by user program.\n"); case SC_Halt:
SysHalt(); DEBUG(dbgSys, "Shutdown, initiated by user program.\n");
cout<<"in exception\n"; SysHalt();
ASSERTNOTREACHED(); cout << "in exception\n";
break; ASSERTNOTREACHED();
case SC_MSG: break;
DEBUG(dbgSys, "Message received.\n"); case SC_MSG:
val = kernel->machine->ReadRegister(4); DEBUG(dbgSys, "Message received.\n");
{ val = kernel->machine->ReadRegister(4);
char *msg = &(kernel->machine->mainMemory[val]); {
cout << msg << endl; char* msg = &(kernel->machine->mainMemory[val]);
} cout << msg << endl;
SysHalt(); }
ASSERTNOTREACHED(); SysHalt();
break; ASSERTNOTREACHED();
case SC_Create: break;
val = kernel->machine->ReadRegister(4); case SC_PrintInt:
{ val = kernel->machine->ReadRegister(4);
char *filename = &(kernel->machine->mainMemory[val]); SysPrintInt(val);
//cout << filename << endl; kernel->machine->WriteRegister(PrevPCReg, kernel->machine->ReadRegister(PCReg));
status = SysCreate(filename); kernel->machine->WriteRegister(PCReg, kernel->machine->ReadRegister(PCReg) + 4);
kernel->machine->WriteRegister(2, (int) status); kernel->machine->WriteRegister(NextPCReg, kernel->machine->ReadRegister(PCReg) + 4);
} return;
kernel->machine->WriteRegister(PrevPCReg, kernel->machine->ReadRegister(PCReg)); case SC_Create:
kernel->machine->WriteRegister(PCReg, kernel->machine->ReadRegister(PCReg) + 4); val = kernel->machine->ReadRegister(4);
kernel->machine->WriteRegister(NextPCReg, kernel->machine->ReadRegister(PCReg) + 4); {
return; char* filename = &(kernel->machine->mainMemory[val]);
ASSERTNOTREACHED(); //cout << filename << endl;
break; status = SysCreate(filename);
case SC_Add: kernel->machine->WriteRegister(2, (int)status);
DEBUG(dbgSys, "Add " << kernel->machine->ReadRegister(4) << " + " << kernel->machine->ReadRegister(5) << "\n"); }
/* Process SysAdd Systemcall*/ kernel->machine->WriteRegister(PrevPCReg, kernel->machine->ReadRegister(PCReg));
int result; kernel->machine->WriteRegister(PCReg, kernel->machine->ReadRegister(PCReg) + 4);
result = SysAdd(/* int op1 */(int)kernel->machine->ReadRegister(4), kernel->machine->WriteRegister(NextPCReg, kernel->machine->ReadRegister(PCReg) + 4);
/* int op2 */(int)kernel->machine->ReadRegister(5)); return;
DEBUG(dbgSys, "Add returning with " << result << "\n"); ASSERTNOTREACHED();
/* Prepare Result */ break;
kernel->machine->WriteRegister(2, (int)result); case SC_Open:
/* Modify return point */ val = kernel->machine->ReadRegister(4);
{ {
/* set previous programm counter (debugging only)*/ char* filename = &(kernel->machine->mainMemory[val]);
kernel->machine->WriteRegister(PrevPCReg, kernel->machine->ReadRegister(PCReg)); //cout << filename << endl;
fd = SysOpen(filename);
kernel->machine->WriteRegister(2, (int)fd);
}
kernel->machine->WriteRegister(PrevPCReg, kernel->machine->ReadRegister(PCReg));
kernel->machine->WriteRegister(PCReg, kernel->machine->ReadRegister(PCReg) + 4);
kernel->machine->WriteRegister(NextPCReg, kernel->machine->ReadRegister(PCReg) + 4);
return;
ASSERTNOTREACHED();
break;
case SC_Write:
val = kernel->machine->ReadRegister(4);
size = kernel->machine->ReadRegister(5);
fd = kernel->machine->ReadRegister(6);
{
char* buffer = &(kernel->machine->mainMemory[val]);
size = SysWrite(buffer, size, fd);
kernel->machine->WriteRegister(2, (int)size);
}
kernel->machine->WriteRegister(PrevPCReg, kernel->machine->ReadRegister(PCReg));
kernel->machine->WriteRegister(PCReg, kernel->machine->ReadRegister(PCReg) + 4);
kernel->machine->WriteRegister(NextPCReg, kernel->machine->ReadRegister(PCReg) + 4);
return;
ASSERTNOTREACHED();
break;
case SC_Close:
fd = kernel->machine->ReadRegister(4);
{
val = SysClose(fd);
kernel->machine->WriteRegister(2, (int)val);
}
kernel->machine->WriteRegister(PrevPCReg, kernel->machine->ReadRegister(PCReg));
kernel->machine->WriteRegister(PCReg, kernel->machine->ReadRegister(PCReg) + 4);
kernel->machine->WriteRegister(NextPCReg, kernel->machine->ReadRegister(PCReg) + 4);
return;
ASSERTNOTREACHED();
break;
case SC_Read:
val = kernel->machine->ReadRegister(4);
size = kernel->machine->ReadRegister(5);
fd = kernel->machine->ReadRegister(6);
{
char* buffer = &(kernel->machine->mainMemory[val]);
size = SysRead(buffer, size, fd);
kernel->machine->WriteRegister(2, (int)size);
}
kernel->machine->WriteRegister(PrevPCReg, kernel->machine->ReadRegister(PCReg));
kernel->machine->WriteRegister(PCReg, kernel->machine->ReadRegister(PCReg) + 4);
kernel->machine->WriteRegister(NextPCReg, kernel->machine->ReadRegister(PCReg) + 4);
return;
ASSERTNOTREACHED();
break;
case SC_Add:
DEBUG(dbgSys, "Add " << kernel->machine->ReadRegister(4) << " + " << kernel->machine->ReadRegister(5) << "\n");
/* Process SysAdd Systemcall*/
int result;
result = SysAdd(/* int op1 */(int)kernel->machine->ReadRegister(4),
/* int op2 */(int)kernel->machine->ReadRegister(5));
DEBUG(dbgSys, "Add returning with " << result << "\n");
/* Prepare Result */
kernel->machine->WriteRegister(2, (int)result);
/* Modify return point */
{
/* set previous programm counter (debugging only)*/
kernel->machine->WriteRegister(PrevPCReg, kernel->machine->ReadRegister(PCReg));
/* set programm counter to next instruction (all Instructions are 4 byte wide)*/ /* set programm counter to next instruction (all Instructions are 4 byte wide)*/
kernel->machine->WriteRegister(PCReg, kernel->machine->ReadRegister(PCReg) + 4); kernel->machine->WriteRegister(PCReg, kernel->machine->ReadRegister(PCReg) + 4);
/* set next programm counter for brach execution */ /* set next programm counter for brach execution */
kernel->machine->WriteRegister(NextPCReg, kernel->machine->ReadRegister(PCReg) + 4); kernel->machine->WriteRegister(NextPCReg, kernel->machine->ReadRegister(PCReg) + 4);
} }
cout << "result is " << result << "\n"; cout << "result is " << result << "\n";
return; return;
ASSERTNOTREACHED(); ASSERTNOTREACHED();
break; break;
case SC_Exit: case SC_Exit:
DEBUG(dbgAddr, "Program exit\n"); DEBUG(dbgAddr, "Program exit\n");
val = kernel->machine->ReadRegister(4); val = kernel->machine->ReadRegister(4);
cout << "return value:" << val << endl; cout << "return value:" << val << endl;
kernel->currentThread->Finish(); kernel->currentThread->Finish();
break; break;
case SC_PrintInt: default:
DEBUG(dbgAddr, "Printing int\n"); cerr << "Unexpected system call " << type << "\n";
val = (int)kernel->machine->ReadRegister(4); break;
SysPrintInt(val); }
break;
kernel->machine->WriteRegister(PrevPCReg, kernel->machine->ReadRegister(PCReg)); default:
kernel->machine->WriteRegister(PCReg, kernel->machine->ReadRegister(PCReg) + 4); cerr << "Unexpected user mode exception " << (int)which << "\n";
kernel->machine->WriteRegister(NextPCReg, kernel->machine->ReadRegister(PCReg) + 4); break;
}
return; ASSERTNOTREACHED();
ASSERTNOTREACHED();
break;
case SC_Open:
DEBUG(dbgAddr, "Open file\n");
{
val = kernel->machine->ReadRegister(4);
char *name = &(kernel->machine->mainMemory[val]);
OpenFileId ret = SysOpen(name);
kernel->machine->WriteRegister(2, ret);
}
kernel->machine->WriteRegister(PrevPCReg, kernel->machine->ReadRegister(PCReg));
kernel->machine->WriteRegister(PCReg, kernel->machine->ReadRegister(PCReg) + 4);
kernel->machine->WriteRegister(NextPCReg, kernel->machine->ReadRegister(PCReg) + 4);
return;
ASSERTNOTREACHED();
break;
case SC_Read:
DEBUG(dbgAddr, "Read file\n");
{
val = kernel->machine->ReadRegister(4);
char *buffer = &(kernel->machine->mainMemory[val]);
int size = kernel->machine->ReadRegister(5);
OpenFileId id = (OpenFileId)kernel->machine->ReadRegister(6);
int ret = SysRead(buffer, size, id);
kernel->machine->WriteRegister(2, ret);
}
kernel->machine->WriteRegister(PrevPCReg, kernel->machine->ReadRegister(PCReg));
kernel->machine->WriteRegister(PCReg, kernel->machine->ReadRegister(PCReg) + 4);
kernel->machine->WriteRegister(NextPCReg, kernel->machine->ReadRegister(PCReg) + 4);
return;
ASSERTNOTREACHED();
break;
case SC_Write:
DEBUG(dbgAddr, "Write file\n");
{
val = kernel->machine->ReadRegister(4);
char *buffer = &(kernel->machine->mainMemory[val]);
int size = kernel->machine->ReadRegister(5);
OpenFileId id = (OpenFileId)kernel->machine->ReadRegister(6);
// fprintf(stderr, "buffer: %p\n", buffer);
// cerr << "size: " << size << endl;
// cerr << "id: " << id << endl;
int ret = SysWrite(buffer, size, id);
kernel->machine->WriteRegister(2, ret);
}
kernel->machine->WriteRegister(PrevPCReg, kernel->machine->ReadRegister(PCReg));
kernel->machine->WriteRegister(PCReg, kernel->machine->ReadRegister(PCReg) + 4);
kernel->machine->WriteRegister(NextPCReg, kernel->machine->ReadRegister(PCReg) + 4);
return;
ASSERTNOTREACHED();
break;
case SC_Close:
DEBUG(dbgAddr, "Close file\n");
{
OpenFileId id = (OpenFileId)kernel->machine->ReadRegister(4);
int ret = SysClose(id);
kernel->machine->WriteRegister(2, ret);
}
kernel->machine->WriteRegister(PrevPCReg, kernel->machine->ReadRegister(PCReg));
kernel->machine->WriteRegister(PCReg, kernel->machine->ReadRegister(PCReg) + 4);
kernel->machine->WriteRegister(NextPCReg, kernel->machine->ReadRegister(PCReg) + 4);
return;
ASSERTNOTREACHED();
break;
default:
cerr << "Unexpected system call " << type << "\n";
break;
}
break;
default:
cerr << "Unexpected user mode exception " << (int)which << "\n";
break;
}
ASSERTNOTREACHED();
} }

View File

@@ -0,0 +1,11 @@
#include "syscall.h"
int
main()
{
int n;
for (n = 0; n < 4; n++) {
PrintInt(1);
}
return 0;
}

View File

@@ -0,0 +1,11 @@
#include "syscall.h"
int
main()
{
int n;
for (n = 0; n < 5; n++) {
PrintInt(2);
}
return 0;
}

View File

@@ -0,0 +1,12 @@
#include "syscall.h"
int
main()
{
int n;
for (n = 0; n < 12; n++) {
PrintInt(3);
}
return 0;
}

View File

@@ -0,0 +1,12 @@
#include "syscall.h"
int
main()
{
int n;
for (n = 0; n < 11; n++) {
PrintInt(4);
}
return 0;
}

View File

@@ -11,68 +11,61 @@
#ifndef __USERPROG_KSYSCALL_H__ #ifndef __USERPROG_KSYSCALL_H__
#define __USERPROG_KSYSCALL_H__ #define __USERPROG_KSYSCALL_H__
#define INT_BUF_LENGTH 13
#include "kernel.h" #include "kernel.h"
#include "synchconsole.h" #include "synchconsole.h"
typedef int OpenFileId;
void SysHalt() void SysHalt()
{ {
kernel->interrupt->Halt(); kernel->interrupt->Halt();
} }
int SysAdd(int op1, int op2) int SysAdd(int op1, int op2)
{ {
return op1 + op2; return op1 + op2;
} }
int SysCreate(char *filename) int SysCreate(char* filename)
{ {
// return value // return value
// 1: success // 1: success
// 0: failed // 0: failed
return kernel->interrupt->CreateFile(filename); return kernel->interrupt->CreateFile(filename);
} }
void SysPrintInt(int value) { void SysPrintInt(int value)
kernel->interrupt->PrintInt(value); {
kernel->interrupt->PrintInt(value);
} }
OpenFileId SysOpen(char *name) { // -1: open fail
OpenFileId id = -1; // fd
for (int i = 0; i < 20; i++) OpenFileId SysOpen(char* filename)
if (kernel->fileSystem->fileDescriptorTable[i] == NULL) { {
id = i; return kernel->interrupt->OpenFile(filename);
kernel->fileSystem->fileDescriptorTable[i]
= kernel->fileSystem->Open(name);
if (kernel->fileSystem->fileDescriptorTable[i] == NULL)
return -1;
break;
}
return id;
} }
int SysWrite(char *buffer, int size, OpenFileId id) { // -1: write fail
if (id < 0 || id >= 20 || kernel->fileSystem->fileDescriptorTable[id] == NULL) // size
return -1; int SysWrite(char* buffer, int size, OpenFileId fd)
return kernel->fileSystem->fileDescriptorTable[id]->Write(buffer, size); {
return kernel->interrupt->WriteFile(buffer, size, fd);
} }
int SysRead(char *buffer, int size, OpenFileId id) { // 1: close success
if (id < 0 || id >= 20 || kernel->fileSystem->fileDescriptorTable[id] == NULL) // 0: close fail
return -1; int SysClose(OpenFileId fd)
return kernel->fileSystem->fileDescriptorTable[id]->Read(buffer, size); {
return kernel->interrupt->CloseFile(fd);
} }
int SysClose(OpenFileId id) { // -1: read fail
if (id < 0 || id >= 20 || kernel->fileSystem->fileDescriptorTable[id] == NULL) // size
return 0; int SysRead(char* buffer, int size, OpenFileId fd)
delete kernel->fileSystem->fileDescriptorTable[id]; {
kernel->fileSystem->fileDescriptorTable[id] = NULL; return kernel->interrupt->ReadFile(buffer, size, fd);
return 1;
} }
#endif /* ! __USERPROG_KSYSCALL_H__ */ #endif /* ! __USERPROG_KSYSCALL_H__ */

View File

@@ -6,13 +6,12 @@
*/ */
#define NOFFMAGIC 0xbadfad /* magic number denoting Nachos #define NOFFMAGIC 0xbadfad /* magic number denoting Nachos
* object code file /* object code file*/
*/
typedef struct segment { typedef struct segment {
int virtualAddr; /* location of segment in virt addr space */ int virtualAddr; /* location of segment in virt addr space */
int inFileAddr; /* location of segment in this file */ int inFileAddr; /* location of segment in this file */
int size; /* size of segment */ int size; /* size of segment */
} Segment; } Segment;
typedef struct noffHeader { typedef struct noffHeader {
@@ -23,6 +22,6 @@ typedef struct noffHeader {
Segment readonlyData; /* read only data */ Segment readonlyData; /* read only data */
#endif #endif
Segment uninitData; /* uninitialized data segment -- Segment uninitData; /* uninitialized data segment --
* should be zero'ed before use * should be zero'ed before use
*/ */
} NoffHeader; } NoffHeader;

View File

@@ -17,7 +17,7 @@
// otherwise, read from this file // otherwise, read from this file
//---------------------------------------------------------------------- //----------------------------------------------------------------------
SynchConsoleInput::SynchConsoleInput(char *inputFile) SynchConsoleInput::SynchConsoleInput(char* inputFile)
{ {
consoleInput = new ConsoleInput(inputFile, this); consoleInput = new ConsoleInput(inputFile, this);
lock = new Lock("console in"); lock = new Lock("console in");
@@ -73,7 +73,7 @@ SynchConsoleInput::CallBack()
// otherwise, read from this file // otherwise, read from this file
//---------------------------------------------------------------------- //----------------------------------------------------------------------
SynchConsoleOutput::SynchConsoleOutput(char *outputFile) SynchConsoleOutput::SynchConsoleOutput(char* outputFile)
{ {
consoleOutput = new ConsoleOutput(outputFile, this); consoleOutput = new ConsoleOutput(outputFile, this);
lock = new Lock("console out"); lock = new Lock("console out");
@@ -106,13 +106,18 @@ SynchConsoleOutput::PutChar(char ch)
lock->Release(); lock->Release();
} }
//----------------------------------------------------------------------
// SynchConsoleOutput::PutInt
// Write a int to the console display, waiting if necessary.
//----------------------------------------------------------------------
void void
SynchConsoleOutput::PutInt(int value) SynchConsoleOutput::PutInt(int value)
{ {
lock->Acquire(); lock->Acquire();
consoleOutput->PutInt(value); consoleOutput->PutInt(value);
waitFor->P(); waitFor->P();
lock->Release(); lock->Release();
} }
//---------------------------------------------------------------------- //----------------------------------------------------------------------

View File

@@ -21,34 +21,34 @@
// a console device // a console device
class SynchConsoleInput : public CallBackObj { class SynchConsoleInput : public CallBackObj {
public: public:
SynchConsoleInput(char *inputFile); // Initialize the console device SynchConsoleInput(char* inputFile); // Initialize the console device
~SynchConsoleInput(); // Deallocate console device ~SynchConsoleInput(); // Deallocate console device
char GetChar(); // Read a character, waiting if necessary char GetChar(); // Read a character, waiting if necessary
private: private:
ConsoleInput *consoleInput; // the hardware keyboard ConsoleInput* consoleInput; // the hardware keyboard
Lock *lock; // only one reader at a time Lock* lock; // only one reader at a time
Semaphore *waitFor; // wait for callBack Semaphore* waitFor; // wait for callBack
void CallBack(); // called when a keystroke is available void CallBack(); // called when a keystroke is available
}; };
class SynchConsoleOutput : public CallBackObj { class SynchConsoleOutput : public CallBackObj {
public: public:
SynchConsoleOutput(char *outputFile); // Initialize the console device SynchConsoleOutput(char* outputFile); // Initialize the console device
~SynchConsoleOutput(); ~SynchConsoleOutput();
void PutChar(char ch); // Write a character, waiting if necessary void PutChar(char ch); // Write a character, waiting if necessary
void PutInt(int value); void PutInt(int value);
private: private:
ConsoleOutput *consoleOutput;// the hardware display ConsoleOutput* consoleOutput;// the hardware display
Lock *lock; // only one writer at a time Lock* lock; // only one writer at a time
Semaphore *waitFor; // wait for callBack Semaphore* waitFor; // wait for callBack
void CallBack(); // called when more data can be written void CallBack(); // called when more data can be written
}; };
#endif // SYNCHCONSOLE_H #endif // SYNCHCONSOLE_H

View File

@@ -15,46 +15,49 @@
#include "copyright.h" #include "copyright.h"
#include "errno.h" #include "errno.h"
/* system call codes -- used by the stubs to tell the kernel which system call /* system call codes -- used by the stubs to tell the kernel which system call
* is being asked for * is being asked for
*/ */
#define SC_Halt 0 #define SC_Halt 0
#define SC_Exit 1 #define SC_Exit 1
#define SC_Exec 2 #define SC_Exec 2
#define SC_Join 3 #define SC_Join 3
#define SC_Create 4 #define SC_Create 4
#define SC_Remove 5 #define SC_Remove 5
#define SC_Open 6 #define SC_Open 6
#define SC_Read 7 #define SC_Read 7
#define SC_Write 8 #define SC_Write 8
#define SC_Seek 9 #define SC_Seek 9
#define SC_Close 10 #define SC_Close 10
#define SC_ThreadFork 11 #define SC_ThreadFork 11
#define SC_ThreadYield 12 #define SC_ThreadYield 12
#define SC_ExecV 13 #define SC_ExecV 13
#define SC_ThreadExit 14 #define SC_ThreadExit 14
#define SC_ThreadJoin 15 #define SC_ThreadJoin 15
#define SC_Add 42
#define SC_PrintInt 16 #define SC_MSG 100
#define SC_PrintInt 16
#define SC_Add 42
#define SC_MSG 100
#ifndef IN_ASM #ifndef IN_ASM
/* The system call interface. These are the operations the Nachos /* The system call interface. These are the operations the Nachos
* kernel needs to support, to be able to run user programs. * kernel needs to support, to be able to run user programs.
* *
* Each of these is invoked by a user program by simply calling the * Each of these is invoked by a user program by simply calling the
* procedure; an assembly language stub stuffs the system call code * procedure; an assembly language stub stuffs the system call code
* into a register, and traps to the kernel. The kernel procedures * into a register, and traps to the kernel. The kernel procedures
* are then invoked in the Nachos kernel, after appropriate error checking, * are then invoked in the Nachos kernel, after appropriate error checking,
* from the system call entry point in exception.cc. * from the system call entry point in exception.cc.
*/ */
/* Stop Nachos, and print out performance stats */ /* Stop Nachos, and print out performance stats */
void Halt(); void Halt();
/*
* Show the int value on console
*/
void PrintInt(int value);
/* /*
* Add the two operants and return the result * Add the two operants and return the result
*/ */
@@ -63,7 +66,7 @@ int Add(int op1, int op2);
/* /*
* Just for simply showing message, not a safe way for console IO * Just for simply showing message, not a safe way for console IO
*/ */
void MSG(char *msg); void MSG(char* msg);
/* Address space control operations: Exit, Exec, Execv, and Join */ /* Address space control operations: Exit, Exec, Execv, and Join */
@@ -102,7 +105,7 @@ int Join(SpaceId id);
* file system has not been implemented. * file system has not been implemented.
*/ */
/* A unique identifier for an open Nachos file. */ /* A unique identifier for an open Nachos file. */
typedef int OpenFileId; typedef int OpenFileId;
/* when an address space starts up, it has two open files, representing /* when an address space starts up, it has two open files, representing
@@ -112,26 +115,26 @@ typedef int OpenFileId;
*/ */
#define SysConsoleInput 0 #define SysConsoleInput 0
#define SysConsoleOutput 1 #define SysConsoleOutput 1
/* Create a Nachos file, with name "name" */ /* Create a Nachos file, with name "name" */
/* Note: Create does not open the file. */ /* Note: Create does not open the file. */
/* Return 1 on success, negative error code on failure */ /* Return 1 on success, negative error code on failure */
int Create(char *name); int Create(char* name);
/* Remove a Nachos file, with name "name" */ /* Remove a Nachos file, with name "name" */
int Remove(char *name); int Remove(char* name);
/* Open the Nachos file "name", and return an "OpenFileId" that can /* Open the Nachos file "name", and return an "OpenFileId" that can
* be used to read and write to the file. * be used to read and write to the file.
*/ */
OpenFileId Open(char *name); OpenFileId Open(char* name);
/* Write "size" bytes from "buffer" to the open file. /* Write "size" bytes from "buffer" to the open file.
* Return the number of bytes actually read on success. * Return the number of bytes actually read on success.
* On failure, a negative error code is returned. * On failure, a negative error code is returned.
*/ */
int Write(char *buffer, int size, OpenFileId id); int Write(char* buffer, int size, OpenFileId id);
/* Read "size" bytes from the open file into "buffer". /* Read "size" bytes from the open file into "buffer".
* Return the number of bytes actually read -- if the open file isn't * Return the number of bytes actually read -- if the open file isn't
@@ -139,7 +142,7 @@ int Write(char *buffer, int size, OpenFileId id);
* characters to read, return whatever is available (for I/O devices, * characters to read, return whatever is available (for I/O devices,
* you should always wait until you can return at least one character). * you should always wait until you can return at least one character).
*/ */
int Read(char *buffer, int size, OpenFileId id); int Read(char* buffer, int size, OpenFileId id);
/* Set the seek position of the open file "id" /* Set the seek position of the open file "id"
* to the byte "position". * to the byte "position".
@@ -158,10 +161,10 @@ int Close(OpenFileId id);
* Could define other operations, such as LockAcquire, LockRelease, etc. * Could define other operations, such as LockAcquire, LockRelease, etc.
*/ */
/* Fork a thread to run a procedure ("func") in the *same* address space /* Fork a thread to run a procedure ("func") in the *same* address space
* as the current thread. * as the current thread.
* Return a positive ThreadId on success, negative error code on failure * Return a positive ThreadId on success, negative error code on failure
*/ */
ThreadId ThreadFork(void (*func)()); ThreadId ThreadFork(void (*func)());
/* Yield the CPU to another runnable thread, whether in this address space /* Yield the CPU to another runnable thread, whether in this address space
@@ -180,8 +183,6 @@ int ThreadJoin(ThreadId id);
*/ */
void ThreadExit(int ExitCode); void ThreadExit(int ExitCode);
void PrintInt(int number);
#endif /* IN_ASM */ #endif /* IN_ASM */
#endif /* SYSCALL_H */ #endif /* SYSCALL_H */

View File

@@ -2,6 +2,6 @@
services: services:
test: test:
build: . build: .
user: '60139:60139' user: ytshih
volumes: volumes:
- './:/work' - './:/work'