POSIXシグナル
シグナルはプロセスに対するイベント発生の通知。ソフトウェア割り込みとも呼ばれる。シグナルは普通、非同期に発生する。
シグナルは、
送ることができる。
シグナルには、処理配備(アクション)が伴う。3種類の処理配備がある。
1.シグナルハンドラにより、シグナルを捕捉する。
SIGKILLとSIGSTOPは捕捉できない。
シグナルハンドラの関数プロトタイプ
void handler(int signo);
2.シグナルを無視する
シグナルの処理配備をSIG_IGNに設定することにより、そのシグナルを無視するように設定できる。SIGKILLとSIGSTOPは無視できない。
3.デフォルトの動作に設定する
シグナル処理配備をSIG_DFLに設定することにより、そのシグナルに対するデフォルトの動作を行うように設定できる。SIGCHLDとSIGURGは、デフォルト動作がシグナル無視となっている。
シグナルの処理配備を設定するためには、sigaction関数を呼び出す。
typedef void Sigfunc(int); Sigfunc* signal(int signo, Sigfunc *func) { struct sigaction act, oact; act.sa_handler = func; sigemptyset(&act.sa_mask); act.sa_flags = 0; if (signo == SIGALRM) { act.sa_flags |= SA_RESTART; } if (sigaction(signo, &act, &oact) < 0) return SIG_ERR; return oact.sa_handler; }
singaction構造体のsa_handlerメンバにfunc引数を設定する。
シグナルハンドラが呼び出されている間ブロックされるシグナルの集合を指定できる。ブロックされたシグナルは、プロセスに配送されなくなる。Posixでは、捕捉されたシグナルは、対応するハンドラが呼び出されている間ブロックされることを保証している。
sigaction構造体のSA_RESTARTが設定されていると、シグナルによって割り込まれたシステムコールを、カーネルが自動的に再実行する。
Posix適合システムにおけるシグナル処理について
この機能を用いるとコードの危険領域(実行中にシグナルの捕捉が起きてはならない部分を保護することが可能になる)
SIGCHLDシグナルの処理
ゾンビ状態の目的は、子プロセスのリソースの利用状況(プロセスID、終了状態、CPU時間、メモリ使用量など)を親プロセスがあとで取得できるようにすること。
プロセスが終了した際、そのプロセスにゾンビ状態になっている子プロセスがあれば、これらの子プロセスの親プロセスIDはすべて1(init)に付け替えられ、initは子プロセスを引き継いで終了処理を行う(子プロセスに対してwaitを実行し、ゾンビプロセスを消滅させる)。psを実行したときに、ゾンビプロセスは、defunctと表示される。
SIGCHLDシグナルを捕捉sるうシグナルハンドラを設定し、このシグナルハンドラ中からwaitを呼び出す。
printfのような標準入出力関数をシグナルハンドラから呼び出すことは、良くない。
//waitを呼び出すシグナルハンドラ void sig_child(int signo) { pid_t pid; int stat; pid = wait(&stat); printf("Child %d terminated\n", pid);/*これは良くないが。表示して分かりやすくため*/ return; }
割り込まれたシステムコールの処理
プロセスが遅いシステムコール(永久のブロックする可能性のあるシステムコール)でブロックして、かつプロセスによるシグナルの捕捉が起き、かつシグナルハンドラから制御が戻った際に、そのシステムコールがEINTRエラーを返す可能性がある。よって、遅いシステムコールがEINTRを返す場合に備えておかなければならない。
//acceptへの割り込みへの対処の例 for (;;) { clilen = sizeof(cliaddr); if (connfd = accept(listenfd, (struct sockaddr*)&cliaddr, &clilen) < 0) { if (errno == EINTR) continue; else exit(1); } }
システムコールが割り込まれたことを検出し、
単にシステムコールを再実行している。
参考文献