ファイヤープロジェクト
sigaction
2003-07-20T15:13+09:00   matsu
sigaction関数はsignal関数よりもより細かい制御ができる.sigactionはX/Open仕様ではsignalよりも信頼できるとして推奨しているらしい.
int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact);
sigactionの引数について以下に示す.
signum
sigaction構造体を設定するシグナル.
act
設定するsigaction構造体.
oldact
設定前(変更前)のsigaction構造体.
sigaction関数は成功すれば0,失敗すると-1を返す.sigaction関数ではsigaction構造体を引数にとる.この構造体がsignal関数との違いの鍵を握っている.以下,/usr/include/bits/sigaction.hより.
sa_sigactionは3つの引数を取る関数で,そのうちの一つsiginfo_tは構造体になっていて,またたくさんのフィールドを持つ.面倒なのでここでは書かないが,こいつを使うとさらに細かい制御ができそうな雰囲気を感じた.
sigactionを使ったサンプルを以下に示す.
以下実行結果.
successed sigaction.
catched SIGINT.
successed raise.

sa_gflagsをSA_ONESHOTにした効果(一回シグナルをキャッチしたらデフォルトのsigactionに戻る)もちゃんと出ている.
sigaction構造体のフィールドsa_maskはsigset_t型でシグナルの集合を表すものある.これはつきつめると/usr/include/bits/sigset.hの以下の部分になっているようだ.
/* A `sigset_t' has a bit for each signal.  */

# define _SIGSET_NWORDS (1024 / (8 * sizeof (unsigned long int)))
typedef struct
  {
    unsigned long int __val[_SIGSET_NWORDS];
  } __sigset_t;

#endif
で先のサンプルでは思い切って
sigset = malloc(_SIGSET_NWORDS);
などとしてしまった(いいのかな).で,このシグナル集合を扱うのに便利な関数がある.
int sigemptyset(sigset_t *set);
setを空に初期化.
int sigfillset(sigset_t *set);
setにすべてのシグナルを設定.
int sigaddset(sigset_t *set, int signum);
setに指定したシグナルを追加.
int sigdelset(sigset_t *set, int signum);
setから指定したシグナルを削除.
int sigismember(const sigset_t *set, int signum);
setに指定いたシグナルが含まれていれば1,含まれていなければ0,signumが不正などの理由でエラーなら-1を返す.
前四者は成功なら0,失敗なら-1を返す.で,このうちsigemptyset,sigaddsetを先のサンプルで使用した(/* シグナル集合の準備 */の部分).
仲間かどうかは知らないが,とにかくman sigactionとすると一緒に出て来る関数が三つある.
int sigprocmask(int how, const sigset_t *set, sigset_t *oldset);
ブロックされているシグナルのリストを変更する.howで追加,設定,削除を選択する.man参照.
int sigpending(sigset_t *set);
(ブロックされていて)待機中のシグナルのセットを引数setに格納する.
int sigsuspend(const sigset_t *mask);
シグナルのマスクを一時的にmaskに置き換えてシグナルを受信するまで待機する.返り値は常に-1.
前者二つはsigactionと同様成功なら0,失敗なら-1を返す.
sigpendingやsigismemberを使用したサンプルを示す.
以下実行結果.C-\でSIGQUITを送信して終了できる.
successed sigaction.
type C-c
signal handler called 1 times.
type C-c more
SIGINT is pending
signal handler done.
signal handler called 2 times.
type C-c more
SIGINT is not pending
signal handler done.
終了
このサンプルから,シグナルハンドラ実行中にブロックされている同じシグナルを何回送信しても一回しかシグナルハンドラが起動されないことが分かる.具体的には
type C-c more
と出てから3秒以内に複数回C-cをタイプして放置しても,一回しかシグナルハンドラが起動されていないことが分かる.
man sigactionで地味に書いてあったのをメモ.
  • sigactionの二番目の引数をNULLにして呼び出し,そのあとoldactを参照すれば,現在のハンドラを確認できる.
  • 二番目と三番目の引数をNULLにして呼び出すことで,signumが現在のマシンで有効かどうかを確認できる.
matsu(C)
Since 2002
Mail to matsu