プロセスが開始される前に、xv6ではinitlog()が起動し、ログをディスクに書き込むための準備が行われる。
- proc.c
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; initlog(); }
ディスクへのアクセスは通常時間がかかるため、ここでsleep()が呼び出され、プロセスの切り替えが行われる。
- ide.c
// Wait for request to finish. while((b->flags & (B_VALID|B_DIRTY)) != B_VALID){ sleep(b, &idelock); }
sleep()は、次に実行されるべきプロセスを選択して、自分自身からコンテキストを切り替える関数だ。
// Atomically release lock and sleep on chan. // Reacquires lock when awakened. void sleep(void *chan, struct spinlock *lk) { ... // Go to sleep. proc->chan = chan; proc->state = SLEEPING; sched();
procには現在のプロセスのポインタが入っているのか?現在の状態を保存した後、sched()を呼び出してプロセス切り替えに入る。
- proc.c
swtch(&proc->context, cpu->scheduler);
sched()はさらにswtchを呼び出し、現在のプロセスのコンテキストを変更する。
swtchを呼び出したときに、cpu->scheduler()、つまりfinalizeforkを呼び出している。さらにtrapretを呼び出している。
- trapasm.S
lw $t0, 132($sp) lw $t1, 136($sp) lw $t2, 144($sp) mtc0 $t0, $COP0_EPC mtc0 $t1, $COP0_ERROREPC mtc0 $t2, $COP0_STATUS ... lw $sp, 112($sp) eret .set pop