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