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:
-
First, you need to rewrite your solution to hw 4,
by separating out the hardware from the
operating systems part.
We also want to slightly enhance
STM hardware, to allow string I/O.
-
Second, we want you to modify your previous STML
program for GCD so that each process will
(1) print helpful prompts for input/output,
and
(2) synchronize the input and outputs by
putting the relevant sections of code as
critical sections.
-
Third part,
modify your multiprogramming SOS to support semaphores.
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.
- If P terminates either deliberately or due to an error, then Q is
resumed, and P is not placed on any queues;
- else, if P executes DOWN(s) and has to block, then Q becomes the active
process, and P is placed at the end of the queue of processes waiting for s;
- else, if P executes a READ or WRITE or P comes to the end of its
quantum, then Q becomes the active process and P is placed at the end
of the ready queue;
- else, if P executes an I/O, then P is placed at the
end of the read queue and Q becomes the active process;
- otherwise, P remains the active process; there is no context switch.
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:
- Your own solution to the previous hw4.
- Our posted solution to hw4.
What you mainly need to do is:
- Implement the new TRAPs.
- Implement data structures for the semaphores and the waiting queues.
- Write procedures for DOWN and UP, and invoke them from "exec_trap"
- Fix the context switching procedure to handle the new cases.
- Initialize the semaphores at the beginning of execution.
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
-
This homework is worth 180 points.
-
Your solution must be emailed to the grader (Ravi) but cc to me.
-
You should package your submission as a single tar file,
FOLLOWING THE INSTRUCTIONS OF the previous homework.
When in doubt, please ask.
-
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).
-
Make sure that all your source codes are properly commented.
-
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.
-
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
-
We should have moved the trap processing from
stm.c to sos.c. That is because the OS defines
the individual traps.
-
All your semaphores, queues, process table, etc ought to be
stored in mem[].
That means that some of the memory should be
reserved for the use of the operating system.
However, since we did not specify this requirement
at the beginning, this is considered optional.
If you implementing this, you should also
segment memory into KERNEL SPACE and USER SPACE.
Let us say you dedicate 16K of the memory for Kernel Space.
This should be a global variable called USERSPACE (e.g.,
USERSPACE=16K). Then mem[0] to mem[USERSPACE-1] is
dedicated to Kernel. The Process Table and other
global information should be stored here.
-
For integer output, we automatically
output a newline after the integer.
But for string output, this newline character must
not be automatically output. The user can request
this character to be output explicitly.
-
The difference between char and int data type should
be carefully considered in I/O. For instance, it is somewhat
confusion that getchar() returns an int, not a char!
Why?
Please see our C-programming page under FAQ's on this
topic.
-
Sometimes, student's gcd programs could not handle the case
where m=n or when m is a multiple of n.