SIGIO arriving for file descriptors, I did not install it and when there is no I / O capability

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 = ".";

    /* set up the signal handler for SIGIO */
    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");

    /* arrange to get the signal */
    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;
}
+4
source share
1 answer

Oh, interesting.

: SIGIO stdin, stdin , , , SIGIO .

si_fd ?

SA_SIGINFO sa_flags, sa_sigaction.

-, #define _GNU_SOURCE F_SETSIG SIGIO, Linux si_fd ( si_band, ) . , , . , si_fd, , .

SIGIO ?

, stdin , , , . fd 0 (2) , SIGIO .

si_band . F_SETSIG, #include <poll.h> si_band POLLIN, POLLOUT .., , / .

, stdin ?

. :

$ [ -w /dev/stdin ] && echo Yes, stdin is writeable
Yes, stdin is writeable    

# Endless SIGIOs
$ ./my-sigio-prog
^C

# No SIGIO
$ ./my-sigio-prog < /dev/null

# Two SIGIOs, after a delay.  One for line-buffered "foo\n" and one for EOF
$ { sleep 3; echo foo; sleep 3; } | ./my-sigio-prog
+6

All Articles