「CPUのMMUが信号を送る」と「カーネルが該当プログラムを問題のプログラムに指示して終了する」という以外には、これに関する情報が見つからないようです。
私はそれが問題のプロセスを終了して印刷することによってそれを処理するシェルに信号を送ると仮定しました"Segmentation fault"
。それで私はミニマリストシェルを書いてこの仮説をテストしました。CRSH(スクラップシェル)。シェルはユーザー入力を受け取り、メソッドに提供する以外は何もしませんsystem()
。
#include <stdio.h>
#include <stdlib.h>
int main(){
char cmdbuf[1000];
while (1){
printf("Crap Shell> ");
fgets(cmdbuf, 1000, stdin);
system(cmdbuf);
}
}
だから私はこのシェルをベアターミナルbash
で実行しています(以下では実行されません)。その後、segfaultを生成するプログラムを実行します。私の仮定が正しい場合、a)crash crsh
、xtermを閉じる、b)印刷されていない、"Segmentation fault"
またはc)両方が発生します。
braden@system ~/code/crsh/ $ xterm -e ./crsh
Crap Shell> ./segfault
Segmentation fault
Crap Shell> [still running]
最初のポイントに戻ったと思います。私はこれを行うことがシェルではなく基本システムであることを証明しました。 「分割エラー」はどのように印刷されますか? 「誰が」こんなことをしていますか?コア?他にはありませんか?シグナルとすべての副作用がハードウェアからプログラムの最終終了までどのように伝播しますか?
答え1
すべての最新のCPUは次のことができます。邪魔する現在実行中のマシンコマンドです。彼らは十分な状態を保存します(通常はそうではありませんが)。また覆う何も起こらなかったかのように後で実行します(通常は中断されたコマンドは最初から再開されます)。その後、実行を開始します。割り込みハンドラ、これは機械語コードにすぎませんが、CPUが事前に位置を知ることができるように特別な位置に配置されます。割り込みハンドラは常にコアオペレーティングシステム:最大権限で実行され、他のすべてのコンポーネントの実行を監視するコンポーネント。1,2
割り込みは次のとおりです。同期つまり、現在実行中の命令が実行する操作に直接応答して、CPU自体によってトリガされることを意味します。非同期これは、外部イベント(ネットワークポートに到着するデータなど)のために予測不可能な時間に発生することを意味します。一部では、非同期割り込みには「割り込み」という用語を使用し、同期割り込みを「トラップ」、「エラー」、または「例外」と呼びますが、これらの単語には異なる意味があるため、「同期割り込み」に従います。
今日、ほとんどの最新のオペレーティングシステムには次の概念があります。プロセス。最も基本的には、これはコンピュータが複数のプログラムを同時に実行できるメカニズムですが、オペレーティングシステムの構成方法の重要な側面です。メモリ保護、これはほとんどの機能です(しかし残念ながらまだそうではありません)。みんな)最新のCPU。同伴仮想メモリ、これはメモリアドレスとRAMの実際の位置との間のマッピングを変更する機能である。メモリ保護により、オペレーティングシステムは各プロセスにのみアクセスできる独自のRAMブロックを提供できます。また、オペレーティングシステム(プロセスの代わりに)がRAM領域を読み取り専用、実行可能、連携プロセスグループ間の共有などとして指定できます。コアでのみ使用できるメモリブロックもあります。サム
各プロセスが CPU 構成が許可する方法でのみメモリにアクセスする限り、メモリ保護は表示されません。プロセスがルールに違反すると、CPUは同期割り込みを生成し、カーネルがそれを処理するように要求します。プロセスが完了しない場合がよく発生します。本物ルールに対してプロセスを続行するには、カーネルだけをいくつかの操作を実行するだけです。たとえば、他のコンテンツ用のRAMスペースを解放するためにプロセスメモリページをスワップファイルに「削除」する必要がある場合、カーネルはそのページにアクセスできないとマークします。次にプロセスがそれを使用しようとすると、CPUはメモリ保護割り込みを生成します。カーネルはスワップからページを検索し、元の場所に戻し、再びアクセス可能とマークし、実行を再開します。
しかし、このプロセスがルールを破ったとしましょう。 RAMにマップされたことのないページにアクセスしようとしているか、機械語コードがないとマークされたページを実行しようとしています。一般的に「Unix(Unix)」と呼ばれるオペレーティングシステムファミリシグナルこの状況を処理するために。4信号は割り込みに似ていますが、ハードウェアで生成され、カーネルで処理されるのではなく、カーネルで生成され、プロセスで処理されます。プロセスを定義できます。信号ハンドラ独自のコードで記述し、カーネルに場所を伝えます。その後、これらのシグナルハンドラが実行され、必要に応じて通常の制御フローを停止します。シグナルには数字と2つの名前があります。そのうちの1つは秘密の略語であり、もう1つは少しあまり秘密ではないフレーズです。プロセスがメモリ保護規則に違反したときに生成される信号は(通常)11番で、名前はSIGSEGV
「セグメント化エラー」です。5,6
信号と割り込みの重要な違いは次のとおりです。基本動作各信号について。オペレーティングシステムがすべての割り込みに対してハンドラを定義できない場合、これはオペレーティングシステムのバグであり、CPUが欠落しているハンドラを呼び出そうとするとコンピュータ全体がクラッシュします。ただし、プロセスはすべての信号に対して信号ハンドラを定義する義務はありません。カーネルがプロセスのシグナルを生成し、シグナルがデフォルトの動作を維持する場合、カーネルはプロセスを中断することなく基本的な操作を続けます。ほとんどの信号に対するデフォルトの動作は、「何もしません」または「このプロセスを終了してコアダンプを生成することもできます」です。SIGSEGV
後者の一つです。
要約すると、メモリ保護規則に違反するプロセスがあります。 CPU はプロセスを一時停止し、同期割り込みを発生します。カーネルは割り込みを処理し、SIGSEGV
プロセスの信号を生成します。プロセスを仮定しましょういいえSIGSEGV
カーネルがプロセスを終了するデフォルトの動作を実行するようにシグナルハンドラを設定します。これは、次のすべてと同じ効果があります。_exit
システムコール:開いているファイルを閉じる、メモリを解放するなど
これまで人間が見ることができるメッセージを印刷したことは何もなく、シェル(またはより一般的には親プロセス終了したばかりのプロセス)はまったく関与しません。SIGSEGV
ルールに違反するプロセスに進み、いいえその親。これNextしかし、シーケンスのステップは、子プロセスが終了したことを親プロセスに通知することです。これはいくつかの異なる方法で発生する可能性があり、そのうちの最も簡単な方法は、次のいずれかを使用して、親がすでにこの通知を待っている場合です。wait
システムコール(wait
、waitpid
などwait4
)。この場合、カーネルは単にシステムコールを返し、親プロセスに次のものを提供します。終了ステータス。7終了ステータスを親に通知します。なぜSIGSEGV
子プロセスは終了します。この場合、信号のデフォルトの動作により子プロセスが終了したことがわかります。
その後、親プロセスはメッセージを印刷して人にイベントを報告できます。シェルプログラムはほとんど常にこれを行います。これを行うコードは含まれていませんが、crsh
Cライブラリルーチンが原因で発生します。system
/bin/sh
「内部的に」フル機能のシェルを実行します。crsh
~である祖父母この場合、親プロセス通知はフィールドとして表示され、/bin/sh
一般的なメッセージを印刷します。それから/bin/sh
何もせずにそれ自体で終了し、Cライブラリのsystem
受信実装はそれ終了通知。の戻り値を確認して、system
コードで終了通知を表示できます。しかし、孫プロセスが中間シェルプロセスによって消費されたため、セグフォルトのために終了したという事実はわかりません。
脚注
一部のオペレーティングシステムでは実装されていません。デバイスドライバただし、カーネルの一部として、すべての割り込みハンドラは、メモリ保護を構成するコードと同様に、カーネルの一部である必要があります。なぜなら、ハードウェアは何も許さないからです。しかし、カーネルはこのようなことをします。
カーネルよりも高い権限を持つ「ハイパーバイザー」または「仮想マシン管理者」というプログラムがあるかもしれませんが、この答えの目的に応じて「はい」と見なすことができます。ハードウェア。
カーネルはプログラムしかし、それはいいえプロセスは図書館に似ています。独自のコードを実行することに加えて、すべてのプロセスは時々カーネルコードの一部を実行します。 「カーネルスレッド」が多いかもしれません。ただカーネルコードは実行されますが、私たちとは何の関係もありません。
処理する必要がある唯一のオペレーティングシステムできないUnixの実装と見なされるのはもちろんWindowsです。この場合、信号は使用されません。 (事実ではありません。持つSignal; Windowsでは、
<signal.h>
インターフェイスはCライブラリによって完全に偽造されました。 )」というものを使用します。構造例外処理「逆に。代わりに、いくつかのメモリ保護違反
SIGBUS
(「バスエラー」)が生成されますSIGSEGV
。 2つの境界は明確に定義されておらず、システムによって異なります。のハンドラを定義するプログラムを作成する場合は、SIGSEGV
同じハンドラを定義することをお勧めしますSIGBUS
。「分割エラー」は、プログラムを実行しているコンピュータの1つでメモリ保護違反によって生成された割り込みの名前です。元のUNIX、おそらくプラズマ11。 」分割「はタイプメモリ保護、しかし今「セグメント化」という用語が使用されています間違って「一般的に、すべてのタイプのメモリ保護違反を示します。
すべてその他親プロセスは子プロセスが終了したことを通知することができ、最終的に親プロセスは終了ステータスを
wait
呼び出して受信します。ちょうど別の事が最初に起こった。
答え2
シェルはメッセージに関連し、crsh
シェルは間接的に呼び出されます。これはおそらくbash
。
私はいつもセグフォルトを生成する小さなCプログラムを書いています。
#include <stdio.h>
int
main(int ac, char **av)
{
int *i = NULL;
*i = 12;
return 0;
}
デフォルトのシェルで実行すると、zsh
次の結果が表示されます。
4 % ./segv
zsh: 13512 segmentation fault ./segv
私がそれを実行すると、bash
あなたの質問から指摘した内容を取得します。
bediger@flq123:csrc % ./segv
Segmentation fault
私のコードにシグナルハンドラを書こうとしましたが、execsystem()
で使用されているライブラリ呼び出しがシェルであることにcrsh
気づき/bin/sh
ましたman 3 system
。/bin/sh
もちろんcrsh
。
crsh
システムコールを使用するようにプログラムを再構築すると、execve()
「セグメント失敗」文字列は表示されません。これは呼び出しシェルから来ますsystem()
。
答え3
「CPUのMMUが信号を送る」と「カーネルが該当プログラムを問題のプログラムに指示して終了する」という以外には、これに関する情報が見つからないようです。
これはやや歪んだ要約です。 Unixシグナルメカニズムは、プロセスを開始するCPU関連イベントとはまったく異なります。
一般的に、CPUは不正なアドレスにアクセスしたり、読み取り専用領域に書き込んだり、実行可能セクションなど)、各「セグメント」(伝統的に読み取り専用実行可能「テキスト」、書き込み可能可変長「データ」、および伝統的にメモリの反対側末尾のスタックが固定アドレス範囲を持つためです。最新のアーキテクチャでは、ページエラー(マッピングされていないメモリの場合)またはアクセス違反(読み取り、書き込み、および実行権限の問題の場合)の可能性が高くなります。これについては、残りの回答で集中的に説明します。
これで、カーネルはいくつかのタスクを実行できます。有効であるがロードされていないメモリ(スワップアウトやマップされたファイルなど)に対してもページエラーが発生する可能性があります。この場合、カーネルはメモリをマップし、ページを発行したコマンドでユーザープログラムを再起動します。間違っています。間違い。それ以外の場合は信号を送信します。シグナルハンドラをインストールするプロセスは、割り込みハンドラのインストールをエミュレートする意図されたプログラムではなく、ほとんどがアーキテクチャとは無関係であるため、「[元のイベント]を問題のプログラムに渡す」というわけではありません。
ユーザプログラムにシグナルハンドラがインストールされている場合は、スタックフレームを作成し、ユーザプログラムの実行位置をシグナルハンドラに設定することを意味します。すべての信号に対して同じ操作が実行されますが、分割違反の場合は、通常、シグナルハンドラが返された場合にエラーが発生したコマンドを再開するように配置されます。ユーザープログラムは、たとえば、メモリを問題のあるアドレスにマッピングしてバグを修正した可能性があります。これが可能かどうかは、アーキテクチャによって異なります。シグナルハンドラはプログラムの別の場所に移動することもできます(通常は次のように)。進行または例外を発生させて)誤ったメモリアクセスを引き起こした操作を中断します。
ユーザプログラムがシグナルハンドラをインストールしない場合、プログラムは直接終了します。一部のアーキテクチャでは、シグナルが無視されると、コマンドが繰り返し再開され、無限ループが発生する可能性があります。
答え4
分割エラーは、許可されていないメモリアドレスへのアクセスです(プロセスの一部ではない、読み取り専用データの書き込みを試みる、または実行できないデータを実行するなど)。これはMMU(現在のCPUの一部であるメモリ管理装置)によって捕捉され、割り込みを発生させます。割り込みは、SIGSEGFAULT
問題のあるプロセスにシグナルを送信するカーネルによって処理されます(例を参照)。signal(2)
この信号のデフォルトハンドラはコアをダンプし(参考資料を参照core(5)
)、プロセスを終了します。
シェルはまったく関与しません。