Seth Woolley's Man Viewer

select_tut(2) - FD_CLR, FD_ISSET, FD_SET, FD_ZERO, pselect, select, FD_CLR, FD_ISSET, FD_SET, FD_ZERO, pselect, select - synchronous I/O multiplexing - man select_tut

([section] manual, -k keyword, -K [section] search, -f whatis)
man plain no title

SELECT_TUT(2)              Linux Programmer's Manual             SELECT_TUT(2)



NAME
       select(2,7,2 select_tut),  pselect,  FD_CLR,  FD_ISSET, FD_SET, FD_ZERO - synchronous I/O
       multiplexing

SYNOPSIS
       #include <sys/time.h>
       #include <sys/types.h>
       #include <unistd.h>

       int  select(2,7,2 select_tut)(int  nfds,  fd_set  *readfds,  fd_set   *writefds,   fd_set
       *exceptfds, struct timeval *utimeout);

       int   pselect(int  nfds,  fd_set  *readfds,  fd_set  *writefds,  fd_set
       *exceptfds, const struct timespec *ntimeout, sigset_t *sigmask);

       FD_CLR(int fd, fd_set *set(7,n,1 builtins));
       FD_ISSET(int fd, fd_set *set(7,n,1 builtins));
       FD_SET(int fd, fd_set *set(7,n,1 builtins));
       FD_ZERO(fd_set *set(7,n,1 builtins));

DESCRIPTION
       select(2,7,2 select_tut) (or pselect) is the pivot function of most C programs that  han-
       dle more than one simultaneous file(1,n) descriptor (or socket(2,7,n) handle) in(1,8) an
       efficient manner. Its principal arguments  are  three  arrays  of  file(1,n)
       descriptors:  readfds,  writefds, and exceptfds. The way that select(2,7,2 select_tut) is
       usually used is to block while waiting for a "change of status" on  one
       or  more  of  the  file(1,n)  descriptors. A "change of status" is when more
       characters become available from the file(1,n)  descriptor,  or  when  space
       becomes  available  within the kernel's internal buffers for more to be
       written to the file(1,n) descriptor, or when a  file(1,n)  descriptor  goes  into
       error(8,n)  (in(1,8)  the  case of a socket(2,7,n) or pipe(2,8) this is when the other end of
       the connection is closed).

       In summary, select(2,7,2 select_tut) just watches multiple file(1,n) descriptors, and  is  the
       standard Unix call to do so.

       The  arrays  of file(1,n) descriptors are called file(1,n) descriptor sets.  Each
       set(7,n,1 builtins) is declared as type fd_set, and its contents can  be  altered  with
       the  macros  FD_CLR, FD_ISSET, FD_SET,  and FD_ZERO. FD_ZERO is usually
       the first function to be used on a newly declared set. Thereafter,  the
       individual file(1,n) descriptors that you are interested in(1,8) can be added one
       by one with FD_SET.  select(2,7,2 select_tut) modifies the contents of the sets according
       to the rules described below; after calling select(2,7,2 select_tut) you can test if(3,n) your
       file(1,n) descriptor is still present in(1,8) the set(7,n,1 builtins) with  the  FD_ISSET  macro.
       FD_ISSET  returns  non-zero if(3,n) the descriptor is present and zero if(3,n) it
       is not. FD_CLR removes a file(1,n) descriptor from the set(7,n,1 builtins) although I  can't
       see the use for it in(1,8) a clean program.


ARGUMENTS
       readfds
              This set(7,n,1 builtins) is watched to see if(3,n) data is available for reading from
              any of its file(1,n) descriptors. After select(2,7,2 select_tut) has returned,  readfds
              will  be  cleared  of all file(1,n) descriptors except for those file(1,n)
              descriptors that are immediately available for  reading  with  a
              recv()  (for  sockets) or read(2,n,1 builtins)() (for pipes, files, and sockets)
              call.

       writefds
              This set(7,n,1 builtins) is watched to see if(3,n) there is space to  write(1,2)  data  to
              any  of its file(1,n) descriptor. After select(2,7,2 select_tut) has returned, writefds
              will be cleared of all file(1,n) descriptors except  for  those  file(1,n)
              descriptors  that  are  immediately available for writing with a
              send(2,n)() (for sockets) or write(1,2)() (for pipes, files, and  sockets)
              call.

       exceptfds
              This  set(7,n,1 builtins) is watched for exceptions or errors on any of the file(1,n)
              descriptors. However, that is actually just a rumor. How you use
              exceptfds  is  to  watch for out-of-band (OOB) data. OOB data is
              data sent  on  a  socket(2,7,n)  using  the  MSG_OOB  flag,  and  hence
              exceptfds  only  really  applies  to  sockets.  See  recv(2) and
              send(2,n)(2) about this. After select(2,7,2 select_tut) has returned, exceptfds will be
              cleared  of  all  file(1,n)  descriptors except for those descriptors
              that are available for reading OOB data. You can only ever  read(2,n,1 builtins)
              one  byte  of  OOB  data though (which is done with recv()), and
              writing OOB data (done with send(2,n)) can be done at  any  time(1,2,n)  and
              will not block. Hence there is no need for a fourth set(7,n,1 builtins) to check
              if(3,n) a socket(2,7,n) is available for writing OOB data.

       nfds   This is an integer  one  more  than  the  maximum  of  any  file(1,n)
              descriptor  in(1,8)  any  of  the sets. In other words, while you are
              busy adding file(1,n) descriptors to your sets,  you  must  calculate
              the  maximum  integer  value of all of them, then increment this
              value by one, and then pass this as nfds to select(2,7,2 select_tut).

       utimeout
              This is the longest time(1,2,n) select(2,7,2 select_tut) must wait before returning, even
              if(3,n)  nothing  interesting  happened.  If  this value is passed as
              NULL, then select(2,7,2 select_tut) blocks  indefinitely  waiting  for  an  event.
              utimeout  can  be  set(7,n,1 builtins)  to  zero seconds, which causes select(2,7,2 select_tut) to
              return immediately. The structure struct timeval is defined as,

              struct timeval {
                  time_t tv_sec;    /* seconds */
                  long tv_usec;     /* microseconds */
              };

       ntimeout
              This argument has the same meaning as utimeout but struct  time-
              spec has nanosecond precision as follows,

              struct timespec {
                  long tv_sec;    /* seconds */
                  long tv_nsec;   /* nanoseconds */
              };

       sigmask
              This argument holds a set(7,n,1 builtins) of signals to allow while performing a
              pselect call (see sigaddset(3) and sigprocmask(2)).  It  can  be
              passed  as  NULL,  in(1,8)  which  case it does not modify the set(7,n,1 builtins) of
              allowed signals on entry and exit(3,n,1 builtins) to the function. It will  then
              behave just like select(2,7,2 select_tut).


COMBINING SIGNAL AND DATA EVENTS
       pselect  must  be  used if(3,n) you are waiting for a signal(2,7) as well as data
       from a file(1,n) descriptor. Programs that receive signals  as  events  nor-
       mally  use  the  signal(2,7) handler only to raise(3,n) a global flag. The global
       flag will indicate that the event must be processed in(1,8) the main loop of
       the program. A signal(2,7) will cause the select(2,7,2 select_tut) (or pselect) call to return
       with errno set(7,n,1 builtins) to EINTR. This behavior is essential so that signals can
       be  processed  in(1,8)  the main loop of the program, otherwise select(2,7,2 select_tut) would
       block indefinitely. Now, somewhere in(1,8) the main loop will  be  a  condi-
       tional  to  check  the  global  flag.  So we must ask: what if(3,n) a signal(2,7)
       arrives after the conditional, but before the select(2,7,2 select_tut) call?  The  answer
       is  that select(2,7,2 select_tut) would block indefinitely, even though an event is actu-
       ally pending. This race condition is solved by the pselect  call.  This
       call can be used to mask out signals that are not to be received except
       within the pselect call. For instance, let us say  that  the  event  in(1,8)
       question  was the exit(3,n,1 builtins) of a child process. Before the start of the main
       loop, we would block SIGCHLD using sigprocmask. Our pselect call  would
       enable  SIGCHLD by using the virgin signal(2,7) mask. Our program would look(1,8,3 Search::Dict)
       like:

       int child_events = 0;

       void child_sig_handler (int x) {
           child_events++;
           signal(2,7) (SIGCHLD, child_sig_handler);
       }

       int main (int argc, char **argv) {
           sigset_t sigmask, orig_sigmask;

           sigemptyset (&sigmask);
           sigaddset (&sigmask, SIGCHLD);
           sigprocmask (SIG_BLOCK, &sigmask,
                                       &orig_sigmask);

           signal(2,7) (SIGCHLD, child_sig_handler);

           for (;;) { /* main loop */
               for (; child_events > 0; child_events--) {
                   /* do event work here */
               }
               r = pselect (nfds, &rd, &wr, &er, 0, &orig_sigmask);

               /* main body of program */
           }
       }

       Note that the above pselect call can be replaced with:

               sigprocmask (SIG_BLOCK, &orig_sigmask, 0);
               r = select(2,7,2 select_tut) (nfds, &rd, &wr, &er, 0);
               sigprocmask (SIG_BLOCK, &sigmask, 0);

       but then there is still the possibility  that  a  signal(2,7)  could  arrive
       after  the  first sigprocmask and before the select(2,7,2 select_tut). If you do do this,
       it is prudent to at least put a finite timeout(1,3x,3x cbreak) so that the process does
       not  block. At present glibc probably works this way.  The Linux kernel
       does not have a native pselect system call as yet so this is all proba-
       bly much of a moot point.




PRACTICAL
       So  what  is  the  point  of  select(2,7,2 select_tut)? Can't I just read(2,n,1 builtins) and write(1,2) to my
       descriptors whenever I want? The point of select(2,7,2 select_tut)  is  that  it  watches
       multiple  descriptors at the same time(1,2,n) and properly puts(3,n) the process to
       sleep(1,3) if(3,n) there is no activity. It does this while enabling you to  han-
       dle  multiple  simultaneous  pipes  and sockets. Unix programmers often
       find themselves in(1,8) a position where they have to handle  IO  from  more
       than  one  file(1,n)  descriptor where the data flow may be intermittent. If
       you were to merely create a sequence of read(2,n,1 builtins) and write(1,2) calls, you would
       find  that  one of your calls may block waiting for data from/to a file(1,n)
       descriptor, while another file(1,n) descriptor is  unused  though  available
       for data. select(2,7,2 select_tut) efficiently copes with this situation.

       A classic example of select(2,7,2 select_tut) comes from the select(2,7,2 select_tut) man(1,5,7) page:

       #include <stdio.h>
       #include <sys/time.h>
       #include <sys/types.h>
       #include <unistd.h>

       int
       main(void) {
           fd_set rfds;
           struct timeval tv;
           int retval;

           /* Watch stdin (fd 0) to see when it has input. */
           FD_ZERO(&rfds);
           FD_SET(0, &rfds);
           /* Wait up to five seconds. */
           tv.tv_sec = 5;
           tv.tv_usec = 0;

           retval = select(2,7,2 select_tut)(1, &rfds, NULL, NULL, &tv);
           /* Don't rely on the value of tv now! */

           if(3,n) (retval == -1)
               perror(1,3)("select(2,7,2 select_tut)()");
           else if(3,n) (retval)
               printf(1,3,1 builtins)("Data is available now.\n");
               /* FD_ISSET(0, &rfds) will be true. */
           else
               printf(1,3,1 builtins)("No data within five seconds.\n");

           exit(3,n,1 builtins)(0);
       }



PORT FORWARDING EXAMPLE
       Here is an example that better demonstrates the true utility of select(2,7,2 select_tut).
       The listing below a TCP forwarding program that forwards from  one  TCP
       port to another.

       #include <stdlib.h>
       #include <stdio.h>
       #include <unistd.h>
       #include <sys/time.h>
       #include <sys/types.h>
       #include <string.h>
       #include <signal.h>
       #include <sys/socket.h>
       #include <netinet/in.h>
       #include <arpa/inet.h>
       #include <errno.h>

       static int forward_port;

       #undef max
       #define max(x,y) ((x) > (y) ? (x) : (y))

       static int listen_socket (int listen_port) {
           struct sockaddr_in a;
           int s;
           int yes;
           if(3,n) ((s = socket(2,7,n) (AF_INET, SOCK_STREAM, 0)) < 0) {
               perror(1,3) ("socket(2,7,n)");
               return -1;
           }
           yes = 1;
           if(3,n) (setsockopt
               (s, SOL_SOCKET, SO_REUSEADDR,
                (char *) &yes, sizeof (yes)) < 0) {
               perror(1,3) ("setsockopt");
               close(2,7,n) (s);
               return -1;
           }
           memset (&a, 0, sizeof (a));
           a.sin_port = htons (listen_port);
           a.sin_family = AF_INET;
           if(3,n) (bind(2,n,1 builtins)
               (s, (struct sockaddr *) &a, sizeof (a)) < 0) {
               perror(1,3) ("bind(2,n,1 builtins)");
               close(2,7,n) (s);
               return -1;
           }
           printf(1,3,1 builtins) ("accepting connections on port %d\n",
                   (int) listen_port);
           listen(1,2,7) (s, 10);
           return s;
       }

       static int connect_socket (int connect_port,
                                  char *address) {
           struct sockaddr_in a;
           int s;
           if(3,n) ((s = socket(2,7,n) (AF_INET, SOCK_STREAM, 0)) < 0) {
               perror(1,3) ("socket(2,7,n)");
               close(2,7,n) (s);
               return -1;
           }

           memset (&a, 0, sizeof (a));
           a.sin_port = htons (connect_port);
           a.sin_family = AF_INET;

           if(3,n) (!inet_aton
               (address,
                (struct in_addr *) &a.sin_addr.s_addr)) {
               perror(1,3) ("bad IP address format");
               close(2,7,n) (s);
               return -1;
           }

           if(3,n) (connect
               (s, (struct sockaddr *) &a,
                sizeof (a)) < 0) {
               perror(1,3) ("connect()");
               shutdown(2,8) (s, SHUT_RDWR);
               close(2,7,n) (s);
               return -1;
           }
           return s;
       }

       #define SHUT_FD1 {                      \
               if(3,n) (fd1 >= 0) {                 \
                   shutdown(2,8) (fd1, SHUT_RDWR);  \
                   close(2,7,n) (fd1);                \
                   fd1 = -1;                   \
               }                               \
           }

       #define SHUT_FD2 {                      \
               if(3,n) (fd2 >= 0) {                 \
                   shutdown(2,8) (fd2, SHUT_RDWR);  \
                   close(2,7,n) (fd2);                \
                   fd2 = -1;                   \
               }                               \
           }

       #define BUF_SIZE 1024

       int main (int argc, char **argv) {
           int h;
           int fd1 = -1, fd2 = -1;
           char buf1[BUF_SIZE], buf2[BUF_SIZE];
           int buf1_avail, buf1_written;
           int buf2_avail, buf2_written;

           if(3,n) (argc != 4) {
               fprintf (stderr,
                        "Usage\n\tfwd <listen-port> \
       <forward-to-port> <forward-to-ip-address>\n");
               exit(3,n,1 builtins) (1);
           }

           signal(2,7) (SIGPIPE, SIG_IGN);

           forward_port = atoi (argv[2]);

           h = listen_socket (atoi (argv[1]));
           if(3,n) (h < 0)
               exit(3,n,1 builtins) (1);

           for (;;) {
               int r, nfds = 0;
               fd_set rd, wr, er;
               FD_ZERO (&rd);
               FD_ZERO (&wr);
               FD_ZERO (&er);
               FD_SET (h, &rd);
               nfds = max (nfds, h);
               if(3,n) (fd1 > 0 && buf1_avail < BUF_SIZE) {
                   FD_SET (fd1, &rd);
                   nfds = max (nfds, fd1);
               }
               if(3,n) (fd2 > 0 && buf2_avail < BUF_SIZE) {
                   FD_SET (fd2, &rd);
                   nfds = max (nfds, fd2);
               }
               if(3,n) (fd1 > 0
                   && buf2_avail - buf2_written > 0) {
                   FD_SET (fd1, &wr);
                   nfds = max (nfds, fd1);
               }
               if(3,n) (fd2 > 0
                   && buf1_avail - buf1_written > 0) {
                   FD_SET (fd2, &wr);
                   nfds = max (nfds, fd2);
               }
               if(3,n) (fd1 > 0) {
                   FD_SET (fd1, &er);
                   nfds = max (nfds, fd1);
               }
               if(3,n) (fd2 > 0) {
                   FD_SET (fd2, &er);
                   nfds = max (nfds, fd2);
               }

               r = select(2,7,2 select_tut) (nfds + 1, &rd, &wr, &er, NULL);

               if(3,n) (r == -1 && errno == EINTR)
                   continue;
               if(3,n) (r < 0) {
                   perror(1,3) ("select(2,7,2 select_tut)()");
                   exit(3,n,1 builtins) (1);
               }
               if(3,n) (FD_ISSET (h, &rd)) {
                   unsigned int l;
                   struct sockaddr_in client_address;
                   memset (&client_address, 0, l =
                           sizeof (client_address));
                   r = accept(2,8) (h, (struct sockaddr *)
                               &client_address, &l);
                   if(3,n) (r < 0) {
                       perror(1,3) ("accept(2,8)()");
                   } else {
                       SHUT_FD1;
                       SHUT_FD2;
                       buf1_avail = buf1_written = 0;
                       buf2_avail = buf2_written = 0;
                       fd1 = r;
                       fd2 =
                           connect_socket (forward_port,
                                           argv[3]);
                       if(3,n) (fd2 < 0) {
                           SHUT_FD1;
                       } else
                           printf(1,3,1 builtins) ("connect from %s\n",
                                   inet_ntoa
                                   (client_address.sin_addr));
                   }
               }
       /* NB: read(2,n,1 builtins) oob data before normal reads */
               if(3,n) (fd1 > 0)
                   if(3,n) (FD_ISSET (fd1, &er)) {
                       char c;
                       errno = 0;
                       r = recv (fd1, &c, 1, MSG_OOB);
                       if(3,n) (r < 1) {
                           SHUT_FD1;
                       } else
                           send(2,n) (fd2, &c, 1, MSG_OOB);
                   }
               if(3,n) (fd2 > 0)
                   if(3,n) (FD_ISSET (fd2, &er)) {
                       char c;
                       errno = 0;
                       r = recv (fd2, &c, 1, MSG_OOB);
                       if(3,n) (r < 1) {
                           SHUT_FD1;
                       } else
                           send(2,n) (fd1, &c, 1, MSG_OOB);
                   }
               if(3,n) (fd1 > 0)
                   if(3,n) (FD_ISSET (fd1, &rd)) {
                       r =
                           read(2,n,1 builtins) (fd1, buf1 + buf1_avail,
                                 BUF_SIZE - buf1_avail);
                       if(3,n) (r < 1) {
                           SHUT_FD1;
                       } else
                           buf1_avail += r;
                   }
               if(3,n) (fd2 > 0)
                   if(3,n) (FD_ISSET (fd2, &rd)) {
                       r =
                           read(2,n,1 builtins) (fd2, buf2 + buf2_avail,
                                 BUF_SIZE - buf2_avail);
                       if(3,n) (r < 1) {
                           SHUT_FD2;
                       } else
                           buf2_avail += r;
                   }
               if(3,n) (fd1 > 0)
                   if(3,n) (FD_ISSET (fd1, &wr)) {
                       r =
                           write(1,2) (fd1,
                                  buf2 + buf2_written,
                                  buf2_avail -
                                  buf2_written);
                       if(3,n) (r < 1) {
                           SHUT_FD1;
                       } else
                           buf2_written += r;
                   }
               if(3,n) (fd2 > 0)
                   if(3,n) (FD_ISSET (fd2, &wr)) {
                       r =
                           write(1,2) (fd2,
                                  buf1 + buf1_written,
                                  buf1_avail -
                                  buf1_written);
                       if(3,n) (r < 1) {
                           SHUT_FD2;
                       } else
                           buf1_written += r;
                   }
       /* check if(3,n) write(1,2) data has caught read(2,n,1 builtins) data */
               if(3,n) (buf1_written == buf1_avail)
                   buf1_written = buf1_avail = 0;
               if(3,n) (buf2_written == buf2_avail)
                   buf2_written = buf2_avail = 0;
       /* one side has closed the connection, keep
          writing to the other side until empty */
               if(3,n) (fd1 < 0
                   && buf1_avail - buf1_written == 0) {
                   SHUT_FD2;
               }
               if(3,n) (fd2 < 0
                   && buf2_avail - buf2_written == 0) {
                   SHUT_FD1;
               }
           }
           return 0;
       }

       The  above  program  properly  forwards  most  kinds of TCP connections
       including OOB signal(2,7) data transmitted by telnet servers. It handles the
       tricky  problem  of having data flow in(1,8) both directions simultaneously.
       You might think it more efficient to use a fork()  call  and  devote  a
       thread to each stream. This becomes more tricky than you might suspect.
       Another idea is to set(7,n,1 builtins) non-blocking IO using an ioctl() call. This also
       has  its  problems  because you end up having to have inefficient time-
       outs.

       The program does not handle more than one simultaneous connection at  a
       time(1,2,n),  although  it  could  easily be extended to do this with a linked
       list of buffers - one for each connection. At the moment,  new  connec-
       tions cause the current connection to be dropped.


SELECT LAW
       Many  people  who try to use select(2,7,2 select_tut) come across behavior that is diffi-
       cult to understand and produces non-portable or borderline results. For
       instance,  the  above  program is carefully written not to block at any
       point, even though it does not set(7,n,1 builtins) its file(1,n) descriptors to non-blocking
       mode  at all (see ioctl(2)). It is easy to introduce subtle errors that
       will remove the advantage of using select(2,7,2 select_tut), hence I will present a  list
       of essentials to watch for when using the select(2,7,2 select_tut) call.


       1.     You should always try use select(2,7,2 select_tut) without a timeout. Your program
              should have nothing to do if(3,n) there is no  data  available.  Code
              that  depends  on timeouts is not usually portable and difficult
              to debug.

       2.     The value nfds must be properly  calculated  for  efficiency  as
              explained above.

       3.     No file(1,n) descriptor must be added to any set(7,n,1 builtins) if(3,n) you do not intend
              to check its result after the select(2,7,2 select_tut) call, and respond appropri-
              ately. See next rule.

       4.     After  select(2,7,2 select_tut)  returns, all file(1,n) descriptors in(1,8) all sets must be
              checked. Any file(1,n) descriptor that is available for writing  must
              be  written  to,  and  any file(1,n) descriptor available for reading
              must be read(2,n,1 builtins), etc.

       5.     The functions read(2,n,1 builtins)(), recv(), write(1,2)(), and send(2,n)() do not  neces-
              sarily  read(2,n,1 builtins)/write(1,2)  the  full  amount  of  data  that  you  have
              requested. If they do read(2,n,1 builtins)/write(1,2) the full  amount,  its  because
              you  have  a  low  traffic  load(7,n)  and a fast stream. This is not
              always going to be the case. You should cope with  the  case  of
              your functions only managing to send(2,n) or receive a single byte.

       6.     Never  read(2,n,1 builtins)/write(1,2) only in(1,8) single bytes at a time(1,2,n) unless your are
              really sure that you have a small amount of data to process.  It
              is  extremely  inefficient not to read(2,n,1 builtins)/write(1,2) as much data as you
              can buffer each time.  The buffers in(1,8) the example above are 1024
              bytes although they could easily be made as large as the maximum
              possible packet size on your local network.

       7.     The functions read(2,n,1 builtins)(), recv(), write(1,2)(), and send(2,n)() as well as the
              select(2,7,2 select_tut)()  call  can  return  -1 with an errno of EINTR or EAGAIN
              (EWOULDBLOCK) which are not errors. These results must be  prop-
              erly  managed  (not done properly above). If your program is not
              going to receive any signals then it is unlikely  you  will  get
              EINTR.  If  your  program does not set(7,n,1 builtins) non-blocking IO, you will
              not get EAGAIN. Nonetheless you should  still  cope  with  these
              errors for completeness.

       8.     Never  call  read(2,n,1 builtins)(),  recv(),  write(1,2)(),  or send(2,n)() with a buffer
              length of zero.

       9.     Except  as  indicated  in(1,8)  7.,  the  functions  read(2,n,1 builtins)(),  recv(),
              write(1,2)(), and send(2,n)() never have a return value less(1,3) than 1 except
              if(3,n) an error(8,n) has occurred. For instance, a read(2,n,1 builtins)() on a pipe(2,8) where
              the  other  end  has  died  returns zero (so does an end-of-file
              error(8,n)), but only returns zero once (a  followup  read(2,n,1 builtins)  or  write(1,2)
              will  return  -1). Should any of these functions return 0 or -1,
              you should not pass that descriptor to select(2,7,2 select_tut) ever again. In the
              above  example, I close(2,7,n) the descriptor immediately, and then set(7,n,1 builtins)
              it to -1 to prevent it being included in(1,8) a set.

       10.    The timeout(1,3x,3x cbreak) value must be initialized  with  each  new  call  to
              select(2,7,2 select_tut),  since some operating systems modify the structure. pse-
              lect however does not modify its timeout(1,3x,3x cbreak) structure.

       11.    I have heard that the Windows socket(2,7,n) layer does  not  cope  with
              OOB  data properly. It also does not cope with select(2,7,2 select_tut) calls when
              no file(1,n) descriptors are set(7,n,1 builtins) at all. Having no  file(1,n)  descriptors
              set(7,n,1 builtins)  is a useful way to sleep(1,3) the process with sub-second preci-
              sion by using the timeout.  (See further on.)


USLEEP EMULATION
       On systems that do not have a usleep function, you can call select(2,7,2 select_tut) with
       a finite timeout(1,3x,3x cbreak) and no file(1,n) descriptors as follows:

           struct timeval tv;
           tv.tv_sec = 0;
           tv.tv_usec = 200000;  /* 0.2 seconds */
           select(2,7,2 select_tut) (0, NULL, NULL, NULL, &tv);

       This is only guarenteed to work on Unix systems, however.


RETURN VALUE
       On  success,  select(2,7,2 select_tut) returns the total number of file(1,n) descriptors still
       present in(1,8) the file(1,n) descriptor sets.

       If select(2,7,2 select_tut) timed out, then the file(1,n) descriptors sets should be all empty
       (but  may  not be on some systems). However the return value will defi-
       nitely be zero.

       A return value of -1 indicates an error(8,n), with errno being set(7,n,1 builtins) appropri-
       ately.  In  the  case  of  an  error(8,n), the returned sets and the timeout(1,3x,3x cbreak)
       struct contents are undefined and should not be used.  pselect  however
       never modifies ntimeout.


ERRORS
       EBADF  A  set(7,n,1 builtins)  contained  an  invalid file(1,n) descriptor. This error(8,n) often
              occurs when you add a file(1,n) descriptor to a  set(7,n,1 builtins)  that  you  have
              already  issued  a  close(2,7,n)  on,  or when that file(1,n) descriptor has
              experienced some kind of error. Hence you should cease adding to
              sets  any  file(1,n)  descriptor  that returns an error(8,n) on reading or
              writing.

       EINTR  An interrupting signal(2,7) was caught like SIGINT  or  SIGCHLD  etc.
              In  this  case  you should rebuild your file(1,n) descriptor sets and
              retry.

       EINVAL Occurs if(3,n) nfds is negative or an invalid value is  specified  in(1,8)
              utimeout or ntimeout.

       ENOMEM Internal memory allocation failure.


NOTES
       Generally  speaking,  all  operating systems that support sockets, also
       support select(2,7,2 select_tut). Some people consider  select(2,7,2 select_tut)  to  be  an  esoteric  and
       rarely  used  function. Indeed, many types of programs become extremely
       complicated without it. select(2,7,2 select_tut) can be used to solve many problems in(1,8)  a
       portable  and  efficient  way  that naive programmers try to solve with
       threads, forking, IPCs, signals, memory sharing and other  dirty  meth-
       ods. pselect is a newer function that is less(1,3) commonly used.

       The  poll(2) system call has the same functionality as select(2,7,2 select_tut), but with
       less(1,3) subtle behavior. It is less(1,3) portable than select(2,7,2 select_tut).


CONFORMING TO
       4.4BSD (the select(2,7,2 select_tut) function first appeared in(1,8) 4.2BSD).  Generally  por-
       table to/from non-BSD systems supporting clones of the BSD socket(2,7,n) layer
       (including System V variants). However, note that the System V  variant
       typically  sets  the  timeout(1,3x,3x cbreak) variable before exit(3,n,1 builtins), but the BSD variant
       does not.

       The pselect function is defined in(1,8) IEEE  Std  1003.1g-2000  (POSIX.1g).
       It  is  found  in(1,8) glibc2.1 and later. Glibc2.0 has a function with this
       name, that however does not take a sigmask parameter.


SEE ALSO
       accept(2,8)(2), connect(2), ioctl(2), poll(2), read(2,n,1 builtins)(2), recv(2),  select(2,7,2 select_tut)(2),
       send(2,n)(2),  sigprocmask(2), write(1,2)(2), sigaddset(3), sigdelset(3), sigemp-
       tyset(3), sigfillset(3), sigismember(3)


AUTHORS
       This man(1,5,7) page was written by Paul Sheer.



Linux 2.4                      October 21, 2001                  SELECT_TUT(2)

References for this manual (incoming links)