SIGNALFD(2) | Linux Programmer's Manual | SIGNALFD(2) |
名前
signalfd -シグナル受け付け用のファイルディスクリプタを生成する書式
#include <sys/signalfd.h>説明
signalfd() は、呼び出し元宛てのシグナルを受け付けるために使用されるファイルディスクリプタを生成する。この方法はシグナルハンドラや sigwaitinfo(2) を用いる方法の代わりとなるものであり、このファイルディスクリプタを select(2), poll(2), epoll(7) で監視できるという利点がある。- SFD_NONBLOCK
- 新しく生成されるオープンファイル記述 (open file description) の O_NONBLOCK ファイルステータスフラグをセットする。このフラグを使うことで、 O_NONBLOCK をセットするために fcntl(2) を追加で呼び出す必要がなくなる。
- SFD_CLOEXEC
- 新しいファイルディスクリプタに対して close-on-exec ( FD_CLOEXEC) フラグをセットする。このフラグが役に立つ理由については、 open(2) の O_CLOEXEC フラグの説明を参照のこと。
バージョン 2.6.26 以前の Linux では、 flags 引き数は未使用であり、0 を指定しなければならない。
signalfd() が返すファイルディスクリプタは以下の操作をサポートしている。
- read(2)
- mask に指定されているシグナルのうち一つ以上がそのプロセスに対して処理待ち (pending) であれば、それらのシグナルの情報が read(2) に渡されたバッファを使って、 signalfd_siginfo 構造体に格納されて返される。 read(2) は、バッファに格納可能な範囲でできるだけ多くの処理待ちのシグナルについての情報を返す。バッファは最低でも sizeof(struct signalfd_siginfo) バイトの大きさがなければならない。 read(2) の返り値は読み出されたトータルのバイト数である。
- read(2) が行われた結果、シグナルは消費され、これらのシグナルはそのプロセスに対しては処理待ちではなくなる (つまり、シグナルハンドラで捕捉されることもなく、 sigwaitinfo(2) を使って受け取ることもできなくなる)。
- mask に指定されているシグナルがそのプロセスに対して一つも処理待ちでなければ、 read(2) は、 mask で指定されたシグナルのうちいずれか一つがそのプロセスに対して発生するまで停止 (block) する、もしくはファイルディスクリプタが非停止 (nonblocking) に設定されている場合はエラー EAGAIN で失敗する。
- poll(2), select(2) (と同様の操作)
- mask に指定されたシグナルのうち一つ以上がそのプロセスに対して処理待ちであれば、ファイルディスクリプタは読み出し可能となる ( select(2) の readfds 引き数や poll(2) の POLLIN フラグ)。
- signalfd ファイルディスクリプタは、これ以外のファイルディスクリプタ多重 API である pselect(2), ppoll(2), epoll(7) もサポートしている。
- close(2)
- ファイルディスクリプタがそれ以降は必要なくなった際には、クローズすべきである。同じ signalfd オブジェクトに関連付けられたファイルディスクリプタが全てクローズされると、そのオブジェクト用の資源がカーネルにより解放される。
signalfd_siginfo 構造体
signalfd ファイルディスクリプタからの read(2) で返される signalfd_siginfo 構造体のフォーマットは以下の通りである。
struct signalfd_siginfo {
struct signalfd_siginfo {
uint32_t ssi_signo; /* シグナル番号 */
int32_t ssi_errno; /* エラー番号 (未使用) */
int32_t ssi_code; /* シグナルコード */
uint32_t ssi_pid; /* 送信元の PID */
uint32_t ssi_uid; /* 送信元の実 UID */
int32_t ssi_fd; /* ファイルディスクリプタ (SIGIO) */
uint32_t ssi_tid; /* カーネルタイマ ID (POSIX タイマ)
uint32_t ssi_band; /* Band イベント (SIGIO) */
uint32_t ssi_overrun; /* POSIX タイマのオーバーラン回数 */
uint32_t ssi_trapno; /* シグナルの原因となったトラップ番号 */
int32_t ssi_status; /* 終了ステータスかシグナル (SIGCHLD) */
int32_t ssi_int; /* sigqueue(3) から送られた整数 */
uint64_t ssi_ptr; /* sigqueue(3) から送られたポインタ */
uint64_t ssi_utime; /* 消費したユーザ CPU 時間 (SIGCHLD) */
uint64_t ssi_stime; /* 消費したシステム CPU 時間 (SIGCHLD) */
uint64_t ssi_addr; /* シグナルを生成したアドレス
(ハードウェアが生成したシグナルの場合) */
uint8_t pad[ X]; /* pad の大きさは 128 バイト
(将来のフィールド追加用の場所の確保) */
};
signalfd_siginfo 構造体の各フィールドは、 siginfo_t 構造体の同じような名前のフィールドと同様である。 siginfo_t 構造体については sigaction(2) に説明がある。返された signalfd_siginfo 構造体の全てのフィールドがあるシグナルに対して有効なわけではない。どのフィールドが有効かは、 ssi_code フィールドで返される値から判定することができる。このフィールドは siginfo_t の si_code フィールドと同様である。詳細は sigaction(2) を参照。
fork(2) での扱い
fork(2) が行われると、子プロセスは signalfd ファイルディスクリプタのコピーを継承する。子プロセスでこのファイルディスクリプタから read(2) を行うと、子プロセスに対するキューに入っているシグナルに関する情報が返される。execve(2) での扱い
他のファイルディスクリプタと全く同様に、 signalfd ファイルディスクリプタも execve(2) の前後でオープンされたままとなる。但し、そのファイルディスクリプタに close-on-exec のマーク ( fcntl(2) 参照) が付いている場合はクローズされる。 execve(2) の前に読み出し可能となっていた全てのシグナルは新しく起動されたプログラムでも引き続き読み出し可能である (これは伝統的なシグナルの扱いと同じであり、処理待ちのブロックされたシグナルは execve(2) の前後で処理待ちのままとなる)。スレッドでの扱い
マルチスレッドプログラムにおける signalfd ファイルディスクリプタの扱いはシグナルの標準的な扱いと全く同じである。言い換えると、あるスレッドが signalfd ファイルディスクリプタから読み出しを行うと、そのスレッド自身宛てのシグナルとプロセス (すなわちスレッドグループ全体) 宛てのシグナルが読み出される。 (スレッドは同じプロセスの他のスレッド宛てのシグナルを読み出すことはできない。)返り値
成功すると、 signalfd() は signalfd ファイルディスクリプタを返す。返されるファイルディスクリプタは、 fd が-1 の場合は新規のファイルディスクリプタであり、 fd が有効な signalfd ファイルディスクリプタだった場合は fd 自身である。エラーの場合、-1 を返し、 errno にエラーを示す値を設定する。エラー
- EBADF
- ファイルディスクリプタ fd が有効なファイルディスクリプタでない。
- EINVAL
- fd が有効な signalfd ファイルディスクリプタではない。
- EINVAL
- flags が無効である。もしくは、Linux 2.6.26 以前の場合には flags が 0 以外である。
- EMFILE
- オープン済みのファイルディスクリプタの数がプロセスあたりの上限に達していた。
- ENFILE
- オープン済みのファイル総数がシステム全体の上限に達していた。
- ENODEV
- (カーネル内の) 無名 inode デバイスをマウントできなかった。
- ENOMEM
- 新しい signalfd ファイルディスクリプタを生成するのに十分なメモリがなかった。
バージョン
signalfd() はカーネル 2.6.22 以降の Linux で利用可能である。正しく動作する glibc 側のサポートはバージョン 2.8 以降で提供されている。 signalfd4() システムコール (「注意」参照) はカーネル 2.6.27 以降の Linux で利用可能である。準拠
signalfd() と signalfd4() は Linux 固有である。注意
実際の Linux のシステムコールでは size_t sizemask という引き数が追加で必要である。この引き数で mask のサイズを指定する。 glibc の signalfd() ラッパー関数にはこの引き数は含まれず、ラッパー関数が必要な値を計算して内部で呼び出すシステムコールに提供する。下層にある Linux のシステムコール
下層にある Linux システムコールは二種類あり、 signalfd() と、もっと新しい signalfd4() である。 signalfd() は flags 引き数を実装していない。 signalfd4() では上記の値の flags が実装されている。 glibc 2.9 以降では、 signalfd() のラッパー関数は、 signalfd4() が利用可能であれば、これを使用する。バグ
カーネル 2.6.25 より前では、 sigqueue(3) により送信されたシグナルと一緒に渡されるデータでは、フィールド ssi_ptr と ssi_int は設定されない。例
下記のプログラムは、シグナル SIGINT と SIGQUIT を signalfd ファイルディスクリプタ経由で受信する。シグナル SIGQUIT 受信後にプログラムは終了する。以下に示すシェルセッションにこのプログラムの使い方を示す。
$ ./signalfd_demo
^C # Control-C generates SIGINT
Got SIGINT
^C
Got SIGINT
^\ # Control-\ generates SIGQUIT
Got SIGQUIT
$
プログラムのソース
#include <sys/signalfd.h>
#include <signal.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#define handle_error(msg) \
do { perror(msg); exit(EXIT_FAILURE); } while (0)
int
main(int argc, char *argv[])
{
sigset_t mask;
int sfd;
struct signalfd_siginfo fdsi;
ssize_t s;
sigemptyset(&mask);
sigaddset(&mask, SIGINT);
sigaddset(&mask, SIGQUIT);
/* Block signals so that they aren't handled
according to their default dispositions */
if (sigprocmask(SIG_BLOCK, &mask, NULL) == -1)
handle_error("sigprocmask");
sfd = signalfd(-1, &mask, 0);
if (sfd == -1)
handle_error("signalfd");
for (;;) {
s = read(sfd, &fdsi, sizeof(struct signalfd_siginfo));
if (s != sizeof(struct signalfd_siginfo))
handle_error("read");
if (fdsi.ssi_signo == SIGINT) {
printf("Got SIGINT\n");
} else if (fdsi.ssi_signo == SIGQUIT) {
printf("Got SIGQUIT\n");
exit(EXIT_SUCCESS);
} else {
printf("Read unexpected signal\n");
}
}
}
関連項目
eventfd(2), poll(2), read(2), select(2), sigaction(2), sigprocmask(2), sigwaitinfo(2), timerfd_create(2), sigsetops(3), sigwait(3), epoll(7), signal(7)この文書について
この man ページは Linux man-pages プロジェクトのリリース 3.51 の一部である。プロジェクトの説明とバグ報告に関する情報は http://www.kernel.org/doc/man-pages/ に書かれている。2009-01-13 | Linux |