fork システムコールコードはどのように書かれていますか。関数が2つの異なる値を返す方法と、それを2つの異なるプロセスに返す方法の詳細を知りたいです。つまり、fork システム コールがどのように実装されているか知りたいですか?
4 に答える
カールの答えは素晴らしかった。多くのオペレーティング システムでは、戻り値がレジスタの 1 つに渡されることを付け加えておきます。x86 アーキテクチャでは、このレジスタは eax である可能性があり、ARM アーキテクチャでは、このレジスタは R0 である可能性があります。
各プロセスにはプロセス制御ブロック (PCB) もあり、割り込み、システムコール、または例外が発生して制御が OS に渡された時点でレジスタの値を格納します。次にプロセスがスケジュールされたときに、レジスターの値が PCB から復元されます。
fork() が発生すると、OS は次のことを実行できます。
child_process->PCB[return_value_register] = 0;
parrent_process->PCB[return_value_register] = child_pid;
そのため、プロセスが再スケジュールされると、それぞれが異なる戻り値を参照します。
例として、 xv6 の fork の実装を見ることができます。そこでは、親プロセスはまだ実行中の状態にあるため、単純な return ステートメントを使用して親の戻り値を返します。ただし、子プロセスの EAX レジスタの値を 0 に設定するため、子プロセスがスケジュールされると、戻り値として 0 が表示されます。
// Clear %eax so that fork returns 0 in the child.
np->tf->eax = 0;
return 0 も "mov eax, 0" のようなものにコンパイルされることに注意してください。
更新:私がやっている趣味の OS に fork() を実装しました。ソースコードはこちらで見ることができます。
あなたはそれがシステムコールだと言ってほとんど説明しました。すべての作業を行うのはオペレーティング システムの仕事であり、オペレーティング システムは、プログラムのコンテキストや、実装している言語の規則の外で、必要なことはほとんど何でも行うことができます。起こる:
- プログラムコール
fork()
システムコール - カーネルフォークシステムコールは、プログラムを実行しているプロセスを複製します
- カーネルは、元のプログラムと複製のシステム コールの戻り値を設定します (それぞれ、複製の PID と 0)。
- カーネルは両方のプロセスをスケジューラ キューに入れます
- 各プロセスがスケジュールされると、カーネルは 2 つのプログラムのそれぞれに「戻ります」。
大学向けのUnix V6ソース コード ブックレットには、Ken Thompson と Dennis Ritchie 自身が注釈を付けたコメントがあり、ダブル リターンが実際にどのように機能するかを説明しています。コメントは次の文で終わります。
これを理解することは期待されていません。
簡単な方法では、たとえば、プロセスはfork()
移動IP/EIP/RIPレジスタを使用して関数に複製され、次のような関数の命令をスキップします。
return pid;
return 0;
最初のプロセスは最初の命令を実行し、スタックから関数をポップし、2 番目のプロセスは開始しますが、2 番目の命令から 0 を返します。