GNU C Library Reference Manualには、シグナル処理に関するすべてを説明する章全体があります。
独自のハンドラーをインストールすると、以前に設定したシグナル ハンドラー (関数ポインター) が常に取得されます (signal()
またはのマンページを参照sigaction()
)。
previous_handler = signal(SIGINT, myhandler);
一般的なルールは、いつでも前のハンドラーとraise()
シグナルにリセットできるということです。
void myhandler(int sig) {
/* own stuff .. */
signal(sig, previous_handler);
raise(sig);
/* when it returns here .. set our signal handler again */
signal(sig, myhandler);
}
一般的な規則には 1 つの欠点があります。シグナルにマップされるハードウェア例外は、通常、例外の原因となった特定の命令に割り当てられます。そのため、シグナルを再度発生させると、関連付けられた命令は元の命令と同じではありません。これは、他のシグナルハンドラに害を及ぼす可能性がありますが、そうすべきではありません。
もう 1 つの欠点は、発生した各シグナルによって多くの処理時間が発生することです。の過度の使用を防ぐためにraise()
、次の代替手段を使用できます。
SIG_DFL
関数ポインターがアドレスを指している場合0
(これは明らかに有効なアドレスではありません)。したがって、ハンドラーとシグナルを再度リセットする必要があります。raise()
if (previous_handler == SIG_DFL)
{
signal(sig, SIG_DFL);
raise(sig);
signal(sig, myhandler);
}
SIG_IGN
値があります1
(これも無効なアドレスです)。ここでは、そのまま戻ることができます (何もしないでください)。
else if (previous_handler == SIG_IGN)
{
return;
}
それ以外の場合 (どちらSIG_IGN
でもないSIG_DFL
)、有効な関数ポインターを受け取っていないため、ハンドラーを直接呼び出すことができます。
else
{
previous_handler(sig);
}
もちろん、さまざまな API も考慮する必要があります (signal()
およびのマンページを参照してくださいsigaction()
)。