[CS Dept logo]

Com Sci 230

Homeworks for Spring 1998

Nachos Project #1
Due Wednesday 15 April 1998
Setup & Project Technique, Context Switch

Copyright information

Last modified: Sun Apr 12 11:27:46 CDT


Project #1 is due on Wednesday, 15 April, at 7:30 AM. The due time is chosen to encourage you to be done many hours before it. This is not the sort of thing to try to finish up at the last minute. I will be extremely busy with a conference 9-11 April, and out of town 12-14 April, so make sure that you bring problems to me before the 9th.

Basic goals

The real goals

In this introductory project, you will familiarize yourself with lab technique and tools for the more substantial later steps. You will use

You will also discover the rather subtle way that the thread scheduling and context switching work in Nachos. The steps in project #1 are small, and have nothing specially to do with making an operating system work. But, it is very important to be fluent in the silly little things so that they don't distract you from the real work later. Unless you have previous experience with systems programming, you will probably spend a lot of time on this assignment.

The postulated goals

The real point of this project is to practice for the real thing. But, for the sake of that practice, we'll postulate the following goals.

  1. Compile the entire Nachos code. (You will probably not achieve quite all of this, as described in Step 3 below.)
  2. Test the basic features of Nachos (Step 4 below).
  3. Modify the Nachos thread scheduler to provide more debug output (Step 5 below).
  4. Demonstrate and describe a mysterious behavior of the thread scheduler, uncovered by your new output.
  5. Work out the flow of control in thread scheduling and context switching with further debug output and a carefully crafted test run.
  6. Com Sci 330 only: Discover, demonstrate, and correct a minor bug in Nachos that leads to a space leak.
The program code that you need to write is very tiny. Nonetheless, this initial project can be a lot of work. The good news is that it will prepare you for the later, conceptually more substantial, assignments.

Step 1: Set up your work environment

  1. Get yourself a CS department instructional UNIX account.
  2. Choose an agreeable place to work, where you can reach classes.cs.uchicago.edu from a workstation running XWindows. You may use the SGI machines in the Ryerson 175 labs with your CS accounts.
  3. Open a Web browser, and use it to read these instructions as you do the project.
  4. Open a window with a UNIX shell on classes.cs.uchicago.edu. Use ssh to connect if at all possible: it has both speed and security advantages (type man ssh to find out more). If ssh is not available where you work, fall back on rlogin, rsh, or telnet.
  5. Get comfortable with shell interaction. If you need help, get the very short book Learning the UNIX Operating System and use it as a tutorial.
  6. Open a window with a good text editor operating on the classes file system. I prefer xemacs or emacs, but some swear by vi. The SGIs in Ryerson 175 are on the same file system as classes, so you can just run your favorite editor directly on these machines. If you are using an X workstation somewhere else, learn how to set the DISPLAY variable, so that an editor running on classes will display on your workstation. If remote X is too slow, these editors will also run in a login window. But, use two different windows for shell interaction and editing in any case.
  7. Execute man command and/or info for any command that you don't understand.
There are lots of different ways to customize your work environment to suit your own taste. Talk to your friends, and experiment.

Step 2: Set up your Nachos code directory

  1. Create your own Nachos code directory on classes. Call it ~/CS230/Nachos/code.
  2. Make your own personal copy of the entire Nachos source code. Take it from /usr/local/classes/current/CS230/01/Nachos/nachos-3.4/code, using cp -r.
  3. Give the command chmod -R u+w code to make your personal code writable.
  4. In your own code directory, give the command chmod go-rx. This will make your personal code directory a private place, readable only by you.

Step 3: Compile Nachos

  1. Go to your code directory, and execute gmake clean. This deletes everything except source code, so you are sure to start with executables that match the source. The code is already clean, so you'll get an error message saying ``no match.'' That's OK.
  2. Execute gmake -n | less, to see what operations gmake intends to do, without actually doing them. You won't get much out of the output this time, but it's a good habit to start. There will be error messages at the end, but go ahead anyway.
  3. Execute gmake >& gmlog1 &. This may take a few minutes, depending on the load. You can look at the output in gmlog1 at leisure. To check the progress, execute tail -f gmlog1.
  4. You will see a lot of compiler warnings. That's OK. The gmake will fail in the test directory. Fortunately, we don't need that part for a few weeks, so I have time to fix it. Whenever you change your Nachos code, you will run gmake again to automatically recompile only those items affected by your change.

Step 4: Run Nachos

  1. In your code directory, execute ls -l */nachos. You should see five different executable versions of nachos in five subdirectories. Run them. All of them should produce some short diagnostic output, except for network/nachos, which will hang until you kill it. Your real project work will involve changing Nachos code, recompiling these executable nachos commands, and demonstrating their behavior.
  2. Execute nachos -rs 47. The -rs option simulates pseudorandom interrupts, using the number that you provide as a seed. This is great for debugging, since the same random seed will produce the same interrupts. Try different seeds of your own choice. The impact of interrupts is not very exciting at this stage: no impact on some of the nachos versions, and a change in the number of ticks reported for others. It will get more interesting later.
  3. Execute nachos -d and observe the extra debugging information. Try threads/nachos -d | grep Yield.
  4. Check the Nachos documentation, and exercise any other interesting features that you notice.

Step 5: Modify Nachos

Now, you will modify threads/scheduler.cc to print more diagnostic information.

  1. Go to your code/threads directory, and check in scheduler.cc with RCS before you change it. Usually, you will need to do mkdir RCS, but I already did that because I had to fix Nachos for the Solaris system. Do ls -l RCS and you'll see that I already checked in Makefile and two other files. Do ci -l scheduler.cc. ci will prompt you for a comment. You can safely skip this comment (type a period followed by return), since it is just a general description of the file. Then, do ls -l RCS again to see that you have checked in scheduler.cc.
  2. Open scheduler.cc in your editor. Find a call to SWITCH(oldThread, nextThread), followed by a DEBUG command printing out currentThread. Add a pair of comments just after this DEBUG command, of the form
    // New from your name
    
    // End your name
    
    Throughout the project, mark every change that you make to a Nachos with similar marks (or ``Modified by your name'' if you change old code instead of adding new code). This is important for your lab technique, and also I will only evaluate the work that you mark in this way.
  3. Make two copies of the DEBUG command inside your marks. Modify them to print out oldThread and nextThread, with appropriate identifying text. Usually, you will add a comment describing the impact of such a change, but in this case the DEBUG commands are self-documenting.
  4. Execute gmake again in your code directory. Find the line in its output indicating that threads/scheduler and threads/nachos were recompiled. Go back to code/threads and do ls -l, noticing what has and hasn't changed.
  5. Run threads/nachos with and without the -d option. Look at the diagnostic output from your new DEBUG commands. You should be puzzled. They are not what the C source code in scheduler.cc suggests.
  6. When you have succeeded in compiling and testing your change, go to code/threads and do ci -l scheduler.cc again. This time, type in a comment, such as, ``Added debug output of oldThread and nextThread after the context switch.'' It is very important to form a habit of checking in with RCS after every small change.
  7. Try out rlog scheduler.cc and rcsdiff scheduler.cc with various options to see what sort of information RCS offers you. My recommended form of check-in, ci -l, checks the file out again. If you goof up the check-in, you will need to learn about the check-out command, co. If you goof up the code files, and need to unwind from an error, you will need to read the manual pages for RCS, ci, and co very carefully.
  8. Add more DEBUG commands in strategic places to illuminate the flow of control in context switching. Use the character flag `c' (for context switch to enable these new DEBUG commands. Don't modify switch.s, but trace back from the call to SWITCH in scheduler.cc. Look at my guide to reading the Nachos source for help. You should definitely add DEBUG commands to scheduler.cc and to thread.cc.
  9. Create a new test program to display the context switch more efficiently than threadtest.cc does. In this case, do not modify threadtest.cc. Instead, copy threadtest.cc to a new file, such as switchtracetest.cc, and modify the new file to suit. When you first check in the new file to RCS, provide a comment of the form ``Initialized from threadtest.cc.'' Give the functions in your new files new names, of course.
  10. Run gmake again, just to be sure that your new material compiles. By now, you are probably tired of watching the voluminous output from gmake in your code directory. The Makefiles in Nachos are organized so that you can make a single directory by executing gmake in that directory (don't assume that this works for all code distributions). But, you need to set things up for switchtracetest.cc, and the right way is a bit delicate. code/threads/Makefile is generated automatically, and you should not change it. Rather, look at code/Makefile.common. Notice how threadtest.cc and threadtest.o are mentioned there. Add switchtracetest.cc and switchtracetest.o in analogous form (of course, you checked in code/Makefile.common with RCS first). Execute gmake depend in code/threads to update code/threads/Makefile, and then execute gmake to compile your new code. Whew.
  11. Run nachos again. Nothing changed, because your new test program didn't get invoked.
  12. Look at threads/main.cc, and notice the call to the function ThreadTest(). You need to change main.cc to call your new function (I called mine TraceSwitch). But, you want to do this without losing the old possibilities of ThreadTest. Notice the conditional compilation of the call to ThreadTest:
    #ifdef THREADS
        ThreadTest();
    #endif
    
    Run grep THREADS Make* to find out where THREADS is defined. Look at the output from gmake, and notice how the definition of THREADS gets into the command that compiles main.cc. You need to do something similar to choose between ThreadTest and TraceSwitch. I chose a variable called SWITCHTRACE, and created the following nested conditional:
    #ifdef THREADS
    #ifdef SWITCHTRACE
        TraceSwitch();
    #else
        ThreadTest();
    #endif
    #endif
    
    We are still essentially concerned with threads, so we don't want to disable THREADS, in case some other code depends on it (now or in the future). Our final problem is to define SWITCHTRACE for next compile. Look again at the way SWITCHTRACE is defined in the Makefile. It's best not to change the Makefile itself, but we can override variable settings when running gmake. gmake DEFINES="-DTHREADS -DSWITCHTRACE" will do it.
  13. Well, gmake DEFINES="-DTHREADS -DSWITCHTRACE" probably had no impact, because a mere change in command-line parameters doesn't trigger recompilation. The -W option to gmake is supposed to deal with this problem, but it doesn't appear to work. So, do touch main.cc to mark main.cc as recently changed, and then do your gmake.
The method above for incorporating a minor change to main.cc probably looks ridiculously convoluted. There is probably a somewhat more elegant method (in particular, we shouldn't have to repeat the definition of THREADS when adding SWITCHTRACE on the command line), and I hope someone will find it and post it. But, the lazy methods, such as just typing the right compiler command directly, are a big mistake for the long run. All that work was not really to make the tiny change to the nachos command. Rather, it was to record the information about a new variation on the nachos command in a form that will interact nicely with other changes that we decide to make later. That is an inherently delicate problem, and that's what the code management problem is all about.

Com Sci 330 only: find and fix the ``undead thread'' problem

By a combination of studying the Nachos code, reading my guide to the code, and running interesting test cases with enlightening debug output, understand the somewhat subtle way in which Nachos removes a thread that has Finished. Discover and demonstrate a subtle bug that sometimes leaves a Finished thread forever in an ``undead'' state (a similar problem happens in UNIX sometimes). The problem occurs when one thread tries to Finish, the next thread is brand new and it Finishes in its first period of execution. Explain the consequences of this bug (they are not usually disastrous, but they can be modestly harmful). Correct the bug, by replicating a small bit of code that needs to appear twice, but only appears once. Demonstrate the behavior of your correcton.

My guide to Nachos code discusses this problem in some detail.

Step 6: Demonstrate your work

Although most people find this counterintuitive, merely getting a computer program to work is less important than demonstrating its behavior to other people. A large part of my evaluation of your project work will depend on your demonstrations. I may occasionally provide test data for input, but designing your own tests is a crucial part of each project assignment. For this preliminary assignment, there isn't much to demonstrate, but we'll go through the motions anyway, to practice for the real thing.

  1. In your code directory, create a subdirectory named Project_1_tests. Put in this directory all supporting materials for your demonstration, particularly files of test input (file-name.in) and the corresponding output (file-name.out).
  2. In your code directory, create a file named project_1_notes.txt. This is the first file that I will look at, and I will expect it to lead me to all other interesting material.
  3. In project_1_notes.txt provide the following 3-4 sections:
    1. A brief statement of the project goals, and what you achieved.
    2. A brief explanation of the changes and additions that you made to Nachos code. This section must contain explicit references to the files that you changed and added. List the changed and added files in an index at the end of the section.
    3. A demonstration of what you accomplished. This section must contain precise instructions that will lead me through the demonstration. Prepare sample inputs in separate files. Provide in this section the commands that I can execute to observe the demonstration. I will execute the commands by cutting and pasting directly from your instructions. After each command that I should execute, describe briefly what we learn from the output.
    4. Optional discussion of your conclusions and observations.
Designing good demonstration inputs is one of the hardest and most important parts of project work. This introductory project is too trivial to provide much practice in that line, but please start thinking about the problem for future project work. Voluminous inputs are not usually helpful. Rather, you need test cases that I can read, which will lead me very efficiently to understand your code. Think of the demonstration inputs as supplements to code reading, not as stand-alone tests.

Step 7: Submit your work

Revised on Sunday 12 April

When you have a coherent, documented version of your project work, run the command /usr/local/classes/current/CS230/01/bin/submit-project Project_1. This command copies your work to a directory where I can evaluate it. You may resubmit as often as you like before 7:30 AM on Wednesday 15 April. Each new submission will wipe out the previous one, and I will only evaluate the last one. I suggest that you submit well organized, but incomplete, results several times along the way. With this strategy, you can reduce last-minute panic, since you'll only be risking the latest improvements, and not all of the early work. But, please do not submit work without the required internal documentation and explanation. That is, submit work that is incomplete in project functionality, but not work that is incomplete in organization.

Soren Dayton (csdayton@cs) created the submit-project command, and he needs to install it in the directory that I mentioned. He will post final instructions when the installation is done. Contact him by e-mail with minor problems. If there are serious problems with the procedure, I will deal with them on Wednesday, and will not penalize anyone for lateness due to the submission procedures.