Chapter 13 -- I/O
all about I/O
-------------
computers aren't useful unless we can put data into them,
and get results out.
input -- data to computer
output -- data from computer
computer model:
----- --------
|CPU| <----> |memory|
----- ^ --------
|
|
\ /
-----
|i/o|
-----
examples of input devices:
keyboard, mouse, network, disk, ??
examples of output devices:
printer, (terminal) display, network, ??
simulator has only 2 I/O devices,
keyboard (for input)
display (for output)
ISSUES THAT MUST BE SOLVED:
programmer interface -- tools give
get_ch, put_ch, put_str
these are actually OS implemented procedures.
(The OS is the program that interfaces between the programmer
or application user and the actual hardware. For us, it is NT.)
protection issues --
in a real system, there could be more than one terminal
(terminal is a keyboard and display together)
Should one user be able to display characters on another's
display? Lock up another's keyboard? Send a file of
infinite length to the printer, effectively shutting
all others out?
In practice, the OS's job is "resource management,"
allocating all portions of the processor. Examples
of resources are the CPU and all I/O devices.
physical issues --
A computer today (1998) can complete an instruction at
the rate of about 1 each nsec.
Unfortunately, typical I/O devices are much slower, often
requiring 10s of milliseconds to deal with a single
character. That is approx. 1 million times slower!
This situation is dubbed the "access gap."
disk - a real, live, phisical device
------------------------------------
Vocabulary, to form a picture of a disk (ch 13, p260)
PLATTER -- sort of like a phonograph record or CD.
data is stored on a SURFACE of a platter.
all platters are tied together and rotate around the SPINDLE
at a fixed speed.
each surface has one or more READ/WRITE HEADS.
Platters are broken down into TRACKS. A single track is
one of many concentric circles on the platter.
All the corresponding tracks on all surfaces, taken together,
form a CYLINDER.
Each track is broken down into SECTORS.
How we read/write to a sector.
Given: the sector position on the cylinder. (looked up in a
table, or calculated from the disk address).
-- the disk is spinning.
-- the read/write head is moving to the correct cylinder (track).
THIS TAKES A LONG TIME RELATIVE TO THE OTHER STUFF. It is
the physical movement, acceleration, etc. comes into play.
This is SEEK time.
-- once the read/write head is over the correct cylinder, there
is bound to be some time to wait until the correct sector
is under the head. This is ROTATIONAL LATENCY.
-- Even at the correct sector, it still takes some time for
the data to be read/written. This is the READ or WRITE
time.
time to read a sector = seek time + rotate time + read time.
So, the nitty gritty issue is: how does the OS accomplish
I/O requests? There are 2 possibilities.
1. have special I/O instructions
-- input
need to know which device, how much data, where the
data is to go
-- output
need to know which device, how much data, where the
data currently is
How does the processor know that the instruction has completed?
(Is there any need to wait?)
What happens if the device encounters an error?
(Does this halt the computer?)
2. the solution of choice
overload memory locations to use as communication channels.
for example,
address
0x0000 0000 -|
. | real memory
. |
. |
0xffff 0000 -|
0xffff 0008 - data from keyboard (Keyboard_Data)
0xffff 0010 - data to display (Display_Data)
then, by reading (loading) from location 0xffff0008, data
is requested from the keyboard
then, by writing (storing) to location 0xffff0010, data
is sent to the display
the syscall code in the OS must be (in essence)
mov eax, Keyboard_Data # get_ch syscall
return from syscall
and
mov Display_Data, eax # put_ch syscall
return from syscall
This method of I/O is called MEMORY-MAPPED I/O.
Problems with memory-mapped I/O as currently given:
-- get_ch presumably returns once a character has been typed.
What happens if the user does not type a character?
Types it on the wrong keyboard? Goes to get a drink
of water?
What happens to the data if the user types 2 characters
before get_ch has been called?
How does the computer know if a character has been typed?
-- put_ch and put_str: how does the computer know that the device
is ready to print out a second character? What if the
printer jams? (printers and terminals are SLOW!)
What is needed is a way to convey information about the
STATUS of I/O devices. This status information is used
to coordinate and SYNCHRONIZE the useage of devices.
address
0x0000 0000 -|
. | real memory
. |
. |
0xffff 0000 -|
0xffff 0008 - data from keyboard (Keyboard_Data)
0xffff 000c - STATUS from keyboard (Keyboard_Status)
0xffff 0010 - data to display (Display_Data)
0xffff 0014 - STATUS from display (Display_Status)
assume that the MSB is used to tell the status of a device.
MSB = 1 means device ready
MSB = 0 means device is busy
note that we can check for device ready/busy by looking to see
if the Status word is negative (2's comp) or not.
for the keyboard, a 1 means that a character has been typed
a 0 means that no character is available
for the display, a 1 means that a new character may be sent
a 0 means that the device is still disposing
of a previous character
Then, the code in the OS must be more like
keyboard_wait: ; for get_ch
test Keyboard_Status, 80000000h
jz keyboard_wait
mov eax, Keyboard_Data
and
display_wait: ; for put_ch
test Display_Status, 80000000h
jz display_wait
mov Display_Data, eax
This scheme is known as BUSY WAITING, or SPIN WAITING.
The little loop is called a SPIN WAIT LOOP.
Something that is not well explained (at this level) is how
these status bits get set and cleared. The spin wait loop
reads the status word, but does not change it.
The device (its CONTROLLER) sets and clears the bit.
An implied fuction is that the device sets the bit
when it becomes ready to work on another character.
AND, a mov from Keyboard_Data also clears the MSB of Keyboard_Status
AND, a mov to Display_Data also clears the MSB of Display_Status
PROBLEMS with this programmed I/O approach:
-- much time is wasted spin waiting.
if it takes 100 instructions to program this, and each
instruction takes 20ns to execute, then it takes
100 * 20nsec = 2000nsec = 2 usec to execute this code
if a device takes 2msec (=2000usec) to deal with one character,
then the percent of time spent waiting is
time waiting 2000us
------------ = --------------- = .999 = 99.9%
total time 2000us + 2usec
We'd like a solution that spent less time "doing nothing"
-- if (somehow) a second key is pressed before the program does
a get_ch, the first key pressed is lost. There is only one
character's worth of storage.
This problem is actually a "Catch-22." The keyboard_wait code has
to be run often enough that no characters are lost, but
executing this code spin waits until a character is pressed.
The system could do nothing but wait around for characters!
Some problems are solved by the use of queues (buffers).
The check for device ready is separated from the sending
and receiving of characters. Code for this is in the
text, pages 265 and 266.
putnextchar: print a character if there is one in the
queue, and the device is ready
(done by OS periodically)
printstring: put character(s) in queue and return
(called by user program)
getnextchar: get a character and place in a queue, if one
is waiting at the keyboard
(done by OS periodically)
getstring: get character from queue (if available) and return;
if queue is empty, spin wait until there is
a character.
(called by user program)
Some difficulties are caused by this situation:
-- OS must call getnextchar regularly and often so as not
to lose characters.
-- What happens if the queue(s) become full? Are characters
lost?
-- OS must call putnextchar regularly to empty out the queue.