18.8. signal — 非同期イベントにハンドラを設定する


This module provides mechanisms to use signal handlers in Python.

18.8.1. General rules

The signal.signal() function allows defining custom handlers to be executed when a signal is received. A small number of default handlers are installed: SIGPIPE is ignored (so write errors on pipes and sockets can be reported as ordinary Python exceptions) and SIGINT is translated into a KeyboardInterrupt exception.

特定のシグナルに対するハンドラが一度設定されると、明示的にリセットしないかぎり設定されたままになります (Python は背後の実装系に関係なく BSD 形式のインタフェースをエミュレートします)。例外は SIGCHLD のハンドラで、この場合は背後の実装系の仕様に従います。

18.8.1.1. Execution of Python signal handlers

A Python signal handler does not get executed inside the low-level (C) signal handler. Instead, the low-level signal handler sets a flag which tells the virtual machine to execute the corresponding Python signal handler at a later point(for example at the next bytecode instruction). This has consequences:

  • It makes little sense to catch synchronous errors like SIGFPE or SIGSEGV that are caused by an invalid operation in C code. Python will return from the signal handler to the C code, which is likely to raise the same signal again, causing Python to apparently hang. From Python 3.3 onwards, you can use the faulthandler module to report on synchronous errors.
  • A long-running calculation implemented purely in C (such as regular expression matching on a large body of text) may run uninterrupted for an arbitrary amount of time, regardless of any signals received. The Python signal handlers will be called when the calculation finishes.

18.8.1.2. Signals and threads

Python signal handlers are always executed in the main Python thread, even if the signal was received in another thread. This means that signals can’t be used as a means of inter-thread communication. You can use the synchronization primitives from the threading module instead.

Besides, only the main thread is allowed to set a new signal handler.

18.8.2. Module contents

バージョン 3.5 で変更: signal (SIG*), handler (SIG_DFL, SIG_IGN) and sigmask (SIG_BLOCK, SIG_UNBLOCK, SIG_SETMASK) related constants listed below were turned into enums. getsignal(), pthread_sigmask(), sigpending() and sigwait() functions return human-readable enums.

以下に signal モジュールで定義されている変数を示します:

signal.SIG_DFL

二つある標準シグナル処理オプションのうちの一つです; 単純にシグナルに対する標準の関数を実行します。例えば、ほとんどのシステムでは、 SIGQUIT に対する標準の動作はコアダンプと終了で、 SIGCHLD に対する標準の動作は単にシグナルの無視です。

signal.SIG_IGN

もう一つの標準シグナル処理オプションで、受け取ったシグナルを単に無視します。

SIG*

全てのシグナル番号はシンボル定義されています。例えば、ハングアップシグナルは signal.SIGHUP で定義されています; 変数名は C 言語のプログラムで使われているのと同じ名前で、 <signal.h> にあります。 『signal()』 に関する Unix マニュアルページでは、システムで定義されているシグナルを列挙しています (あるシステムではリストは signal(2) に、別のシステムでは signal(7) に列挙されています)。全てのシステムで同じシグナル名のセットを定義しているわけではないので注意してください; このモジュールでは、システムで定義されているシグナル名だけを定義しています。

signal.CTRL_C_EVENT

CTRL+C キーストロークに該当するシグナル。このシグナルは os.kill() でだけ利用できます。

利用出来る環境: Windows.

バージョン 3.2 で追加.

signal.CTRL_BREAK_EVENT

CTRL+BREAK キーストロークに該当するシグナル。このシグナルは os.kill() でだけ利用できます。

利用出来る環境: Windows.

バージョン 3.2 で追加.

signal.NSIG

最も大きいシグナル番号に 1 を足した値です。

signal.ITIMER_REAL

実時間でデクリメントするインターバルタイマーです。タイマーが発火したときに SIGALRM を送ります。

signal.ITIMER_VIRTUAL

プロセスの実行時間だけデクリメントするインターバルタイマーです。タイマーが発火したときに SIGVTALRM を送ります。

signal.ITIMER_PROF

プロセスの実行中と、システムがそのプロセスのために実行している時間だけデクリメントするインターバルタイマーです。ITIMER_VIRTUAL と組み合わせて、このタイマーはよくアプリケーションがユーザー空間とカーネル空間で消費した時間のプロファイリングに利用されます。タイマーが発火したときに SIGPROF を送ります。

signal.SIG_BLOCK

A possible value for the how parameter to pthread_sigmask() indicating that signals are to be blocked.

バージョン 3.3 で追加.

signal.SIG_UNBLOCK

A possible value for the how parameter to pthread_sigmask() indicating that signals are to be unblocked.

バージョン 3.3 で追加.

signal.SIG_SETMASK

A possible value for the how parameter to pthread_sigmask() indicating that the signal mask is to be replaced.

バージョン 3.3 で追加.

signal モジュールは1つの例外を定義しています:

exception signal.ItimerError

Raised to signal an error from the underlying setitimer() or getitimer() implementation. Expect this error if an invalid interval timer or a negative time is passed to setitimer(). This error is a subtype of OSError.

バージョン 3.3 で追加: This error used to be a subtype of IOError, which is now an alias of OSError.

signal モジュールでは以下の関数を定義しています:

signal.alarm(time)

time がゼロでない値の場合、この関数は time 秒後頃に SIGALRM をプロセスに送るように要求します。それ以前にスケジュールしたアラームはキャンセルされます (常に一つのアラームしかスケジュールできません)。この場合、戻り値は以前に設定されたアラームシグナルが通知されるまであと何秒だったかを示す値です。 time がゼロの場合、アラームは一切スケジュールされず、現在スケジュールされているアラームがキャンセルされます。戻り値がゼロの場合、現在アラームがスケジュールされていないことを示します。(Unix マニュアルページ alarm(2) を参照してください)。利用できる環境: Unix。

signal.getsignal(signalnum)

シグナル signalnum に対する現在のシグナルハンドラを返します。戻り値は呼び出し可能な Python オブジェクトか、 signal.SIG_IGNsignal.SIG_DFL、および None といった特殊な値のいずれかです。ここで signal.SIG_IGN は以前そのシグナルが無視されていたことを示し、 signal.SIG_DFL は以前そのシグナルの標準の処理方法が使われていたことを示し、 None はシグナルハンドラがまだ Python によってインストールされていないことを示します。

signal.pause()

シグナルを受け取るまでプロセスを一時停止します; その後、適切なハンドラが呼び出されます。戻り値はありません。Windows では利用できません。(Unix マニュアルページ signal(2) を参照してください。)

See also sigwait(), sigwaitinfo(), sigtimedwait() and sigpending().

signal.pthread_kill(thread_id, signalnum)

Send the signal signalnum to the thread thread_id, another thread in the same process as the caller. The target thread can be executing any code (Python or not). However, if the target thread is executing the Python interpreter, the Python signal handlers will be executed by the main thread. Therefore, the only point of sending a signal to a particular Python thread would be to force a running system call to fail with InterruptedError.

Use threading.get_ident() or the ident attribute of threading.Thread objects to get a suitable value for thread_id.

If signalnum is 0, then no signal is sent, but error checking is still performed; this can be used to check if the target thread is still running.

Availability: Unix (see the man page pthread_kill(3) for further information).

See also os.kill().

バージョン 3.3 で追加.

signal.pthread_sigmask(how, mask)

Fetch and/or change the signal mask of the calling thread. The signal mask is the set of signals whose delivery is currently blocked for the caller. Return the old signal mask as a set of signals.

The behavior of the call is dependent on the value of how, as follows.

  • SIG_BLOCK: The set of blocked signals is the union of the current set and the mask argument.
  • SIG_UNBLOCK: The signals in mask are removed from the current set of blocked signals. It is permissible to attempt to unblock a signal which is not blocked.
  • SIG_SETMASK: The set of blocked signals is set to the mask argument.

mask is a set of signal numbers (e.g. {signal.SIGINT, signal.SIGTERM}). Use range(1, signal.NSIG) for a full mask including all signals.

For example, signal.pthread_sigmask(signal.SIG_BLOCK, []) reads the signal mask of the calling thread.

Availability: Unix. See the man page sigprocmask(3) and pthread_sigmask(3) for further information.

See also pause(), sigpending() and sigwait().

バージョン 3.3 で追加.

signal.setitimer(which, seconds[, interval])

which で指定されたタイマー (signal.ITIMER_REAL, signal.ITIMER_VIRTUAL, signal.ITIMER_PROF のどれか) を、 seconds 秒後と (alarm() と異なり、floatを指定できます)、それから interval 秒間隔で起動するように設定します。 seconds に0を指定すると、which で指定されたタイマーをクリアすることができます。

インターバルタイマーが起動したとき、シグナルがプロセスに送られます。送られるシグナルは利用されたタイマーの種類に依存します。 signal.ITIMER_REAL の場合は SIGALRM が、 signal.ITIMER_VIRTUAL の場合は SIGVTALRM が、 signal.ITIMER_PROF の場合は SIGPROF が送られます。

以前の値が (delay, interval) のタプルとして返されます。

無効なインターバルタイマーを渡すと ItimerError 例外が発生します。利用できる環境: Unix。

signal.getitimer(which)

which で指定されたインターバルタイマーの現在の値を返します。利用できる環境: Unix。

signal.set_wakeup_fd(fd)

Set the wakeup file descriptor to fd. When a signal is received, the signal number is written as a single byte into the fd. This can be used by a library to wakeup a poll or select call, allowing the signal to be fully processed.

The old wakeup fd is returned (or -1 if file descriptor wakeup was not enabled). If fd is -1, file descriptor wakeup is disabled. If not -1, fd must be non-blocking. It is up to the library to remove any bytes from fd before calling poll or select again.

Use for example struct.unpack('%uB' % len(data), data) to decode the signal numbers list.

スレッドが有効な場合、この関数はメインスレッドからしか実行できません。それ以外のスレッドからこの関数を実行しようとすると ValueError 例外が発生します。

バージョン 3.5 で変更: On Windows, the function now also supports socket handles.

signal.siginterrupt(signalnum, flag)

システムコールのリスタートの動作を変更します。 flagFalse の場合、 signalnum シグナルに中断されたシステムコールは再実行されます。それ以外の場合、システムコールは中断されます。戻り値はありません。利用できる環境: Unix (詳しい情報についてはマニュアルページ siginterrupt(3) を参照してください)。

signal() を使ってシグナルハンドラを設定したときに、暗黙のうちに flag に true を指定して siginterrupt() が実行されるため、中断に対するリスタートの動作がリセットされることに注意してください。

signal.signal(signalnum, handler)

シグナル signalnum に対するハンドラを関数 handler にします。 handler は二つの引数 (下記参照) を取る呼び出し可能な Python オブジェクトか、 signal.SIG_IGN あるいは signal.SIG_DFL といった特殊な値にすることができます。以前に使われていたシグナルハンドラが返されます (上記の getsignal() の記述を参照してください)。 (Unix マニュアルページ signal(2) を参照してください。)

スレッドが有効な場合、この関数はメインスレッドからしか実行できません。それ以外のスレッドからこの関数を実行しようとすると ValueError 例外が発生します。

handler は二つの引数とともに呼び出されます: シグナル番号、および現在のスタックフレーム (None またはフレームオブジェクト; フレームオブジェクトについての記述は 標準型の階層における説明 か、 inspect モジュールの属性の説明を参照してください)。

On Windows, signal() can only be called with SIGABRT, SIGFPE, SIGILL, SIGINT, SIGSEGV, SIGTERM, or SIGBREAK. A ValueError will be raised in any other case. Note that not all systems define the same set of signal names; an AttributeError will be raised if a signal name is not defined as SIG* module level constant.

signal.sigpending()

Examine the set of signals that are pending for delivery to the calling thread (i.e., the signals which have been raised while blocked). Return the set of the pending signals.

Availability: Unix (see the man page sigpending(2) for further information).

See also pause(), pthread_sigmask() and sigwait().

バージョン 3.3 で追加.

signal.sigwait(sigset)

Suspend execution of the calling thread until the delivery of one of the signals specified in the signal set sigset. The function accepts the signal (removes it from the pending list of signals), and returns the signal number.

Availability: Unix (see the man page sigwait(3) for further information).

See also pause(), pthread_sigmask(), sigpending(), sigwaitinfo() and sigtimedwait().

バージョン 3.3 で追加.

signal.sigwaitinfo(sigset)

Suspend execution of the calling thread until the delivery of one of the signals specified in the signal set sigset. The function accepts the signal and removes it from the pending list of signals. If one of the signals in sigset is already pending for the calling thread, the function will return immediately with information about that signal. The signal handler is not called for the delivered signal. The function raises an InterruptedError if it is interrupted by a signal that is not in sigset.

The return value is an object representing the data contained in the siginfo_t structure, namely: si_signo, si_code, si_errno, si_pid, si_uid, si_status, si_band.

Availability: Unix (see the man page sigwaitinfo(2) for further information).

See also pause(), sigwait() and sigtimedwait().

バージョン 3.3 で追加.

バージョン 3.5 で変更: The function is now retried if interrupted by a signal not in sigset and the signal handler does not raise an exception (see PEP 475 for the rationale).

signal.sigtimedwait(sigset, timeout)

Like sigwaitinfo(), but takes an additional timeout argument specifying a timeout. If timeout is specified as 0, a poll is performed. Returns None if a timeout occurs.

Availability: Unix (see the man page sigtimedwait(2) for further information).

See also pause(), sigwait() and sigwaitinfo().

バージョン 3.3 で追加.

バージョン 3.5 で変更: The function is now retried with the recomputed timeout if interrupted by a signal not in sigset and the signal handler does not raise an exception (see PEP 475 for the rationale).

18.8.3. 例

以下は最小限のプログラム例です。この例では alarm() を使ってファイルを開く処理を待つのに費やす時間を制限します; 例えば、電源の入っていないシリアルデバイスを開こうとすると、通常 os.open() は未定義の期間ハングアップしてしまいますが、この方法はそうした場合に便利です。ここではファイルを開くまで 5 秒間のアラームを設定することで解決しています; ファイルを開く処理が長くかかりすぎると、アラームシグナルが送信され、ハンドラが例外を送出するようになっています。

import signal, os

def handler(signum, frame):
    print('Signal handler called with signal', signum)
    raise OSError("Couldn't open device!")

# Set the signal handler and a 5-second alarm
signal.signal(signal.SIGALRM, handler)
signal.alarm(5)

# This open() may hang indefinitely
fd = os.open('/dev/ttyS0', os.O_RDWR)

signal.alarm(0)          # Disable the alarm