※ この記事はまだ勉強中のため、いろいろ間違いがあるかもしれません。
さて、mpmain()の中で何が起きているのか、階層トレースを見てみながら、追い掛けていこう。
まずは、schedulerが呼ばれて、enableinterrupt()により割り込みが有効になる。
<FunctionCall 59147183: mpmain(0x8010530c)> <Return: mpmain> <FunctionCall 59147195: cprintf(0x801007fc) ...> <Return: cprintf> <FunctionCall 59149641: atomic_swap(0x80105204)> <Return: atomic_swap> <FunctionCall 59149660: scheduler(0x80106964)> <FunctionCall 59149666: enableinterrupt(0x80105e8c)> <FunctionCall 59149672: is_interruptible(0x80105e4c)> <FunctionCall 59149678: read_cop0_status(0x80105df0)> <Return: read_cop0_status> <Return: is_interruptible> <FunctionCall 59149703: read_cop0_status(0x80105df0)> <Return: read_cop0_status> <FunctionCall 59149721: write_cop0_status(0x80105e1c)> <Return: write_cop0_status> <Return: enableinterrupt> <FunctionCall 59149744: acquire(0x801072c4)> <FunctionCall 59149751: pushcli(0x80107538)> <FunctionCall 59149758: disableinterrupt(0x8010717c)> <FunctionCall 59149764: is_interruptible(0x8010713c)> <FunctionCall 59149770: read_cop0_status(0x801070e0)> <Return: read_cop0_status> <Return: is_interruptible> <Return: disableinterrupt> <FunctionCall 59149811: is_interruptible(0x8010713c)> <FunctionCall 59149817: read_cop0_status(0x801070e0)> <Return: read_cop0_status> <Return: is_interruptible> <Return: pushcli> <FunctionCall 59149851: holding(0x801074dc)> <Return: holding> <FunctionCall 59149873: atomic_swap(0x80107238)> <Return: atomic_swap> <FunctionCall 59149902: getcallerpcs(0x801073ec)> <Return: getcallerpcs> <Return: acquire> <FunctionCall 59150135: switchuvm(0x8010a994)> <FunctionCall 59150142: pushcli(0x80107538)> <FunctionCall 59150149: disableinterrupt(0x8010717c)> <FunctionCall 59150155: is_interruptible(0x8010713c)> <FunctionCall 59150161: read_cop0_status(0x801070e0)> <Return: read_cop0_status> <Return: is_interruptible> <Return: disableinterrupt> <Return: pushcli> <FunctionCall 59150226: tlbwi(0x8010a324)> <Return: tlbwi> <FunctionCall 59150258: popcli(0x801075a4)> <FunctionCall 59150264: is_interruptible(0x8010713c)> <FunctionCall 59150270: read_cop0_status(0x801070e0)> <Return: read_cop0_status> <Return: is_interruptible> <Return: popcli> <Return: switchuvm>
scheduler()は無限ループになっており、実行可能なプロセスを探しては実行状態にしていく構造のようだ。
void scheduler(void) { struct proc *p; for(;;){ // Enable interrupts on this processor. enableinterrupt(); // Loop over process table looking for process to run. acquire(&ptable.lock); for(p = ptable.proc; p < &ptable.proc[NPROC]; p++){ if(p->state != RUNNABLE) continue; // Switch to chosen process. It is the process's job // to release ptable.lock and then reacquire it // before jumping back to us. proc = p; switchuvm(p); p->state = RUNNING; swtch(&cpu->scheduler, proc->context); switchkvm(); // Process is done running for now. // It should have changed its p->state before coming back. proc = 0; } release(&ptable.lock); } }
switchuvmとswitchkvmとは何だろう?x86の実装では、以下のようになっていた。TSSとは、Task State Segmentというものらしい。
void scheduler(void) { struct proc *p; for(;;){ // Enable interrupts on this processor. enableinterrupt(); // Loop over process table looking for process to run. acquire(&ptable.lock); for(p = ptable.proc; p < &ptable.proc[NPROC]; p++){ if(p->state != RUNNABLE) continue; // Switch to chosen process. It is the process's job // to release ptable.lock and then reacquire it // before jumping back to us. proc = p; switchuvm(p); p->state = RUNNING; swtch(&cpu->scheduler, proc->context); switchkvm(); // Process is done running for now. // It should have changed its p->state before coming back. proc = 0; } release(&ptable.lock); } }
タスク・ステート・セグメント - OS Project Wiki
マルチタスクを実現するための、メモリ上のデータ領域。 タスクの状態(主にレジスタの値)を保存しておくためのセグメントで、システム・セグメントの一種。 一つのタスクに対して、一つのTSSが与えられる。
あー、なるほど、バックアップ領域ね。バックアップした後に、lcr3によりカーネルページテーブルをcr3にロードする。
pushcliとpopcliは、cli(clear IFlag), sti(set IFlag)をラップし、さらにpush、popのように階層化する。