Linuxシステムプログラミング44シグナル-シグナルの応答プロセスの分析!!!

シグナルの信頼性の欠如
実行シーンは私たちによって調整されるのではなく、カーネルによって調整されるため、シグナルの信頼性の低い動作を指します。したがって、最初の呼び出しが終了する前に2番目の呼び出しが発生する可能性があります。

リエントラント関数:信号の信頼性の欠如を解決するためのものです。
最初の呼び出しが終了していない場合、2番目の呼び出しは発生しますが、エラーはありません。このような関数はリエントラント関数と呼ばれます。すべてのシステムコールは再入可能であり、memcpy()などの一部のライブラリ関数も再入可能です。

カーネルはプロセスごとに2つのビットマップを維持します:
シグナルマスクマスク:現在の信号の状態を示すために使用され、マスクの初期値は通常すべて1つの
保留中のビットマップです:現在のプロセスが受信するシグナルを記録するために使用されます、通常は初期値すべて0です

考え:
1。信号の受信から応答までの必然的な遅延があります
。2 信号を無視する方法。3。
標準信号が失われる理由
。4。標準信号の応答に厳密な順序はありません

。5。信号処理関数は外部にジャンプできません(setjmp。longjmp)

信号の応答プロセスを分析する例として、上記のセクションの実験を取り上げます。

#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>

void sig_handler(int s)
{
	write(1,"!",1);
}

int main()
{
	int i;

	signal(SIGINT,sig_handler);

	for(i=0 ; i<12 ; i++)
	{
		write(1,"*",1);
		sleep(1);
	}

	exit(0);
}

ここに画像の説明を挿入

最初のステップ:
プログラムが実行され、プログラムのタイムスライスが使い果たされると(何らかの形でそれ自体に送信される割り込み信号としても理解できます)、プログラムは現在のプロセス状態(使用されるプログラム実行位置を含む)を保存します。前の状態に戻るには)カーネルモードに、準備ができるのを待っている、タイムスライスを取得するのを待っている、つまり自分自身にスケジュールされた後、自分自身にスケジュールされた後、ユーザーに戻るのを待っているカーネルの待機キューにマウントします保存されたプロセス状態のモード、およびこの時点でカーネルモードからユーザーモードに切り替える時間ポイントは非常に重要です。この時点で、ジョブが実行されます。マスクビットマップはビットマップであり、保留中のビットマップであるかどうかを判断します。信号を受信します。2つのビットマップの初期状態に従って計算すると、ビットマップ以降は0であり、信号がないことを意味します。そうして初めて、前のプログラム実行のアドレスに戻り、前のプログラムの実行を続行します。

ステップ2:
端末からCTRL + Cを実行して、SIGINT終了信号をプログラムに送信します。このとき、保留中のビットマップSIGINT信号は1に設定され、現在のプログラムがSIGINT信号を受信したことを示します。しかし、現時点では、プログラムはSIGINTシグナルに応答できません。なぜですか。プログラムは信号を受信して​​から信号に応答するまでに必然的な遅延があるため、プログラムがカーネルモードからユーザーモードに切り替わるときにのみ、マスクビットマップと保留中のビットマップが比較されることが最初のステップからわかっています。 。この時点でのみ信号が受信されたかどうか、どの信号が受信されたかを知るために、信号に応答します。

3番目のステップ:
プログラムのタイムスライスが再び使い果たされ(何らかの形でそれ自体に送信される割り込み信号としても理解できます)、プログラムは現在のプログラム状態を再び保存してカーネル状態に入り、ディスパッチキューにマウントして待機します発送されます。プログラムは再度スケジュールされ、タイムスライスを取得し、カーネルモードからユーザーモードに切り替わります。この時点で、プログラムはマスクビットマップを保留中のビットマップと比較し、ビット単位のAND演算を実行して決定します。信号、保留中のビットマップのSIGINTビットが1であることがわかり、SIGINT信号が受信されたことを示しているため、SIGINT信号に応答する準備ができています。つまり、信号応答プログラムは次のようになります。実行されました。このとき、プログラムは以前に実行したアドレスには戻りませんが、以前に登録した信号応答機能のアドレスに移動して信号応答を実行します。つまり、保存されたプログラム情報のアドレス情報はに変更されます。信号応答関数のアドレス、この時点でマスクビットマップと保留中のビットマップのSIGINT信号ビットは0に設定されます。応答プログラムを実行した後、再びカーネルモードに戻り、マスクビットマップのSIGINTを1に設定します。保存したアドレス情報を元の実行アドレスに戻し、カーネルモードからユーザーモードに切り替えて、マスクビットマップとペンディングビットマップを再度比較します。この期間中にSIGINT信号が再度受信されない場合、この時点での比較結果は0です。つまり、新しいSIGINT信号が受信されておらず、他のビットの信号が同じであり、前のビットが同じであることがわかります。プログラムは引き続き実行されます。つまり、print *

したがって、考えるべき質問は次のとおりです。

1信号を受信して​​から応答するまで、やむを得ない遅延があります。
信号は、カーネルモードからユーザーモードへのプログラムの応答であり、この時点でしか応答できないことがわかります。したがって、この遅延は、プログラムがカーネルモードからユーザーモードに再び切り替わる必要がある時間です。つまり、新しい割り込みが発生するか、タイムスライスが使い果たされ、プログラムがカーネルモードに入り、必要な時間待機します。スケジュール後にユーザーモードに戻るため、プログラムが信号を受信した後、割り込みが発生していないか、タイムスライスが使い果たされていない、つまりカーネルモードになっていない場合は、カーネルモードからユーザーモードに切り替えられ、2つのビットマップを比較できません。信号を見つけます。

つまり、シグナルは、カーネルモードからユーザーモードに戻るプログラムの応答です。

2信号を無視する
方法上記の信号応答プロセスから、マスクビットマップの対応する信号ビットが常に0に設定されている限り、それを知ることができます。このように、対応する信号を受信して​​も、2つのビットマップを比較した後、結果も0になります。つまり、信号はありません。

3標準信号が失われるのはなぜですか?
プログラムが信号に応答すると、マスクビットマップと保留中のビットマップの対応する信号ビットが0に設定されます。このとき、SIGINT信号が10,000回送信されると、結果は次のようになります。保留中のビットマップのみ。SIGINT信号は110,000回繰り返し設定され、結果は1のままです。つまり、プログラムが信号応答の実行を終了してユーザーモードに戻ると、マスクビットマップのSIGINTビットが1にリセットされ、2つのビットマップを再度比較すると、SIGINT信号は10,000回受信されますが、最後の受信だけを知っています。信号に。

4標準信号の応答には厳密な順序はありません

5信号処理機能からランダムにジャンプすることはできません。
プログラムがカーネルモードからユーザーモードに切り替わり、マスクビットマップと保留中のビットマップの変更が検出されたため、カーネルが実行プログラムのアドレスを次のように置き換えていることがわかります。信号応答プログラムを実行し、マスク信号シールド位置は0です。応答プログラムが実行された後、カーネルは再びコアリングされ、マスク信号シールド位置は再び1になります。つまり、信号シールドワードのブロックが解除されます。 、信号を将来正常に受信し、最終的にユーザー状態に戻すことができるようにします。信号応答プログラムの他の位置にジャンプすると、信号シールドワードのブロック解除操作を見逃し、将来、対応する信号に応答できなくなります。
したがって、setjmp()およびlongjmp()は、信号処理関数で注意して使用する必要があります。

このプロセスでは、プログラムが信号に応答すると、再入力を防ぐためにマスクビットマップが0に設定されます。これについては、後で詳しく説明します。

おすすめ

転載: blog.csdn.net/LinuxArmbiggod/article/details/114004435