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");
}

 

Usage Example:

% timeout 3

 

 

ü 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];
        siginterrupt(SIGALRM, 1);


       
signal(SIGALRM, handle_ALARM);
        alarm(1);
        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);
        alarm(1);

}

Usage Example:

% ChatServerSelect 10990 &

% ChatClientAlarm localhost 10990 1

 

 

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);
                }
            }
}

 

Usage Example:

% block

 

Ø   Nonblocking:

 

ü Example 4:nonblockRead.c

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);
    }
  }
}

Usage Example:

% nonblockRead 3

 

 

ü Example 5: nonblockWrite.c

 

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;
}

Usage Example:

% nonblockWrite 3

 

 

ü 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);
                sleep(1);

        }
}

 

Usage Example:

% ChatServerSelect 10990 &

% ChatClientNonBlock localhost 10990

 

 

vAsynchronous

 

ü 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);
      }
   }

}

 

Usage Example:

 % ChatServerSelect 10990 &

% ChatClientSelect localhost 10990

 

 

ü 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);
}

 

Usage Example:

% error /tmp/testfile

 

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

 

 

Example 10: fdTypeTest.c

 

Usage Example:

% fdTypeTest 101990 &

% telnet localhost 10990