Linux で非同期シグナル ハンドラーの実行がどのように機能するかを正確に知りたいです。まず、どのスレッドがシグナル ハンドラを実行しているかがわかりません。次に、スレッドにシグナル ハンドラを実行させるための手順を知りたいです。
最初の問題について、一見相反するように見える 2 つの異なる説明を読みました。
The Linux Kernel, by Andries Brouwer, §5.2「シグナルの受信」には次のように記載されています。
シグナルが到着すると、プロセスが中断され、現在のレジスタが保存され、シグナル ハンドラが呼び出されます。シグナル ハンドラーが戻ると、中断されたアクティビティが続行されます。
StackOverflowの質問「マルチスレッド プログラムでの非同期シグナルの処理」により、Linux の動作はSCO Unix の動作に似ていると思います。
シグナルがプロセスに配信されるとき、シグナルがキャッチされている場合は、次の条件のいずれかを満たすスレッドの 1 つだけによって処理されます。
キャッチされたシグナルのタイプが引数に含まれている sigwait (2) システムコールでブロックされたスレッド。
キャッチされたシグナルのタイプがシグナルマスクに含まれていないスレッド。
その他の考慮事項:
- sigwait (2)でブロックされたスレッドは、シグナル タイプをブロックしていないスレッドよりも優先されます。
- 複数のスレッドがこれらの要件を満たす場合 (おそらく 2 つのスレッドがsigwait (2)を呼び出している場合)、そのうちの 1 つが選択されます。この選択は、アプリケーション プログラムでは予測できません。
- 適切なスレッドがない場合、スレッドが適切になるまで、シグナルはプロセスレベルで「保留中」のままになります。
また、Moshe Bar による「The Linux Signals Handling Model」には、 「非同期シグナルは、シグナルをブロックしていないことが判明した最初のスレッドに配信されます」と記載されています。 .
どちらが正しいですか?
2 つ目の問題として、選択したスレッドのスタックとレジスタの内容はどうなるでしょうか。シグナルハンドラーを実行するスレッドTが関数の実行中にあるとしdo_stuff()
ます。スレッドTのスタックは、シグナル ハンドラを実行するために直接使用されますか (つまり、シグナル トランポリンのアドレスがTのスタックにプッシュされ、制御フローがシグナル ハンドラに移動します)。または、別のスタックが使用されていますか? それはどのように機能しますか?