Linuxで非同期シグナルハンドラの実行がどのように機能するかを正確に知りたいです。まず、どれのスレッドはシグナル ハンドラを実行します。次に、スレッドがシグナル ハンドラを実行するために実行される手順を知りたいです。
最初の問題については、一見矛盾しているように見える 2 つの異なる説明を読みました。
Linuxカーネル、Andries Brouwer著、§5.2 「信号の受信」の状態:
シグナルが到着すると、プロセスが中断され、現在のレジスタが保存され、シグナル ハンドラが呼び出されます。シグナル ハンドラが戻ると、中断されたアクティビティが続行されます。
のStackOverflow の質問「マルチスレッド プログラムでの非同期シグナルの処理」Linuxの挙動はSCO Unixのような:
シグナルがプロセスに配信され、キャッチされている場合、そのシグナルは、次のいずれかの条件を満たすスレッドのうちの 1 つだけによって処理されます。
スレッドがブロックされました待機(2)引数を持つシステムコールするキャッチされた信号の種類を含めます。
シグナルマスクを持つスレッドではないキャッチされた信号の種類を含めます。
追加の考慮事項:
また、Moshe Bar著の「Linuxシグナル処理モデル」には次のように記されている。「非同期シグナルは、シグナルをブロックしていない最初のスレッドに配信されます。」これは、シグナルがsigmaskを持つスレッドに配信されることを意味すると解釈しています。ない信号を含みます。
どちらが正しいか?
2番目の問題では、選択されたスレッドのスタックとレジスタの内容はどうなるでしょうか?シグナルハンドラを実行するスレッドがT関数の実行中ですdo_stuff()
。スレッドTのスタックはシグナルハンドラを実行するために直接使用されます(つまり、シグナルトランポリンのアドレスがTのスタックと制御フローはシグナル ハンドラーに送られますか? あるいは、別のスタックが使用されますか? どのように機能しますか?
ベストアンサー1
Linux ハッカーはスレッドとプロセスの違いについて混乱する傾向があるという事実を考慮すると、これら 2 つの説明は実際には矛盾していません。これは主に、スレッドをメモリを共有するプロセスとして実装できると偽ろうとした歴史的な誤りによるものです。:-)
そうは言っても、説明 2 の方がはるかに詳細かつ完全で、正確です。
スタックとレジスタの内容については、各スレッドは独自の代替シグナル処理スタックを登録でき、プロセスはシグナルごとにどのシグナルを代替シグナル処理スタックに配信するかを選択できます。中断されたコンテキスト (レジスタ、シグナル マスクなど) は、トランポリンucontext_t
戻りアドレスとともに、スレッドの (おそらく代替) スタック上の構造体に保存されます。SA_SIGINFO
フラグを使用してインストールされたシグナル ハンドラーは、必要に応じてこの構造体を調べることができますが、このucontext_t
構造体を使用して実行できる移植可能な操作は、保存されたシグナル マスクを調べること (および場合によっては変更すること) だけです。(変更が標準で許可されているかどうかはわかりませんが、シグナル ハンドラーが中断されたコードのシグナル マスクを復帰時にアトミックに置き換えることができるため、非常に便利です。たとえば、シグナルをブロックしたままにして、再び発生しないようにすることができます。)