proc.c void sched(void)

トップページ
jupiteroak.hatenablog.com


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

void
sched(void)
{
  int intena;
  struct proc *p = myproc();

  if(!holding(&ptable.lock))
    panic("sched ptable.lock");
  if(mycpu()->ncli != 1)
    panic("sched locks");
  if(p->state == RUNNING)
    panic("sched running");
  if(readeflags()&FL_IF)
    panic("sched interruptible");
  intena = mycpu()->intena;
  swtch(&p->context, mycpu()->scheduler);
  mycpu()->intena = intena;
}

sched関数は、現在実行中のプロセスからカーネルスレッド(scheduler関数の処理)への切り替え処理を行います(プロセスの切り替えとハードウェアコンテキストの切り替えを行います)。


処理の内容

struct proc *p = myproc();

現在実行しているプロセスに対応するプロセスディスクリプタを取得します。

if(!holding(&ptable.lock))
    panic("sched ptable.lock");

holding関数を呼び出して、ptableのロックが保持されているかを確認します。
!holding(&ptable.lock) が真となる場合→holding関数の戻り値が0となる場合→ptableのロックが保持されていない場合は、panic関数を呼び出してメッセージを出力します。

 if(mycpu()->ncli != 1)
    panic("sched locks");

mycpu()->ncli != 1 が真となる場合→pushcli関数の呼び出し回数が1回以外の場合→pushcli関数の呼び出しがネストしている場合は、panic関数を呼び出してメッセージを出力します。

if(p->state == RUNNING)
    panic("sched running");

p->state == RUNNINGが真となる場合→プロセスの状態がRUNNIG状態の場合は、panic関数を呼び出してメッセージを出力します。

if(readeflags()&FL_IF)
    panic("sched interruptible");

readeflags関数を呼び出して取得したフラグレジスタ(EFLFGS)の値をFL_IF 0x00000200の値を使ってマスク処理することにより、フラグレジスタのbit9(EFLFGSレジスタのIF:インターラプトエネーブルフラグ)の値を取り出しています。
readeflags()&FL_IFが真となる場合→フラグレジスタのbit9(EFLFGSレジスタのIF)が1の場合→ハードウェア割り込みを許可している場合は、panic関数を呼び出してメッセージを出力します。

intena = mycpu()->intena;

switchサブルーチンを呼び出してハードウェアコンテキストの切り替えを行う前に、このプロセッサについての割り込みの有効・無効の状態を記録した値を保存しておきます。

swtch(&p->context, mycpu()->scheduler);

swtch(&p->context, mycpu()->scheduler)の処理が完了すると、プロセッサの実行している処理が、プロセスディスクリプタpに対応するプロセスから、カーネルスレッド(scheduler関数) に切り替わります。
このプロセスの処理の続き(shed関数の続き)は、このプロセス(shed関数の続き)を実行対象として選択したプロセッサが実行します。

mycpu()->intena = intena;
||<