SIGNAL(2)

名前
signal - ANSI C シグナル操作

書式
#include <signal.h>

typedef void (*sighandler_t)(int);

sighandler_t signal(int signum, sighandler_t sighandler);

説明
警告:
 signal() の動作は UNIX のバージョンにより異なる。 また、歴史的に見て Linux のバージョンによっても異なっている。 このシステムコールの使用は避け、 代わりに sigaction(2) を使用すること。 下記の「移植性」を参照。

signal() はシグナル signum の処理方法を handler に設定する。 handler には、 SIG_IGN、 SIG_DFL、 プログラマが定義した関数 (「シグナルハンドラー」) のアドレスの いずれかを指定する。

シグナル signum がプロセスに配送されると、以下のいずれかが発生する。

*   処理方法が SIG_IGN に設定されている場合、そのシグナルは無視される。

*   処理方法が SIG_DFL に設定されている場合、シグナルに関連づけられた デフォルトの動作が行われる (signal(7) 参照)。

*   処理方法として関数が設定されている場合、 まず最初に処理方法が SIG_DFL にリセットされるかそのシグナルのブロックが実行された後、 signum を引数として handler が呼び出される。 ハンドラーが起動される際にシグナルがブロックされた場合、 ハンドラーが返る際にそのシグナルのブロックが解除される。

シグナル SIGKILL と SIGSTOP は捕捉できず、無視することもできない。

返り値
signal() は、今までのシグナルハンドラーの値を返す。 エラーの場合は SIG_ERR を返し、 errno にエラーの原因を示す値を設定する。

エラー

EINVAL
    signum が不正である。

準拠
POSIX.1-2001, POSIX.1-2008, C89, C99.

注意
マルチスレッドプロセスにおける signal() の結果は、指定されていない。

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);

  移植性
移植性のある signal() の使い方は、シグナルの処理方法を SIG_DFL か SIG_IGN に設定する方法だけである。 シグナルハンドラーを設定するのに signal() を使ったときの動作はシステムにより異なる (POSIX.1 は明示的にこの違いを認めている)。 移植性が必要なときはこのシステムコールを使用しないこと。

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 での状況は以下の通りである。

*   カーネルの signal() システムコールは System V 方式を提供している。

*   By default, in glibc 2 and later, the signal() wrapper function does not invoke the kernel system call. Instead, it calls sigaction(2) using flags that supply BSD semantics. This default behavior is provided as long as a suitable feature test macro is defined: _BSD_SOURCE on glibc 2.19 and earlier or _DEFAULT_SOURCE in glibc 2.19 and later. (By default, these macros are defined; see feature_test_macros(7) for details.) If such a feature test macro is not defined, then signal() provides System V semantics.

関連項目
kill(1), alarm(2), kill(2), pause(2), sigaction(2), signalfd(2), sigpending(2), sigprocmask(2), sigsuspend(2), bsd_signal(3), killpg(3), raise(3), siginterrupt(3), sigqueue(3), sigsetops(3), sigvec(3), sysv_signal(3), signal(7)

この文書について
この man ページは Linux man-pages プロジェクトのリリース 5.10 の一部である。プロジェクトの説明とバグ報告に関する情報は https://www.kernel.org/doc/man-pages/ に書かれている。