7

ファイル記述子で 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;
}
4

1 に答える 1