我正在尝试在文件描述符上进行I / O时接收信号。该程序在不执行I / O时需要做其他事情,因此不能使用select(2)。
当我在下面运行示例代码时,即使在stdin上没有数据,它也会从处理程序内部以最快的速度打印消息。甚至更奇怪的是,siginfo_t结构中报告的文件描述符因运行而异。我只将其设置为stdin(fd 0); 处理程序为什么还要报告其他任何值?有时我看到0,有时我看到1,大多数时候我看到“?”,这表示0、1或2以外的值。
这是在OpenSUSE 12.3,Linux内核3.7.10-1.16上,但是我看到在带有其备用内核的CentOS 6.4上似乎是相同的问题。
我在处理程序中使用write,因为signal(7)表示它是可重入的,因此在信号处理程序中使用是合法的。这也是为什么我不打印sinfo-> si_fd的值的原因。snprintf不是可重入的。有一阵子我怀疑使用SIGIO的stdio库,这就是为什么示例程序中的任何地方(除了库函数err(3)之外)都没有stdio调用的原因。
感谢您花时间阅读我的代码。
#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; }
啊,有趣。
简短的答案是,因为stdin是 可写的 ,所以SIGIO反复到达stdin ,并且单独地,您的SIGIO传递设置不正确。
为什么si_fd显然不可靠?
首先,您需要先指定SA_SIGINFO sa_flags才能安全使用sa_sigaction处理程序。
sa_flags
sa_sigaction
其次,#define _GNU_SOURCE在Linux 为您填充si_fd(和si_band)之前,您需要将F_SETSIG显式地添加到SIGIO 。有点傻,恕我直言,但事实如此。si_fd如您所发现的,没有这个,传入的值就没有意义。
#define _GNU_SOURCE
si_fd
si_band
为什么要反复交付SIGIO?
我猜您程序的stdin是从您调用的shell继承的,我猜它是一个终端设备并且是可写的。就像fd 0会持续 select(2) 可写一样,它也会连续为您生成SIGIO。
无论如何,si_band保持答案。启用F_SETSIG,,#include <poll.h>并检查si_bandPOLLIN,POLLOUT等,以确定哪些I / O事件使信号跳闸。
#include <poll.h>
真的,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