C/400

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

プロセス識別子 pid のプロセス ( = ジョブ ) に対してシグナル ( 信号 ) を送って
割り込みをかけるのは

kill(pid, SIGUSR1);

のようにして、とても簡単である。
このシグナルを受ける側では

struct sigaction sigact;

というシグナル構造体に

sigact.sa_handler = catcher;

のようにしてシグナル・ハンドラー、つまりシグナルを受け取ったときに起動される関数として
catcher という名前の関数を起動することを指定する。
これだけで何かを実行中であっても別のジョブから他のジョブへ割り込みを
かけることができるのである。

【 サンプル: TESTSVR1 】

シグナル: SIGUSR1, SIGUSR2, SIGUSR3 を受け取ることができるサンプル

0001.00 #include <stdio.h>                                    
0002.00 #include <stdlib.h>                                   
0003.00 #include <string.h>                                   
0004.00 #include <signal.h>                                   
0005.00 #include <errno.h>                                    
0006.00                                                       
0007.00 #define TRUE         0                                
0008.00 #define FALSE       -1                                
0009.00                                                       
0010.00 #define SIGUSR3      9                                
0011.00 void  catcher(int sig);                               
0012.00 struct sigaction sigact;                              
0013.00 void main(void){                                      
0014.00                                                       
0015.00   printf("** TESTSVR1: シグナル受信用 **\n");         
0016.00   getchar();                                          
0017.00      sigemptyset(&sigact.sa_mask);                    
0018.00      sigact.sa_flags = 0;                             
0019.00      sigact.sa_handler = catcher;                     
0020.00      sigaction(SIGUSR1, &sigact, NULL);               
0021.00      sigaction(SIGUSR2, &sigact, NULL);               
0022.00      sigaction(SIGUSR3, &sigact, NULL);               
0023.00                                                       
0014.00                                                      
0015.00   printf("** TESTSVR1: シグナル受信用 **\n");        
0016.00   getchar();                                         
0017.00      sigemptyset(&sigact.sa_mask);                   
0018.00      sigact.sa_flags = 0;                            
0019.00      sigact.sa_handler = catcher;                    
0020.00      sigaction(SIGUSR1, &sigact, NULL);              
0021.00      sigaction(SIGUSR2, &sigact, NULL);              
0022.00      sigaction(SIGUSR3, &sigact, NULL);              
0023.00                                                      
0024.00   printf("* シグナルを待機します。 \n");             
0025.00   getchar();                                         
0026.00 }                                                    
0027.00 /********************/                               
0028.00 void catcher(int sig)                                
0029.00 /********************/                               
0030.00 {                                                    
0031.00   system("DSPLIBL *PRINT");                          
0032.00   errno = 0;                                         
0033.00   return;                                            
0034.00 }                                      
【コンパイル】

CRTBNDC PGM(MYLIB/TESTSVR1) SRCFILE(PGMRLIB/QCSRC) AUT(*ALL)

【解説】
0017.00      sigemptyset(&sigact.sa_mask);                   
0018.00      sigact.sa_flags = 0;                            
0019.00      sigact.sa_handler = catcher;                    
0020.00      sigaction(SIGUSR1, &sigact, NULL);              
0021.00      sigaction(SIGUSR2, &sigact, NULL);              
0022.00      sigaction(SIGUSR3, &sigact, NULL);

によって シグナル SIGUSR1, SIGUSR2 または SIGUSR3 が送られてきたときに
割り込みハンドラー関数: catcher が呼び出されて実行することを意味している。
catcher 関数は呼び出された回数分、

system("DSPLIBL *PRINT");

によってライブラリー・リストを QPRINT に印刷出力する。

【実行】

実行の前には DSPJOBコマンドによって ジョブ名、ユーザー名とジョブ番号を控えておいてから

CALL MYLIB/TESTSVR1 + [実行]

によって起動すると次のような画面が表示される。

【 サンプル: TESTCLT1 】

TESTSVR1 にシグナル: SIGUSR3 を送って割り込み要求をかけるプログラム

0001.00 #include <stdio.h>                                                     
0002.00 #include <stdlib.h>                                                    
0003.00 #include <string.h>                                                    
0004.00 #include <sys/signal.h> /* kill */                                     
0005.00 #include <QUSRJOBI.h>                                                  
0006.00 #include <errno.h>                                                     
0007.00                                                                        
0008.00 #define TRUE         0                                                 
0009.00 #define FALSE       -1                                                 
0010.00 #define SIGUSR3      9                                                 
0011.00 typedef struct {                                                       
0012.00    int  BYTESPRO;                                                      
0013.00    int  BYTESAVL;                                                      
0014.00    char MSGID[7];                                                      
0015.00    char RESRVD;                                                        
0016.00    char EXCPDATA[100];                                                 
0017.00 } ERRSTRUCTURE;     /* Define the error return structure            */ 
0018.00 ERRSTRUCTURE  errcode;/* Error Code Structure for RCVMSG      */       
0019.00 typedef struct {                                                       
0020.00    char job[10];                                                       
0021.00    char user[10];                                                      
0022.00    char jobnbr[6];                                                     
0023.00 } JOBINFO;                                                             
0024.00 JOBINFO jobinfo;                                                            
0025.00   int  sig;                                                                 
0026.00                                                                             
0027.00 void main(void){                                                            
0028.00    char job[11], user[11], jobnbr[7], msg[256];                             
0029.00    Qwc_JOBI0800_t jobi0800;                                                 
0030.00    sigset_t  sigmask;                                                       
0031.00    int pid;                                                                 
0032.00                                                                             
0033.00    strcpy(job, "QPADEV000F");                                               
0034.00    strcpy(user, "QTR       ");                                              
0035.00    strcpy(jobnbr, "689582");                                                
0036.00    printf("*  シグナル送信 %s, %s, %s\n", job, user, jobnbr);               
0037.00    getchar();                                                               
0038.00    errcode.BYTESPRO = 160;                                                  
0039.00    errcode.BYTESAVL = 0;                                                    
0040.00    memcpy(jobinfo.job, job, 10);                                            
0041.00    memcpy(jobinfo.user, user, 10);                                          
0042.00    memcpy(jobinfo.jobnbr, jobnbr, 6);                                       
0043.00     QUSRJOBI(&jobi0800, sizeof(jobi0800), "JOBI0800",                       
0044.00               &jobinfo,  "                ", &errcode);                     
0045.00     if(errcode.BYTESAVL != 0){/* APIERR */                                  
0046.00       sprintf(msg, "%s/%s/%s のジョブ情報を検索することができません。 ",    
0047.00           job, user, jobnbr);                                               
0048.00       printf("%s\n", msg);                                       
0049.00       getchar();                                                 
0050.00       exit(-1);                                                  
0051.00     }/* APIERR */                                                
0052.00     pid = jobi0800.Process_ID_Number;                            
0053.00     sig = SIGUSR3;                                               
0054.00     if(kill(pid, sig) < 0){/* ERR */                             
0055.00       sprintf(msg, " シグナル送信エラー :%s", strerror(errno));  
0056.00       printf("%s\n", msg);                                       
0057.00       getchar();                                                 
0058.00       exit(-1);                                                  
0059.00     }/* ERR */                                                   
0060.00     printf(" シグナル sig=%d を送信しました。 \n", sig);         
0061.00     getchar();                                                   
0062.00 }                                                                
【コンパイル】

CRTBNDC PGM(MYLIB/TESTCLT1) SRCFILE(PGMRLIB/QCSRC) AUT(*ALL)

【解説】
0033.00    strcpy(job, "QPADEV000F");                                               
0034.00    strcpy(user, "QTR       ");                                              
0035.00    strcpy(jobnbr, "689582");

には事前に TESTSVR1 のジョブで控えておいたジョブ名、ユーザー名およびジョブ番号に変更してから
コンパイルすること。

0043.00     QUSRJOBI(&jobi0800, sizeof(jobi0800), "JOBI0800",                 
0044.00               &jobinfo,  "                ", &errcode); 

によってジョブ名、ユーザー名およびジョブ番号からプロセス識別

pid = jobi0800.Process_ID_Number;

を取得することができるので

kill(pid, sig)

によってシグナルを送信することが可能になる。

【実行】

TESTSVR1 が実行されているのとは別のジョブ、つまり別の5250セッションを立ち上げて

CALL MYLIB/TESTCLT1 + [実行]

によって 「 シグナル = 9 を送信しました。」 のメッセージが出るまで
実行キーを押していくと TESTSVR1 は何の変化も見られないが QPRINT にはライブラリー・リストが
TESTCLT1 が実行された回数分、印刷出力されていることがわかる。

つまり TESTSVR1 に対して割り込み要求が実行されて catcher 関数 が実行されたことになる。
このように別のジョブに割り込みをかけて、こちらからの要求を実行させることが
シグナルの基本である。

一般ではシグナルは他のジョブに割り込みをかけて強制的に終了させる、という単純な機能にのみ
利用されることが多いようである。
従って Webでシグナル割り込みの事例を探してもほとんどが強制終了が目的であり
適用業務にどのように応用したらよいのかがわからないのであろう。
このシリーズではシグナル割り込みの応用から高度な事例までを紹介しよう。