Apache: CGIでシグナルハンドラを使用する方法

2010年2月14日

Apache2系ではデフォルトのプロセスモデルが「Worker + Prefork」方式になりました。 簡単に言うと、
  • HTTPリクエストに応答するWebサーバープロセスを予め複数起動しておくことで プロセス生成時間を排除することで応答時間(スループット)を短縮しようというのがPrefork。
  • 当該プロセスからさらに応答スレッドを複数生成して大量のリクエストに応答しようというのが Worker。
ということになります。

上記モデルが採用されたことでApacheはさらに応答速度、同時応答数の性能を増加させた 訳ですが、一方で隠された仕様変更も生じています。
CGI内でSIGALRMシグナルを使用できないというのもその代表例です。
つまり、SIGALRMで応答するシグナルハンドラを定義してもそれが実行できないということです。 これは知らなかったらハマル原因になりますので、気をつけましょう。
Phactoryではがっつり

ハマリ

ましたが。。。

これはなぜかというと、SIGALRMシグナルはデフォルトではプロセス、スレッドが停止(TERMINATE)するように OSレベルで定義されています。従って、スレッド内で勝手にCGIにSIGALRMを送りつけられると、親スレッドが 当該シグナルを受け取って終了してしまいかねない訳です。このような問題を予め回避するために、Apacheでは SIGALRMシグナルがブロック(マスク)されています。従って、CGIプロセス・スレッドも親Apacheプロセスの マスクを継承し、全体としてSIGALRMがブロックされているという訳です。
Linux系のOSでは、
  • 親プロセスのシグナルマスク情報が子プロセスに継承される
  • シグナルを受信するのは親スレッドだけ
ということは背景知識としておぼえておきましょう。

ですので、CGIでシグナルを用いて非同期処理する際は十分注意が必要です。
シグナルマスクを解除するには、sigprocmaskシステムコールを使用します。
CGIでスクリプト系言語を使用している場合は、上記システムコールを叩くAPIはそれぞれ異なると 思いますので、そこはご自身で調べてみてください。

参考文献