spl: set priority level

昨日はsleep/wakeupの話を書いたが、これだけあればカーネル内の同期・排他制御が完璧かというとそうではない。sleepするにはコンテキストが必要なので、割込みハンドラ内でsleepできない。そこで、割込み処理が動くとまずい箇所は割込みを禁止する必要がある。

PDP-11にはx86と異なり割込みレベル(優先度)という概念が存在する。プロセッサと周辺機器それぞれに0〜7の8段階の優先度があり、数字が大きいほど優先度が高い。前者のプロセッサ優先度の方が後者の割り込み優先度以上の場合は割込みをブロックする。プロセッサ優先度はPSに格納されており、プログラマが変更できる。一方、割込み優先度は(たぶん)ハードワイヤドであり、4〜7だけになる。

UNIXではプロセッサ優先度を制御する関数をspl(set priority level)と呼び、V6にはspl(0|1|5|6|7)の5つが存在する*1。このspl関数群を使って、プロセッサ優先度を設定することで、周辺機器からの割込みを制御し、排他制御を適切に行うことができる。

例えば、sleep関数内ではカレントプロセスのproc構造体を変更する場合、一時的にプロセッサ優先度を6まで上げている。これはクロック割込み(割込み優先度は6)が発生した流れでwakeup関数が呼ばれ、これらのproc構造体のメンバが操作されると整合性が崩れるからである。

2075: spl6();
2076: rp->p_wchan = chan;
2077: rp->p_stat = SWAIT;
2078: rp->p_pri = pri;
2079: spl0();

UNIBUSや割込みまわりは、例によって@superhogeさんのこのエントリがまとまっている。Lions本読み会のGoogle sitesのページを更新していたのだが、すごい勢いでエントリが増えていて驚いた。まだ、全然追いついてないのだが、あとでまとめて読もう。

*1:Plan 9にもその名残があって、spllo/splhiと2レベルの操作が行われる。x86ではcli/sti相当なので、割込みを許可するかどうかの意味しかない。splはマルチプロセッサシステムではうまく働かないので、モダンなOSではコード上に残っているとしても形骸化しているような気がする。