Reputation: 11
I am trying to handle a socket connection from a different process while asynchronously handling SIGALRMs from the alarm
function. To simulate and test this, I'm using the Linux commands nc 127.0.0.1 [port]
and kill -14 $(myprocess)
. However, when running the kill
command followed by the nc
command, select
returns instantaneously in an infinite loop like fashion. The C code which contains the select
statement is below.
int main() {
int port = 4555;
int master_sockfd;
bind_and_listen(&master_sockfd, port);
signal(SIGALRM, handle_alarm);
for (;;) {
fd_set readfds;
int max_fd = master_sockfd;
FD_ZERO(&readfds);
FD_SET(master_sockfd, &readfds);
printf("waiting for master_sockfd to be set\n");
int activity = select(max_fd + 1, &readfds, NULL, NULL, NULL);
if ((activity < 0) && (errno != EINTR)) {
perror("select() ");
exit(EXIT_FAILURE);
} else if (errno == EINTR) {
perror("select() ");
if (FD_ISSET(master_sockfd, &readfds)) {
printf("Why is sockfd ready for I/O if select was interrupted with a signal?\n");
}
continue;
} else if (FD_ISSET(master_sockfd, &readfds)) {
printf("Reading from socket\n");
// handle client
}
}
return 0;
}
void handle_alarm() {
printf("handling alarm\n");
}
Then, upon executing kill -14 $(myprocess); nc 127.0.0.1 4555
The output is as follows:
select() : Interrupted system call
Why is sockfd ready for I/O if select was interrupted with a signal?
waiting for master_sockfd to be set
select() : Interrupted system call
Why is sockfd ready for I/O if select was interrupted with a signal?
waiting for master_sockfd to be set
select() : Interrupted system call
Why is sockfd ready for I/O if select was interrupted with a signal?
waiting for master_sockfd to be set
.
.
.
Which prints out infinitely.
Why would this be happening?
Upvotes: 1
Views: 44
Reputation: 10445
When select() fails, you cannot rely on the values of the parameters from it. They might reflect something, nothing, or some intermediary state. In your case, it looks like select() never updated the fdsets at all; so they reflect your initial value. This makes sense; it was interrupted so it never wrote back its results.
Your error detection isn't quite right either, it should be:
if (activity < 0) {
/* select failed */
if (errno != EINTR) {
/* handle non-eintr cases */
} else {
/* handle eintr case */
}
} else {
/*select succeeded */
}
Upvotes: 2