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