C/400

86. 利用範囲が広がるシグナルの応用 (3)

ここに紹介した意図は、このテクニックの紹介である。
実はシグナルを受けるサーバー側で recvmsg で待機するジョブにシグナルを
受けるときは少々工夫が必要となる。
HTTP サーバーを初めとするサーバーが recvmsg によって待機しているときに
シグナルを受けると、

  1. そのシグナルに関連づけられたシグナル・ハンドラーとしての関数が
    定義されていれば、その関数が実行される。

  2. recvmsg は再び待機状態になるのではなく

    EINTR : Interrupted function call.

    のエラー・メッセージで終了してしまう。
    この EINTR というエラーは Linux では

    データが受信可能になる前に受信がシグナルによって割り込まれました。

    というエラーである。

という状態となる。
この 2. の EINTR というエラーが問題でこれは recvmsg でデータを待機していたのだが
シグナルによる割り込みのために受信が中断された、という意味である。
このエラーを回避しないと recvmsg による待機ジョブは終了してしまうことになる。

■ 解決

シグナル待機をもう一度、再セットしてから処理を継続する。

【 サンプル・ソース 】
ソースコード
0021.00 #include <errno.h> 
 :
0153.00 struct sigaction sigact;  
 :
0395.00      rc = recvmsg(worker_sd, &msg, 0);               
0396.00      if(rc < 0){/* recvmsg エラー */                 
0397.00         if(errno == EINTR){/* シグナル割り込み */    
0398.00           setSignal();                               
0399.00           continue;                                  
0400.00         }/* シグナル割り込み */                      
  :
1672.00 /********************/                     
1673.00 void  setSignal(void)                      
1674.00 /********************/                     
1675.00 {                                          
1676.00   /* recvmsg のための初期化 */             
1677.00    memset(&msg, 0, sizeof(msg));           
1678.00    memset(iov,  0, sizeof(iov));           
1679.00    iov[0].iov_base = buffer;               
1680.00    iov[0].iov_len = sizeof(buffer);        
1681.00    msg.msg_iov    = iov;                   
1682.00    msg.msg_iovlen = 1;                     
1683.00    msg.msg_accrights = (char*)&sockfd;     
1684.00    msg.msg_accrightslen = sizeof(sockfd);  
1685.00                                            
1686.00    sigemptyset(&sigact.sa_mask);           
1687.00    sigact.sa_flags = 0;                    
1688.00    sigact.sa_handler = catcher;            
1689.00    sigaction(SIGUSR1, &sigact, NULL);      
1690.00    sigaction(SIGUSR2, &sigact, NULL);      
1691.00    sigaction(SIGUSR3, &sigact, NULL);      
1692.00 }                                          
【解説】

recvmsg のエラーが EINTR ( EINTRerrno.h の中で定義されている ) であれば
もう一度 setSignal 関数によって シグナル構造体 sigact を再セットしてから
continue で処理を継続する。
このとき recvmsg の初期化も同時に行なっているので次の recvmsg も正しく待機させることができる。
このテクニックは Webサイトを探してもどこにもまだ紹介されていない実用的なテクニックである。
これによって Spoolライターの サーバーでの子ブロセスの QTEMP 情報を自由に検索することが
できるようになったのである。