ホームページ > システムチュートリアル > Linux > Linux 非同期シグナル ハンドルの簡単な分析

Linux 非同期シグナル ハンドルの簡単な分析

WBOY
リリース: 2024-02-13 22:03:13
転載
395 人が閲覧しました

Linux システムは、マルチタスクの同時実行をサポートするオペレーティング システムであり、複数のプロセスを同時に実行できるため、システムの使用率と効率が向上します。ただし、これらのプロセス間でデータ交換とコラボレーションが必要な場合は、メッセージ キュー、共有メモリ、セマフォなどのプロセス間通信 (IPC) メソッドを使用する必要があります。その中でも、シグナルは比較的シンプルで柔軟な IPC メソッドであり、あるプロセスが別のプロセスに短いメッセージを送信して、何らかのイベントまたは例外が発生したことを通知できます。 Linux システムには、同期信号と非同期信号という 2 種類の信号があります。この記事では、非同期信号の意味、生成、送信、受信、処理、無視など、Linux の非同期信号処理メソッドを簡単に分析します。

Linux 非同期シグナル ハンドルの簡単な分析

Linux プログラミングを初めて学んだとき、ユーザー プログラムは singal などのシステム コールを使用して、特定の信号に対する信号処理関数 (ハンドル関数) を登録することができます。
プログラムのバイナリ コードはメモリ内で特定の実行フローを持っていますが、なぜプログラムは非同期シグナルを受信した後に「中断」され、ハンドル関数にジャンプして実行されるのでしょうか?カーネルはどのようにしてプログラムにそのようなジャンプをさせることができるのでしょうか? プログラムの実行可能コードを一時的に変更することは不可能ですよね?

その後、カーネルの知識を学んだ後、プロセスがシグナルを受信した後、すぐに「中断」されるのではなく、最初に特定のシグナルの受信をプロセスの制御構造体 (task_struct) に記録し、プロセスがカーネル モードからユーザー モードに戻ろうとすると、プロセスは「中断」され、ハンドル関数が呼び出されます。
ユーザープロセスはいつカーネルモードからユーザーモードに戻りますか?一般に、システム コール (ユーザー プロセスが能動的にカーネルに入る)、割り込み (ユーザー プロセスが受動的にカーネルに入る)、およびスケジュールされた実行 (ユーザー プロセスが実行待機状態から実行される状態に変化する) の 3 つの主な状況があります。
プロセスがシグナルを受信して​​からカーネル状態からユーザー状態に戻るには、ある程度の時間がかかります。ただし、この時間は一般に非常に短く、少なくともクロック割り込みにより、比較的高い頻度 (たとえば、1 ミリ秒に 1 回) でユーザー プロセスがカーネルに取り込まれます (もちろん、実行中のプロセスに対してのみ)。

プロセスがカーネル モードからユーザー モードに戻ろうとしているときに、処理する必要があるシグナルがある場合、対応するハンドル関数が呼び出されます (もちろん、ハンドルが登録されていない可能性もあります)。カーネルはデフォルトでシグナルを処理します)。プロセスはまだカーネル モードであることに注意してください。カーネルはユーザー モードでどのようにハンドル関数を呼び出すのでしょうか?
直接電話してもいいですか?もちろん違います。カーネル コードは高い CPU 特権レベルで実行されます。ハンドル関数が直接呼び出された場合、ハンドル関数も同じ CPU 特権で実行されます。そうすれば、ユーザーはハンドル関数でやりたいことを何でもできるようになります。
したがって、呼び出しハンドルは最初にユーザー モードに戻る必要があります。しかし、ユーザー モードに戻った後は、プログラム フローはカーネルによって制御されなくなります。本当に、カーネルがユーザー プロセスの実行可能コードを一時的に変更する可能性はありますか?

カーネルの実際のアプローチは非常に巧妙です。ユーザー プロセスがカーネルに入った後、プロセスが戻ることができるように、対応するカーネル スタックに戻りアドレスを残します。カーネルがハンドル関数を呼び出す方法は、スタック上の戻りアドレスを一時的に変更し、その後ユーザー モードに戻る元のプロセスに従って戻ります。その結果、この戻り値はハンドル関数に渡されます。 (もちろん、変更する必要があるのは戻りアドレスだけではなく、呼び出しスタック全体です。)
戻り先アドレスは一時的に変更されますが、最終的にはユーザープロセスは元の戻り先アドレスに戻ります。では、元のリターン アドレスとそのコール スタックはどこに保存されるべきでしょうか?プロセスのカーネル スタック領域は限られており、ハンドル関数で発生する可能性のあるシステム コールも処理する必要があるため、カーネルがこの情報をカーネル スタックに置くのは非現実的であり、プッシュすることしかできません。ユーザースタック。

ハンドル関数が実行されると、実行プロセスはカーネルに戻ります。同様に、CPU 特権レベルが異なるため、RET 命令を使用してハンドル関数からカーネルに戻ることはできません。システムコールを実行する必要があります。

ハンドルが実行された後、カーネルに戻り、カーネルから元の戻りアドレスに戻る必要があるのはなぜですか?元の返送先住所に直接返送していただければ大変便利です。これを行うことは難しくありません。元のリターン アドレスとそのコール スタックはユーザー スタックにプッシュされています。カーネルはハンドル関数のコール スタックに対して少し操作を行うだけで済みます。
1. 元のリターンアドレスに戻すということは、そのアドレスに戻すだけではなく、シーン全体(主にレジスタなど)を戻す必要があります。もちろん、カーネルはユーザー スタック上のコードを押してこれらの処理を完了することもできます。
2. 処理する信号が複数ある可能性があるため、ユーザー プロセスをカーネルに戻して他の信号の処理を続行することが最善です。

カーネルに戻るために、カーネルはハンドル関数に戻る前に戻りアドレスをユーザー スタックにプッシュします。これにより、ハンドルから戻るときに指定されたアドレスに戻ることができます。この指定されたアドレスは、実際にはプロセスのユーザー スタック上にも存在し、カーネルはこのアドレスにいくつかの命令を配置し (実行可能コードをスタックに配置し)、プロセスが sigreturn と呼ばれるシステム コールを呼び出せるようにします。

ハンドル関数に戻る前のユーザースタックはおおよそ次のとおりです:
元のデータ -> sigreturn を呼び出す命令 (アドレスを a とする) -> 元の戻りアドレスとそのコールスタック -> 戻りアドレス (値は a) -> ハンドルのスタック変数

カーネルは sigreturn 命令をハンドル関数の呼び出しスタックに配置します。これは Linux 2.4 での慣例です。ユーザーのハンドル関数が呼び出されるたびに、非常に多くの命令をユーザー スタックにコピーする必要があり、これは良くありません。
Linux 2.6 には vsyscall ページと呼ばれるページがあり、このページには、sigreturn 命令の呼び出しなど、ユーザー プログラム用にカーネルによって準備されたいくつかの命令が含まれています。この vsyscall ページは、各プロセスの仮想アドレス空間の最後にマップされ、すべてのユーザー プロセスによって共有され、ユーザー プロセスに対して読み取り専用になります。この方法では、ハンドル関数のコール スタックに sigreturn 命令を挿入する必要はなく、ハンドル関数の戻りアドレスを vsyscall ページ内の対応するコードに設定するだけです。

ハンドルの実行後に sigreturn を自動的に呼び出してカーネルに戻るために、カーネルは多くのことを行います。それでは、ユーザーが自分で sigreturn を呼び出せるようにすることに同意できますか?
もちろん、これは可能です。信号処理メカニズムを完全なメカニズムにするためだけに、カーネルはこれを実行しませんでした。そうしないと、ユーザーが handle 関数で sigreturn を呼び出すのを忘れた場合、プロセスが原因不明のクラッシュを引き起こす可能性があります。そして、コンパイラがそのようなエラーを見つけることは困難です。

プロセスが sigreturn システム コールを呼び出してカーネルに再入すると、元のリターン アドレスと、ユーザー スタックにプッシュされたそのコール スタックが取得されます。最終的に、カーネルはプロセスがユーザー空間に戻るときに元の戻りアドレスに戻るようにスタックを変更します。

この記事では、非同期信号の意味、生成、送信、受信、処理、無視など、Linux の非同期信号処理メソッドを簡単に分析します。この知識を理解して習得することで、Linux 信号処理の中核となる知識を習得し、システムの安定性と効率を向上させることができます。もちろん、Linux 非同期シグナル ハンドルには他にも多くの機能や用途があり、継続的な学習と研究が必要です。この記事があなたにインスピレーションと助けをもたらすことを願っています。

以上がLinux 非同期シグナル ハンドルの簡単な分析の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

ソース:lxlinux.net
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート