select(), pselect() — Monitor activity on files or sockets and message queues

Standards

Standards / Extensions C or C++ Dependencies

XPG4.2
Single UNIX Specification, Version 3

both  

Format

X/Open:
#define _XOPEN_SOURCE_EXTENDED 1
#define _OPEN_MSGQ_EXT
#include <sys/types.h>
#include <sys/time.h>
#include <sys/msg.h>

int select(int nmsgsfds, fd_set *__restrict__ readlist,
           fd_set *__restrict__ writelist, fd_set *__restrict__ exceptlist,
           struct timeval *__restrict__ timeout);
SUSV3:
#define _POSIX_C_SOURCE 200112L
#include <sys/select.h>

int pselect(int nmsgsfds, fd_set *__restrict__ readlist,
           fd_set *__restrict__ writelist, fd_set *__restrict__ exceptlist,
           const struct timespec *__restrict__ timeout,
           const sigset *__restrict__ sigmask);
Berkeley sockets:
#define _OE_SOCKETS
#define _OPEN_MSGQ_EXT
#include <sys/types.h>
#include <sys/time.h>
#include <sys/msg.h>

int select(int nmsgsfds, fd_set *readlist,
           fd_set *writelist, fd_set *exceptlist,
           struct timeval *timeout);

_OPEN_MSGQ_EXT must be defined if message queues are to be monitored (X/Open sockets only).

General description

The pselect() and select() functions monitor activity on a set of sockets and/or a set of message queue identifiers until a timeout occurs, to see if any of the sockets and message queues have read, write, or exception processing conditions pending. This call also works with regular file descriptors, pipes, and terminals.

The select() function is equivalent to the pselect() function, except as follows:

Parameter
Description
nmsgsfds
The number of message queues and the number of file or socket descriptors to check.

This parameter is divided into two parts. The first half (the high-order 16 bits) gives the number of elements of an array that contains message queue identifiers. This number must not exceed the value 32767.

The second half (the low-order 16 bits) gives the number of bits within a bit set that correspond to the file or socket descriptors to check. This value should equal the greatest descriptor number to check + 1.

If either half of the nmsgsfds parameter is equal to a value of 0, the corresponding bit sets or arrays are assumed not to be present.

If _OPEN_MSGQ_EXT is not defined, only file or socket descriptors may be monitored. In this case nmsgsfds must be less than or equal to FD_SETSIZE (defined to be 2048 in sys/time.h), and greater than or equal to zero. Also, FD_SETSIZE may not be defined by your program.

The bit set used to specify file or socket descriptors is fixed in size with 1 bit for every possible file or socket. Use the nmsgsfds parameter to force pselect() or select() to check only a subset of the allocated bit set.

If your application allocates sockets 3, 4, 5, 6, and 7 and you want to check all of your allocations, the second half of nmsgsfds should be set to 8, the highest descriptor you specified + 1. If your application checks sockets 3 and 4, the second half of nmsgsfds should be set to 5.

To select on descriptor numbers between 2048 and 65534, either the _OPEN_MSGQ_EXT or _OPEN_SYS_HIGH_DESCRIPTORS feature test macro must be defined, and a bit set larger than the default size must be used. Note that when you are also selecting on message queues, as is possible when _OPEN_MSGQ_EXT is defined, the largest descriptor number is restricted to 2047. To select on descriptor numbers between 65535 and 524287, feature test macro _OPEN_SYS_HIGH_DESCRIPTORS must be defined and feature test macro _OPEN_MSGQ_EXT must not be defined. In addition, the process' MAXFILEPROC limit must be greater than 65536. With this feature, any number of sockets can be selected on (without message queues). FD_SETSIZE may also be redefined in this case, though it is recommended that the application explicitly allocate the larger bit set using malloc().

readlist,writelist,exceptlist
Pointers to fd_set types, arrays of message queue identifiers, or sellist structures to check for reading, writing, and exceptional conditions, respectively. The type of parameter to pass depends on whether you want to monitor file/socket descriptors, message queue identifiers, or both. To monitor file/socket descriptors only, set the high-order halfword of nmsgsfds to 0, the low-order halfword to (highest descriptor number + 1), and use fd_set pointers. To monitor message queues only, set the low-order halfword of nmsgsfds to 0, the high-order halfword to the number of elements in each array you want select() to consider, and pass pointers to arrays of message queue identifiers. To monitor both, set nmsgsfds as described above, and pass pointers to sellist structures.
The sellist structure allows you to specify both file/socket descriptors and message queues. Your program must define the sellist structure in the following form:
struct sellist {
    fd_set fdset;            /* file/socket descriptor bit set */
    int    msgids[max_size]; /* array of message queue identifiers */
    };

If you use a sellist structure, the highest descriptor you can monitor is 2047.

The description of the type fd_set is given below. Each integer of the msgids array specifies a message queue identifier whose status is to be checked. Elements with a value of -1 are acceptable and will be ignored. The value contained in the first half of nmsgsfds determines exactly how many elements of the array are to be checked.

timeout
The pointer to the time to wait for the pselect() or select() call to complete.
sigmask
The signal mask of the caller by the set of signals pointed to by sigmask before examining the descriptors, and will restore the signal mask of the calling thread before returning.

If timeout is not a NULL pointer, it specifies a maximum interval to wait for the selection to complete. The maximum timeout value is 31 days. If timeout is a NULL pointer, the pselect() and select() call blocks until a socket or message becomes ready. To poll the sockets and return immediately, timeout should be a non-NULL pointer to a zero-valued timeval structure or timespec structure.

If sigmask is not a null pointer, then the pselect() function will replace the signal mask of the caller by the set of signals pointed to by sigmask before examining the descriptors, and will restore the signal mask of the calling thread before returning.

To allow you to test more than one socket at a time, the sockets to test are placed into a bit set of type fd_set. A bit set is a string of bits such that if x is an element of the set, the bit representing x is set to 1. If x is not an element of the set, the bit representing x is set to 0. For example, if socket 33 is an element of a bit set, then bit 33 is set to 1. If socket 33 is not an element of a bit set, then bit 33 is set to 0.

Because the bit sets contain a bit for every socket that a process can allocate, the size of the bit sets is constant. If your program needs to allocate a large number of sockets, you may need to increase the size of the bit sets. Increasing the size of the bit sets should be done when you compile the program. To increase the size of the bit sets, define FD_SETSIZE before including sys/time.h. FD_SETSIZE is the largest value of any socket that your program expects to use pselect() or select() on. It is defined to be 2048 in sys/time.h.
Note: FD_SETSIZE may only be defined by the application program if the extended version of select() is used (by defining _OPEN_MSGQ_EXT). Do NOT define FD_SETSIZE in your program if a sellist structure will be used.
Note: The z/OS® UNIX POSIX.1 implementation allows you to control the maximum number of open descriptors allowed per process. This maximum possible value is 524288. If your application program requires a large number of either socket or file descriptors, you should protect your code from possible runtime errors by:
  • Adding a check before your pselect(), select() or selectex() calls to see if the bit set size contained in nmsgsfds is larger than FD_SETSIZE.
  • Dynamically allocate bit strings large enough to hold the largest descriptor value in your application program, rather than rely on the static bit strings created at compile time. When allocating your own bit strings, use malloc() to define an area large enough to represent each bit, rounded up to the next 4-byte multiple. For example, if your largest descriptor value is 31, you need 4 bytes; if your largest descriptor is 32, you need 8 bytes.
  • If you dynamically allocate your own bit strings, the FD_ZERO() macro will not work. The application must zero that storage, by using the memset function—that is, memset(ptr,0,mallocsize). The other macros can be used with the dynamically allocated bit strings, as long as the descriptor you are manipulating is within the bit string. If the descriptor number is larger than the bit string, unpredictable results can occur.

The application program must make sure that the parameters readlist, writelist, and exceptlist point to bit strings that are as large as the bit string size in parameter nmsgsfds z/OS UNIX services will try to access bits 0 through n-1 (where n = the value of the second halfword of nmsgsfds), for each of the bit strings. If the bit strings are too short, you will receive unpredictable results when you run your application program.

The following macros are provided to manipulate bit sets.
Macro
Description
FD_ZERO(&fdset)
Sets all bits in the bit set fdset to zero. After this operation, the bit set does not contain sockets as elements. This macro should be called to initialize the bit set before calling FD_SET() to set a socket as a member.
Note: If you used malloc() to dynamically allocate a new area, the FD_ZERO() macro can cause unpredictable results and should not be used. You should zero the area using the memset() function.
FD_SET(sock, &fdset)
Sets the bit for the socket sock to a 1, making sock a member of the bit set fdset.
FD_CLR(sock, &fdset)
Clears the bit for the socket sock in bit set fdset. This operation sets the appropriate bit to a zero.
FD_ISSET(sock, &fdset)
Returns nonzero if sock is a member of the bit set fdset. Returns 0 if sock is not a member of fdset. (This operation returns the bit representing sock.)
The following macros are provided to manipulate the nmsgsfds parameter and the return value from pselect() and select():
Macro
Description
_SET_FDS_MSGS(nmsgsfds, nmsgs, nfds)
Sets the high-order halfword of nmsgsfds to nmsgs, and sets the low-order halfword of nmsgsfds to nfds.
_NFDS(n)
If the return value n from pselect() or select() is nonnegative, returns the number of descriptors that meet the read, write, and exception criteria. A descriptor may be counted multiple times if it meets more than one given criterion.
_NMSGS(n)
If the return value n from pselect() or select() is nonnegative, returns the number of message queues that meet the read, write, and exception criteria. A message queue may be counted multiple times if it meets more than one given criterion.

A socket is ready for reading when incoming data is buffered for it or when a connection request is pending. To test whether any sockets are ready for reading, use either FD_ZERO() or memset(), if the function was dynamically allocated, to initialize the fdset bit set in readlist and invoke FD_SET() for each socket to test.

A socket is ready for writing if there is buffer space for outgoing data. A socket is ready for reading if there is data on the socket to be received. For a nonblocking stream socket in the process of connecting the connect() will return with a -1. The program needs to check the errno. If the errno is EINPROGRESS, the socket is selected for write when the connect() completes. In the situation where the errno is not EINPROGRESS, the socket will still be selected for write which indicates that there is a pending error on the socket. Acall to write(), send(), or sendto() does not block provided that the amount of data is less than the amount of buffer space. If a socket is selected for write, the amount of available buffer space is guaranteed to be at least as large as the size returned from using SO_SNDBUF with getsockopt(). To test whether any sockets are ready for writing, initialize the fdset bit set in writelist with either FD_ZERO() or memset(), if dynamically allocated, and use FD_SET() for each socket to test.

A message queue is ready for reading when any time it has a message on it. It is considered ready for writing when any time it is not full. A message queue is full when it has either reached its number of messages limit or its number of bytes limit. An exception condition exists when a message queue is deleted while a select() caller is waiting on the queue.

The programmer can pass NULL for any of the readlist, writelist, and exceptlist parameters. However, when they are not NULL, they must all point to the same type of structures. For example, suppose the readlist points to a sellist. If the writelist is not NULL, it must point to a sellist also. Now, let us say the writelist is not NULL. If the programmer wants to check a set of file descriptors for read status only, the appropriate bits in the bit set in the sellist structure pointed to by the writelist must be set to 0. If the programmer wants to check a set of message queues for write status only, the appropriate elements in the array in the sellist structure pointed to by the readlist must be set to -1. Regular files are always ready for reading and writing.

Because the sets of sockets passed to pselect() and select() are bit sets, the pselect() and select() call must test each bit in each bit set before polling the socket for its status. The pselect() and select() call tests only sockets in the range 0 to n-1 (where n = the value of the second halfword of nmsgsfds).

Special behavior for C++: To use this function with C++, you must use the _XOPEN_SOURCE_EXTENDED 1 feature test macro.

Returned value

The value -1 indicates the error code should be checked for an error. The value zero indicates an expired time limit.

When the return value is greater than 0, then it is similar to nmsgsfds in that the high-order 16 bits give the number of message queues, and the low-order 16 bits give the number of descriptors. These values indicate the sum total that meet each of the read, write, and exception criteria. Note that a descriptor or a message queue may be counted multiple times if it meets more than one given criterion. Should the return value for message queues exceed the value 32767, only 32767 will be reported. This is to ensure that the return value does not appear to be negative. Should the return value for file/socket descriptors be greater than 65535, only 65535 will be reported.

If the return value is greater than 0, the files/sockets that are ready in each bit set are set to 1. Files/Sockets in each bit set that are not ready are set to zero. Use the macro FD_ISSET() with each file/socket to test its status. For those message queues that do not meet the conditions their identifiers in the msgsid arrays will be replaced with a value of -1.
Error Code
Description
EBADF
One of the bit sets specified an invalid socket or a message queue identifier is invalid. FD_ZERO() was probably not called to clear the bit set before the sockets were set.
EFAULT
One of the parameters contained an invalid address.
EINTR
The pselect() or select() function was interrupted before any of the selected events occurred and before the timeout interval expired.
EINVAL
One of the fields in the timeval structure or timespec structure is invalid, or there was an invalid nmsgsfds value.
EIO
One of the descriptors in the select mask has become inoperative and it is being repeatedly included in a select even though other operations against this descriptor have been failing with EIO. A socket descriptor, for example, can become inoperative if TCP/IP is shut down. When a descriptor fails a failure from select could not tell you which descriptor had failed so generally select will succeed and these descriptors will be reported to you as being ready for whatever events were specified on the select. Subsequently when the descriptor is used on a receive or other operation you will receive the EIO failure then and can react to the problem with the individual descriptor. In general you would close() the descriptor and remove it from the next select mask. If the individual descriptor's failing return code is ignored though and an inoperative descriptor is repeatedly selected on and used, even though each time it is used that call fails with EIO, eventually the select call itself will fail with EIO.
Note: The pselect() function can also return errno’s set by the sigprocmask() function.

Example

In the following example, select() is used to poll sockets for reading (socket sr), writing (socket sw), and exception (socket se) conditions, and to check message queue ids mr, mw, and me.
#define _XOPEN_SOURCE_EXTENDED  1
#define _OPEN_MSGQ_EXT

#include <sys/types.h>
#include <sys/time.h>
#include <sys/msg.h>

struct sellist {
     fd_set fdset;
     int msgids[2];
};

/*
 * sock_msg_stats(sr, sw, se, mr, mw, me) - Print the status of
 *     sockets sr, sw, and se, and of message queue ids mr, mw,
 *     and me.
 */
 int sock_msg_stats(sr, sw, se, mr, mw, me)
 int sr, sw, se, mr, mw, me;
 {
    struct sellist  *reading, *writing, *excepting;
    struct sellist read, write, except;
    struct timeval timeout;
    int rc, max_sock, sock_size, nmsgsfds;
    int msgids[1];        /* we only check 1 message queue */

    /* What's the maximum socket number? */
    max_sock = MAX( sr, sw );
    max_sock = MAX( max_sock, se );

    /* initialize the static bit sets */
    FD_ZERO( &read.fdset );    reading = &read;
    FD_ZERO( &write.fdset );   writing = &write;
    FD_ZERO( &except.fdset );  excepting = &except;

    /* add sr, sw, and se to the appropriate bit set */
    FD_SET( sr, &reading->fdset );
    FD_SET( sw, &writing->fdset );
    FD_SET( se, &excepting->fdset );

    /* initialize the message id arrays */
    reading->msgids[0] = mr;
    writing->msgids[0] = mw;
    excepting->msgids[0] = me;

    /* set the nmsgsfds parameter */
    _SET_FDS_MSGS( nmsgsfds, 1, max_sock+1 );

    /* make select poll by sending a 0 timeval */
    memset( &timeout, 0, sizeof(timeout) );
    /* poll */
    rc = select( nmsgsfds, reading, writing, excepting, &timeout);

    if ( rc < 0 ) {
         /* an error occurred during the SELECT() */
         perror( "select" );
    }
    else if ( rc == 0 ) {
         /* no sockets or messages were ready in our little poll */
         printf( "nobody is home.\n" );
    } else
        if (_NFDS(rc) > 0)  {
         /* at least one of the sockets is ready */
         printf("sr is %s\n",
                FD_ISSET(sr,&reading->fdset) ? "READY" : "NOT READY");
         printf("sw is %s\n",
                FD_ISSET(sw,&writing->fdset) ? "READY" : "NOT READY");
         printf("se is %s\n",
                FD_ISSET(se,&excepting->fdset) ? "READY": "NOT READY");
        } else
            if (_NMSGS(rc) > 0)  {
              /* at least one message queue is ready */
              printf("mr is %s\n",
                reading->msgids[0] == -1 ? "NOT READY" : "READY");
              printf("mw is %s\n",
                writing->msgids[0] == -1 ? "NOT READY" : "READY");
              printf("me is %s\n",
                excepting->msgids[0] == -1 ? "NOT READY" : "READY");
            }
 }

CELEBP72

⁄* CELEBP72

   This example demonstrates the use of pselect()

   Expected output:
   Parent: Issuing pselect

   This is the child
   Child: Sending signal to the parent at:


   This is the signal handler
   Signal received: 14 (14 is SIGALRM)
   The pselect call was made at:

   The SIGALRM was caught at:

   TEST PASSED!

*⁄
#define _POSIX_C_SOURCE 200112L
#include <sys⁄select.h>
#include <stdio.h>
#include <fcntl.h>
#include <signal.h>
#include <string.h>
#include <time.h>
#include <unistd.h>


time_t t1,t2;

void incatchr(int signum){
   double diff=0;

   time(&t2);
   printf("\n\nThis is the signal handler\n");
   printf("Signal received: %d (14 is SIGALRM) \n",signum);
   printf("The pselect call was made at: \t%s\n",ctime(&t1));
   printf("The SIGALRM was caught at:    \t%s\n",ctime(&t2));
   diff = difftime(t2,t1);
   if(diff <  10) {
      printf("TEST FAILED!\n\n");
   }
   else{
      printf("TEST PASSED!\n\n");
   }
}

int main(void){
   int fd[1], rc, nfds=3, fd1, fd2, fd3;
   pid_t cpid, ppid;
   fd_set fdsread;
   struct sigaction action, info;
   sigset_t pselect_set;
   struct timespec t;
   time_t t3;

   t.tv_sec=10;
   t.tv_nsec=0;

   FD_ZERO(&fdsread);

   action.sa_handler = incatchr;
   action.sa_flags = 0;
   sigaction(SIGALRM,&action,&info);

   sigemptyset(&pselect_set);
   sigaddset(&pselect_set, SIGALRM);

   fd1 = open(".⁄testchd.txt",O_RDWR|O_CREAT);
   fd2 = open(".⁄testchd2.txt",O_RDWR|O_CREAT);
   if((rc=pipe(fd)) != 0){
      printf("Error in pipe\n");
      return(-1);
   }

   FD_SET(fd[0],&fdsread);

   if ((cpid = fork()) < 0){
      printf("Fork error\n");
      return(-1);
   }
   else{
      if (cpid == 0){
         fd3 = open(".⁄testchd.txt",O_RDWR|O_CREAT);
         printf("This is the child\n");
         sleep(2);
         ppid= getppid();
         time(&t3);
         printf("Child: Sending signal to the parent at: ");
         printf("%s",ctime(&t3));
         kill(ppid,SIGALRM);
         sleep(3);
         _exit(0);
      }
      else{
         printf("Parent: Issuing pselect\n\n");
         time(&t1);
         if (pselect(nfds,&fdsread,NULL,NULL,&t,&pselect_set) == -1)
            printf("Error in pselect\n");
      }
      close(fd[0]);
   }

   return 0;
}

Related information