プロセス1実行編①(カーネルモード) void forkret(void) (Xv6を読む~OSコードリーディング~)

前回
jupiteroak.hatenablog.com
トップページ
jupiteroak.hatenablog.com




proc.c
https://github.com/mit-pdos/xv6-public/blob/master/proc.c#L396

void
forkret(void)
{
  static int first = 1;
  // Still holding ptable.lock from scheduler.
  release(&ptable.lock);

  if (first) {
    // Some initialization functions must be run in the context
    // of a regular process (e.g., they call sleep), and thus cannot
    // be run from main().
    first = 0;
    iinit(ROOTDEV);
    initlog(ROOTDEV);
  }

  // Return to "caller", actually trapret (see allocproc).
}

新規に作成されたプロセスは、scheduler関数で実行対象として選ばれた後に、forkret関数を一番最初に実行します。


処理の内容

クリティカルセクション内でfirstフラグを設定する

  static int first = 1;

ptableのロックを解放する前にfirstを1に設定します。
新規に作成されたプロセスは、scheduler関数の処理からptableのロックを取得したままの状態で、forkret関数を実行しています。
このクリティカルセクション内でfirstフラグを設定することで、新規に作成されたプロセスだけが、後に続く初期化処理を実行できるようにしています。

ptableのロックを解放する

// Still holding ptable.lock from scheduler.
  release(&ptable.lock);

scheduler関数の処理から取得したままになっているptableのロックを解放します。

プロセスの初期化処理を行う

if (first) {
    // Some initialization functions must be run in the context
    // of a regular process (e.g., they call sleep), and thus cannot
    // be run from main().
    first = 0;
    iinit(ROOTDEV);
    initlog(ROOTDEV);
  }

前の処理で説明したように、ptableの操作を行うクリティカルセクション内でのみfirstフラグが1となるので、新規に作成されたプロセスだけが、この初期化処理を実行できます。


first = 0;
firstフラグを0に戻しておきます。


iinit(ROOTDEV);
iinit関数を呼び出して、iノードのキャッシュ領域を初期化しておきます。


initlog(ROOTDEV);
initlog関数を呼び出して、log構造体(ロギングに関わるデータ構造)を初期化しておきます。

forkret関数の実行後

forkret関数を実行完了すると、forkret関数の呼び出し元に戻る処理が始まります(スタックのトップに退避されている値をeipレジスタに復帰する処理が始まります)。allocproc関数の処理でみたように、スタックのトップにはtrapretのアドレスが退避されているので、fork関数を実行完了すると、trapretの処理に移ります。




次回
jupiteroak.hatenablog.com