jaspersugarlandSoftware and s/w Development

Dec 14, 2013 (3 years and 6 months ago)




CS 471: Operating System Concepts

Course Project

Fall 2003

September 1, 2003

Draft 1

General Description

The purpose of this assignment is to implement several basic components of a multi
ming operating
system and to test the effect of differen
t memory sizes, the speed of I/O devices, etc. Much of the code you
will write is similar to the code found in a real operating system. However, simulation is used to create a
process queue (a queue to keep processes which cannot enter the system due to
the degree of
multiprogramming limitation or their generation time is beyond the current time; at time 0 all processes are
in this queue) and to mimic I/O behavior of user programs. (The simulation routines required are simple;
all but the most trivial ar
e provided below.)

You will be dealing with the following resources: the CPU, the primary memory, disk 1 (temporary
storage), disk 2 (secondary storage for virtual memory), disk 3 (spooler output), and the printer. For
simplicity, in this project, you wil
l be measuring time in units of
memory references

instead of units of
time or units of CPU instructions. Even CPU time and I/O time will be measured in this funny “memory
reference units.” Similarly, memory size is simply expressed as memory units. That i
s, when we say
memory size is 20 k, we do not explicitly say whether it is bytes or words. Assume that the same units are
used when referring to memory size, disk space, and program address space. This is just for convenience.
This is the unit through whic
h a memory can be addressed.

Your primary task is to write routines to (a) manage the processes in the system through the use of a ready
queue, a blocked queue, and a print queue (these are besides the process queue that keeps all the initially

processes), (b) manage primary and secondary memory, and translate virtual to physical
addresses (only in phase 2, you will deal with virtual memory). (You may need additional queues such as
queue for disk 1, disk 2, and disk 3. This depends on your imple
mentation.) You will have to produce
enough data about the behavior of your system to demonstrate that it is working correctly, and to analyze
its behavior. You will also experiment with your code to measure the performance effects of alternate
and settings.

routine provided to you should be used to generate the processes to be executed by
your system. Each generated process will have the following attributes: <
process_id, generation_time,
process_priority, primary_memory_size,

process_type (0 for CPU
bound, 1 for I/O
bound, 2 for
Mixed), execution time
>. The process_id is generated automatically starting from 1 to process_queue_size
(a system run
time parameter). All the specified number of processes are generated at the begin
ning itself
and placed in the
process queue

(it is our own term and not a standard term by any means). To simplify the
simulation aspects of this project, no additional processes will be added after this initial queue is created. A
routine should periodic
ally scan this list and based on the generation_time

field of a process

a new process
should be started. Each process then executes to completion in a multiprogramming environment and is
purged from the system on completion. When this list is empty

all active processes have completed,
the system generates various reports and shuts down. (Note: Even though a process is generated at time say
500, it may not be able to enter the system due to the non
availability of resources such as primary and/or
ndary storage, and the limit placed by degree of multiprogramming (MP). In other words, when the
degree of MP is 4 and there already 4 processes in the system, then the new process has to wait in the
process queue (or some other queue) until it is possible

to enter the system.)

To simulate a process's execution, use the

(address generator) procedure provided to produce
addresses within each process's address space. Each process will also generate I/O requests randomly as
described below. For sim
plicity, we assume that I/O requests are only on temporary storage. In other


words, a write I/O requests for additional temporary space on a disk and writes the information. (If the disk
is full at the time of this request, the process will be blocked unti
l some other process releases space.) A
read I/O does not require additional temporary space, but is blocked until the read I/O is complete. When a
process generates an I/O request, it should be moved to the blocked queue (or to disk 1 queue, depending
your implementation) for the proper amount of time. After that time delay, it should be moved back to
the ready queue. Your dispatcher (a process that decided which ready process should execute next) should
give preference to higher priority processes. F
or processes with identical priority, it should use round
scheduling: after having "executed" a fixed number of instructions for a process (if an I/O or print
instruction was not executed to interrupt the execution and the process did not complete),

select another
process from the ready queue to execute. The maximum "time slice" given to each process is the same for
all processes (and is a parameter). When a process has completed its execution, it releases its resources
(i.e., the PCB and the tempor
ary disk space) and is purged from the system. (The maximum time slice is
also a parameter to the program. The effect of this parameter on the overall system should also be
determined through experimentation.)

In addition to the I/O requests for the disk
(write I/O uses temporary space on the disk), a process can also
generate print requests. When a process executes a print request, due to the use of spooling, the information
is first written on the spooler disk (i.e., disk 3). You may think that each proc
ess has one temporary print
file. When a process completes execution, the print file will be printed by the printer daemon and then the
disk space is released. (More details on printer daemon to follow.)

I/O interrupts and print requests should be generat
ed randomly. In other words, since there is no actual
user process available, you are simulating the behavior of a process. Each instruction of a process can be
one of the following types: (i) CPU instruction (ii) write I/O instruction (iii) read I/O inst
ruction and (iv)
print instruction. You should simulate the behavior of a process depending on its type (I/O
bound, CPU
bound, or Mixed). The probability of occurrence of a specific type of instruction in a process is dictated by
whether its type. These pr
obabilities are run
time parameters. (In fact, a process is first identified as a user
process (created by you) or a system process (there are only two system processes: OS and printer
daemon). If it is a user process, then it is further classified as CPU
bound, I/O
bound, or Mixed.)

Operating System Interrupts:
While you will not represent the overhead of all operating system routines,
the overhead due to several standard operating system interrupts is to be represented explicitly. The
execution time fo
r each type of interrupt is listed in the table below. Thus when one of these interrupts is
detected, the CPU is given to the appropriate interrupt handler and it executes the number of instructions in
the table below. You should assume that these handle
rs are always resident in memory so that no new
memory must be allocated for them to run. For simplicity, assume that an interrupt handler is never
interrupted. In other words, once an interrupt
handler starts executing, it holds the CPU until it is
ted. In addition, assume that an interrupt
handler never needs I/O; it only requires CPU and primary
memory. Also assume that the system routines never generate printer outputs (since this requires access to

handler execution times

terrupt type

# of Memory



Is it Invoked?

Process initiator


On process creation

Process terminator


On process termination

Page fault


On each page fault

Clock interrupt


After proc gets time slice



On each contex
t switch

I/O (or print) instruction



On each I/O (or print)

I/O (or print) instruction


On each I/O (or print)



Printer daemon (a separate system process):
The only other OS function you need to explicitly
sent is the printer daemon. It does not run (and has no a priori memory allocated; it needs 12k
memory) until some routine tries to print. (What we mean by a process tries to print is that a process has
completed execution and generated a spooler file du
ring its execution. A spooler file is not printed until it is
closed.) If a process does generate print
output, a printer daemon is started. It then dies when all printing
has been completed (i.e., whenever the print queue is empty). While the printer da
emon is running, if a
second process generates print
output, it uses the existing printer daemon. Thus, if the system were busy, it
is possible that the first process to complete will cause the printer daemon to start (be loaded into memory
and placed on
the ready queue); this instance of the daemon might continue running until system shuts
down. Thus, it really behaves like a user application, but is created only when needed. Additionally, it
should never be true that two instances of printer daemon are
running at the same time. Assume that the
printer daemon takes 5 instructions (equivalent to 5 memory references) per 1k of output. After executing
the instructions, it must wait for the output buffer contents to be transferred to the printer (this transf
always takes the equivalent of 35 memory references for 1k of output). The size of the printer daemon
code is 12k.

OS (system process) runs at the highest
priority of 1
. Printer daemon runs at
priority 2
. User processes
priority 3
. (The priori
ty of a user process is determined at the time of its generation.) As your
simulation program executes each process, it should regularly check to see if it is time to start another
process (from the process queue).

Resource Management

Your system has on
ly three types of resources: CPU, memory, and disk space (disk 1, disk 2, and disk 3).
For simplicity, both main memory and disk space are allocated in 1k units. The CPU is managed using
ready and blocked queues. In phase 1, memory space is managed by a

table (each block of 1k memory is
either busy or free). In the second phase, you will implement virtual memory. Since disk has a large
number of blocks, you may need several list structures (e.g., list of free blocks of disk space) to manage it.

Each process uses disk space for three purposes: virtual memory (in phase 2), temporary
space due to I/O, and print (spooler) files. The management of virtual memory space will be discussed in
chapter 10 and is not described here. While temporary
I/O is on disk 1, print files are created on disk 3, and
virtual memory is managed using disk 2. Your phase 1 implementation will not use virtual memory and
thus will not require disk 2. It is used only in phase 2.

The management of disk space as temporar
y space will be represented by the maintenance of two kinds of
lists: a separate allocation list for each active process and one free space list. Each process control block
has a pointer for a list of its allocated secondary space. Each element in an al
located space list should have
three fields: a location on disk, the size of this element of disk space, and a pointer to the next element in
the list. Allocation for this space is handled dynamically; you should make the following simplifying

each write
I/O interrupt is for disk space
: each time a process generates a write I/O
request, we assume it has filled a 2k buffer. Space must be allocated in secondary memory to hold the
contents of this buffer. Similarly, when it generates a read

I/O request, we assume that it reads into a 2k
buffer. However, no new space needs to be allocated.


Disk space for a print file should be released only when the print daemon has processed it.

Once a process terminates, its memory space is rele
ased, and its output (also on secondary memory) joins
the print queue. If several processes are ahead of it in the print queue, it may be some time before the
spooler gets to this output. For the print queue, the process priorities are used. (In other wo
rds, higher
priority jobs are printed first.) After the output spooler has finally "printed" the output for the process, this
disk space is released. Each time a print instruction is executed, assume that it has filled 1k buffer.

Initial System Design



The following is list of modules for your system. It is by no means complete. But it should help you get
started on a system design. Your design (and program) will certainly include many more routines.

simulation_initializer: The routine reads all r
time parameters and initializes the
process queue.

os_initializer: All system tables are also set up by this routine.

process_scheduler: The purpose of the process scheduler is to select a process from the
process queue and report its choice to the
process_initiator. The process_scheduler scans
from the front of the queue and selects all processes whose start time matches the current
simulation time.

process_initiator: This is an interrupt handler. The process initiator allocates the necessary
sources for a process, builds a process control block (the contents of which are described
below) and places the control block in the blocked queue waiting for the process
executable code to be loaded into memory.

dispatcher: The purpose of the dispatche
r is to select the next process for execution from
the ready queue.

interrupt_manager: This routine checks for interrupts and invokes the appropriate
interrupt handlers. Interrupts include: Clock, I/O start, I/O complete, Page Fault, Process
Process Terminate.

address_translator: This routine translates a virtual address into a physical address. How
this is done depends on the memory management scheme used. Initially, all this routine
does is add an offset to the virtual address to get the

physical address. Later, you will
implement a virtual memory scheme so that page tables must be maintained to support
address translation.

context_switch_manager: This routine preempts the process that is currently executing,
saves its current address
(so that when the process is selected for execution again, it will
begin with the same address) in the process control block, and places the process at the
end of the processes with the same priority in the ready queue. It can be invoked by
several of the

interrupt handlers.

process_terminator: This is an interrupt handler; it releases all resources allocated to the
process. If the process generated any output, the process_terminator places the process on
the print queue and starts the print_spooler if

necessary. If the process generated no
output, the process_terminator calls the process_purger. (Actually, process_purger is
called whether or not a process has generated output. In the first case, it first checks
whether or not the print_spooler is alre
ady running, start it if necessary, and then call
purge_process. In the second case, it calls it right away.) This routine calls the

process_report_generator: The process_report_generator prints the data collected by the

on the performance of each individual process. This should include, for example,
the number of I/O requests, beginning and ending execution times, number of page faults,
print begin and end times, etc.

system_log_generator: This routine (or collection
of routines) generates the "system log"
described below. The system_log_generator is invoked whenever a "significant" event
occurs and records the time of the event, the type of event, and pertinent data about the


event on the system log file. Significan
t events, for this project, include: process
initiation, process termination, process purge, and system shutdown.

system_summary_generator: This routine generates the summary report described below.

Your design will include many additional routines inc
luding several for handling all the lists that must be
maintained. You should take care that the executable code for any routine, once complete, should be no
longer than one page. If the code for any routine is longer than a page, you should consider dec
omposing it
into smaller routines.

Process Control Block

Each process control block, mentioned in the process_initiator description, should contain at least the


process id,


process priority,


process state (initiated, blocked, active, etc.),


if process state is blocked, the reason for the blocking (page fault, I/O wait, etc.),


process type (system or user);


if process type is user, is it I/O
bound or CPU


next memory reference to be made by the process (this is initially set to 0),


ber of memory references remaining (used only for simulation purpose),


process code location in primary memory (beginning and length), until for phase 2,


list of virtual memory pages and their location in disk 2 (replaces above for phase 2)


the first loca
tion in disk 3 of its spooled output (this is initially null).


the first location in secondary memory of its temporary space (this is initially null).


various statistics about the process (start time, number of I/O interrupts, etc.)

The process control bl
ock, once created, is moved between the ready and blocked queues as necessary (and
finally to the print queue if the process created any print output).

time Parameters

One purpose of this assignment is to experiment with the operating system that yo
u have written. For this
reason, the following variables should be run
time parameters:

RP1: new_process_queue_size: The number of processes to be put into the process_queue.
The process queue will hold a control block of each process to be executed. T
ype: Integer;
Range: 1

250. (In other words, this number of processes you will be creating at the start of
simulation and placing in the process queue.)

RP2: time_between_process_generation: Interarrival time between new process generation. For

if this parameter is 100, and the last process had a generation time of 1020, then the
next process (whose process ID is 1 more than the last one) will have a generation time that is
between 0 and 100. The interarrival time is exponentially distributed. T
ype: Integer; Range:

RP3: degree_of_multiprogramming: The maximum number of processes permitted to share
memory concurrently. Type: Integer; Range: 1

10. (When RP3>RP1, the effect of RP3 will
disappear on system performance)



RP4: maximum_add
ress: Each process may have a different address space size. This is
determined randomly at its generation. This parameter is the largest address (in 1k units) any
process can have; most processes will not have an address space this size. Addresses run f
0 to (maximum_address * 1024)
1. This parameter is used by the parameters routine (below).
Type: Positive integer; Range: Phase 1: 4
20; Phase 2: 50

RP5: maximum_references: Processes will vary (randomly) in the number of total memory
s each will make during its execution. The minimum number of references is 1. The
maximum is maximum_references. Note that in the simulation, we are using memory
references as a surrogate for time. This value is used by the parameters routines to set t
number of memory references for each process. Type: Positive integer; Range: 1000

RP6: references_per_slice (Used in round
robin scheduling of CPU): A process cannot
monopolize the processor. It will be allowed a time slice of references_per_
slice memory
references. It will then go back to the ready queue. Note that if it completes or generates an
I/O interrupt, it will not receive the maximum. Type: Positive integer; Range: 10

RP7: main_memory_size: Size (in 1k units) of primary memo
ry. Valid addresses run from 0
to main_memory_size*1024

1. Type: Positive integer; Range: Phase 1: 200; Phase 2: 200

RP8: secondary_memory_size: Size (in 1k units) of secondary memory. Type: Positive
integer; Disk1: 10 M to 100 M; Disk 2: 200
M to 500 M (k=2

and M = 2
); Disk 3: 10 M to
100 M;

RP9: i_o_time_delay (for 1k units): The amount of time (measured in memory references)
required to complete an I/O request. For this project the value is constant. (For a better model,
we might
want to make this value random). Type: Positive integer; Range: 100
1000 memory
references of time.

RP10: system_write_ i_o_interrupt_prob: The probability of a write I/O interrupt occurring
with each memory reference of a
routine. Type: Real num
this is assumed to be

RP11: system_read_ i_o_interrupt_prob: The probability of a read I/O interrupt occurring with
each memory reference of a
routine. Type: Real number;
this is assumed to be 0.0

RP12: system_print_prob: The probabi
lity of a print statement occurring with each memory
reference of a
routine. Type: Real number;
this is assumed to be 0.0
. (Note: Since
RP10=RP11=RP12=0.0, you can infer that a system process only requires primary memory
and CPU and not disk. Since
we assume that the OS routines are preloaded into the system,
they do not require disk access even when virtual memory is considered in phase 2.)

RP13: CPU_bound_prob: The probability that a user process is CPU
bound. Type: Real;
Range: Between 0 and 1

RP14: IO_bound_prob: The probability that a user process is IO
bound. Type: Real; Range:
Between 0 and 1.

RP15: Mixed_type_prob: The probability that a user process is Mixed type. Type: Real;
Range: Between 0 and 1. (Note: RP13+RP14+RP15=1.0)



16: CPU_bound__write_i_o_interrupt_prob: The probability of a write I/O interrupt
occurring with each reference of a CPU


routine. Type: Real; Range: Between 0
and 1.

RP17: CPU_bound__read_i_o_interrupt_prob: The probability of a read I/O int
occurring with each reference of a CPU


routine. Type: Real; Range: Between 0
and 1.

RP18: CPU_bound_print_prob: The probability of a print statement occurring with each
reference of a CPU


routine. Type: Real; Range: Betwee
n 0 and 1.

(Note: For a CPU
bound job, RP16+RP17+RP18 < 1.0. In fact, 1
RP18 gives the
probability that a CPU
bound process’ instruction needs CPU and memory and not a disk. Of
course, in a virtual memory environment (phase 2) even a memory acce
ss might give rise to
Disk2’s access.)

RP19: IO_bound_write_i_o_interrupt_prob: The probability of a write I/O interrupt occurring
with each reference of an I/O
routine. Type: Real; Range: Between 0 and 1.

RP20: IO_bound_read_i_o_interrupt_p
rob: The probability of a read I/O interrupt occurring
with each reference of an I/O
routine. Type: Real; Range: Between 0 and 1.

RP21: IO_bound_print_prob: The probability of a print statement occurring with each
reference of an I/O

routine. Type: Real; Range: Between 0 and 1.

(Note: For an I/O
bound job, RP19+RP20+RP21 < 1.0. In fact, 1
RP21 gives the
probability that an I/O
bound process’ instruction needs CPU and memory and not a disk. Of
course, in a virtual memory

environment (phase 2) even a memory access might give rise to
Disk2’s access.)

RP22: Mixed_type_write_i_o_interrupt_prob: The probability of a write I/O interrupt
occurring with each reference of a mixed
routine. Type: Real; Range: Between 0
and 1.

RP23: Mixed_type_read_i_o_interrupt_prob: The probability of an read I/O interrupt
occurring with each reference of a mixed
routine. Type: Real; Range: Between 0
and 1.

RP24a: Mixed_type_print_prob: The probability of a print statemen
t occurring with each
reference of a mixed

routine. Type: Real; Range: Between 0 and 1.

(Note: For a mixed
type job, RP22+RP23+RP24 < 1.0. In fact, 1
RP24 gives the
probability that a mixed
type process’ instruction needs CPU and memo
ry and not a disk. Of
course, in a virtual memory environment (phase 2) even a memory access might give rise to
Disk2’s access.)

RP24b: locality_factor: The factor that determines the locality of references. Higher value
means successive references are c
loser. Type: Real; Range: 0.0, 0.1, 0.4, 0.8

RP25: begin_trace: The time at which the system is to begin printing a trace of all significant
events. (Some significant events are listed below.) This is used for verification and validation
of the simulat
or. Type: Nonnegative integer; Range: 0, 10000, 50000



RP26: length_trace: This is used in conjunction with "begin_trace;" the length of time the
trace is to continue. If zero, no trace should be generated. Type: Nonnegative integer; Range:
0, 10000, 1
00000, a large number.

RP27: debug_flags: This is used for program debugging. If zero, no debugging data are
generated; if one, debugging statements are executed. You should have several debugging
flags, one for each of the phases of the project. You
may find it helpful to include additional
flags also. Type: Integer; Range: 0, 1, etc.

In addition, all execution times mentioned above (including, for example, the execution times for the
various interrupts) should be coded as constants so that they ca
n be easily changed. The values used for
these numbers are very artificial. In might be necessary to change several of their values to a set of class
selected values. Make sure your code is such that they are easily changed if needed.

Program Verifica

Your program must be capable of producing output to assist in debugging and verification. For phases 1
and 2, you must produce enough information to convince you, the grader, and me that your program is
doing everything it is supposed to do and is d
oing it correctly.

In the design of your software, you must include extensive error testing and debugging code. First you
must include several "debug" Boolean variables, that if set, cause your program to print relevant variables,
tables, and lists as th
e program executes. The error testing and debugging routines must be part of your
design, not added latter in a desperate attempt to figure out what's going wrong. This type of code must be
included in your minimal implementation (phase 1) and in phase 2

You should be able to turn off completely the printing of verification and debugging data with the run
parameters. Once program behavior has been verified, the code should not be removed (the "assert"
procedure should still function).

Required O

Your program must produce all required information in a readable format to allow someone other than the
programmer to understand the output and also allow you to write the required report. Your program should
produce two types of output: report da
ta and verification data. Verification data must be produced by
phases 1 and 2. Some report data should be produced by both phases.

For each phase, the system summary report produced should be reasonably complete. No report data are
expected on those f
eatures that are yet to be implemented.

For all statistics, time is measured in terms of memory references. Your final program, phase 2, must
compute and print all of the following:

1. All run
time parameters, appropriately labeled (so that someon
e other than the programmer can tell
what they are). This should go to the standard output file.

2. A "system trace" to be used for debugging and program verification. This file is very important
during the development of your system, but the file

should not be created when you perform the required
experimentation with your system. When "debug" flags are set, all debugging data should go to this file.
All system trace data, controlled by "begin_trace" and "length_trace" should go to this file als
o. The
system trace should show the time of occurrence of each "significant event" that occurs. This trace file is
similar to the "system log" file described below but is in significantly more detail. It lists all events which
show up in the system log
plus the following:

a. I/O interrupts



b. Removal of process from blocked queue (and/or Disk 1,Disk 2, and Disk 3 queues)

c. Switching the processor between processes

To assist in verification, each time the processor is switc
hed from one process to another, the ready queue,
the blocked queue, and the output queue should be printed. You should print the information in each of
these queues in a readable format. You must also print the allocated and free space lists that are us
ed for
secondary memory management. For example, the ready and blocked queues might be printed as follows:

Time: 1426

Ready Queue

Process Next Num Memory


Address Refs Remaining


Prt daemon 481 14

14 1706 204

7 803 6

18 34 1

Blocked Queue (Similarly, for Disks 1
3 queues)

Process Next

Id Address


Proc Init 0

12 109

8 22067

9 5216

Note tha
t these queues contain both user and system processes.

The "system trace" should be a separate output file.

3. A "system log," showing all "significant" events. An identification of each event, and data relevant
to the event along with th
e time of its occurrence should be printed. Significant events include at least the

a. Process initiations

b. Process terminations

c. Begin print (output spool) for a process

d. End print for a process

e. Empty ready queue

f. Secondary space shortage

g. Unable to initiate any process due to resource shortage

Thus one should be able to look at your system log and see when a process was initiated, when it
terminated, when it b
egan printing, and when if finished printing. In addition, some aspects of system
performance can be evaluated (running out of secondary space, ready queue often empty, etc.)

The "system log" should be a separate output file.

4. A "proces
s log," including for each process:


Process identifier (generated sequentially as each process begins execution)






bound or I/O


Start time


Termination time


Time the output began printing (if the process generated any output; otherwise thi
s should be


Time the output finished printing


The time duration from start until the output finished printing (or until process termination if
the process generated no output).


Primary memory size


Secondary memory size


Memory references


Number of I/O re


Size of the output file generated

The "process log" should be written to the standard output, which will contain a list of all run
parameters and the system summary, listed below.

5. A system summary, including:


Total number o
f user instructions during the run


Total number of system instructions during the run.


Total idle time (the ready queue is empty and all active processes are in the blocked queue)


Total time executing system routines


Total user time


Total number of I/O int


Total number of times the ready queue was empty (all active processes were in the blocked


Utilization of memory


Maximum percentage allocation of memory


Utilization of disk space


Maximum percentage allocation of secondary memory


Total number
of times there was insufficient secondary space


Total number of times there were processes


in the process queue but a process could not be started even though it was time to start it.


Total number of times process could not be initiated due to primary mem
ory fragmentation


Total number of times processes could not be initiated due to secondary memory

This file should also be written to the standard output.

You should look at your output to determine, as far as possible, if the valu
es produced are reasonable.
While some do not lend themselves to intuitive values, others do. For example, some simple arithmetic
should indicate approximately how many I/O interrupts you should expect for a given set of input

Sample Output


You should design your output for on 8.5 by 11 inch paper. This is true for both required reports and
debugging and validation reports. Whenever possible, present the output in a tabular format, using column
headings. For example, part of your

output report might look like:

time Parameters

Size of process queue:




Multiprogramming level:


Maximum process size:


Maximum process length: 450

Size of time slice:


Memory size:


Disk size:


I/O delay time:


Inter. I/O inter. prob:


inter. I/O inter. prob:


Begin trace time:


Length of trace:


Debug flag, minimal:


Debug flag, op sys routines:


Debug flag, I/O interrupts:


Process Log

Proc St. Term. Beg. End Dura

c Mem. Num I/O Size

Id Time Time Print Print tion Type Memory Disk Refs Req. Output


1 5 1428 1435 1535 1540 CPU 230k 42k 890 54 54k

2 8 1632 1654 1680 1672 CPU 512k 0k 1247 26 26k

3 21 1650 1695 1973 1951 I/O 170k 4420k 457 153 153k

6 1342 2419 2443 2651 1309 CPU 812k 12k 426 31 31k

5 35 2580 2691 2705 2670 CPU

46k 0k 302 5 5k

9 1541 2591 2755 2855 1314 CPU 112k 4420k 281 16 16k


The idea is to make the output as readable as possible for the reader (and grader). The system summary
should have the format similar to:

System Summary

Total memory references:


Total idle time:


Total user time:


Total system tim


CPU utilization:


System time:



Proc. init:


Proc. t


Page fault:


I/O start:


I/O stop:


Print daemon:




Number I/O interrupts:


Empty ready queue count:


Number of page faults:


Memory utilization:


Maximum memory allocated:


Disk utilization:


Maximum disk allocated:




Memory shortage count:


Disk shortage c


Additional Comments

An overview of your program must be part of your documentation. For example, since you will have many
routines, you should include a diagram showing the program's calling structure. Since this is a large proj
(and a large program) you must take some effort to make the structure of your program as understandable
as possible.

You must think carefully about the data structures required in this project. You will certainly need to use
queues. Several data str
uctures should be linked lists of structs. To control the space on secondary storage,
a simple variable is sufficient. The "process queue" should probably be a list of structs.

Believe it or not, there are several significant design decisions that have
not been covered. Some of these
will be discussed in due time.

Project Phases and Due Dates

You must implement the project piecewise as indicated here. This is not only standard procedure for
dealing with large systems, but serves to distribute y
our workload more evenly over the term. The project
is divided into several phases for your convenience. The deadlines are only set for completed phase 1 and
phase 2.

Phase 1.1: Random number validation

Description: This is verification that you

have an acceptable implementation of the provided random
number routines. You must update the documentation since what is provided is incorrect.

Phase 1.2: Project Design

Description: This is project design part. The better job you do with the
design of your system, the less
total time you will have to spend overall on this project. THIS IS THE MOST CRUCIAL PART OF THE
PROJECT. Your design consists of three components.

This design must be complete for Phase 1.3 only. Thus the focus of th
is design is on managing the
blocked and ready queues. See the description below. The design must be easily extended to the second

1. A system description. The system description consists of two parts: a description of each of the
ponents in the system, and a "top level" view of the sequence of actions of your system. Each
description should be about a paragraph long and should include the function of the component and what
other components it interacts with directly. The "top leve
l" view should be a pseudo
code representation of
your main driving program. By reading your system description, I and the grader should be able to
understand, at least at a high level, how your system functions.



2. A description of the data st
ructures. As part of your project design, you must think carefully about
the information your system must maintain to function properly and produce the required reports. This
includes how that information is to be coded and what data structures are requi
red to efficiently store and
manipulate the information. Some aspects of the system require only a simple variable, others will require
fixed size arrays, others queues, other lists. For each data structure, you must describe its function, how the
ts are structured (field descriptions), what values are valid, and what each value means.

3. A stubbed C++ program. The stubbed C++ program, which must compile without syntax errors
but need not execute, should implement the descriptions in the

first two sections. The main driving routine
should be complete, but most of the lower level routines should be stubbed. Each stubbed routine should
include documentation describing the purpose of the routine and sufficient information for a reader to
nderstand how the routine interacts with the rest of the system (a list of global variables, if any, and of
routines called). All parameter declarations should be complete.

Normally, your project design would also include both an implementation plan and
a verification plan. In
this case, this document can serve those functions.

Phase 1.3: Minimal Implementation, part 1

Description: This is a minimal system that is used to test your overall design. Features that are not to be
implemented yet be
st describe it. Phase 1.3 should not implement virtual memory, or disk management;
and should only handle clock and I/O interrupts. It should start processes at their specified times (if
memory is available) by placing them directly on the ready queue (n
o delay to load the process into
memory), switch the CPU between processes at process termination or after the currently executing process
receives its time slice, generate program addresses, and terminate processes. The printer daemon need not
run. Once

all processes have executed, the program should terminate, printing some useful statistics. It is
important that these statistics demonstrate that your program is behaving reasonably. Think carefully about
these statistics carefully so that they meet th
is goal.

Memory management: this phase should include a memory management module that will be
replaced in later phase. Use contiguous memory allocation. Without virtual memory, no page faults can be

Phase 1.3, even as a minima
l implementation must include debugging code.

Get your program running with a single process. After you get this working, generate a longer list of user
processes to run. Turn in runs with output from both levels. You should submit source code, and a pr
output with the run
time parameters, the "system trace," the "system log," and the system summary outputs.
I should be able to tell from the verification output data that your program is doing everything it is
supposed to do. These outputs are requ
ired for the verification for all program development phases of this
project. If the grader cannot easily tell from your verification output that your program is correctly doing
all it is required to do, you will not receive full credit.

Due date:
October 8, 2003

Phase 2.1: Inclusion of overhead from operating system routines

Description: User processes should no longer directly enter the blocked queue when scheduled. You
must now explicitly show the overhead of the process scheduler, load
er, process terminator, and print
spooler, etc. Thus the indicated system routines should now appear in the blocked and ready queues as
appropriate. You must dynamically allocate secondary memory to handle the output generated by user
processes. In addit
ion, your system may now create a print queue that you must manage. After the spooler
has "printed" the output for a user process, you must release the space allocated for the process’s output so
that it can be reused.

Phase 2.2: Implementation of virtu
al memory.



Description: This phase should complete the implementation the project. Processes should now
generate page faults and be delayed until a fault is resolved. Selection of victims should

Implement a version of “least recently used” as discu
ssed in the course (Use the one that maintains a
reference bit for each page; any reference to the page causes the bit to be set). When a page fault occurs,
the algorithm searches sequentially for a page where the reference bit has not been set, resettin
g the bit as it
searches. Remember, you must also keep track of dirty pages and you also need to “lock” a page in
memory whenever an I/O interrupt occurs.

Phase 2.3: Experimentation and Project Report

Description: In this part, you will use your
completed system to experiment with your operating system.
These experiments are performed by changing the run
time parameters for a series of executions of your
system. You will receive a description of the experiments you must run later in the semester

After you have completed the experiments, you must write a project report. The report should describe
your system, including an evaluation of your code and an evaluation of the quality of your program as a
model of an operating system. Samples of

the verification data, along with output from verification runs
should be included.

It should also describe the results of your experiments. The format of this report will be discussed in

Due date: December 3, 2003

The programmi
ng components of each phase will be graded using the following weights:

Documentation: 15%

Design, structure

and clarity:


ect execution: 50%

Error testing and

debugging code 15%

The weight of each phase is as follows:

Phase 1: 40%

Phase 2: 60%

Note that t
his grading scheme has a cumulative effect for failure to complete a phase. The
experimentation and project report cannot be completed until all previous phases are complete.

Lateness Policy

For late assignments, 10% is deducted for each day late fo
r the first week after an assignment is due.
Each assignment is due at the beginning of the class meeting on the date indicated. If turned in by 5 p.m.
on the day after the assignment is due, the assignment will be considered one day late. For computing
lateness penalty, the weekend counts as one day (from 5 p.m.

Friday until 5 p.m. Monday). If an assignment is more than one week late no more that 50% credit is

Sample High
level Design

/ Draft 1, high level design, 471 term

// Warning 1:
it's up to you:

// a) whether or not to use this approach, and

// b) to decide if it really will work.



// Warning 2: I've indicated parameters for some routines. These are

// only conceptual, added for clarity. In reality, I would likely

// n
ot use the parameters as indicated.


// Initialization


Gen_process_and_attributes_list( Num_procs );

Initialize_OS; // e.g., ready queue, blocked queue, disk 1 and disk 2 queues, Clock


hutdown = Check_for_shutdown; // Stop if no blocked or unrun procs.

// OS now booted; start running processes

while ( Not_shutdown )


// Find process to start

Select_new_proc( Proc_id ); // may not find any

while ( Proc_id < 0 )
// assume neg id means no proc selected




Manage_interrupts; // If more_work, then this will eventually recognize

// an I/O completion or will start a new process.

Select_new_proc( Proc_id ); // What if none selected?

Request_memory( Proc_id ); // What if this fails?

// If request invalid, delete proc with err msg.

} // Could this every be an infinite loop?

// If here, have found

a process to run

if ( DebugPh1 )

print "Proc " Proc_id " started at time " clock;

Set_timer_interrupt( Time_slice );

Init_process_stats( Proc_id );

Start_proc_running( Proc_id );

while ( Still_running )


struction; // Here, this generate new addr to ref.




} // Could this ever be an infinite loop?


if ( DebugPh1 )


print "At time " clock " process

queue contains ";


print "Ready queue contains ";


print "Blocked queues contains ";


print "Memory map ";

print_memory_map; // etc., etc.


ck_for_shutdown( Not_shutdown );

} // Could this ever be an infinite loop?




Manage_interrupts must determine if any of several types of interrupts have occurred and for each (several migh
t occur at the same
time), invoke the appropriate interrupt handler.

Each interrupt handler should report what it did if DebugPh1 flag is set.