2009年11月3日火曜日

Lions' Commentary (3) - setpriの真相はいかに -

setpri(2156)にはちょっとした問題がある。

関数のコメントには以下のように書かれている。

2150 /*
2151  * Set user priority.
2152  * The rescheduling flag (runrun)
2153  * is set if the priority is higher
2154  * than the currently running process.
2155  */
つまり、優先度を再計算して、現在実行中のプロセスより優先度が高くなっていたら再スケジューリングのためにrunrunを++する、と書かれている。ところが実際のコードは
2156 setpri(up)
2157 {
2158         register *pp, p;
2159 
2160         pp = up;
2161         p = (pp->p_cpu & 0377)/16;
2162         p =+ PUSER + pp->p_nice;
2163         if(p > 127)
2164                 p = 127;
2165         if(p > curpri)
2166                 runrun++;
2167         pp->p_pri = p;
2168 }
 であり、再計算した優先度が、実行中のプロセスの優先度より低ければ(if (p > curpri))再スケジューリング(runrun++)となっている。

で、Lions本によれば「自力でバグでない事を確認せよ(ヒント:呼び出し時の引数)」との事。さっそくgrepした感じではsetpriはプリエンプションの時に呼ばれているように見える。つまり、走行中のプロセスが持ち時間を使い切ってタイマーによって割り込まれた際に、CPU使用時間を計上してからsetpriを呼んでいる。優先度を下げる方向で再計算させているのであり、curpriは走行中のプロセスが選択された時の優先度。 下げてるんだからここでは常に「p > curpri」が成立するのは自明であり、再スケジューリングが走るのはしかるべきである。つまりコメント側が間違っている、という理解。バグではないという事で納得した・・・と思ったんですが。。。

例の2238 Clubにはバグという記述がありました。確かにベル研の資料には以下のように書かれている模様。
30)
    Bug fix in "setpri()": p>curpri should be p<curpri.
むぅ・・・公式にバグと言ってるわけだから、やっぱりバグなのだろうか。。。
真実を知っている人がいたら、ぜひ答えを教えて下さい。

1 件のコメント:

とよしま さんのコメント...

自己レス。

(4)に書いた通り、clockをきちんと読むと、実行中プロセスの優先度は下げ、それ以外のプロセスの優先度は上げてsetpriを呼んでいる。よってやはりコード側のバグと考えるのが正解か。実際、どっちでも大差ないけど。直した方が無駄なswtchが減る?