This assignment implements a simple batch-oriented operating system, which behaves as follows:
The operating system should execute as many process as possible. In particular, if one process fails due to some error condition, the operating system should throw it out and continue to tend to the other running processes (if any). Under no circumstances should a failing process cause the operating system itself to fail.
In these assignments, implementing an operating system involves two parts:The index block - disk block 0, the first block on the disk - contains an index of the programs in the disk. The ith word of the index block contains the size in disk blocks of the ith program in the batch disk. Unused entries in the index block are set to zero. Every batch disk contains an index block.
For example, this diagram
shows a batch disk containing three programs. The first program has size 3; that is, the first program occupies three disk blocks. The second program has size 1 and the third program has size 2.
A program is loaded in User Space in order of increasing addresses. The
contents of the program's first disk block is loaded into User Space starting
at location i; the contents of the program's second disk block is loaded
into User Space starting at location i + Hardware.Disk.blockSize
, and so on. The program's blocks must all fit
in User Space. A program may be loaded anywere in User Space it can fit.
Once loaded into primary storage, the program's first instruction has address i, the address of the first word of the program. The program counter should be set to i when the process first executes.
After boot-up initialization, the operating system should load and begin executing the first program on the batch disk; word 0 of the index block contains information on the first program. If the batch disk contains no programs, the operating system should halt.
exec
, exit
,
yield
, putSlot
and getSlot
. These are the first of many
system calls you will be implementing in these assignments, so you might want
to give some though to designing an easily changeable system-call
implementation (or you have to be willing to throw-away and rewrite your
system-call implementation several times, which is probably the better approach
to take).
The system calls can be split into two groups: process-management system calls and inter-process communication system calls.
OperatingSystem.SystemCall.exit
)
OperatingSystem.SystemCall.exec
)After the exec system call returns, the caller's register 0 contains the system call status
Hardware.Status.ok | command completed successfully |
Hardware.Status.badPid | there is no program with the given id |
Hardware.Status.noResource | required resource not available |
and register 1 contains the new process's id if the exec was successful; otherwise the contents of register 1 is undefined.
The contents of registers 0 and 2 through 10 in the new process (the child process) are identical to the contents of the associated registers in the process that issued the exec (the parent process). Register 1 in the child process contains the parent process's id.
OperatingSystem.SystemCall.yield
)
The yield system call returns when the caller regains the CPU; register 0
should always contain Hardware.Status.ok
.
OperatingSystem.SystemCall.putSlot
)After the put-slot system call returns, the caller's register 0 contains the system call status
Hardware.Status.ok | command completed successfully |
Hardware.Status.badPID | there is no process with the given id |
Hardware.Status.noResource | required resource not available |
If register 0 contains Hardware.Status.ok
when the put-slot call returns, then the
given value was succsfully written into the receiving process's slot (note that
this does not imply that the receiving process has read the value from its
slot). If register 0 contains Hardware.Status.noResource
, then the attempt to write
the given value into receiver's slot has failed because the slot already
contains an unread value.
OperatingSystem.SystemCall.getSlot
)After the get-slot system call returns, the caller's register 0 contains the system call status
Hardware.Status.ok | command completed successfully |
Hardware.Status.noResource | required resource not available |
If register 0 contains Hardware.Status.ok
when the get-slot call returns, then register
1 contains the value read from the slot and register 2 contains the id of the
process that put the value. If register 0 contains Hardware.Status.noResource
, then
the slot didn't contain a value, and the contents of registers 1 and 2 are
undefined.
pa1-bad.dsk
batch
disk).
pa1-bad.dsk
batch disk).
/export/home/class/cs-os/pa1
contains some batch disks you can
use to test your operating system:
pa1-empty.dsk
- The empty disk; it contains no programs.
pa1-solo.dsk
- A single program does nothing for a while and then calls
exit.
pa1-bad.dsk
- A disk containing a program that
does bad things. Despite all the bad things that are going on, there should be
no output other than the usual end of execution information.
pa1-execs.dsk
- A disk containing two programs. The first program sets
a count and execs the second program. The second program reduces the count by
one and, if the count is still positive, execs another copy of itself.
pa1-dcs.dsk
- The first, client, program execs the second, server,
program and sends it a value. The doubling server receives a value, doubles it
and sends it back to the client. Then both processes exit.
pa1-ydcs.dsk
- Like dcs but the client yields if the get-slot system
call fails.
pa1-tree.dsk
- A root program execs two child programs, each of which
execs two child programs and so on until they form a seven-process complete
binary tree, then the leaves pass values back to their parents and exit, and so
on.
pa1-ytree.dsk
- Same as pa1-tree.dsk
except processes yield
whenever a put- or get-slot system call fails.
If you're looking for a way to proceed, you might want to consider the following steps: