シグナルセーフの私的メモ

私的メモ

シグナルは一種のプロセス間通信の機能であり、BSDなどのOSと作成されたプロセスの間で規定のフラグを送信することを可能としたもの。
シグナルを受けて、あらかじめ登録されていた処理が動作する。この動作をシグナルハンドラと呼ぶ。
シグナルハンドラ内で使うことを許された関数を「非同期シグナルセーフな関数」と呼ぶ。

  • いつでも他のシグナルに割り込まれても問題ないように作る。
  • シグナルハンドラ内で行ってよい処理は以下
    • 自動変数の操作
    • “volatile sig_atomic_t” 型の大域変数の操作
    • 「非同期シグナルセーフ」関数の呼び出し
  • signal(2) は時代遅れである。新規のプログラムでは POSIXシグナルだけを使う。sigaction!
  • sigprocmaskは他のシグナルハンドラを排除する、しかしそもそもシグナルハンドラは高速に動くべきである。
  • 例えばSIGHUPによるログ切り替えの実装はシグナルハンドラはフラグを立てるだけにしておき、後でそのフラグを見て安全なタイミングにしてから切り替えるべき。
  • 「再読み込みフラグ」は volatile sig_atomic_t (変数に対して部分的に最適化を抑制する。sig_atomic_tはCPUに応じて適切にtypedefしてくれる整数型)
  • シグナルハンドラ内でprintf(3)は駄目、絶対。writeをつかう。
  • 子プロセスが終了した際に発生するシグナルはSIGCHLD。これを受け取ってフラグを書き換え、後でwait(子プロセスの開放)してやる。放置するとゾンビが生まれる。

おまけ。
私はUSの妖しいアプリを持ってきては無理やり動かすような仕事をしている。
本日そのアプリが突然刺さってしまい、聡明な人を背後霊にしていろいろ追いかけたところSIGHUPしているところで刺さっているようだった。
よくよく解析すると、シグナルハンドラ内の処理で時間がかかかる処理が行われており、その処理の最中に他から何かのシグナルを受け取ったりしたとき、デッドロックしてしまうように見えた。
それ自身はUSのバグトラッキングを追いかけると最新版でFIXしていたのでよしとする。

しかしそこでふと気が付く、あまりまともにシグナルセーフを理解して無いかもしれない。