sleep/wakeup
setlabel/gotolabelによるコルーチンでプロセススイッチしている箇所を見たが,今日はsleep/wakeup関数を見てみようと思う.
sleepで自発的に実行権を放棄したプロセスは,タイムアウトなどの条件が成立すると,wakeupされ,Ready状態に復帰する.sleepでは,まずwakeup処理が必要なことを知らせるために,Rendez構造体(カレントプロセスへのポインタとロック変数を持つ)にカレントプロセスをセットする.755行目のif文が偽になり,カレントプロセスがスリープする必要がある場合は,プロセスをWakeme状態にし,プロセスコンテキストを保存し,setlabelを呼ぶ.setlabelの戻り値は0なので,gotolabelでschedinitの先頭のラベルへ飛ぶ.schedinit〜schedの流れは前回述べた通りなので省略するが,カレントプロセスが入れ替わり,176行目のgotolabelで778行目のラベルに戻ってくる.このとき(gotolabel)の戻り値は1なので,カレントプロセスのコンテキストが復帰される.
729: void 730: sleep(Rendez *r, int (*f)(void*), void *arg) 731: { 732: int s; 735: s = splhi(); 753: r->p = up; 754: 755: if((*f)(arg) || up->notepending){ 760: r->p = nil; 763: } else { 771: up->state = Wakeme; 772: up->r = r; 777: procsave(up); 778: if(setlabel(&up->sched)) { 779: /* 780: * here when the process is awakened 781: */ 782: procrestore(up); 783: spllo(); 784: } else { 785: /* 786: * here to go to sleep (i.e. stop Running) 787: */ 790: gotolabel(&m->sched); 791: } 802: splx(s); 803: }
sleepの対になるwakeupは,Rendez構造体が示すWakemeプロセスをレディキューにつなげている.
856: Proc* 857: wakeup(Rendez *r) 858: { 859: Proc *p; 860: int s; 861: 862: s = splhi(); 865: p = r->p; 866: 867: if(p != nil){ 873: ready(p); 875: } 878: splx(s); 879: 880: return p; 881: }