==== Start Lecture #11
====
Chapter 5: Input/Output
5.1: Principles of I/O Hardware
5.1.1: I/O Devices
- Not much to say. Devices are varied
- Block versus character devices:
- Devices, like disks or CD-roms, with addressible chunks
(sectors in this case) are called block
devices.
These devices do not support seeking.
- Devices, like an ethernet or modem connection, that are a
stream of characters are called character
devices
These devices do not support seeking
- Some cases, like tapes, are not so clear
5.1.2: Device Controllers
These are the ``real devices'' as far as the OS is concerned. That
is the OS code is written with the controller spec in hand not with
the device spec.
The figure in the book is so oversimplfied as to be borderline
false. The following picture is closer to the truth (but really there
are several I/O buses of different speeds).
- The controller abstracts away some of the low level features of
the device.
- For disks, the controler does error checking, buffering and
handles interleaving of sectors. Sectors are interleaved if the
controler or cpu cannot handle the data rate and would otherwise have
to wait a full revolution. I do not believe this is a concern with
modern machines where the electronics have increased in speed faster
than the devices.
- For analog monitors (aka CTRs) the controler does
a great deal. Analog video is far from a bunch of ones and zeros.
- Controllers are also called adaptors.
- Typically the interface the OS sees consists of some device
registers located on the controler (address to access, read vs write,
length, data value, etc).
- Memory-mapped I/O vs. I/O
space. In memory mapped I/O the device registers are mapped
into normal memory space. So you need to know that
load 8888<--4
tells the disk read the sector whose address you previously loaded
into 8800. In the I/O space you used different instructions (not
ordinary loads and stores) to do essentially the same thing.
Homework: 2
5.1.3: Direct Memory Access (DMA)
- The disk controler gets the desired data from the disk to its
buffer
- For programmed I/O (PIO) the cpu then does loads and
stores (or I/O instructions) to copy the data from the buffer to the
desired memory location.
- With a DMA controller, the controller writes the memory without
intervention of the CPU.
- Clearly DMA saves CPU work. But this might not be important if
the CPU is limited by the memory or by system buses.
- Very important is that there is less data movement so the buses
are used less and the entire operation takes less time.
- Since PIO is pure software it is easier to change, which is an
advantage.
- DMA does need a number of bus transfers from the CPU to the
controler to specify the dma. So dma is most effective for large
transfers where the setup is amortized.
- Why have the buffer? Why not just go from the disk straight to
the memory.
Ans: Speed matchine. The disk gives data a fixed rate which might
exceed the rate the memory can accept it. Also might have two dma
controlers that have been given requests.
Homework: 5
5.2: Principles of I/O Software
As with any large software system, good design and layering is
important.
5.2.1: Goals of the I/O Software
Device independence
We want to have most of the OS, unaware of the characteristics of
the specific devices attached to the system. Indeed we also want the
OS to be largely unaware of the cpu type itself.
It is thanks to this device independence that programs can be
written to write and read generic devices and then at run time
specific devices are assigned. Writing to a disk has differences from
writing to a terminal, but unix cp (dos copy) doesn't see these
differences. Indeed, most of the OS, including the filesystem code,
Is unaware of whether the device is a floppy or hard disk.
Uniform naming
Recall that we discussed the value
of the name space implemented by filesystems. There is no dependence
between the name of the file and the device on which it is stored.
Error handling
There are several aspects to error handling including: detection,
correction (if possible) and reporting.
- Detection should be done as close to where the error occurred as
possible before more damage is done (fault containment). This is not
trivial.
- Correction is sometimes easy, for example ECC memory does this
automatically (but the OS wants to know about it and schedule
replacement of the faulty chips before unrecoverable double errors
occur).
Other easy cases include successful retries for failed ethernet
transmissions. In this example, while logging is appropriate, it is
quite reasonable for no action to be taken.
- Error reporting tends to be awful. The trouble is that the error
occurs occurs at a low level but by the time it is reported the
context is lost. Unix/linux in particular is horrible in this area.
Creating the illusion of synchronous I/O
- I/O must be asynchronous for performance. That is the OS
cannot simply wait for an I/O to complete. Instead, it
proceeds with other activities and responds to the notification when
the I/O has finished.
- Users (mostly) want no part of this. The code sequence
Read X
Y <-- X+1
Print Y
should print a value one greater than that read. But if the
assignment is performed before the read completes ...
- Performance junkies sometimes do want the asynchrony as they want
to do what the OS does.
Sharable vs dedicated devices
For devices like printers and tape drives, only one user at a time
is permitted. These are called serially resuable
devices and are studied next chapter.
Layering
Layers of abstraction as usual prove to be effective. Most systems
are believed to use the following layers (but for many systems, the OS
code is not available for inspection).
- User level I/O routines
- Device independent I/O software
- Device drivers
- Interrupt handlers
We give a bottom up explanation.
5.2.2: Interrupt Handlers
We discussed an interrupt handler before when studying page faults.
Then it was called ``assembly language code''.
In the present case, we have a process (actually the device driver
OS code running in behalf of a user process) blocked on I/O and the I/O
event has just completed. So the goal is to make the process ready.
Possible methods are.
- Releasing a semaphore on which the process is waiting
- Sending a message to the process.
- Inserting the process table entry onto the ready list.
5.2.3: Device Drivers
The portion of the OS that ``knows'' the characteristics of the
controler.
The driver has two ``parts'' corresponding to its two access
points. Recall the following figure from the beginning of the course.
- Access by the main line OS with an I/O request.
- Accessed by the interrupt handler when the I/O completes (this
completion is signaled by an interrupt).
Tanenbaum describes the actions of the driver assuming it is
implemented as a process (which he recommends). I give both that view
point and the self-service paradigm in which the driver is invoked by
the OS acting in behalf of a user process (more precisely the process
shifts into kernel mode).
Driver as a process (tanenbaum)
- The user issues an I/O request. The main line OS prepares a
generic (e.g. read, not read using buslogic scsi controler) request for
the driver and the driver is awakened (perhaps a message is sent to
the driver to do both jobs).
- The driver wakes up
- If the driver was idle (i.e., the controler is idle), the
driver writes device registers on the controler ending with a
command for the controler to begin the actual I/O.
- If the controler is busy (doing work the driver gave it), the
driver simply queues the current request (the driver dequeues this
below).
- The driver blocks waiting for an interrupt or for more
requests.
- An interrupt arrives (i.e. an I/O has been completed)
- The driver informs the main line perhaps passing data and
surely passing status (error, OK).
- Find next work item or block
- If the queue of requests is non-empty dequeue one and
proceed as if just received a request from the main line.
- If queue is empty, the driver blocks waiting for an
interrupt or a request from the main line.
Driver in a self-service paradigm
- The user issues an I/O request. The main line OS prepares a
generic request for the driver and calls the driver.
- The driver is called
- If the driver was idle (i.e., the controler is idle), the
driver writes device registers on the controler ending with a
command for the controler to begin the actual I/O.
- If the controler is busy (doing work the driver gave it), the
driver simply queues the current request (the driver dequeues this
below).
- The driver returns to the main line
- An interrupt arrives (i.e. an I/O has been completed)
- The driver informs the main line perhaps passing data and
surely passing status (error, OK).
- Find next work item or return
- If the queue of requests is non-empty dequeue one and
proceed as if just received a request from the main line.
- If queue is empty, the driver returns to the main line.
5.2.4: Device-Independent I/O Software
Most of the functionality. But not necessarily most of the code
since there can be many drivers all doing essentially the
same thing is slightely different way due to slightly different
controllers.
- Naming. Again an important O/S functionality.
Must offer a consistent interface to the device drivers.
In unix this is done by associating each device with a (special)
file in the /dev directory. The inodes for these files contain an
indication that these are special files and also contain so called
major and minor device numbers. The major device number gives the
number of the driver. (These numbers are rather ad hoc, they
correspond to the position of the function pointer to the driver in a
table of function pointers.)
- Protection. A wide range of possibilities are
actually done in real systems. Including both extreme examples of
everything is permitted and nothing is permitted (directly).
- In ms-dos any process can write to any file. Presumably our
offensive nuclear missile launchers do not run dos.
- In IBM and other mainframe OS's, normal processors do not
access devices. Indeed the main CPU doesn't issue the I/O
requests. Instead an I/O channel is used and the mainline
constructs a channel program and tells the channel to invoke it.
- Unix uses normal rwx bits on files in /dev (I don't believe x
is used).
- Buffering is necessary since requests come in a
size specified by the user and data is delivered in a size specified
by the device.
- Enforce exclusive access for non-shared devices like tapes.
5.2.5: User-Space Software
A good deal of I/O code is actually executed in user space. Some
is in library routines linked into user programs and some is in daemon
processes.
- Some library routines are trivial and just move their arguments
int the corrct place (e.g. registers) and then issue a trap to the
correct system call.
- Some, notably standard-IO (stdio) in unix, are definitely not
trivial. For example consider the formatting of floating point
numbers done in printf and the reverse in scanf.
- Printing to a local printer is often in part by a regular program
(lpr in unix) and part by a deamon (lpd in unix).
The daemon might be started when the system boots or might be started
on demand. I guess it is called a daemon because it is not under the
control of any user.
- Pringing uses spooling, i.e., the file to be
printed is copied somewhere by lpr and then the daemon works with this
copy. Mail uses a similar technique (but generally it is not called
spooling but queuing).
Homework:
Homework: 6, 7, 8.
5.3: Disks
The ideal storage device is
- Fast
- Big (in capacity)
- Cheap
- Impossible
Disks are big and cheap, but slow.
5.3.1: Disk Hardware
Show a real disk opened up and illustrate the components
- Platter
- Surface
- Head
- Track
- Sector
- Cylinder
- Seek time
- Rotational latency
- Transfer time
Overlapping I/O operations is important. Many controllers can do
overlapped seeks, i.e. issue a seek to one disk while another is
already seeking.
Despite what Tannenbaum says, modern disks cheat and do not have
the same number of sectors on outer cylinders as on inner one. Often
the controller ``cover for them'' and protect the lie.
Again contrary to Tannenbaum, it is not true that when one head is
reading from cylinder C, all the heads can read from cylinder C with
no penalty.