Due at 9:00 AM on Friday, May 28.
For this assignment you will implement two styles of device scheduling:
We provide a version that implements First-Come-First-Served (FCFS). As you implement each algorithm, you will compare its performance with those you obtained using the original FCFS version.
Under OSP, disk scheduling involves the functions in file devices.c. (As before, the names of all routines and data structures used by OSP must remain unchanged.) The diagram at the end of this document shows how OSP interacts with the functions in this file, specifically enq_io (which enqueues, or add a request to the queue, dispatching it immediately if the device is currently idle) and deq_io (which dequeues, or removes the first request from the queue and dispatches it). These two routines are where you will be concentrating your efforts.
Don't add global variables unless they are really necessary. If so, they should go just prior to memory_init, and you will need to use devices_init (which is called when OSP is set up) to initialize those global variables.
Copy the following files into your working directory:
The only file you should modify is devices.c (and optionally
dialog.c). Modifying the other files will probably "break" OSP.
Compile, link, and run the program as you did for the last assignment.
In OSP, each device has just one surface (think of it as a single-sided floppy disk), which is divided into a fixed number of concentric tracks; the number of tracks per device is named in a defined constant, MAX_TRACK. The other constant of interest is MAX_BLOCK, the number of blocks that can be stored on a device. The block location for a request will be in the range 0..MAX_BLOCK-1. You will have to calculate which track an I/O request is on (in the range 0..MAX_TRACK-1).
Note also that there are several devices in OSP (0..MAX_DEV); each one has a separate I/O queue and should be scheduled independent of the other devices.
The following diagram illustrates how the functions in devices.c interact with the rest of OSP.
Whenever I/O is requested by the "executing process":
When a device signals completion of an I/O request:
Note that the I/O request itself (iorb_node) only stores a block_id to indicate location. You will have to "translate" this into a track location in order to know what to do with it. Note that the first IORB in the queue (Dev_Tbl[dev_id].iorb) must be the IORB that is currently being serviced by the device.
Think carefully about whether you want to order the I/O queue or whether you want to change how a request is dispatched. You are free to use the hook in the IORB nodes if you desire. You may also introduce a couple of global variables if they'll help you (as long as they are positioned just before devices_init).
You will have to make a small change to purge_iorbs for the N-step algorithm. See comments in the code.
Debugging hint: Although devices.c is the file you are most concerned with, take a look at dialog.c as well. In particular, note that you can call the routine print_dev_tbl() to save yourself from having to write a print routine to dump the current contents of the device table. There is also a routine print_sim_dev_tbl() that will show you what OSP thinks you should have in your device table. They should both have the same number of entries and the same data for each entry. If you are unsure how to use these functions, try modifying the devices.c code so that the two tables are printed just before you dispatch a new request. Compile, link, and run the program as in step (1) and notice where the information is printed. NOTE: OSP's copy of the device table printed by print_sim_dev_tbl is not updated very often. In the middle of enq_io or deq_io it may not contain all the IORBs that are really in the queue.
You may need to instrument your code -- for example, printing out the track location for each request -- to check that your code works. After you're sure the code works, delete (or comment out) the instrumentation.
Survival hint: THINK before you start. If your design for C-LOOK is not simple, it will not lend itself to an easy change to N-Step C-LOOK. Be sure you get this one really clean before you try to add the aging mechanism.
Once you have C-LOOK working, only a very few lines of code are needed in each of purge_iorbs, enq_io, and deq_io to change it to N-Step C-LOOK. If you find yourself adding more than one or two pointers or variables, or adding more than a handful of code, stop! Re-think what you're trying to do. Draw some diagrams to see if that will help.
Since it is essential that you have a good version of C-LOOK to start from, this project will be graded in two pieces. First, we will look at your implementation of C-LOOK alone (including the table, memo, etc.); this will account for 75% of your grade, and you will be eligible for the points even if you don't turn in N-Step C-LOOK. If you do turn in N-Step C-LOOK, it will be graded for the remaining points. A poor version of C-LOOK will cause you to get a poor grade on both pieces, since it is impossible to do a good job of N-Step without a sound foundation. This means you will get a better grade by turning in a good version of C-LOOK, than by turning in a weaker version of N-Step C-LOOK.