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: }