I am trying to get a signal when I / O is possible in a file descriptor. A program should do something else when it does not perform I / O, so using select (2) is not an option.
When I run the sample code below, it prints the message inside the handler as fast as it can, even if there is no data on stdin. Even stranger, the file descriptor reported in the siginfo_t structure varies from run to run. I just set it for stdin (fd 0); why should a handler communicate any other value? Sometimes I see 0, sometimes I see 1, most of the time I see “?”, Which indicates a value other than 0, 1 or 2.
This is on OpenSUSE 12.3, the Linux kernel is 3.7.10-1.16, but I see that it looks like the same problem on CentOS 6.4 with its kernel.
I use the entry in the handler because the signal (7) says that it is reentrant and therefore legal for use in the signal handler. That is why I do not print the value sinfo-> si_fd; snprintf is not reentrant. For a while I suspected the stdio library of using SIGIO, so there are no calls to stdio in any sample program (except, perhaps, in the err (3) library function).
Thanks for taking the time to read my code.
#include <fcntl.h>
#include <time.h>
#include <string.h>
#include <stdio.h>
#include <signal.h>
#include <unistd.h>
#include <stdlib.h>
#include <err.h>
#include <errno.h>
int needRead = 0;
const unsigned int bufsize = 256;
void handler(int sig, siginfo_t *sinfo, void *value)
{
char *cp;
cp = "in handler. fd: ";
write(2, cp, strlen(cp));
switch(sinfo->si_fd) {
case 0: cp = "0\n"; break;
case 1: cp = "1\n"; break;
case 2: cp = "2\n"; break;
default: cp = "?\n"; break;
}
write(2, cp, strlen(cp));
needRead = 1;
}
int main(int argc, char *argv[])
{
struct sigaction act;
unsigned int counter = 0;
int flags;
char *outp = ".";
act.sa_sigaction = handler;
act.sa_flags = 0;
act.sa_flags = SA_RESTART;
sigemptyset(&act.sa_mask);
if (sigaction(SIGIO, &act, NULL) == -1)
err(1, "attempt to set up handler for SIGIO failed");
if (fcntl(0, F_SETOWN, getpid()) == -1)
err(1, "fnctl to set F_SETOWN failed");
flags = fcntl(0, F_GETFL);
if (flags >= 0 && fcntl(0, F_SETFL, flags | O_ASYNC ) == -1)
err(1, "fnctl F_SETFL to set O_ASYNC failed");
while (1) {
char in_buf[bufsize];
int nc;
counter++;
write(STDERR_FILENO, outp, strlen(outp));
if (needRead) {
needRead = 0;
if ((nc = read(STDIN_FILENO, in_buf, bufsize)) == -1) {
err(1, "read from stdin failed");
} else {
outp = "Read '";
write(STDERR_FILENO, outp, strlen(outp));
write(STDERR_FILENO, in_buf, nc);
outp = "'\n";
write(STDERR_FILENO, outp, strlen(outp));
}
}
}
return 0;
}