SIGIO прибывает для файловых дескрипторов, для которых я не устанавливал, и когда IO не возможен

Я пытаюсь получить сигнал, когда возможен ввод-вывод по дескриптору файла. Программа должна делать что-то еще, когда она не выполняет ввод-вывод, поэтому использование select (2) не вариант.

Когда я запускаю приведенный ниже пример кода, он печатает сообщение из обработчика так быстро, как только может, даже когда на stdin нет данных. Еще более странным является то, что дескриптор файла, сообщаемый в структуре siginfo_t, меняется от запуска к запуску. Я только настроил это для стандартного ввода (fd 0); почему обработчик сообщает любое другое значение? Иногда я вижу 0, иногда я вижу 1, большую часть времени я вижу '?', который указывает значение, отличное от 0, 1 или 2.

Это на OpenSUSE 12.3, ядре Linux 3.7.10-1.16, но я вижу то же самое, что и в CentOS 6.4 с его стандартным ядром.

Я использую запись в обработчике, потому что signal (7) говорит, что он является реентерабельным и, следовательно, допустимым для использования в обработчике сигналов. Это также, почему я не печатаю значение sinfo->si_fd; snprintf не является реентерабельным. Некоторое время я подозревал, что библиотека stdio использует SIGIO, поэтому нигде в примере программы нет вызовов stdio (кроме, возможно, функции библиотеки err (3)).

Спасибо за потраченное время на чтение моего кода.

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

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;
}

Ответы на вопрос(1)

Ваш ответ на вопрос