Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- /********************************************************************
- * I/O multiplexing *
- * When you have slow I/O, for example I/O across network, and you *
- * have multiple files being requested for reading or writing, how *
- * you know which file descriptor is ready at a time? *
- * We have learned O_NONBLOCK, which allows the program to keep *
- * reading or writing until finish, but without knowing which file *
- * descriptors are ready. select(2) and poll(2) can give us this *
- * information. Both functions comply with POSIX.1. But select(2) *
- * was adopted by POSIX.1 long before poll(2). We usually see old *
- * C code still using select(2). So we will now learn select(2). *
- * If there are ready file descriptors, select(2) will return the *
- * number of ready descriptors, we can then test if the ready *
- * descriptors are in read set (rset) or write set (wset). *
- * In this example, we are trying to read from ./tem1, ./tem2 and *
- * write to ./tem3. So prior to running this program, create files *
- * ./tem1 and ./tem2, while ./tem3 will be created by the program. *
- * You can replace these files to remote files. Then it is more *
- * realistic for slow input or output. *
- ********************************************************************/
- #include <sys/select.h> /* select(2) */
- #include <sys/stat.h> /* fstat(2); to get the info of open files */
- #include <stdio.h>
- #include <stdlib.h> /* exit(3) */
- #include <ctype.h> /* isprint(3) */
- #include <fcntl.h> /* open(2) */
- #include <errno.h> /* errno and EINTR (error due to interrupt */
- #include <unistd.h> /* read(2) and write(2) */
- #define MAXLINE 256
- #define TEM1 "./tem1" /* can be replaced with a remote file */
- #define TEM2 "./tem2" /* can be replaced with a remote file */
- #define TEM3 "./tem3" /* can be replaced with a remote file */
- #define max(a, b) ((a) > (b) ? (a) : (b)) /* simply find max value */
- /* prototypes */
- void err_sys(const char *);
- ssize_t readn(int, void *, size_t); /* keep reading until finish */
- ssize_t writen(int, const void *, size_t); /* keep writing until finish */
- int main()
- {
- int i, /* for looping */
- n, /* number of file descriptors in sets */
- rc, /* returned value from select(2) */
- nfd, /* the highest file descriptor */
- fd1, fd2, fd3; /* file descriptors */
- char buff[MAXLINE];
- struct timeval t; /* for setting timeout */
- struct stat *stbuf1 = malloc(sizeof (struct stat)), /* stat buffer */
- *stbuf2 = malloc(sizeof (struct stat));
- fd_set rset, wset; /* read set and write set */
- /* select() can also be used with nonblocking i/o i.e. O_NONBLOCK
- * with open() or fcntl(). */
- if ((fd1 = open(TEM1, O_RDONLY)) == -1) /* Open as read only */
- err_sys("open");
- if ((fd2 = open(TEM2, O_RDONLY)) == -1) /* Open as read only */
- err_sys("open");
- /* Open for writing, create and truncate file size to zero *
- * using bitwise ORing. The last argument is bitwise ORing *
- * for file permission. */
- if ((fd3 = open(TEM3, O_CREAT | O_TRUNC | O_WRONLY, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)) == -1)
- err_sys("open");
- if (fstat(fd1, stbuf1) == -1) /* Get file info and store it in stbuf1. */
- err_sys("fstat");
- if (fstat(fd2, stbuf2) == -1) /* Get file info and store it in stbuf2. */
- err_sys("fstat");
- t.tv_sec = 0;
- t.tv_usec = 1; /* Set timeout to 0 second + 1 micro second. */
- FD_ZERO(&rset); /* Clear read set. */
- FD_ZERO(&wset); /* Clear write set. */
- FD_SET(fd1, &rset); /* Add fd1 to read set. */
- FD_SET(fd2, &rset); /* Add fd2 to read set. */
- FD_SET(fd3, &wset); /* Add fd3 to write set. */
- nfd = max(fd1, max(fd2, fd3)); /* Find max interger file descriptor. */
- for (n = nfd - STDERR_FILENO - 1;;) { /* assuming no other open fd */
- /* select(2) state the 1st argument is max descriptor + 1. *
- * The 2nd argument is an address of read set. *
- * The 3rd argument is an address of write set. *
- * The 4th argument is an address of exception set. *
- * We don't use in this example. So leave it NULL. *
- * The 5th argument is an address of timeout struct. */
- rc = select(nfd + 1, &rset, &wset, NULL, &t);
- if (rc == -1)
- err_sys("select");
- if (rc == 0) {
- printf("timeout\n");
- break;
- }
- if (FD_ISSET(fd1, &rset)) { /* Test if fd in read set is ready. */
- readn(fd1, buff, stbuf1->st_size); /* Read until finish. */
- for (i = 0; i < stbuf1->st_size; i++)
- /* Check if each char is printable. */
- if (!isprint(buff[i])) {
- buff[i] = 0; /* If not add NULL terminated string. */
- break;
- }
- printf("%s\n", buff); /* Then print it. */
- FD_CLR(fd1, &rset); /* Clear such fd from read set. */
- if (n > 0)
- n--; /* Decrease fd count. */
- else
- break; /* if n == 0, no remaining fd; leave for (;;) loop */
- }
- if (FD_ISSET(fd2, &rset)) { /* Test if fd in read set is ready. */
- readn(fd2, buff, stbuf2->st_size); /* Read until finish. */
- for (i = 0; i < stbuf2->st_size; i++)
- /* Check if each char is printable. */
- if (!isprint(buff[i])) {
- buff[i] = 0; /* If not add NULL terminated string. */
- break;
- }
- printf("%s\n", buff); /* Then print it. */
- FD_CLR(fd2, &rset); /* Clear such fd from read set. */
- if (n > 0)
- n--; /* Decrease fd count. */
- else
- break;
- }
- if (FD_ISSET(fd3, &wset)) { /* Test if fd in write set is ready. */
- writen(fd3, "sample\n", 7); /* Write until finish. */
- FD_CLR(fd3, &wset); /* Clear such fd from write set. */
- if (n > 0)
- n--; /* Decrease fd count. */
- else
- break;
- }
- }
- close(fd1);
- close(fd2);
- close(fd3);
- free(stbuf1);
- free(stbuf2);
- return 0;
- }
- void err_sys(const char *str)
- {
- fflush(stdout);
- perror(str);
- fflush(stderr);
- exit(EXIT_FAILURE);
- }
- /* Keep reading until finish. */
- ssize_t readn(int fd, void *vptr, size_t n)
- {
- size_t nleft;
- ssize_t nread;
- char *ptr;
- ptr = vptr;
- nleft = n;
- while (nleft > 0) {
- if ((nread = read(fd, ptr, nleft)) < 0) {
- if (errno == EINTR)
- nread = 0;
- else
- return -1;
- } else if (nread == 0)
- break; /* EOF */
- nleft -= nread;
- ptr += nread;
- }
- return n - nleft;
- }
- /* Keep writing until finish. */
- ssize_t writen(int fd, const void *vptr, size_t n)
- {
- size_t nleft;
- ssize_t nwritten;
- const char *ptr;
- ptr = vptr;
- nleft = n;
- while (nleft > 0) {
- if ((nwritten = write(fd, ptr, nleft)) <= 0) {
- if (errno == EINTR)
- nwritten = 0;
- else
- return -1;
- }
- nleft -= nwritten;
- ptr += nwritten;
- }
- return n;
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement