Hello, dear friend, you can consult us at any time if you have any questions, add WeChat: daixieit

CS 471/571 Operating Systems

Spring 2023

Programming Assignment 1 (PA1)

Due date for Part 1: Friday, March 10, 11:59 pm

Due date for Part 2: Wednesday, March 29, 11:59 pm

1. Introduction

We finished the discussion of threads and general synchronization in class, and you became familiar with the basic OS/161 environment in the first assignment (PA0).  In this assignment you will implement synchronization primitives for OS/161 and learn how to use them to solve a synchronization problem.      Once you have completed the written and programming exercises you should have a fairly solid grasp of the pitfalls of concurrent programming and synchronization.

This project has two parts with two distinct deadlines: Part 1 is due by March 10 and it consists ofyour answers to code reading questions, declaration of your project partner (if any), and a short progress report. Part 2 is due by March 29 and it consists of your coding solutions (the programming part) and a design     document.

To complete this assignment, you will need to be familiar with the OS/161 thread code. The thread system provides interrupts, control functions, and semaphores.

Note that in addition to developing non-trivial synchronization code in C, you will need to again do some code reading and directory exploring in OS/161. This is normal. Considering that debugging synchronization programs requires also more time, make sure to allocate sufficient time from the beginning – if you start just a few days before the due date, you are likely to experience significant difficulties.

Working with partner

In this assignment you can - and you are ENCOURAGED to - work with a partner: another CS 471/571   student from your own section. No team can have more than two members.  If you have worked alone in Project 0, you can form a team with another CS 471/571 student who worked alone in Project 0. You can also continue to work with the same partner you worked with in Project 0 (however, you cannot switch to a new partner). If believe you can finish it without a partner, you are welcome to work alone; but there will not be any bonus points for those working alone, and you should keep in mind that the assignment specification has been developed assuming that two students will actively interact and cooperate in exploring OS/161 and developing a synchronization program.

2. Begin your assignment

Copy necessary files

For this assignment, you need to replace three ofyour existing files as follows:

The updated versions of these files can be found in the /usr/local/shared/cs471/PA1 directory on Zeus.

1. cd ~/os161/os161-1.11/kern

2. cp /usr/local/shared/cs471/PA1/menu.c main/

3. cp /usr/local/shared/cs471/PA1/test.h include/

4. cp /usr/local/shared/cs471/PA1/stoplight.c asst1/

You must replace these three files accurately before you start coding the solution.

Tag your Git Repository

Before you do any real work on this assignment, tag your Git repository. The purpose of tagging your repository is to make sure that you have something against which to compare your final tree. Make sure  that you do not have any outstanding updates in your tree. Use git commit to get your tree committed in the state from which you want to begin this assignment.

% git commit -am "End of project-0"

% git push

Now, tag your repository as shown below.

% cd ~/os161/os161-1.11

% git tag asst1-begin

NOTE 1: Tags are not pushed to remote GitLab repo by default. This means if you work in a group on this project, you and your partner both need to run git tag asst1-begin”  separately.

NOTE 2: If you are working with a partner, you may want to set up the GitLab repository so that it may be accessed by both members ofyour group. In case you have not setup GitLab, the instructions for the initial setup can be found here:

https://mason.gmu.edu/~zan2/gitlab_setup.html

Configure OS/161 for ASST1

We have provided you with a framework to run your solutions for ASST1. This framework consists of driver code (found in kern/asst1/stoplight.c) and menu items that can be used to execute the solutions  from the OS/161 kernel boot menu.

You have to reconfigure your kernel before you can use this framework. The procedure for configuring a kernel is the same as in ASST0, except you will use the ASST1 configuration file:

% cd ~/os161/os161-1.11/kern/conf

% ./config ASST1

You should now see an ASST1 directory in the compile directory.

Building for ASST1

As in PA0, in order to build kernel, you have two options. You can use the php file provided by the TA or use the alternative method. Before starting any of the methods, make sure to issue the module load command

% module load sys161/2.0.8

IMPORTANT:  You should remember to issue the module load command above every time you logon to zeus when you intend to work on os161!  (the command will only work on zeus.vse.gmu.edu).

First method: This is based on running a script provided by the TA. Give the following command to get the script file.  The scripts folder should exist after following the steps for PA0.  If not, you can create it.

% cd ~/os161

% cd scripts

% cp /usr/local/shared/cs471/scripts/build-asst1.php .

Then run this php file in your scripts directory by typing

% php build-asst1.php

Warnings and Errors in the build will be output to ~/os161/scripts/os161_errors.txt Or as the second method, you can run make from compile/ASST1.

% cd os161-1.11

% ./configure --ostree=$HOME/os161/root

% cd kern/conf

% ./config ASST1

% cd ~/os161/os161-1.11/kern/compile/ASST1

% make depend

% make

% make install

Command Line Arguments to OS/161

Your solutions to ASST1 will be tested by running OS/161 with command line arguments that correspond to the menu options in the OS/161 boot menu. IMPORTANT: DO NOT change the menu option strings!

"Physical" Memory

In order to execute the tests in this assignment, you will need more than the 512 KB of memory configured into System/161 by default. We suggest that you allocate at least 2MB of RAM to System/161. This configuration option is passed to the busctl device with the ramsize parameter in your sys161.conf file (located under ~/os161/root/) . Make sure the busctl device line looks like  the following:

31 busctl ramsize=2097152    (Note: 2097152 bytes is 2MB).

3. Concurrent Programming with OS/161

If your code is properly synchronized, the timing of context switches and the order in which threads run should not change the behavior of your solution. Of course, your threads may print messages in different orders, but you (and we!)  should be able to easily verify that they follow all of the constraints applied to them and that they do not deadlock.

Built--in thread tests

When you booted OS/161 in ASST0, you may have seen the options to run the thread tests. The thread test code uses the semaphore synchronization primitive. You should trace the execution of one of these    thread tests in GDB to see how the scheduler acts, how threads are created, and what exactly happens in a context switch. You should be able to step through a call to mi_switch() and see exactly where the current thread changes.

Thread test 1 ( "tt1" at the prompt or tt1 on the kernel command line) prints the numbers 0 through 7 each time each thread loops. Thread test 2 ("tt2") prints only when each thread starts and exits. The latter is intended to show that the scheduler doesn't cause starvation -- the threads should all start together, spin for a while, and then end together.

Debugging concurrent programs

thread_yield() is automatically called for you at intervals that vary randomly. While this randomness is fairly close to reality, it complicates the process of debugging your concurrent programs.

The random number generator used to vary the time between these thread_yield() calls uses the  same seed as the random device in System/161. This means that you can reproduce a specific execution sequence by using a fixed seed for the random number generator. You can pass an explicit seed into random device by editing the "random" line in your sys161.conf file.

For example, to set the seed to 1, you would edit the line to look like:

28 random seed=1

OS/161 uses this random number generator to randomly vary the timing of the context switches, to allow for some randomness in the scheduling.  Even with the same seed, the time you spend in the menu will

make a very large number of calls to the random number generator, which means if you run the system normally, your seed will not appear to give you the same results every time you run your stoplight

program.

To address this, if you are using a fixed seed, you will need to run the OS/161 by launching your stoplight program immediately, bypassing the menu.  To do this, simply execute the following from your                ~/os161/root directory:

% sys161 kernel 1c

This command will run the stoplight program (test 1c) without spending any time in the menu, giving you a deterministic set of random selections using your fixed seed.  This also implies that if you wish to run    your stoplight program again with the same seed, you will need to quit OS/161 and re-launch it with this  command.

We recommend that while you are writing and debugging your solutions you pick a seed and use it consistently. Once you are confident that your threads do what they are supposed to do, set the random device to autoseed. This should allow you to test your solutions under varying conditions and may  expose scenarios that you had not anticipated.

4. Part 1 (15 points)

Code reading

Please answer the following questions and save your answers in a file named code-reading.txt” .

To implement synchronization primitives, you will have to understand the operation of the threading  system in OS/161. It may also help you to look at the provided implementation of semaphores. When you are writing solution code for the synchronization problems it will help ifyou also understand exactly what the OS/161 scheduler does when it dispatches among threads.  Place the answers to the following questions in code-reading.txt.

Thread Questions

1. What happens to a thread when it exits (i.e., calls thread_exit())? What about when it sleeps?

2. What function(s) handle(s) a context switch?

3. What does it mean for a thread to be in each of the possible thread states?

4. What does it mean to turn interrupts off? How is this accomplished? Why is it important to turn off interrupts in the thread subsystem code?

5. What happens when a thread wakes up another thread? How does a sleeping thread get to run again?

Scheduler Questions

6. What function is responsible for choosing the next thread to run?

7. How does that function pick the next thread?

8. What role does the hardware timer play in scheduling? What hardware independent function is called on a timer interrupt?

Synchronization Questions

9. Describe how thread_sleep() and thread_wakeup() are used to implement semaphores. What is the purpose of the argument passed to thread_sleep()?

10. Why does the lock API in OS/161 provide lock_do_i_hold(), but not lock_get_holder()? Once you finish the code reading questions, create a second file named progress-report.txt”

In that file, first give the full names and G numbers of the team members who decided to collaborate in   project PA1 (see the “Working with a partner” paragraph in Section 1 of the hand-out for the rules governing partner selection).  Then, in the same file, give a short (around one-page) summary of the        progress you made on the design and coding part of your project. Do not provide any code; just summarize your efforts. While you are not required to submit any code in Part 1, you are expected to     begin thinking about overall design and also start coding – implementation of the locks could be a good  target. In the progress report, you should summarize your efforts towards that goal (for example, you can describe your efforts towards implementing/testing locks.)

Finally, briefly explain the responsibilities of the team members in Part 2 of the project (the coding part). Failure to submit the progress report may result in deduction of points.

You can work with a partner in Part 2 (Coding Part) below only if that student’s name is explicitly stated in Part 1 submission in a timely manner.

Submission of Part 1:

Create a directory called asst1-part1’, inside the ‘~/os161/’ directory.

% cd ~/os161/

% mkdir asst1-part1

When both code-reading.txt andprogress-report.txt files are ready, put these two files in it. Next, tar and compress your asst1-part1 directory.

% cd ~/os161

% tar -czf uid1_uid2-asst1-part1.tar.gz asst1-part1

You should replace uid1 and uid2 with you and your partner's GMU email IDs. If you are working alone, the last line should read tar -czf uid-asst1-part1.tar.gz. Submit the compressed     Part 1 file on Blackboard. All members of a group must submit separately the same compressed file, and before the Part 1 deadline 3/10 11:59 PM . Make sure to coordinate.  Make sure to double check that you are submitting the correct file  -- if you submit wrong, corrupt, or empty file you are likely to get zero.

Late penalty for Part 1 will be 15% for each day. Submissions made on March 13 or later will not get credit. Please plan in advance.

You can make multiple submissions; we will consider ONLY the last submission that you make: so in case you need to re-submit, make sure the compressed file contains all the components listed above.

Note: The contents of Part 1 should be submitted separately from Part 2, and in a timely manner.

5.  Part 2 - Coding  Solution and Design Document (85 points)

Synchronization Primitives (20/85 Points)

Implement (mutual exclusion) locks for OS/161. The interface for the lock structure is defined in kern/include/synch.h. Stub code is provided in kern/thread/synch.c. You can use the implementation of semaphores as a model, but do NOT build your lock implementation on top of  semaphores; your code should not use semaphores (or condition variables) in any way (i.e., do not call    any semaphore or cv functions in your lock implementation). The stub code also contains code templates for condition variables; you should ignore those parts.

Solving the Synchronization Problem (55/85 Points)

The following problem will give you the opportunity to write some fairly straightforward concurrent  programs and get a more detailed understanding of how to use threads to solve problems. We have  provided you with basic driver code that starts a predefined number of threads. You are responsible for    what those threads do. Remember to specify a seed to use in the random number generator by editing       your sys161.conf file. It is much easier to debug initial problems when the sequence of execution and context switches is reproducible.

Please note: Since the kernel calls the lock functions during boot-up, if you have a partial implementation, or have an error in your lock implementation, the kernel may either hang or terminate early without menu input options.  This is probably happening because ofyour lock implementation.  You need to complete/fix your lock implementation first.

When you configure your kernel for ASST1, the driver code and extra menu options for executing your    solutions are automatically compiled in. For example, you will see an option for “lock variables”; you can choose that option to see if your lock implementation is correct or not.  Similarly, by invoking the

“stoplight.c” option (typing “1c”) in the menu, you can run an initial test for your driver code  stoplight.c implementation (The grader is likely to run additional tests; but you can consider these   as initial tests).  Note: typing '?t' on the kernel command line will show the full test list in os161 and then use 'sy2' on the kernel command line to test your lock implementation. You can ignore the elapsed time’ information displayed by those tests.

If your lock implementation is correct, the ‘sy2’ command will print ‘lock test done’ along with the elapsed time, but without any garbled characters.  If you see garbled characters in the output of ‘sy2’, that means there is an error in your lock implementation.

Synchronization Problem: Traffic Management at Podunk

You must solve this problem using the locks that you implemented above along with

thread_sleep() and thread_wakeup ()functions.

Other solutions (condition variables, semaphores, etc.) are not acceptable.

Your solution shouldnt use busy waiting either.

Traffic through the main intersection in the town of Podunk, KS has increased over the past few years.   Until now the intersection has been a three-way stop but now the impending gridlock has forced the       residents of Podunk to admit that they need a more efficient way for traffic to pass through the                intersection. Your job is to design and implement a solution using the synchronization primitives (locks) that you have developed in the previous part.

Modeling the intersection

 

For the purpose of this problem we will model the intersection as shown above, dividing it into three         portions (AB, BC, CA) and identifying each portion with the names of the lanes entering/leaving the         intersection through that section. (Just to clarify: Podunk is in the US, so we're driving on the right side of the road.) Turns are represented by a progression through one or two portions of the intersection (for         simplicity assume that U-turns do not occur in the intersection). So if a car approaches from Route-A,       depending on where it is going, it proceeds through the intersection as follows:

●    Right: AB

●    Left: AB-BC

In addition to Cars”, there are also Trucks” in Podunk. Trucks have a lower priority than cars when        entering the intersection. If a lane in a given route has both cars and trucks in it, then the cars should cross the intersection before the trucks in that route. When no more cars are waiting, then the trucks on that lane can cross the intersection. It is fine if some trucks suffer starvation (i.e., cross last). Note that, cars have    higher priority than trucks approaching the intersection through the same route (Route-A, Route-B, or       Route-C). For example, if there are six vehicles (four cars and two trucks) approaching the intersection     through Route-A, the two trucks should not start to cross before any of the four cars.

Before you begin coding, answer the follow questions in a file named exercises.txt (to be submitted in Part 2, along with your code):

1.   Assume that the residents of Podunk are exceptional and follow the old (and widely ignored)   convention that whoever arrives at the intersection first proceeds first. Using the language of   synchronization primitives describe the way this intersection is controlled. In what ways is this method suboptimal?

2.   Now, assume that the residents of Podunk are like most people and do not follow the convention described above. In what one instance can this three-way-stop intersection produce a deadlock?   (It will be helpful to think of this in terms of the model we are using instead of trying to visualize an actual intersection).

Implementing your solution

The file you are to work with is in ~/os161/os161-1.11/kern/asst1. Ignore catsem.c and catlock.c. You only need to work with stoplight.c

We have given you the model for the intersection. The following are the requirements for your solution:

●    Each vehicle approaches” the intersection when the corresponding thread is created,  it enters” the intersection when the conditions are right for it to proceed (see below),  and after crossing the intersection, it  “leaves” . No two vehicles can be in the same portion of the intersection at the     same time. (In Podunk they call this an accident).

●     Cars have a higher priority than trucks. Before proceeding to (entering) the intersection, the        trucks in a given lane must wait until all cars (which have already approached) on that lane have entered the intersection.

●    Your solution must improve traffic flow without allowing traffic from any direction to starve       traffic from any other direction. However, as per the spec, the trucks are supposed to proceed last in a given lane and that is how you should implement (i.e., extended waiting experienced by the  trucks in the presence of cars is not a problem).

●     For full credit, your solution should maximize concurrency across threads and should not impose  unnecessary delays not imposed by the constraints given above. For example, while a vehicle X is crossing the intersection, it should not unnecessarily delay the entry of another vehicle                  (approaching from the same route or different route) to the intersection if the other constraints of the problem are not violated. Similarly, having the vehicles cross the intersection one by one is not acceptable.

●    A truck must not wait for cars which have not approached yet (because this will incur                    unnecessary delay.) A truck can (and should) enter the intersection if its path does not cause a car to get delayed. A truck should not wait for any future” cars which have not yet approached the   intersection. In other words, generating all the vehicles approaching a given lane first, putting      them in priority order (cars first), and only then allowing the vehicles to proceed to the                  intersection is not acceptable.

●     Each vehicle should print a message as it approaches, enters, and leaves the intersection                indicating the vehicle number, vehicle type (car or truck), approach direction and destination        direction. You should also print messages to clearly show when a vehicle is in a specific portion  (AB, BC, CA) of the intersection.  The messages should unambiguously describe all the events in the intersection with proper ordering. This message is very important and it is your task to make  sure that the message is displayed with clarity to allow the grader to follow all the events!  (If      necessary use synchronization primitives to enforce clear printing). Projects whose vehicle thread execution order cannot be clearly followed will not receive substantial scores.

Your code should be based on the locks that you implemented, along with the thread_sleep() and thread_wakeup () functions.   Using other synchronization primitives or resorting to busy waiting is not allowed.  This last constraint implies that a vehicle thread that cannot make progress in the                 intersection should not keep continuously checking the condition; instead, it should suspend its execution (using thread_sleep()) to enable other threads to execute on the processor. Later, it should be      awakened by calling thread_wakeup (). The thread may need to re-check the condition when it is   awakened before proceeding; that is acceptable.  Of course you are allowed to call other thread functions to create and terminate threads in your program.

The driver for the Podunk Traffic problem is in (the version that you updated from Blackboard)           ~/os161/os161-1.11/kern/asst1/stoplight.c (a not so subtle hint about one possible solution). It consists of createvehicles() which creates 20 vehicles and passes them to               approachintersection() which assigns each a random direction. It also assigns each vehicle a random type as ‘car’ or ‘truck’ . We assigned them a random turn direction as well. The file                  stoplight.c also includes routines turnright() and turnleft() that may or may not be     helpful in implementing your solution. Use them or discard them as you like.

Please note:  The OS- 161 menu should not appear on the screen until all the car (and truck) threads have completed; this is part of the synchronization problem you are solving!

Design document (10/85 points):

A component of your PA1 submission will be a design document, that will provide an overview of your synchronization problem solution that you implement. Put your design answers in a separate file named design.txt, and submit as part of your Part 2 submission (you can also submit a pdf design             document file, ifyou want to). A 2-page design document should be sufficient to convey the main         features of your approach.

In your design document, after giving a high-level overview of your solution, explain:

i.)  How many locks you used in your program and for what purpose(s),

ii.) How you achieved the objective of giving high-priority to cars (compared to trucks); explain what type of data structures and synchronization primitives you used for that purpose

iii.) Specific rules you implemented to admit, suspend, and wake up a vehicle thread, approaching  the intersection from a specific lane: you may want to list separate cases you considered.

In the design document, you should not copyyour C code: someone reading the document should be able to understand the main logic without having to inspect your C code if they are familiar with locks, and thread sleep/wakeup functionalities.

6. Recommendations

If this is your first multi-threaded programming project (likely to be the case for most students) make sure to allocate sufficient time, in particular for testing and debugging. It’s not uncommon to spend very          significant time on debugging first multi-threaded programs, because it takes time to adjust to thinking     with multiple threads executing the same program. That is why you are given several weeks to complete  this project.

It is our strong recommendation that you develop the solution to the traffic management problem             incrementally to make debugging a tractable task; for example,  by developing and testing the locks, then modeling the intersection by allowing the vehicles to cross in any order, ignoring the “accidents”, and     printing the events properly. While that is not an acceptable solution to the project, it will give you good know-how about creating threads and displaying their progress at run-time, so that you can proceed with confidence.

In the next phase, you can update your solution to prevent accidents, and when successful, you can add     high priority to cars.  Finally, you can make sure that your solution maximizes concurrency across threads and doesn’t impose any unnecessary delay.

All these phases require good planning and working according to a timetable through several weeks. Last- minute scrambles are known to be not very helpful in multithreaded projects.

7. Coding style, submission and grading

In your programming assignments, you are expected to write well-documented, readable code. There are a variety of reasons to strive for clear and readable code. Since you will be working in pairs, it will be    important for you to be able to read your partner's code. Also, since you will be working on OS/161 in a future assignment, you may need to read and understand code that you wrote several weeks earlier.

Finally, clear, well-commented code makes your TA happy!

Here are some general tips for writing better code:

    Group related items together, whether they are variable declarations,  lines of code, or functions.

    Use descriptive names for variables and procedures. Be consistent with  this throughout the

program.

●    Comments should describe the programmer's intent, not the actual mechanics of the code. A   comment which says "Find an eligible car"  is much more informative than one that says "Find the first non-zero  element of array."

You and your partner will probably find it useful to agree on a coding style - for instance, you might want to agree on how variables and functions will be named since your code will have to interoperate.

Working Environment

You will need to develop your code on zeus server.  Your programs will be tested on zeus.vse.gmu.edu (no exceptions!).

Submission  for Part 2:

When you are finished, creating a directory called asst1-part2’, inside the ‘~/os161/’ directory.

% cd ~/os161/

% mkdir asst1-part2

Make sure you commit your latest working copy first:

% cd ~/os161/os161-1.11/

% git commit -am "Completed project-1"

Tag your latest working copy and run a diff:

% git tag asst1-end

% git diff asst1-begin asst1-end > ../asst1-part2/asst1.diff In the asst1-part2’ directory, you should place the following:

asst1.diff: a diff file listing all the changes you made for this assignment.

your sys161.conf file.

exercises.txt: your answers to the written synchronization exercises (do NOT include code- reading.txt)

design.txt: your 2-page design document.

Next, tar and compress your asst1-part2 directory AND your entire source tree.

% cd ~/os161

% tar -czf uid1_uid2-asst1-part2.tar.gz os161-1.11 asst1-part2

You should replace uid1 and uid2 with you and your partner's GMU email IDs. If you are working      alone, the last line should read tar -czf uid-asst1-part2.tar.gz. Submit the compressed     Part 2 file on Blackboard. All members of a group must submit separately the same compressed file, and before the Part 2 deadline 3/29 11:59 PM . Make sure to coordinate.                                              Make sure to double check that you are submitting the correct file  -- if you submit wrong, corrupt, or empty file you are likely to get zero.

You can make multiple submissions; we will consider ONLY the last submission that you make: so in case you need to re-submit, make sure the compressed file contains all the components listed above.

Late penalty for Part 2 will be again 15% for each day. Submissions made on or after April 1st will not be accepted. Please plan in advance.

Questions

Programming and system-related questions about the project should be directed Spring 2023 CS            471/571 OS/161 Project Piazza Page, which is monitored by the GTAs from 10 AM to 6 PM on               weekdays.  Your posts to the Piazza are by default private, meaning that it is received only by the            instructors and GTAs. Occasionally, the GTAs can decide to make some questions and answers public, if they think they are relevant for many students. Also: the GTAs are NOT allowed to reveal/code the          solution or debug your programs; however, they can help with clarification and guidance.

The code-reading and exploring the OS/161 kernel files is a component of the assignment, so you should not expect detailed explanations of how the OS/161 kernel functions work (including the thread               functions). You can direct conceptual questions about the Podunk Traffic Synchronization problem         specification to the Piazza.

Similarly the Piazza page has specific threads you can use to post your partner-search” ads, classified by CS471/571 sections. Post your ad to the appropriate thread, if you are looking for a partner.