typedef void (*sighandler_t)(int);
sighandler_t signal(int signum, sighandler_t sighandler);
signal() はシグナル signum の処理方法を handler に設定する。 handler には、 SIG_IGN、 SIG_DFL、 プログラマが定義した関数 (「シグナルハンドラー」) のアドレスの いずれかを指定する。
シグナル signum がプロセスに配送されると、以下のいずれかが発生する。
シグナル SIGKILL と SIGSTOP は捕捉できず、無視することもできない。
POSIX では、 kill(2) や raise(3) で生成できないシグナル SIGFPE, SIGILL, SIGSEGV を無視 (ignore) した場合、その後の動作は未定義である。 ゼロによる整数割り算の結果は未定義となる。 アーキテクチャーによっては、このとき SIGFPE シグナルが生成される。 (同様に負の最大整数を -1 で割ると SIGFPE が生成されるかもしれない) このシグナルを無視すると無限ループに陥るかもしれない。
See sigaction(2) for details on what happens when the disposition SIGCHLD is set to SIG_IGN.
シグナルハンドラー内から安全に呼び出すことができる、 async-signal-safe functions (非同期シグナルで安全な関数) のリストについては signal-safety(7) を参照。
The use of sighandler_t is a GNU extension, exposed if _GNU_SOURCE is defined; glibc also defines (the BSD-derived) sig_t if _BSD_SOURCE (glibc 2.19 and earlier) or _DEFAULT_SOURCE (glibc 2.19 and later) is defined. Without use of such a type, the declaration of signal() is the somewhat harder to read:
void ( *signal(int signum, void (*handler)(int)) ) (int);
POSIX.1 は、 sigaction(2) を規定することで移植性に関する混乱を解決した。 sigaction(2) はシグナルハンドラーが起動される際の挙動を明示的に制御できる。 signal() の代わりにこのインターフェイスを使うこと。
オリジナルの UNIX システムでは、 signal() を使って設定されたハンドラーがシグナルの配送により起動されると、 そのシグナルの処理方法は SIG_DFL にリセットされ、システムは同じシグナルがさらに生成されても シグナルの配送をブロックしなかった。これは、以下のフラグで sigaction(2) を呼び出すのと等価である。
sa.sa_flags = SA_RESETHAND | SA_NODEFER;
System V でも、 signal() に対してこれらの挙動を規定している。 こうした挙動はまずく、ハンドラーがハンドラー自身を再設定する機会が 来るより前に、同じシグナルがまた配送される可能性がある。 さらに、同じシグナルが立て続けに配送されると、同じシグナルが ハンドラーを繰り返し起動されることになる。
BSD はこの状況が改善したが、残念なことに、その過程で既存の signal() の挙動も変更された。 BSD では、シグナルハンドラーが起動された際、 シグナルの処理方法はリセットされず、 ハンドラーの実行中は、同じシグナルのさらなる生成は配送がブロックされる。 また、 シグナルハンドラーが中断された場合、 停止中のシステムコールのいくつかは自動的に再スタートされる。 BSD の挙動は、 以下のフラグを指定した sigaction(2) の呼び出しと等価である。
sa.sa_flags = SA_RESTART;
Linux での状況は以下の通りである。
[man1]
[man2]
[man3]
[man4]
[man5]
[man6]
[man7]
[man8]
[a]
[b]
[c]
[d]
[e]
[f]
[g]
[h]
[i]
[j]
[k]
[l]
[m]
[n]
[o]
[p]
[q]
[r]
[s]
[t]
[u]
[v]
[w]
[x]
[y]
[z]