Project #2: Multiprogramming - jonathanloganmoran/cse150-nachos_5.0j GitHub Wiki
We will be implementing a multiprogramming system using the MIPS R3000 simulated chip and the partially-incomplete Nachos 5.0j.
Index
- Task #1: Implement the file system calls (30%)
- Task #2: Implement support for multiprogramming (25%)
- Task #3: Implement
syscall.h(30%) - Task #4: Implement the
LotterySchedulerclass (15%) - Design Questions
- References
Task #1: Implement the file system calls (30%)
Objectives
Our goal is to complete the UserProcess.java class, giving user processes the ability to access a file system (previously implemented)
Correctness Constraints
File system calls
- Users must only make valid kernel calls, except for
halt()- i.e. attempting to access unmapped memory or jumping to bad addresses
- user-generated errors should return
-1or appropriate value fromtest/syscall.h
halt()can only be invoked by therootprocess- all other attempts should be ignored and return immediately
- Maximum length for strings passed as
syscallarguments is256 bytes - Minimum of 16 open file files per process (including
stdinandstdout)- each file should have a unique
file descriptor(non-negative integer)
- each file should have a unique
Modifications
Completed N/A, commit: TBA
-
NEW
creat()handler_ -
NEW
open()handler -
NEW
read()handler -
NEW
write()handler -
NEW
close()handler -
NEW
unlink()handler
Pseudocode
NEW creat() handler_
init file descriptor to -1 return error if no empty slots to write
find empty space in process_fd[] to store file check if free space contains index if null, return error else if name is null, return error flag as open file if valid proceed with remaining verifications
return file descriptor instance
- NEW
open()handler
• Very similar steps to “handleCreat”. First step is to initialize our file descriptor to -1 to return errors if the program fails to change our values.
• Search through file indexes to find our first null index.
• Begin error checks:
• If the file descriptor didn’t take an index, return an error
• If the file name does not exist, return an error
• If the file contains nothing, return an error
• Remove the last open file from the kernel
• If our file didn’t open, return an error
• Once error-checks pass, we can set our current file given by the file descriptor to open.
• Conclude by returning the value of our file descriptor.
- NEW
read()handler
We first must check the validity of these three variables
• Counter: We need to check that the counter is a non-negative value.
• If it’s negative, return an error.
• Buffer: We need to check that our buffer is valid.
• If it’s improperly set up, return an error.
• File Descriptor: We need to make sure our file descriptor is within the bounds of our max number of files.
• If we have no files open or over 16 files open, return an error.
• If there’s also no file descriptor provided at all, return an error.
• Read through each index in our file.
• Look for a non-negative value for read. If it’s negative, return an error.
• We need to check at the end if everything’s been written to our virtual memory that was read. If we didn’t get everything we read, return an error.
• Once we pass these error checks, we return success and return the bytes read.
- NEW
write()handler
We need to check the validity of these before continuing:
• Buffer Size: We need to check we have a non-negative value for available buffer size.
• If we have a negative value, return an error.
• Buffer Pointer: We need to create a test buffer and check it against our buffer pointer.
• If the offset and length of the two equals one, return an error.
• File Descriptor: We need to check if the file descriptor is within the range of minimum and maximum number of files open.
• If outside that range, return an error.
• If we have no file descriptor given, return an error.
• Once we’ve verified our three variables, we need to fill up the remaining buffer space. We do this by comparing our reader variable to our Buffer Size variable.
• We read through the memory addresses and read the values. If we read a zero, we have a zero counter to keep track. If the zero counter reaches 3 zeroes in a row, then we have a major issue and return an error. With each non-zero value returned, however, we will return our zero counter to 0 and restart our count.
• We continue cycling through this process until we’ve returned three zeroes in a row, or our reader reaches the size of our buffer.
• After this we check if we have a valid file open and buffer space we can still utilize. First, we check that our file descriptor is still valid.
• We start writing while the data to write is less than the buffer size and if we haven’t become stuck while writing 3 or more attempts in a row. If not, we return an error.
• We save all values written to a new writer variable used strictly in this writing process.
• We check if our new writer variable returns as negative, then we return an error.
• If our new writer variable returns as a zero, this means no data was written and we increment our stuck writer variable by one. As stated above, if we increment three times in a row, we return an error.
• If this new writer variable does return a value greater than zero, we reset our stuck counter to zero again, and continue the process. If we reach three in a row, this most likely means our buffer is full and we return the value written.
- NEW
close()handler
Before closing a file, we need to quickly check that our file to be closed is a valid file.
• We check only if our file descriptor is within the minimum and maximum bounds of the number of files allowed. If it’s negative or greater than 16, we return an error.
• We create a new file to use for the process of closing this file, closingFile
• We next need error checks to verify that the file being closed is valid again, this time using our new closing file variable
• If our file to be closed doesn’t exist, then we return an error.
• Once we’ve verified everything is valid, we use our file descriptor to get the index of this file in the file array.
• We set the index of this file descriptor to null. This frees up this index value to be used again in the next handleCreat process.
• At this point, we return a zero value as we’ve successfully closed the file.
- NEW
unlink()handler
Before attempting any processes, we have to create two variables; One string to save our address to, and one Boolean to store true or false.
• The first process we need to accomplish is retrieving the address of our file’s name from within the memory.
• As with every other handler, we need to run some error checks now before fully proceeding.
• If the length of our address is zero, or our address does not exist that we just attempted to retrieve, then return an error.
• We now set our Boolean to remove the address from the kernel.
• To verify this step worked, we check if it’s properly closed in the system. If not closed, then return an error.
• Once we’ve verified it’s closed, we return zero as a success. The file is now unlinked from the kernel.
Task #2: Implement support for multiprogramming (25%)
Objectives
Our goal is to complete the UserKernel.java classes for reading/writing to the UserProcess.VritualMemory space.
Correctness Constraints
Allocating physical memory
- Allocate a fixed number of pages for the process's stack
- 8 pages should be sufficient
UserProcess.loadSections()should allocated number of pages needed for size of user program
- Store a global linked-list of free physical pages in
UserKernelclass- Allocate pages in non-contiguous manner, making use of "gaps" in the free memory pool
Freeing user memory
- Ensure that ALL of a process's memory has been freed on exit
- Can be freed on syscall
exit()or from an illegal execution
- Can be freed on syscall
- Minimum of 16 open file files per process (including
stdinandstdout)
Maintaining pageTable entries
- Map the user's virtual addresses to physical addresses for each process
- The
TranslationEntryclass represents a single virtual-to-physical address translation - The
TranslationEntry.readOnlyflag should betrueif page returned fromCOFF = read only - Methods should not throw exceptions, instead return the num of bytes transferred
- The