ファイル記述子で 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 でも同じ問題が発生しているように見えます。
signal(7) は、再入可能であり、シグナル ハンドラーでの使用が合法であると述べているため、ハンドラーで write を使用しています。これが、sinfo->si_fd; の値を出力しない理由でもあります。snprintf は再入可能ではありません。しばらくの間、SIGIO を使用する stdio ライブラリを疑っていました。これが、サンプル プログラムのどこにも 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;
}