\section{\module{signal} ---
         非同期イベントにハンドラを設定する}

\declaremodule{builtin}{signal}
\modulesynopsis{非同期イベントにハンドラを設定します。}


このモジュールでは Python でシグナルハンドラを使うための機構を
提供します。シグナルとハンドラを扱う上では、一般的なルールが
いくつかあります:

\begin{itemize}

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

\item
クリティカルセクションから一時的にシグナルを``ブロック''することは
できません。この機能をサポートしない\UNIX{}系システムも存在するた
めです。

\item
Python のシグナルハンドラは Python のユーザが望む限り非同期で呼び
出されますが、呼び出されるのは Python インタプリタの 
``原子的な (atomic)'' 命令実行単位の間です。従って、
(巨大なサイズのテキストに対する正規表現の一致検索のような) 
純粋に C 言語のレベルで実現されている時間のかかる処理中に
到着したシグナルは、不定期間遅延する可能性があります。

\item
シグナルが I/O 操作中に到着すると、シグナルハンドラが処理を返した
後に I/O 操作が例外を送出する可能性があります。
これは背後にある \UNIX{} システムが割り込みシステムコールにどういう
意味付けをしているかに依存します。

\item
\C{} 言語のシグナルハンドラは常に処理を返すので、\constant{SIGFPE}
や \constant{SIGSEGV} のような同期エラーの捕捉はほとんど意味が
ありません。

\item
Python は標準でごく小数のシグナルハンドラをインストールしています:
\constant{SIGPIPE} は無視されます (従って、パイプやソケットに対する
書き込みで生じたエラーは通常の Python 例外として報告されます)
\constant{SIGINT} は \exception{KeyboardInterrupt} 例外に変換されます。
これらはどれも上書きすることができます。

\item
シグナルとスレッドの両方を同じプログラムで使用する場合にはいくつか
注意が必要です。シグナルとスレッドを同時に利用する上で基本的に注意
すべきことは: 常に \function{signal()} 命令は主スレッド (main thread)の
処理中で実行するということです。どのスレッドも \function{alarm()}、
\function{getsignal()}、あるいは \function{pause()} を実行する
ことができます; しかし、主スレッドだけが新たなシグナルハンドラを
設定することができ、従ってシグナルを受け取ることができるのは主スレッド
だけです (これは、背後のスレッド実装が個々のスレッドに対するシグナル
送信をサポートしているかに関わらず、Python \module{signal} モジュール
が強制している仕様です)。従って、シグナルをスレッド間通信の手段として
使うことはできません。代わりにロック機構を使ってください。
\end{itemize}

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

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

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

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

\begin{datadesc}{NSIG}
最も大きいシグナル番号に 1 を足した値です。
\end{datadesc}

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

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

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

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

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

複数スレッドの使用が有効な場合、この関数は主スレッドからのみ呼び出す
ことができます; 主スレッド以外のスレッドで呼び出そうとすると、例外
\exception{ValueError} が送出されます。

\var{handler} は二つの引数: シグナル番号、および現在のスタックフレーム
(\code{None} またはフレームオブジェクト; フレームオブジェクトに
ついての記述はリファレンスマニュアルの標準型の階層 か、
\refmodule{inspect}モジュールの属性の説明を参照してください)、
とともに呼び出されます。
\obindex{frame}
\end{funcdesc}

\subsection{例}
\nodename{Simple Example}

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

\begin{verbatim}
import signal, os

pdef handler(signum, frame):
    print 'Signal handler called with signal', signum
    raise IOError, "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
\end{verbatim}
