当文件描述符上可以进行 I/O 时,我正在尝试接收信号。程序在不执行 I/O 时需要执行其他操作,因此不能选择使用 select(2)。
当我运行下面的示例代码时,它会尽可能快地从处理程序内部打印消息,即使标准输入上没有数据也是如此。更奇怪的是,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 不可重入。有一段时间我怀疑 stdio 库使用了 SIGIO,这就是为什么在示例程序中的任何地方都没有 stdio 调用(可能在库函数 err(3) 中除外)。
感谢您花时间阅读我的代码。
#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;
}