SIGNALFD
Section: Linux Programmer's Manual (2)
Updated: 2009-01-13
Index
JM Home Page
roff page
名前
signalfd - シグナル受け付け用のファイルディスクリプタを生成する
書式
#include <sys/signalfd.h>
int signalfd(int fd, const sigset_t *mask, int flags);
説明
signalfd()
は、呼び出し元宛てのシグナルを受け付けるために使用されるファイル
ディスクリプタを生成する。
この方法はシグナルハンドラや
sigwaitinfo(2)
を用いる方法の代わりとなるものであり、このファイルディスクリプタを
select(2),
poll(2),
epoll(7)
で監視できるという利点がある。
mask
引き数には、呼び出し元がこのファイルディスクリプタ経由で受け付けたい
シグナル集合を指定する。この引き数で指定するシグナル集合の内容は、
sigsetops(3)
で説明されているマクロを使って初期化することができる。
通常、ファイルディスクリプタ経由で受信するシグナル集合は、
そのシグナルがデフォルトの配送方法に基いて処理されるのを防ぐために、
sigprocmask(2)
を使ってブロックしておくべきである。
シグナル
SIGKILL
と
SIGSTOP
を signalfd ファイルディスクリプタ経由で受信することはできない。
これらのシグナルが
mask
で指定された場合には黙って無視される。
fd
引き数が -1 の場合、
signalfd()
は新しいファイルディスクリプタを生成し、
mask
で指定されたシグナル集合をそのファイルディスクリプタに関連付ける。
fd
引き数が -1 以外の場合、
fd
には有効な既存の signalfd ファイルディスクリプタを指定しなければならず、
そのディスクリプタに関連付けられているシグナル集合は
mask
を使って置き換えられる。
Linux 2.6.27 以降では、
以下の値のいくつかをビット単位の論理和 (OR) で指定することで、
signalfd()
の振舞いを変更することができる。
- 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(2) から送られた整数 */
uint64_t ssi_ptr; /* sigqueue(2) から送られたポインタ */
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)
が行われると、子プロセスは signalfd ファイルディスクリプタのコピーを
継承する。
子プロセスでこのファイルディスクリプタから
read(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()
ラッパー関数にはこの引き数は含まれず、
ラッパー関数が必要な値を計算して内部で呼び出すシステムコールに提供する。
一つのプロセスは複数の signalfd ファイルディスクリプタを生成することができる。
これにより、異なるファイルディスクリプタで異なるシグナルを受け取ることが
できる (この機能は
select(2),
poll(2),
epoll(7)
を使ってファイルディスクリプタを監視する場合に有用かもしれない。
異なるシグナルが到着すると、異なるファイルディスクリプタが利用可能に
なるからだ)。
一つのシグナルが二つ以上のファイルディスクリプタの
mask
に含まれている場合、そのシグナルの発生はそのシグナルを
mask
に含むファイルディスクリプタのうちいずれか一つから読み出すことができる。
下層にある Linux のシステムコール
下層にある Linux システムコールは二種類あり、
signalfd()
と、もっと新しい
signalfd4()
である。
signalfd()
は
flags
引き数を実装していない。
signalfd4()
では上記の値の
flags
が実装されている。
glibc 2.9 以降では、
signalfd()
のラッパー関数は、
signalfd4()
が利用可能であれば、これを使用する。
バグ
カーネル 2.6.25 より前では、
sigqueue(2)
により送信されたシグナルと一緒に渡されるデータでは、フィールド
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 arenaqt 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)
Index
- 名前
-
- 書式
-
- 説明
-
- signalfd_siginfo 構造体
-
- fork(2) での扱い
-
- execve(2) での扱い
-
- スレッドでの扱い
-
- 返り値
-
- エラー
-
- バージョン
-
- 準拠
-
- 注意
-
- 下層にある Linux のシステムコール
-
- バグ
-
- 例
-
- プログラムのソース
-
- 関連項目
-
This document was created by
man2html,
using the manual pages.
Time: 03:26:55 GMT, April 25, 2010