Multiplexing i/o A look at some alternatives under multiple sources of device-input

advertisement
Multiplexing i/o
A look at some alternatives under
Linux for dealing concurrently with
multiple sources of device-input
What’s the problem?
• Some applications need to process input
from more than one peripheral device
• Input is normally obtained using a ‘read()’
operation on an open file-descriptor
• But ‘read()’ may cause a process to sleep
if no data is ready from a particular device
• While asleep the process is unable to read
new data that is ready on any other device
Alternative approaches
• There are at least five possible ways for
overcoming this problem of ‘deadlock’
• All of these approaches have been used,
but some have worked better than others
• Four of these alternatives are supported
by the standard features of UNIX systems
• (The fifth approach, while very interesting,
seems to be unique to the Mach system)
One immediate application
• We proposed the idea of a Linux program
that would utilize our recent knowledge of
how to program RealTek’s 8139 network
controllers in our classroom’s workstations
• We want any pair of users who are sitting
at different computers to be able to ‘chat’
by typing messages in a window that will
be visible remotely in a different window
• This requires multiplexed input (Project 2)
Method 1: timesharing
• Any UNIX application can fork a number of
child processes, each dedicated to reading
data from just one of the open device-files
• The operating system’s scheduler will then
give each process its opportunity to read
and process any new data that becomes
available from its particular device-file
• But scheduling consumes CPU time, and
any task-coordination can add complexity
Method 2: non-blocking i/o
• UNIX applications can open device-files in
a ‘non-blocking’ mode (if the driver allows)
• Instead of sleeping when no data is ready,
a process can proceed immediately to try
reading from one of the other device-files
• But this produces a ‘CPU-bound’ program
that can ‘starve’ other system applications
(by constantly calling ‘read()’ for no data)
Method 3: using signals
• UNIX programs can install signal-handlers
• Then the application can ‘sleep’ until it is
woken up by a signal that indicates new
data can be read from a specific device
• Indeed this approach is widely used -- in
cases where the underlying device-driver
implements the required support-routines
for so-called ‘asynchronous’ input-output
Method 4: using ‘select()’
• UNIX programs can invoke a convenient
library-function, called ‘select()’, which lets
the process ‘sleep’ until at least one of the
device-files of interest is ready for reading
new data (or for writing new data), or until
a predetermined ‘timeout’ has expired
• This approach is favored because it enjoys
even greater efficiency and flexibility, not
to mention simplicity, than using ‘signals’
Method 5: multiplexed-read
• This method is the most efficient of all, as
it needs only one system-call, in ‘blocking
mode’, to be sure of obtaining new data
from at least one device in a specified set
• Its programming syntax is not (yet) part of
the POSIX (Portable Operating Systems)
standard; it’s not implemented in Linux
Using Method 4
• To support use of the ‘select()’ function, a
character-mode device-driver needs only
to implement a ‘poll()’ driver-method
• It is very straightforward to do this: review
Chapter 6 of “Linux Device Drivers (3Ed)”
• We do it for our RealTek driver ‘withpoll.c’
• Our ‘trychat.cpp’ demo-program uses the
services of this ‘withpoll.c’ device-driver
The ‘fd_set’ object
Header-file:
Declare:
Initialize:
Setup for use:
#include <sys/select.h>
fd_set
readset;
FD_ZERO( &readset );
FD_SET( nic, &readset );
FD_SET( kb, &readset );
Use:
int m = 1 + ( ( kb < nic ) ? nic : kb;
if ( select( m, &readset, 0, 0, 0 ) < 0 ) break;
if ( FD_ISSET( kb, &readset ) read_kb();
if ( FD_ISSET( nic, &readset ) read_nic();
In-class exercise
• Try your hand at implementing Method 1
(the timeshare method) for a version of
‘nicchat.cpp’ that does not require ‘poll()’
• You can use our earlier ‘rxplustx.c’ driver
• You can replace the ‘select()’ function-call
with a ‘fork()’ function-call, letting the childprocess read from standard-input while the
parent-process reads from ‘/dev/nic’.
Download