[ Team LiB ] |
6.9 pselect FunctionThe pselect function was invented by POSIX and is now supported by many of the Unix variants.
pselect contains two changes from the normal select function:
With regard to the second point, consider the following example (discussed on pp. 308–309 of APUE). Our program's signal handler for SIGINT just sets the global intr_flag and returns. If our process is blocked in a call to select, the return from the signal handler causes the function to return with errno set to EINTR. But when select is called, the code looks like the following: if (intr_flag) handle_intr(); /* handle the signal */ if ( (nready = select( ... )) < 0) { if (errno == EINTR) { if (intr_flag) handle_intr(); } ... } The problem is that between the test of intr_flag and the call to select, if the signal occurs, it will be lost if select blocks forever. With pselect, we can now code this example reliably as sigset_t newmask, oldmask, zeromask; sigemptyset(&zeromask); sigemptyset(&newmask); sigaddset(&newmask, SIGINT); sigprocmask(SIG_BLOCK, &newmask, &oldmask); /* block SIGINT */ if (intr_flag) handle_intr(); /* handle the signal */ if ( (nready = pselect ( ... , &zeromask)) < 0) { if (errno == EINTR) { if (intr_flag) handle_intr (); } ... } Before testing the intr_flag variable, we block SIGINT. When pselect is called, it replaces the signal mask of the process with an empty set (i.e., zeromask) and then checks the descriptors, possibly going to sleep. But when pselect returns, the signal mask of the process is reset to its value before pselect was called (i.e., SIGINT is blocked). We will say more about pselect and show an example of it in Section 20.5. We will use pselect in Figure 20.7 and show a simple, albeit incorrect, implementation of pselect in Figure 20.8.
|
[ Team LiB ] |