I am currently studying the concepts of network programming in which I came across one of the functions pselect() which resolves the issue of select ie. with select(), there is a chance of problem which 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.
if (intr_flag)
handle_intr(); /* handle the signal */
if ( (nready = select( ... )) < 0) {
if (errno == EINTR) {
if (intr_flag)
handle_intr();
}
However, it says that 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) //here
handle_intr(); /* handle the signal */
if ( (nready = pselect ( ... , &zeromask)) < 0) {
if (errno == EINTR) { //here
if (intr_flag)
handle_intr ();
}
...
}
The explanation that it gives for the code to be reliable is that - 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).
But in the code with pselect mentioned above, we block the signals then how can we check the error EINTR? Since the pselect blocks all the signals then when Interrupt occurs it should block that from disrupting or being delivered to the process. It is only when pselect returns then the signal can be delivered.
According to the lines in front of which comment here is mentioned, INTERRUPT signal can still happen before pselect is called or in-between the first check and pselect or when pselect is called contradicting the purpose of blocking the Interrupt and any other signals and thus should lead to race condition as with select is there.
Please anyone explain how this is possible as I am new to these concepts.