I/O Systems
I/O Hardware
·
Incredible variety of I/O devices
·
Common concepts
o
Port
o
Bus
o
Controller
·
I/O instructions control
devices
·
Devices have addresses, used
by
o
Direct I/O instructions
o
Memory-mapped I/O
A Typical PC Bus Structure

Device I/O Port Locations on
PCs (partial)

Polling
·
Determines
state of device
o ready
o busy
o Error
·
Busy-wait
cycle to wait for I/O from device
Interrupts
· CPU
Interrupt-
triggered by I/O device
· Interrupt
handler receives
interrupts
· Maskable to ignore or
delay some interrupts
· Interrupt
vector to dispatch interrupt to correct handler
o
Based on priority
o
Some nonmaskable
· Interrupt
mechanism also used for exceptions
Direct Memory Access
· Used
to avoid programmed I/O for large
data movement
· Requires
DMA controller
· Bypasses
CPU to transfer data directly between I/O device and memory

Application I/O Interface
· I/O system calls
encapsulate device behaviors in generic classes
· Device-driver
layer hides differences among I/O controllers from kernel
· Devices
vary in many dimensions:
§ Character-stream or block
§ Sequential or random-access
§ Sharable or dedicated
§ Speed
of operation
§ read-write, read only, or write only

A Kernel I/O Structure

Block and Character Devices
· Block
devices include disk drives
§ Commands include read(), write(), seek()
§ Raw I/O or file-system access
§ Memory-mapped file access possible
· Character
devices include keyboards,
mice, serial ports
§ Commands include get(), put()
· Libraries layered on top allow line editing.
Network Devices
· Varying enough from block and character to
have own interface
· Unix and Windows include socket interface
Separates network
protocol from network operation.
vClocks
and Timers
· Provide current time, timer
· Programmable interval timer used for timings,
periodic interrupts.
ü Example1: timeout.c
main(int argc, char *argv[])
{
char buf[BUFSIZ];
int timeout;
timeout = atoi(argv[1]);
while (1) {
signal(SIGALRM, alarmhandler);
alarm(timeout);
printf("Enter
a string (withen %d seconds): ", timeout);
if ( gets(buf)!=
NULL) {
alarm(0);
printf("got
%s\n", buf);
}
}
}
alarmhandler(int sig)
{
printf("Timeout,
Hurry Up!\n");
}
ü Example2: ChatClientAlarm.c
int main(int argc, char **argv)
{
int sockfd;
struct
sockaddr_in servaddr;
struct
hostent *hp, *gethostbyname();
char buffer[512];
int nread;
sockfd = socket(AF_INET, SOCK_STREAM,
0);
bzero(&servaddr, sizeof(servaddr));
hp = gethostbyname(argv[1]);
bcopy(hp->h_addr, &(servaddr.sin_addr.s_addr), hp->h_length);
servaddr.sin_family
= AF_INET;
servaddr.sin_port
= htons(atoi(argv[2]));
if (connect(sockfd,
(SA *) & servaddr, sizeof(servaddr)) < 0) {
perror("connect
error");
exit(-1);
}
AlarmChat (sockfd);
}
AlarmChat(int sockfd)
{
int
nread;
char buffer[512];
signal(SIGALRM,
handle_ALARM);
ualarm(1000);
for (;;)
{
nread = read(0, buffer, 512);
if (nread == 0)
exit(0);
write(sockfd, buffer, nread);
nread = read(sockfd,
buffer, 512);
if
(nread == 0)
exit(0);
write(1,
buffer, nread);
}
}
handle_ALARM(int signo)
{
signal(SIGALRM,
handle_ALARM);
ualarm(1000);
}
vBlocking
and Nonblocking I/O
Ø Blocking - process suspended until I/O completed
Ø Nonblocking - Returns quickly with count of bytes read or
written
Ø Asynchronous - I/O subsystem signals process when I/O
completed
Ø
Blocking:
ü Example 3: block.c
int main(int argc, char *argv[])
{
char buffer[512];
int nread;
while
(1) {
printf("Enter
a string: ");
nread = read(0, buffer, 512);
if (nread
> 0) {
printf("\ngot: ");
write(1, buffer, nread);
}
}
}
Ø Nonblocking:
int
main(int argc, char *argv[])
{
char buffer[512];
int sleeptime;
int nread;
int val;
sleeptime = atoi(argv[1]);
val = fcntl(0,
F_GETFL, 0);
fcntl(0, F_SETFL, val
| O_NONBLOCK);
while (1) {
printf("Enter
a string: ");
nread =
read(0, buffer, 512);
if (nread
== -1) {
if (errno == EWOULDBLOCK) {
printf("WouldBlock, sleeping: %d\n", sleeptime);
sleep(sleeptime);
} else {
perror("read
error");
exit(-1);
}
} else if (nread
== 0) {
printf("EOF\n");
exit(0);
} else {
printf("\nGot: ");
write(1, buffer, nread);
}
}
}
char buffer[128];
void fillbuf();
int
main(int argc, char *argv[])
{
int sleeptime;
int nwrite;
int val;
int Total = 0;
sleeptime = atoi(argv[1]);
fillbuf();
val = fcntl(1,
F_GETFL, 0);
fcntl(1, F_SETFL, val
| O_NONBLOCK);
while (1) {
nwrite =
write(1, buffer, sizeof(buffer));
printf("..%d..",
nwrite);
if (nwrite)
Total += nwrite;
if (nwrite
== -1) {
if (errno == EWOULDBLOCK) {
sleep(sleeptime);
printf("\nwrote %d, slept %d\n", Total, sleeptime);
Total = 0;
sleep(sleeptime);
}
}
}
}
fillbuf()
{
int i;
for (i = 0; i <= sizeof(buffer); i++)
buffer[i]
= NULL;
}
ü Example 6: ChatClientNonBlock.c
int main(int argc, char **argv)
{
int sockfd;
struct
sockaddr_in servaddr;
struct
hostent *hp, *gethostbyname();
char buffer[512];
int nread;
sockfd = socket(AF_INET, SOCK_STREAM,
0);
bzero(&servaddr, sizeof(servaddr));
hp = gethostbyname(argv[1]);
bcopy(hp->h_addr, &(servaddr.sin_addr.s_addr), hp->h_length);
servaddr.sin_family
= AF_INET;
servaddr.sin_port
= htons(atoi(argv[2]));
if (connect(sockfd,
(SA *) & servaddr, sizeof(servaddr)) < 0) {
perror("connect
error");
exit(-1);
}
ChatNonBlock
(sockfd);
}
ChatNonBlock(int
sockfd)
{
int
nread;
char buffer[512];
int val;
val = fcntl (sockfd, F_GETFL, 0);
fcntl (sockfd, F_SETFL, val | O_NONBLOCK);
val = fcntl (0, F_GETFL,
0);
fcntl (0, F_SETFL, val |
O_NONBLOCK);
for (;;)
{
nread = read(0, buffer, 512);
if
(nread == 0)
exit(0);
write(sockfd, buffer, nread);
nread = read(sockfd,
buffer, 512);
if (nread == 0)
exit(0);
write(1,
buffer, nread);
usleep(1000);
}
}
ü Example 7: ChatClientSelect.c
int main(int argc, char **argv)
{
int sockfd;
int pid;
struct sockaddr_in servaddr;
struct hostent *hp, *gethostbyname();
sockfd = socket(AF_INET, SOCK_STREAM,
0);
bzero(&servaddr, sizeof(servaddr));
hp = gethostbyname(argv[1]);
bcopy(hp->h_addr, &(servaddr.sin_addr.s_addr),
hp->h_length);
servaddr.sin_family
= AF_INET;
servaddr.sin_port
= htons(atoi(argv[2]));
if (connect(sockfd, (SA *) & servaddr, sizeof(servaddr)) < 0) {
perror("connect
error");
exit(-1);
}
AsynchIO(0,
sockfd);
}
AsynchIO(int
fd1, int fd2)
{
fd_set readset;
char buffer[512];
int nread;
int i;
for (;;) {
FD_SET(fd1, &readset);
FD_SET(fd2, &readset);
bzero(buffer,
sizeof(buffer));
select(MAXFD, &readset,
NULL, NULL, NULL);
if (FD_ISSET(fd1, &readset))
{
nread
= read(fd1, buffer, 512);
if (nread
== 0) exit(0);
if (write(fd2, buffer, nread) == -1) exit(0);
}
if (FD_ISSET(fd2, &readset))
{
nread
= read(fd2, buffer, 512);
if (nread
== 0) exit(0);
if (write(fd1, buffer, nread) == -1) exit(0);
}
}
}
ü Example
8: ChatServerSelect.c
int main(int
argc, char **argv)
{
int i;
strcpy(ServerPort, argv[1]);
TCPServer.sin_family
= AF_INET;
TCPServer.sin_addr.s_addr
= htonl(INADDR_ANY);
TCPServer.sin_port
= htons(atoi(ServerPort));
for (i = 0; i <= MAXTCP; i++) connfd[i] = -1;
TCPSocket = socket(AF_INET, SOCK_STREAM,
0);
if (bind(TCPSocket, (SA *) & TCPServer, sizeof(TCPServer)) < 0) {
close(TCPSocket);
perror("binding
TCPSocket socket");
exit(-1);
}
listen(TCPSocket, 4);
FD_ZERO(&allset);
FD_SET(TCPSocket, &allset);
for (;;) {
readset =
allset;
select(MAXCLIENTS, &readset,
NULL, NULL, NULL);
if (FD_ISSET(TCPSocket, &readset)) {
for (i
= 0; i <= MAXTCP; i++) {
if (connfd[i] == -1) {
connfd[i] =
accept(TCPSocket, 0, 0);
FD_SET(connfd[i], &allset);
break;
}
}
}
for (i =
0; i <= MAXTCP; i++) {
if ((connfd[i]) == -1) continue;
if (FD_ISSET(connfd[i], &readset))
handleTCP(i);
}
}
}
handleTCP(int index)
{
int nread;
char buffer[BUFSIZE];
int i;
int myIndex
= index;
bzero(buffer, sizeof(buffer));
if ((nread =
read(connfd[myIndex], buffer, sizeof(buffer))) < 0) {
if (errno
== EINTR) return;
else perror("read
connfd");
}
if (nread ==
0) {
connfd[myIndex] = -1;
return;
}
for (i = 0; i
<= MAXTCP; i++)
if (connfd[i] != -1)
write(connfd[i], buffer, nread);
}
v Error
Handling
System calls return an error
number or code when I/O request fails.
In Unix
we use the C-lib function perror to
translate the error number into text message.
ü Example 9: error.c
main(int argc, char *argv[])
{
int fd;
char *fname;
fname = argv[1];
if ((fd =
open(fname, O_RDWR)) == -1) {
printf("errno:
%d\n", errno);
perror(fname);
exit(-1);
} else
printf(
"fd is %d\n", fd);
printf("opened %s\n", fname);
}
I/O Protection
User process may accidentally or purposefully
attempt to disrupt normal operation via illegal I/O instructions
· All
I/O instructions defined to be privileged
· I/O
must be performed via system calls
Kernel Data Structures
Kernel keeps state info for I/O components,
including open file tables, network connections, and character device state
UNIX I/O Kernel Structure
