C Language
信号処理
サーチ…
構文
- void(* signal(int sig、void(* func)(int)))(int);
パラメーター
パラメータ | 詳細 |
---|---|
sig | シグナルハンドラをSIGABRT 、 SIGFPE 、 SIGILL 、 SIGTERM 、 SIGINT 、 SIGSEGV または何らかの実装定義値のいずれかに設定するSIGFPE 。 |
機能 | 以下のいずれかであるシグナルハンドラ: SIG_DFL 、デフォルトのハンドラ用SIG_IGN シグナルを無視する、または署名付き関数ポインタvoid foo(int sig); 。 |
備考
C標準からの保証のみを伴うシグナルハンドラの使用は、ユーザ定義のシグナルハンドラで何ができるか、できないかを様々な制限を課す。
SIGSEGV
、SIGFPE
、SIGILL
または他のインプリメンテーション定義のハードウェア割り込みを処理しているときにユーザー定義関数が戻ると、その動作はC標準では定義されません。これは、Cのインタフェースが障害状態(例えば、0
除算した後)を変更する手段を与えないため、プログラムを返すときにハードウェア割り込みが発生する前とまったく同じエラー状態になるためです。abort
、またはraise
呼び出しの結果としてユーザー定義関数が呼び出された場合、シグナル・ハンドラーはraise
を再度呼び出すraise
はできません。信号はどんな動作の途中でも到達する可能性があるため、動作の不可分性は一般的に保証されず、信号処理も最適化でうまく機能しません。したがって、シグナルハンドラ内のデータに対するすべての変更は、変数
- タイプ
sig_atomic_t
(すべてのバージョン)またはロックフリーのアトミックタイプ(C11以降) -
volatile
修飾されたものです。
- タイプ
C標準ライブラリの他の関数は、プログラムのグローバルな状態で変数を変更する可能性があるため、通常はこれらの制限を守りません。 C標準は
abort
、_Exit
(C99以降)、quick_exit
(C11以降)、signal
(同じシグナル番号)、およびいくつかのアトミック操作(C11以降)のみを保証します。
上記の規則のいずれかに違反した場合、C標準によって動作が未定義になります。プラットフォームには特定の拡張機能が含まれている場合がありますが、一般的にそのプラットフォームを超えて移植することはできません。
通常、システムは、シグナルハンドラから使用できるCライブラリ関数である非同期シグナルセーフである独自の関数リストを持っています。通常、
printf
はこれらの機能の1つです。特に、Cの標準では、スレッドインタフェース(C11以降)やPOSIXスレッドなどのプラットフォーム固有のスレッドライブラリとのやりとりについてはあまり規定していません。そのようなプラットホームは、それ自体でシグナルとそのようなスレッドライブラリの相互作用を特定しなければならない。
"signal()"による信号処理
シグナル番号は、プログラム自体が誤動作したり、非同期( SIGINT
- インタラクティブな注意)のように、プログラムの外部から開始されたとき( Cntrl-C
キー入力など)にトリガされたときに、 SIGSEGV
ような同期化することができます。
signal()
関数はISO C標準の一部であり、特定のシグナルを処理する関数を割り当てるために使用できます
#include <stdio.h> /* printf() */
#include <stdlib.h> /* abort() */
#include <signal.h> /* signal() */
void handler_nonportable(int sig)
{
/* undefined behavior, maybe fine on specific platform */
printf("Catched: %d\n", sig);
/* abort is safe to call */
abort();
}
sig_atomic_t volatile finished = 0;
void handler(int sig)
{
switch (sig) {
/* hardware interrupts should not return */
case SIGSEGV:
case SIGFPE:
case SIGILL:
/* quick_exit is safe to call */
quick_exit(EXIT_FAILURE);
/* use _Exit in pre-C11 */
_Exit(EXIT_FAILURE);
default:
/* Reset the signal to the default handler,
so we will not be called again if things go
wrong on return. */
signal(sig, SIG_DFL);
/* let everybody know that we are finished */
finished = sig;
return;
}
}
int main(void)
{
/* Catch the SIGSEGV signal, raised on segmentation faults (i.e NULL ptr access */
if (signal(SIGSEGV, &handler) == SIG_ERR) {
perror("could not establish handler for SIGSEGV");
return EXIT_FAILURE;
}
/* Catch the SIGTERM signal, termination request */
if (signal(SIGTERM, &handler) == SIG_ERR) {
perror("could not establish handler for SIGTERM");
return EXIT_FAILURE;
}
/* Ignore the SIGINT signal, by setting the handler to `SIG_IGN`. */
signal(SIGINT, SIG_IGN);
/* Do something that takes some time here, and leaves
the time to terminate the program from the keyboard. */
/* Then: */
if (finished) {
fprintf(stderr, "we have been terminated by signal %d\n", (int)finished);
return EXIT_FAILURE;
}
/* Try to force a segmentation fault, and raise a SIGSEGV */
{
char* ptr = 0;
*ptr = 0;
}
/* This should never be executed */
return EXIT_SUCCESS;
}
signal()
を使用signal()
、シグナルハンドラの内部で何ができるかが重要な制限を受けます。詳しくは、備考を参照してください。
POSIXはの使用をお勧めsigaction()
代わりのsignal()
その不足の挙動と著しい実装変動に。 POSIXはまた、 SIGUSR1
やSIGUSR2
など、ISO C標準よりも多くのシグナルを定義しています 。これは、プログラマが自由に任意の目的で使用できます。