Operating Systems (V22.0202)
Homework 5
Implementation of Semaphores

Due: Dec 8, 2006

Introduction

In this homework, you continue to extend the toy machine STM. In the previous homework, you had already extended it to run multiple processes. Now you need to get these multiple processes to perform simple synchronizations.

There are three parts to this assignment:

Part 1: Reorganization of STM

We first discuss a reorganization of the stm code. Although the original stm.c file was very simple, it was conceptually unsatisfactory because this code mixes the hardware (STM) with the software (the operating system). Let us call the operating system SOS, for Simple Operating System. We split the stm.c file into three files:
stm.h,
stm.c,
sos.c.
Here, stm.h is the header file or dot-h file. The nature of "dot-h" files was explained in Lecture 13. The new stm.c file has no main routine -- so it could not be executed directly. The main routine has been moved into sos.c, since the main routine is really part of the operating system. Note also the use of "extern" declaration for the various variables in stm.h.

Now, stm.c contain ONLY the hardware part of STM, and sos.c should only contain the operating system. We suggest you read these files to see how we have separated the two functionality. To use the new organization, you proceed as follows: first compile stm.c into stm.o (object file). Then compile sos.c but linked into stm.o. These two steps are illustrated in our new Makefile: you first type "make stm" to produce the stm.o, and then type "make sos" to create the executable file (sos.exe). Henceforth, to run a stm program, you must use "sos.exe".

One benefit of this re-organization is that we can easily enforce the rule that your programs are not allowed to change the hardware: we just compile your sos.c program by linking to OUR own stm.o file.

All these files are available here: src.

To improve I/O, we now allow string input/output. This is done by new specifications for TRAP 1 (input) and TRAP 2 (output). Please read stm-new.html for this specification. We want you to modify stm.c, stm.h, sos.h to implement these changes, including the changes from the previous homework.

To help you debug your I/O traps, here is a hello.stm program that simply prints the string "Hello, World!".

WARNING: after the changes in I/O traps, you must modify our original primes.stm, fraction.stm, sort.stm appropriately.

PLEASE CALL YOUR MODIFIED FILES stm-xxx.c, stm-xxx.h, sos-xxx.h where xxx is your lastname (all small letters).

Semaphore System

There are 8 semaphores, indexed 0-7. Each semaphore consists of a value , which is a non-negative integer, and a FIFO queue of processes waiting for the semaphore.

The operations on the semaphores are defined as follows.

DOWN(s):
{ if (s > 0) s--;
   else block the current process --
        i.e. take the current process off the ready queue and 
             put it at the end of the queue of processes waiting for s.
}


UP(s)
{ QW = the queue of processes waiting for s;
  if (QW is empty) then s++;
   else { P = pop the first process off QW;
          push P onto the end of the ready queue.
        }
}
Semaphore operations are invoked by STML code by doing traps to the kernel. Specifically, to execute DOWN(s), load the code 3 into register R15, load the index of semaphore s into register R14, and execute the instruction "TRP". To execute UP(s), load the code 4 into register R15, load the index of semaphore s into register R14, and execute the instruction "TRP".

At the start of execution, semaphores are initialized to 1.

Example

The STML file fractionx.stm has a modified version of "fraction.stm" in which semaphores are used to enforce mutual exclusion on the reading and the writing section of the code. HOWEVER, we have not enhanced the input/output with string prompts.

Semaphore 0 protects the reading; semaphore 1 protects the writing. The result is that if several instances of "fractionx.stm" are run in parallel, the inputs to each process all sequential, and the outputs are all sequential, whereas our previous project interspersed reading from the different processes, and interspersed the outputs from the different processes.

The particular example shown here has the command line
"stm -d DEBUG fractionx.stm fractionx.stm fractionx.stm":

Note:
1/7 base 10 is .142857 ...
13/19 base 100 is .68 42 10 52 63 ...
700/1001 base 1000 is .699 300 699 300 ...

Context switches

A call to UP or DOWN causes a context switch only in the case where the current process blocks doing a DOWN. Otherwise, the rules for context switches is the same as in the previous project (i.e., I/O Traps causes context switches). Putting these all together, therefore, the rule for context switches is this:

Let P be the current process, and let Q be the next process on the ready queue.

REMARK: in a more realistic STM, we should execute the I/O trap asynchronously, and there should be an independent I/O queue which returns through an interrupt.

Debugging output

If the debugging flag is 1 or 2, the program should generate a trace statement each time an UP or DOWN occurs, stating that the operation has occurred. If the operation causes a process to block or to unblock, that should be stated.

Part 2: GCD with Semaphores

In the previous homework, you wrote a gcd.stm program. The program reads two input numbers and outputs their gcd. The input of these 2 numbers might be interspersed. To prevent interspersing, we want you to enclose these two input operations with a DOWN(0) and UP(0) operation (using semaphore 0).

For I/O, we want you to enhance the original program so that it prints some meaningful prompts for input and output. E.g., before reading the first input number it might print the string ``> Arg 1: ", etc. Before printing the answer, it might print the string ``> The GCD sequence is ''.

In addition, you must modify your gcd.stm program to store in local storage all the intermediate remainders of computing gcd. E.g., gcd(26, 19)=1 will produce the following sequence of remainders: 7, 4, 3, 1. Instead of just outputting a single number "1", you must output this entire sequence only at the end of the gcd computation, not while computing them. However, you must ensure that this sequence is printed without interruption. So you need to enclose the output of this sequence by a DOWN(1) and UP(1) operation (using semaphore 1).

This part of your homework should be in a file named gcds.stm ("gcd semaphore").

STML Assembler for your convenience

David Stewart from a previous class has written an assembler in Perl scripting language for STML. Here is a README file. This could speed up your coding in STML.

NOTE: This software is provided without any warrantees. Please use as you see fit, and send me any improvements you might incorporate for the benefit of future students.

HOWEVER, when you submit your *.stm files, you are responsible for making sure that it remains human readable (each line should have the usual four parts: hex-code, hex-address, assembly code, comment.

On some systems, the perl output contains a strange looking character that looks like "@^" (on my computer, but others report a blank box symbol). This is apparently some encoding of a white space character. Just think of this as a space. The system will treat it as a space. If you don't like this ugly output, use an editor to clean up or send me an improved assem.pl.

Part 3: Implementing Semaphors

As usual, the coding should be done using C. Collaborations and discussions with each other are encouraged, but all coding and write-up must represent your own work. You can take as your starting point either: What you mainly need to do is: This part of your program should be in a file called sos2-xxx.c (separate from sos-xxx.c for Part 1). POSTSCRIPT: it would have been great if you factor our the necessary header information in a file called sos2-xxx.h.

Submitting your work

  1. This homework is worth 180 points.
  2. Your solution must be emailed to the grader (Ravi) but cc to me.
  3. You should package your submission as a single tar file, FOLLOWING THE INSTRUCTIONS OF the previous homework. When in doubt, please ask.
  4. Your submission must include the following files:
    (1) a text file file called README,
    (2) a Makefile (with a capital "M") which is just an extension of the Makefile which we provided,
    (3) program files for each part: "stm-xxx.h", "stm-xxx.c", "sos-xxx.c" (Part 1), "gcds-xxx.stm" (Part 2) and "sos2-xxx.c" (and perhaps "sos2-xxx.h") (Part3). Here xxx is your lastname (all small letters).
  5. Make sure that all your source codes are properly commented.
  6. The README file must identify this homework and you, and it must give an overview of your modifications. Data structures and important routines must be identified and explained here.
  7. The Makefile should include these targets: (a) the default target should simply compile sos-xxxx.c. (b) A target called "gcd" that runs sos-xxxx on one copy of "gcd.stm". (c) Two targets called "t1" and "t2" that test sos-xxxx on multiple processes.

ADDITIONAL COMMENTS