SIGTERMの受信設定と動作例 - Apache httpd デーモンの場合 -
次に、Linuxディストリビューションで提供されている代表的なプログラムにおけるシグナルハンドラの実装例を見てみましょう。まずは主要なLinuxディストリビューションで提供されているApache Webサーバのpreforkモデルについて見ていきます。
preforkモデルでは、親プロセス(httpd)が子プロセスを先行して生成し、1つの子プロセスが1つのリクエストを処理します。
シグナル処理はhttpdの本体からリンクされたモジュールmod_mpm_prefork.soによって行われます。この中で、親プロセスはシグナルハンドラsig_term()の登録を行い、SIGTERMシグナル受信時にクリーンアップ処理を行います。親プロセスのシグナルハンドラの登録にはsigacton()を、子プロセスのシグナルハンドラの登録にはsignal()を使用しています。
 
 図「httpdのSIGTERMシグナルハンドラ」の①~③で実行されている動作
- 
      ① 親プロセスはシステムコールsigaction()によりシグナルハンドラsig_term()を登録(子プロセスはシステムコールsignal()によりシグナルハンドラjust_die()を登録)
- 
      ② killコマンドによりhttpdの親プロセスにSIGTERMを送信
- 
      ③ SIGTERMシグナルを受信したhttpd(親)のシグナルハンドラsig_term()は終了待ちフラッグを立て、それを検知した処理ルーチンはSIGTERMシグナルの送信によって、すべての子プロセスを終了させ、最後に親プロセス自身が終了。
このように、httpdはSIGTERMシグナルを受信するとクリーンアップ処理をしてから終了します。
ただし、httpdの親プロセスをSIGKILLシグナルによって強制終了した場合、クリーンアップ処理が行われず、子プロセスが残ってしまいます[1]。httpdの親プロセスが消滅した場合は、子プロセスに対して設定ファイルに従った正しい制御ができず、またSysVinitのserviceコマンドやsystemdのsystemctlコマンドでも制御ができなくなります[2]。
SIGTERMとSIGKILLの違い
httpdの例で見てきたように、SIGTERMシグナルを受信したプロセスはクリーンアップ処理を実行して終了し、SIGKILLシグナルを受信したプロセスはシグナルを捕捉できないためクリーンアップ処理を実行できずに終了します。WebブラウザのFirefoxやメールクライアントのThunderbird(共にLinux版)では、終了時のクリーンアップ処理の中でロックファイル(lock)を削除して終了しますが、SIGKILLシグナルを送信して終了させた場合には、ロックファイルは削除されずに残ってしまいます。このため、次回起動時にはロックファイルを削除してからでないと起動できません。
このように、外部からシグナルを送信してプロセスを終了させる場合には、プロセスがクリーンアップ処理を実行することのできないSIGKILLシグナルによる強制終了ではなく、プロセスがクリーンアップ処理を実行するSIGTERMシグナルによる終了が推奨されます[3]。
SIGHUPの受信設定と動作例 - BIND named デーモンの場合 -
BIND named、Apache httpd、xinetdなどのデーモンプログラムは、SIGHUPシグナルを受信すると設定ファイルを再読み込みするように実装されています。このようなデーモンは、設定ファイルを編集した後にSIGHUPシグナルを送信することで、再起動によるサービスの中断なしに設定ファイルの内容を有効にすることができます[4][5]。
ここではDNSサーバ「BIND named」(以下、named)のシグナル処理を例として見ていきます。namedはsigacton()を使用してシグナルハンドラreload_action()を登録し、SIGHUPシグナル受信時に設定ファイルの再読み込みを行います。
 
 - 
      ➀ システムコールsigaction()により、シグナルハンドラreload_action()を登録
- 
      ② killコマンドによりnamedにSIGHUPシグナルを送信
- 
      ③ SIGHUPシグナルを受信したnamedのシグナルハンドラreload_action()は設定ファイルnamed.confとゾーンファイルの再読み込みを行う
注
[1]: 親プロセスが子プロセスの終了処理をせずに強制終了で消滅した場合、SysVinitを採用しているシステムではinitプロセスが、systemdを採用しているシステムではsystemdが代わって親になります。
[2]: この場合、killallコマンドやpkillコマンドなどで、すべての子プロセスを終了させる必要があります。
[3]: SIGKILLシグナルは、設定あるいは動作異常によりSIGTERMシグナルの処理を行わないプロセスを強制終了する場合に使用します。
[4]: SIGHUPシグナルを受信すると再起動するデーモンもあります。また、デフォルトのハンドラが起動してプロセスが終了するデーモンもあります。
[5]: Apache httpdの場合、SIGHUPシグナルを受信した親プロセスは設定ファイルを再読み込みし、子プロセスを再起動します。

 
              
               
              
               
              
               
              
               
              
               
                  
                   
                  
                 
                  
                 
                  
                 
                                            
                                         
                                            
                                         
                                            
                                         
                                            
                                         
                                            
                                         
                    