シグナルを処理するもう 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) を同期シグナルで使用しないように注意してください。