Docsity
Docsity

Prepare for your exams
Prepare for your exams

Study with the several resources on Docsity


Earn points to download
Earn points to download

Earn points by helping other students or get them with a premium plan


Guidelines and tips
Guidelines and tips

Nachos Project: Implementing Locks and Condition Variables for Synchronization, Study Guides, Projects, Research of Operating Systems

A project for the comp310 course where students are required to complete a thread system in nachos by implementing locks and condition variables. The goal is to ensure that properly synchronized code works correctly regardless of the order the scheduler chooses to run threads. Students are also expected to write test cases for their code and test for various error conditions.

Typology: Study Guides, Projects, Research

Pre 2010

Uploaded on 08/18/2009

koofers-user-xag
koofers-user-xag 🇺🇸

10 documents

1 / 5

Toggle sidebar

This page cannot be seen from the preview

Don't miss anything!

bg1
COMP310: Nachos Project #1: Build a thread system
Due: Wednesday, Oct 13, 2:10pm
In this assignment, we give you part of a working thread system; your job is to complete it, and then to use
it to solve several synchronization problems.
Project 0 helped you understand the thread system in Nachos, so now you should be good to go. :)
The files for this assignment are:
main.cc, threadtest.cc a simple test of our thread routines.
thread.h, thread.cc thread data structures and thread operations such as thread fork, thread sleep and
thread finish.
scheduler.h, scheduler.cc manages the list of threads that are ready to run.
synch.h, synch.cc synchronization routines: semaphores, locks, and condition variables.
list.h, list.cc generic list management (LISP in C++).
synchlist.h, synchlist.cc synchronized access to lists using locks and condition variables (useful as an
example of the use of synchronization primitives).
system.h, system.cc Nachos startup/shutdown routines.
utility.h, utility.cc some useful definitions and debugging routines.
switch.h, switch.s assembly language magic for starting up threads and context switching between them.
interrupt.h, interrupt.cc manage enabling and disabling interrupts as part of the machine emulation.
timer.h, timer.cc emulate a clock that periodically causes an interrupt to occur.
stats.h collect interesting statistics.
Properly synchronized code should work no matter what order the scheduler chooses to run the threads
on the ready list. In other words, we should be able to put a call to Thread::Yield (causing the scheduler
to choose another thread to run) anywhere in your code where interrupts are enabled without changing
the correctness of your code. You will be asked to write properly synchronized code as part of the later
assignments, so understanding how to do this is crucial to being able to do the project.
To aid you in this, code linked in with Nachos will cause Thread::Yield to be called on your behalf in a
repeatable but unpredictable way. Nachos code is repeatable in that if you call it repeatedly with the same
arguments, it will do exactly the same thing each time. However, if you invoke “nachos -rs #”, with a
different number each time, calls to Thread::Yield will be inserted at different places in the code.
1
pf3
pf4
pf5

Partial preview of the text

Download Nachos Project: Implementing Locks and Condition Variables for Synchronization and more Study Guides, Projects, Research Operating Systems in PDF only on Docsity!

COMP310: Nachos Project #1: Build a thread system

Due: Wednesday, Oct 13, 2:10pm

In this assignment, we give you part of a working thread system; your job is to complete it, and then to use it to solve several synchronization problems.

Project 0 helped you understand the thread system in Nachos, so now you should be good to go. :)

The files for this assignment are:

main.cc, threadtest.cc — a simple test of our thread routines.

thread.h, thread.cc — thread data structures and thread operations such as thread fork, thread sleep and thread finish.

scheduler.h, scheduler.cc — manages the list of threads that are ready to run.

synch.h, synch.cc — synchronization routines: semaphores, locks, and condition variables.

list.h, list.cc — generic list management (LISP in C++).

synchlist.h, synchlist.cc — synchronized access to lists using locks and condition variables (useful as an example of the use of synchronization primitives).

system.h, system.cc — Nachos startup/shutdown routines.

utility.h, utility.cc — some useful definitions and debugging routines.

switch.h, switch.s — assembly language magic for starting up threads and context switching between them.

interrupt.h, interrupt.cc — manage enabling and disabling interrupts as part of the machine emulation.

timer.h, timer.cc — emulate a clock that periodically causes an interrupt to occur.

stats.h – collect interesting statistics.

Properly synchronized code should work no matter what order the scheduler chooses to run the threads on the ready list. In other words, we should be able to put a call to Thread::Yield (causing the scheduler to choose another thread to run) anywhere in your code where interrupts are enabled without changing the correctness of your code. You will be asked to write properly synchronized code as part of the later assignments, so understanding how to do this is crucial to being able to do the project.

To aid you in this, code linked in with Nachos will cause Thread::Yield to be called on your behalf in a repeatable but unpredictable way. Nachos code is repeatable in that if you call it repeatedly with the same arguments, it will do exactly the same thing each time. However, if you invoke “nachos -rs #”, with a different number each time, calls to Thread::Yield will be inserted at different places in the code.

For each section, part of your assignment will be to create test cases for your code. You will be graded on whether or not you test that your code works correctly on a wide range of cases. This score will be independent of whether or not your code actually works on these cases. So even if your code does not work for a given case, you should still illustrate what your code does on that case. See the notes at the end for advice on how to incorporate these test cases into the nachos program.

Warning: in our implementation of threads, each thread is assigned a small, fixed-size execution stack. This may cause bizarre problems (such as segmentation faults at strange lines of code) if you declare large data structures to be automatic variables (e.g., “int buf[1000];”). You will probably not notice this during the semester, but if you do, you may change the size of the stack by modifying the StackSize define in switch.h.

Although the solutions can be written as normal C routines, you will find organizing your code to be easier if you structure your code as C++ classes. Also, there should be no busy-waiting in any of your solutions to this assignment.

  1. [15 pts] Implement locks and condition variables. You may either use semaphores as a building block, or you may use more primitive thread routines (such as Thread::Sleep). We have provided the public interface to locks and condition variables in synch.h. You need to define the private data and imple- ment the interface. Note that it should not take you very much code to implement either locks or condition variables. [10 pts (for defensive implementation and correct error tests)] You should write your code ”defen- sively” in the sense that you should make an attempt to detect error conditions and react appropriately. For error conditions that could result in a race condition or deadlock, your library routines should exit
    • there is no way to recover from these errors, so they should be fatal to the program. There is a convenient macro ASSERT() that you can use to check for error conditions and abort if necessary (grep through the Nachos source code files for examples of how to use it). To help motivate you to get into the habit of testing for error conditions, write test programs that test for the following errors: (1) acquiring the same Lock twice, (2) releasing a Lock that isn’t held, (3) deleting a Lock that is held, (4) waiting on a condition variable without holding a Lock, (5) signaling a condition variable wakes only one thread and broadcasting wakes up all threads, (6) signaling and broadcasting to a condition variable with no waiters is a no-op, and future threads that wait will block (i.e., the signal/broadcast is ”lost”). These are the minimal set of error conditions for which we’ll test your Lock and Condition implementations.
  2. [15 pts] Implement Thread::Join(). Two threads are involved in Join; for the sake of intuition, let’s call them the parent and the child. At a high level, Join enables the parent thread to wait for the child thread to finish. To do this, the parent thread is the one that invokes Join, and it invokes it on the child: (executing as the parent thread)

Thread *child = new Thread("child", 1); child->Fork(SomeProcedure, SomeArgument); ... child->Join(); // parent blocks until child terminates

To implement Join, start by adding a parameter to the thread constructor to indicate whether or not Join will be called on this thread, and then implement the new Join method. Use the following signatures for the updated constructor and Join method:

making this up!). Your job is to write the three procedures Male(), Female(), and Matchmaker() using semaphores. Each whale is represented by a separate thread. A male whale calls Male(), which waits until there is a waiting female and matchmaker; similarly, a female whale must wait until a male whale and a matchmaker are present. Once all three are present, all three return. [3pts] Write test cases to show that the conditions above are met for different combinations of whales arriving in different orders.

(Note below based on notes by Dr. Glick)

The Makefiles in nachos are somewhat complicated, and you want to change them as little as possible.

This programming project has you writing two applications that will run on top of nachos (the mating whales problem and the bridge crossing problem). The other parts of the project (implementing locks and condition variables, writing the Thread::Join() function) do not involve creating a new application.

So here is what you should do: Go into the main.cc file in the threads directory, and where ThreadTest() is called write a short loop that presents the user with a menu of choices. By the time you finish the first project, the choices will be ThreadTest(), miscTest(), whaleTest(), and bridgeTest() - or some such names for your functions. ThreadTest() should run the same test that nachos now runs; miscTest should illustrate the implementation of parts 1 and 2 of this assignment; whaleTest() should illustrate your solution to the mating whales problem; and bridgeTest() should illustrate your solution to the bridge problem. You can then write whatever .cc and .h files you need to implement the applications.

To compile and link nachos with your code, go up one directory and edit the Makefile.common file by adding whatever .cc files you have created to the definition of THREAD C, whatever .h files you have created to the definition of THREAD H, and for each .cc file add an entry in the definition of THREAD O. Then go back into the threads directory and type ”gmake depend”. This will create a new Makefile in the threads directory. Type ”gmake” and gmake will try to build your program. Each time you want to rebuild nachos, just type ”gmake” in the threads subdirectory again. Of course, each time you add new files, you will have to repeat the above process of editing the Makefile.common file.

Part of your grade in each section involved coming up with a test set to demonstrate that your code works correctly. For each of your test cases, you may want to write a separate driver. For example, in the mating whales application, in one driver you might start 2 female, and then two males, and finally a matchmaker. Choose a minimal but complete set of test drivers to convince yourself (and me) that your program works. The main application function (for example, whaleTest()) should present the user with a menu to select from among the different test drivers that you have written. So when I run the nachos program in your directory I should be able to select an application and then a particular test in that application.

All this menu stuff I am having you do is to keep just one executable file (called nachos) in the threads directory. This way, you do not have to mess around with the Makefile.common too much, and I do not have to keep track of lots of executables.

When you have finished your project, you should create two more files and leave them in the threads sub- directory. The first is called README, and it should contain a written outline of what you did for the assignment, explaining and motivating your design choices (design choices for the classes you created and design choices for the application you wrote). Keep this short and to the point. Some problems have parts

that ask you to explain something about your design; this explanation should also go in the README file.

The second extra file to include should be called TESTCASES, and it should contain the results of the test cases that you run. Include with the results an explanation of what each test case is supposed to show.

When your project is ready to grade, do the following: 1) Tell me which class account your project is in, and make sure I have the password to it. 2) Make sure that I can get to the threads directory by just typing ”cd code/threads”. So don’t change the directory structure of nachos. 3) I will rebuild all of the nachos code by typing ”gmake clean” and then ”gmake” in the code directory. Make sure that this works. 4) Turn in to me a printout of all the code that you have written or changed for this project (highlighting any new or changed code), plus the README and TESTCASES files that I describe above.

Your grade on the project will be based on 1) your program and class design (this includes your descrip- tion in the README file), 2) your program implementation (is your implementation correct, simple and straightforward), and 3) your selection of testcases and your presentation and discussion of them in your TESTCASES file. (The points awarded for testcases are specified with each problem).

I would like to know the author of the different pieces of your project. In the source code, every file and every function should have an author indicated. Because I encourage you to do pair programming, it’s best if both your names are on all the code. :) You should also indicate authorship of the parts of the README and TESTCASES files.

Late projects will lose 15% per day or fraction thereof, up to a maximum of 3 days. After 3 days I will not accept the project and you will receive no credit. It is almost always to your advantage to turn in whatever you have by the due date.

I will be setting up individual meetings with groups on October 7th and 8th. These meetings will be between 15 and 30 minutes long. You will be responsible for giving me a status report on how you have implemented or plan to implement each problem. This is your chance to get help with any problems you have encountered as you begin implementation. You do not have to have completed all the problems, but you should have at least looked at all of them and have an idea of how you will solve them. This status report will be worth 5 points.

Start early and come see me with questions!