Advertisement
ptkrisada

i/o multiplexing

Mar 15th, 2020
236
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 6.50 KB | None | 0 0
  1. /********************************************************************
  2.  * I/O multiplexing                                                 *
  3.  * When you have slow I/O, for example I/O across network, and you  *
  4.  * have multiple files being requested for reading or writing, how  *
  5.  * you know which file descriptor is ready at a time?               *
  6.  * We have learned O_NONBLOCK, which allows the program to keep     *
  7.  * reading or writing until finish, but without knowing which file  *
  8.  * descriptors are ready. select(2) and poll(2) can give us this    *
  9.  * information. Both functions comply with POSIX.1. But select(2)   *
  10.  * was adopted by POSIX.1 long before poll(2). We usually see old   *
  11.  * C code still using select(2). So we will now learn select(2).    *
  12.  * If there are ready file descriptors, select(2) will return the   *
  13.  * number of ready descriptors, we can then test if the ready       *
  14.  * descriptors are in read set (rset) or write set (wset).          *
  15.  * In this example, we are trying to read from ./tem1, ./tem2 and   *
  16.  * write to ./tem3. So prior to running this program, create files  *
  17.  * ./tem1 and ./tem2, while ./tem3 will be created by the program.  *
  18.  * You can replace these files to remote files. Then it is more     *
  19.  * realistic for slow input or output.                              *
  20.  ********************************************************************/
  21.  
  22. #include <sys/select.h> /* select(2) */
  23. #include <sys/stat.h>   /* fstat(2); to get the info of open files */
  24. #include <stdio.h>
  25. #include <stdlib.h>     /* exit(3) */
  26. #include <ctype.h>      /* isprint(3) */
  27. #include <fcntl.h>      /* open(2) */
  28. #include <errno.h>      /* errno and EINTR (error due to interrupt */
  29. #include <unistd.h>     /* read(2) and write(2) */
  30.  
  31. #define MAXLINE 256
  32. #define TEM1    "./tem1"    /* can be replaced with a remote file */
  33. #define TEM2    "./tem2"    /* can be replaced with a remote file */
  34. #define TEM3    "./tem3"    /* can be replaced with a remote file */
  35. #define max(a, b)   ((a) > (b) ? (a) : (b)) /* simply find max value */
  36.  
  37. /* prototypes */
  38. void err_sys(const char *);
  39. ssize_t readn(int, void *, size_t);         /* keep reading until finish */
  40. ssize_t writen(int, const void *, size_t);  /* keep writing until finish */
  41.  
  42. int main()
  43. {
  44.     int i,  /* for looping */
  45.         n,  /* number of file descriptors in sets */
  46.         rc, /* returned value from select(2) */
  47.         nfd,    /* the highest file descriptor */
  48.         fd1, fd2, fd3;  /* file descriptors */
  49.     char buff[MAXLINE];
  50.     struct timeval t;   /* for setting timeout */
  51.     struct stat *stbuf1 = malloc(sizeof (struct stat)), /* stat buffer */
  52.                 *stbuf2 = malloc(sizeof (struct stat));
  53.     fd_set rset, wset;  /* read set and write set */
  54.  
  55.     /* select() can also be used with nonblocking i/o i.e. O_NONBLOCK
  56.      * with open() or fcntl(). */
  57.     if ((fd1 = open(TEM1, O_RDONLY)) == -1) /* Open as read only */
  58.         err_sys("open");
  59.     if ((fd2 = open(TEM2, O_RDONLY)) == -1) /* Open as read only */
  60.         err_sys("open");
  61.     /* Open for writing, create and truncate file size to zero  *
  62.      * using bitwise ORing. The last argument is bitwise ORing  *
  63.      * for file permission.                                     */
  64.     if ((fd3 = open(TEM3, O_CREAT | O_TRUNC | O_WRONLY, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)) == -1)
  65.         err_sys("open");
  66.     if (fstat(fd1, stbuf1) == -1)   /* Get file info and store it in stbuf1. */
  67.         err_sys("fstat");
  68.     if (fstat(fd2, stbuf2) == -1)   /* Get file info and store it in stbuf2. */
  69.         err_sys("fstat");
  70.     t.tv_sec = 0;
  71.     t.tv_usec = 1; /* Set timeout to 0 second + 1 micro second. */
  72.     FD_ZERO(&rset); /* Clear read set. */
  73.     FD_ZERO(&wset); /* Clear write set. */
  74.     FD_SET(fd1, &rset); /* Add fd1 to read set. */
  75.     FD_SET(fd2, &rset); /* Add fd2 to read set. */
  76.     FD_SET(fd3, &wset); /* Add fd3 to write set. */
  77.     nfd = max(fd1, max(fd2, fd3));  /* Find max interger file descriptor. */
  78.     for (n = nfd - STDERR_FILENO - 1;;) { /* assuming no other open fd */
  79.         /* select(2) state the 1st argument is max descriptor + 1.  *
  80.          * The 2nd argument is an address of read set.              *
  81.          * The 3rd argument is an address of write set.             *
  82.          * The 4th argument is an address of exception set.         *
  83.          * We don't use in this example. So leave it NULL.          *
  84.          * The 5th argument is an address of timeout struct.        */
  85.         rc = select(nfd + 1, &rset, &wset, NULL, &t);
  86.         if (rc == -1)
  87.             err_sys("select");
  88.         if (rc == 0) {
  89.             printf("timeout\n");
  90.             break;
  91.         }
  92.         if (FD_ISSET(fd1, &rset)) { /* Test if fd in read set is ready. */
  93.             readn(fd1, buff, stbuf1->st_size);  /* Read until finish. */
  94.             for (i = 0; i < stbuf1->st_size; i++)
  95.                 /* Check if each char is printable. */
  96.                 if (!isprint(buff[i])) {
  97.                     buff[i] = 0;    /* If not add NULL terminated string. */
  98.                     break;
  99.                 }
  100.             printf("%s\n", buff);   /* Then print it. */
  101.             FD_CLR(fd1, &rset);     /* Clear such fd from read set. */
  102.             if (n > 0)
  103.                 n--;                /* Decrease fd count. */
  104.             else
  105.                 break; /* if n == 0, no remaining fd; leave for (;;) loop */
  106.         }
  107.         if (FD_ISSET(fd2, &rset)) { /* Test if fd in read set is ready. */
  108.             readn(fd2, buff, stbuf2->st_size);  /* Read until finish. */
  109.             for (i = 0; i < stbuf2->st_size; i++)
  110.                 /* Check if each char is printable. */
  111.                 if (!isprint(buff[i])) {
  112.                     buff[i] = 0;    /* If not add NULL terminated string. */
  113.                     break;
  114.                 }
  115.             printf("%s\n", buff);   /* Then print it. */
  116.             FD_CLR(fd2, &rset);     /* Clear such fd from read set. */
  117.             if (n > 0)
  118.                 n--;                /* Decrease fd count. */
  119.             else
  120.                 break;
  121.         }
  122.         if (FD_ISSET(fd3, &wset)) { /* Test if fd in write set is ready. */
  123.             writen(fd3, "sample\n", 7); /* Write until finish. */
  124.             FD_CLR(fd3, &wset);     /* Clear such fd from write set. */
  125.             if (n > 0)
  126.                 n--;                /* Decrease fd count. */
  127.             else
  128.                 break;
  129.         }
  130.     }
  131.     close(fd1);
  132.     close(fd2);
  133.     close(fd3);
  134.     free(stbuf1);
  135.     free(stbuf2);
  136.     return 0;
  137. }
  138.  
  139. void err_sys(const char *str)
  140. {
  141.     fflush(stdout);
  142.     perror(str);
  143.     fflush(stderr);
  144.     exit(EXIT_FAILURE);
  145. }
  146.  
  147. /* Keep reading until finish. */
  148. ssize_t readn(int fd, void *vptr, size_t n)
  149. {
  150.     size_t nleft;
  151.     ssize_t nread;
  152.     char *ptr;
  153.  
  154.     ptr = vptr;
  155.     nleft = n;
  156.     while (nleft > 0) {
  157.         if ((nread = read(fd, ptr, nleft)) < 0) {
  158.             if (errno == EINTR)
  159.                 nread = 0;
  160.             else
  161.                 return -1;
  162.         } else if (nread == 0)
  163.             break; /* EOF */
  164.         nleft -= nread;
  165.         ptr += nread;
  166.     }
  167.     return n - nleft;
  168. }
  169.  
  170. /* Keep writing until finish. */
  171. ssize_t writen(int fd, const void *vptr, size_t n)
  172. {
  173.     size_t nleft;
  174.     ssize_t nwritten;
  175.     const char *ptr;
  176.  
  177.     ptr = vptr;
  178.     nleft = n;
  179.     while (nleft > 0) {
  180.         if ((nwritten = write(fd, ptr, nleft)) <= 0) {
  181.             if (errno == EINTR)
  182.                 nwritten = 0;
  183.             else
  184.                 return -1;
  185.         }
  186.         nleft -= nwritten;
  187.         ptr += nwritten;
  188.     }
  189.     return n;
  190. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement