シグナルを処理するもう 1 つの方法に、完了セマンティクス法があります。
完了セマンティクス法を使用するのは、シグナルが重大な障害が発生したことを示しているために現在のコード部を継続実行しても意味がない場合です。問題の原因となったコード部を引き続き実行する代わりに、シグナルハンドラが実行されます。つまり、シグナルハンドラによって、当該コード部の処理が完了されます。
例 5-3 で、if 文の then 部分の本体が問題のコード部です。setjmp(3C) の呼び出しは、プログラムの現在のレジスタ状態を jbuf に退避して 0 で復帰します。そして、このコード部が実行されます。
sigjmp_buf jbuf; void mult_divide(void) { int a, b, c, d; void problem(); sigset(SIGFPE, problem); while (1) { if (sigsetjmp(&jbuf) == 0) { printf("Three numbers, please:¥n"); scanf("%d %d %d", &a, &b, &c); d = a*b/c; printf("%d*%d/%d = %d¥n", a, b, c, d); } } } void problem(int sig) { printf("Couldn't deal with them, try again¥n"); siglongjmp(&jbuf, 1); } |
SIGFPE (浮動小数点例外条件) が発生すると、シグナルハンドラが呼び出されます。
シグナルハンドラは、siglongjmp(3C) を呼び出します。この関数は、jbuf に退避されていたレジスタ状態を復元し、プログラムを sigsetjmp() 部分から復帰させます (プログラムカウンタとスタックポインタも退避されています)。
このとき、sigsetjmp(3C) は siglongjmp() の第 2 引数である 1 を返します。その結果、問題のコード部はスキップされ、while ループの次の繰り返しに入ります。
sigsetjmp(3C) と siglongjmp(3C) をマルチスレッドプログラムで使うこともできますが、別のスレッドで呼び出された sigsetjmp() の結果を使って、siglongjmp() を呼び出すことはできません。
また、sigsetjmp() と siglongjmp() は、シグナルマスクを退避または復元しますが、setjmp(3C) と longjmp(3C) は、シグナルマスクを退避または復元しません。
シグナルハンドラでは、sigsetjmp() と siglongjmp() を使用してください。
完了セマンティクス法は、例外条件の処理でよく使用されます。特に Sun AdaTM プログラミング言語では、このモデルが使用されています。
同期シグナルに対して sigwait(2) を決して使用しないでください。