150 likes | 275 Views
Project 2: Initial Implementation Notes. Tao Yang. Part I: Multiprogramming. Fork(func) creates a new user-level (child) process, whose address space starts out as an exact copy of that of the caller (the parent), Yield(): temporarily relinquish the CPU to another process.
E N D
Part I: Multiprogramming • Fork(func) creates a new user-level (child) process, whose address space starts out as an exact copy of that of the caller (the parent), • Yield(): temporarily relinquish the CPU to another process. • Exit(int) call takes a single argument, which is an integer status value as in Unix. The currently executing process is terminated.. • Exec(filename) spawns a new user-level thread (process), but creates a new address space. It should return to the parent a SpaceId. • Join(ID) call waits and returns only after a process with the specified ID has finished.
Getting Started • Review start.s (under test directory) which includes all system call stubs, following the style of Halt. • Modify ExceptionHandler() in exception.cc to include all system call entries. • After each system call, increment PC registers so that ExceptionHandler() execution flow returns back to next instruction after user’s system call place. • counter = machine->ReadRegister(PCReg); • machine->WriteRegister(PrevPCReg,counter); • counter = counter + 4;machine->WriteRegister(PCReg,counter); • counter = counter + 4; machine->WriteRegister(NextPCReg,counter); • Arguments of a system call are in Register s 4, 5, 6 etc. • how to verify? You may review MPIS assembly code produced for a test C program using gcc -S. • If needed, return result is register 2 • machine->WriteRegister(2,result);
PCB (Process Control Block) • Write the PCB and a process manager. Create a PCB class that will store the necessary information about a process. Don't worry about putting everything in it right now, you can always add more as you go along. To start, it should have a PID, parent PID, and Thread*. • The process manager- it can have getPID and clearPID methods, which return an unused process id and clear a process id respectively.
Memory Manager • Write a Memory Manager that will be used to facilitate memory allocation: • Track memory page usage. • Allocate a page • Free a page • Modify AddrSpace:AddrSpace (addrspace.cc) to use the memory manager. • Modify the page table constructors to use pages allocated by your memory manager • Create a PCB (process control block) also for each process to include key control information.
AddSpace.cc • Write a function (e.g. AddrSpace::Translate), which converts a virtual address to a physical address. It does so by breaking the virtual address into a page table index and an offset. • Write a function( e.g. AddrSpace::ReadFile), which loads the code and data segments into the translated memory, instead of at position 0. • Read data into a system buffer (diskBuffer). • Copy buffered data into proper memory locations (e.g. at machine->mainMemory[physAddr].)
Implement Fork() in ExceptionHandler() • FuncEntry = Value of register 4 ( sys call argu) • Target function to be executed in the new space. • Create a new kernel thread. • Create a new AddrSpace to be a duplicate of the CurrentThread's space and get a new PCB. • The current thread calls Yield() so the new thread can run. • The new thread runs a dummy function that creates a bridge for execution of the user function). • Call NewThread->Fork(ForkBridge, FuncEntry) • Why? It needs to set program counter properly in a new space.
ForkBridge() : Key parts • Set counter = FuncEntry • Initialize and restore the registers. For example, • currentThread->RestoreUserState(); • currentThread->space->RestoreState(); • machine->WriteRegister(PCReg, counter); • machine->WriteRegister(PrevPCReg,counter-4); • machine->WriteRegister(NextPCReg,counter+4); • Call machine->Run() which executes the forked user process in the desired FuncEntry address.
Implement Exec() • Exec is creating a new process with new code and data segments from a file. • Allocate a new address space which fits this file. • Load data/code from an OpenFile object constructed from the filename passed in by the user. • In order to get that file name you will have to write a function that copies over the string from user space. • Allocate a new kernel thread and a PCB to execute with the above space. • Fork the new thread to run a dummy bridge function that sets the machine registers straight and runs the code • Call NewThread->Fork(ExecBridge ,NULL); • The calling thread should yield to give control to the newly spawned thread. • Return the process ID that executes this binary.
ExecBridge(): Key parts • Initialize registers/restore state. • (currentThread->space)->InitRegisters(); • (currentThread->space)->RestoreState(); • Machine->run();
System Calls for File System • For the entire system, maintain a set of objects (SysOpenFile class) representing system-wide opened files. • Each file may be opened by many user processes. • Call it fileOpenTable[]; • For each process, maintain a set of objects in PCB (UserOpenFile class) representing files opened by this process. • Each file has filename, index to the system-wide open table entry, and offset for the current read/write pointer
Implement create() • Nachos already has a simple file system implemented • filesys.cc and openfile.cc under filesys directory. • Use Nachos fileSystem to add a new file to its directory.
Implement open() • Use fileSystem->Open() (nachos’open) to locate the file object. • Add the opened file object to the system-wide fileOpenTable. • If it is already opened by some other user process, just share the entry. • Else insert to the local file open table in PCB.
Implement read() • Allocate an internal buffer. • If Inputfile ID is ConsoleInput • Then use getchar() and save data in the internal buffer. • Read until EOF or \n. • Else, find the current read offset. • Use openFile:ReadAt (defined in openfile.cc) to read data from the nachos file. • Copy data from the internal buffer to the destination memory location. • Need to copy one by one since the address needs to be translated one by one.
Implement write() • Allocate an internal buffer. • Copy data from the source memory location to the internal buffer. • Need to copy one by one since the address needs to be translated one by one. • If Outputfile ID is ConsoleOutput • Then use printf (assuming string type). • Else, find the current write offset. • Use openFile:WriteAt (defined in openfile.cc) to write data to the nachos file.