The goals of project 1 are:
Part 1 of this assignment does not use the NACHOS system. The goal of this part of the project is to explore the use of the fork(), wait(), exit(), exec() and all of its variants. We will look at how these system calls might be used in an operating system command interpreter such as sh or csh. You will want to familiarize yourself with the use of these system calls by reading all of the unix man pages for them. Note some of these have man pages for user commands and for system calls, you will be interested in the pages for system calls.
First write a bootstrap program that uses the fork() system call to make a copy of itself. The bootstrap program should be able to recognize if it is the parent or the child process and print an appropriate message. You can have the parent and the child processes both go into an infinite loop after printing a message and use ps -u We now want to extend the bootstrap program to use the exec() and wait() system calls. The child process from above should now use the exec() system call to load another program. That program should be a simple command interpreter that you write. The parent program should use the wait() system call to wait for the child process to exit.
The command interpreter program can be as simple or complex as you like. At a minimum it should provide a command line prompt that accepts a character string as input. The character string should be examined to determine if it is one of the commands that the interpreter understands (what it understands is up to you). If the interpreter understands the command it should do some processing, this may involve using fork() and exec() to start up another process (ex. a program that does a fancy ls command) or it may do something itself. If the interpreter does not understand the command it should print an error message (ex. I don't know how to ...) The interpreter must understand the string "exit" and use the exit() system call to terminate. The interpreter should continue to accept and process commands until the exit command is received. Don't get too elaborate with what your command interpreter does because there is a lot more to do in the other parts of this assignment. Just get a feel for the types of things you could do and how you would do them.
The parent (bootstrap) process should terminate after the child terminates and the wait() system call returns. The parent should print a message about the exit status of the child (command interpreter) process. What happens if the parent process doesn't execute a wait command? How does that compare to running one of the standard unix shells with an & (i.e. type sh & at a csh command prompt)? Play around with this to see what happens in different circumstances.
Note that the significance of this simple system is that it is very similar to what occurs in a real OS. When the computer starts up it loads the OS kernel and a system login program that validates usernames and passwords. When a login is validated the login program starts a process for the user. This process is usually a command interpreter from which the user can start other processes. Our bootstrap program is analogous to the login program that launches the command interpreter.
For part 1 of the assignment just hand in well commented hard copies of the final bootstrap program, the command interpreter and any programs that the command interpreter launches. You will need to briefly demonstrate this system in your design review meeting.
You need to copy the NACHOS program files from my account and make sure that you are able to compile them from your account. The NACHOS files that you will need for the first project are stored in the directory /export/home/fac/braught/cs354/proj1.stu. You will need to copy this directory and all of its contents to your account to complete the first project.
After you have copied the proj1.stu directory into your account you need to make the test NACHOS system. To do this cd into the threads directory that is inside the proj1.stu directory and type make. Using the make utility provides a convenient way to compile a project that consists of many files. The make utility uses the file Makefile as input to tell it which files are part of the project. The make utility is also smart about which of those files to compile. It will only recompile those files that have changed since the last time a make was performed.
Typing make compiles all of the files in the threads directory and creates an executable file called nachos. You will see several compiler warning messages during the make process but the process should complete and leave you with the nachos executable. If it does not you may need to modify your .cshrc file slightly.
If typing make causes errors and the nachos executable is not generated you need to make sure the directory /opt/gnu/bin appears in the path statement of your .cshrc file before any of the following; /usr/ccs/bin, /usr/bin, /usr/local/bin. Making this change to your .cshrc file should fix the problem.
After you have successfully created the nachos executable type nachos on the command line to run it. The results should look something similar to:
There is nothing to hand in for part 2 of this assignment. Basically, if you don't get part 2 done then you can't do the rest of the project.
I suggest you print out all of the .cc and .h files in the threads directory for reference before proceeding. I also suggest that you make a backup copy of any of the NACHOS files you are changing so that you can go back to the default system if needed.
You should play around with the threadtest.cc file until you understand what is happening with NACHOS threads. You should be able to fork a new thread for any function you define. Add a second printf statement to the for loop in SimpleThread(...) and call NACHOS using the -rs # flag (see main.cc for a description of the -rs flag.) Understand why the sequence of printfs changes for different random seeds in the -rs flag. Add a third thread for SimpleThread(...) and see what happens. You need to understand where NACHOS might insert a context switch and where it will not.
Implement the Join operator for NACHOS threads. The join operation causes the calling thread to wait until the thread that is being joined terminates. So if Thread1 calls Join(Thread2) Thread1 is blocked until Thread2 finishes. If Thread2 has already finished or does not exist then Thread1 simply continues its execution. You may want to look at the man pages for thr_join to see how Solaris supports the join operator.
Some specifics for the Join operator that you need to implement in NACHOS:
Some hints for this part of the project:
As a final test of your join function implement a solution to the following problem. In a bank you need two keys to open a safety deposit box. One is possessed by the customer who rents box and the other by the bank manager. Both the bank manager and the customer must be present for the box to be opened. When the box is opened then the bank manager must wait around until the customer is finished with the box. When the customer is finished with the box both the customer and the manager may go about their business. Code for this should be in the threadtest.cc file and should be run if you use a command line flag to nachos of the form nachos -P1TJ#.
To solve this problem:
For part 3 of the project you will need to turn in a complete design document for the Join operator (probably no more than 5 pages). You will need to briefly describe the implementation (the data structures and their uses) and testing of your join operator during the design review meeting. You also need to turn in a separate design document for the bank saftey deposit box test case (I would guess 2-3 pages should do it). You should plan to cover a subset of this material during your design review meeting. The electronic versions of your Nachos files will also need to be turned in so that I may test the Join operator with my own test files.
Under no circumstances should you modify any of the contents of the machine directory for any parts of this project. You can modify any of the files in the threads directory but you should make the minimal number of changes to prevent any unforeseen repercussions. I will be combining your threads directory with a clean copy of the machine directory to compile your submitted projects for testing.
You will turn in one set of electronic NACHOS files for the entire project (the threads directory). These files should support all of the functionality of parts 3, 4 & 5 of the project. NACHOS is an operating system after all and it must be able to do everything with one set of executables.
Implement semaphores, locks and condition variables in NACHOS. Some of the code for semaphores is given in the synch.h and synch.cc files. You will only need to implement the P() and V() functions to get a working semaphore class. Then use semaphores to implement the locks and condition variables. (Or you can implement them from scratch using Sleep() etc.) There are prototypes and many comments describing the public functions that you must implement for the locks and condition variables. You may not use busy waiting in the implementation of any of these synchronization mechanisms. The use of busy waiting will get 0 credit.
For the implementation of semaphores:
As a final test of the semaphores class that you implemented code a solution to the dining philosophers problem. (Note a solution is given in your book so you should be able to do this quickly to verify if your semaphores are working). You must ensure and justify that there is no possibility of deadlock or starvation in your solution. Code for this should be in the threadtest.cc file and should be run if you use a command line flag to nachos of the form nachos -P1ST#.
For the implementation of Locks:
For the implementation of Condition Variables:
Implement a solution to the bounded buffer producer / consumer problem using locks and condition variables. Each producer and each consumer are represented by an individual thread - so if you have 2 producers and 1 consumer you have three threads.
Implement a solution to the following problem using locks, condition variables and semaphores. You need to synchronize the flow of traffic over a narrow one lane light weight bridge. Traffic may only cross the bridge in one direction at a time and there may be no more than 3 cars on the bridge at any time (or it will collapse.)
Some particulars for the solution of this problem:
For part for of this project you need to turn in a design documents for each of the following:
Implement non-preemptive priority scheduling for threads in NACHOS. So every time the NACHOS scheduler is called it will pick the thread from the ready queue that has the highest priority.
Some specifics for this part of the project:
Some Hints for this part of the project:
For part 5 of the project you need to turn in a complete design document (approx. 4-5 pages). You will also need to discuss your design and testing of priority scheduling during the design review meeting. The solution to this part of the project should also be in the electronic version of the nachos files that you submit to me.
The design review meeting will be held outside of class time during the week after the project is due. Each group will have 1/2 hour to discuss and demonstrate that their project works. You need to discuss all parts of the project as indicated above. You will need to decide on the level of coverage for each part so that you can fit everything into the 1/2 hour time slot. I suggest that your group practice your meeting presentation at least once before the meeting for timing purposes. You will be strictly limited to 1/2 hour.
Part 2: Setting up the basic NACHOS system: (0%)
*** thread 0 looped 0 times
*** thread 1 looped 0 times
*** thread 0 looped 1 times
*** thread 1 looped 1 times
*** thread 0 looped 2 times
*** thread 1 looped 2 times
*** thread 0 looped 3 times
*** thread 1 looped 3 times
*** thread 0 looped 4 times
*** thread 1 looped 4 times
No threads ready or runnable, and no pending interrupts.
Assuming the program completed.
Machine halting!
Ticks: total 130, idle 0, system 130, user 0
Disk I/O: reads 0, writes 0
Console I/O: reads 0, writes 0
Paging: faults 0
Network I/O: packets received 0, sent 0
Cleaning up...
Part 3: NACHOS Threads Familiarity & the Join operator: (35%)
nachos -P1ST
Nachos should pass -P1ST to the ThreadTest function. Thread test can then decide what functions to call based upon the flag.
For example threadtest could use logic similar to:
if flag = "-P1ST" then SimpleThreadTest();
This way I can just put my ThreadTest.cc and ThreadTest.h into the threads directory that you submit and do a make to test your solutions with my test cases.
if flag = "-P1JT1" then JoinTest1();
if flag = "-P1JT2" then JoinTest2();
etc...
Part 4: Semaphores, Locks and Condition Variables (40%)
Car(int direction)
{
ArriveBridge(int direction);
Cross Bridge(int direction) {cout << "Car crossing bridge dir=" << direction};
ExitBridge(int direction);
}
Note: These design documents should each individually be fairly short. You shouldn't need more than 2-3 pages each. You will also need to discuss some subset of this information during your design review meeting. The electronic versions of your Nachos files will also need to be turned in so that I may test the Semaphores, Locks and Condition variable operators with my own test files.
Part 5: Scheduling Algorithms (15%)
The design review meeting
These pages designed and maintained by Grant Braught
Braught@Dickinson.edu