分割エラーは後ろでどのように機能しますか?

分割エラーは後ろでどのように機能しますか?

「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システムコール(waitwaitpidなどwait4)。この場合、カーネルは単にシステムコールを返し、親プロセスに次のものを提供します。終了ステータス7終了ステータスを親に通知します。なぜSIGSEGV子プロセスは終了します。この場合、信号のデフォルトの動作により子プロセスが終了したことがわかります。

その後、親プロセスはメッセージを印刷して人にイベントを報告できます。シェルプログラムはほとんど常にこれを行います。これを行うコードは含まれていませんが、crshCライブラリルーチンが原因で発生します。system/bin/sh「内部的に」フル機能のシェルを実行します。crsh~である祖父母この場合、親プロセス通知はフィールドとして表示され、/bin/sh一般的なメッセージを印刷します。それから/bin/sh何もせずにそれ自体で終了し、Cライブラリのsystem受信実装はそれ終了通知。の戻り値を確認して、systemコードで終了通知を表示できます。しかし、孫プロセスが中間シェルプロセスによって消費されたため、セグフォルトのために終了したという事実はわかりません。


脚注

  1. 一部のオペレーティングシステムでは実装されていません。デバイスドライバただし、カーネルの一部として、すべての割り込みハンドラは、メモリ保護を構成するコードと同様に、カーネルの一部である必要があります。なぜなら、ハードウェアは何も許さないからです。しかし、カーネルはこのようなことをします。

  2. カーネルよりも高い権限を持つ「ハイパーバイザー」または「仮想マシン管理者」というプログラムがあるかもしれませんが、この答えの目的に応じて「はい」と見なすことができます。ハードウェア

  3. カーネルはプログラムしかし、それはいいえプロセスは図書館に似ています。独自のコードを実行することに加えて、すべてのプロセスは時々カーネルコードの一部を実行します。 「カーネルスレッド」が多いかもしれません。ただカーネルコードは実行されますが、私たちとは何の関係もありません。

  4. 処理する必要がある唯一のオペレーティングシステムできないUnixの実装と見なされるのはもちろんWindowsです。この場合、信号は使用されません。 (事実ではありません。持つSignal; Windowsでは、<signal.h>インターフェイスはCライブラリによって完全に偽造されました。 )」というものを使用します。構造例外処理「逆に。

  5. 代わりに、いくつかのメモリ保護違反SIGBUS(「バスエラー」)が生成されますSIGSEGV。 2つの境界は明確に定義されておらず、システムによって異なります。のハンドラを定義するプログラムを作成する場合は、SIGSEGV同じハンドラを定義することをお勧めしますSIGBUS

  6. 「分割エラー」は、プログラムを実行しているコンピュータの1つでメモリ保護違反によって生成された割り込みの名前です。元のUNIX、おそらくプラズマ11。 」分割「はタイプメモリ保護、しかし今「セグメント化」という用語が使用されています間違って「一般的に、すべてのタイプのメモリ保護違反を示します。

  7. すべてその他親プロセスは子プロセスが終了したことを通知することができ、最終的に親プロセスは終了ステータスをwait呼び出して受信します。ちょうど別の事が最初に起こった。

おすすめ記事