SPL(9)

名称
splbio, splclock, splhigh, splimp, splnet, splsoftclock, splsofttty, splstatclock, spltty, splvm, spl0, splx - 割り込み優先度の操作

書式
<sys/types.h> <sys/systm.h> intrmask_t splbio(void) intrmask_t splclock(void) intrmask_t splhigh(void) intrmask_t splimp(void) intrmask_t splnet(void) intrmask_t splsoftclock(void) intrmask_t splsofttty(void) intrmask_t splstatclock(void) intrmask_t spltty(void) void spl0(void) void splx(intrmask_t ipl)

解説
spl() 関数ファミリは CPU の割り込み優先度の “レベル” を設定します。 これはブロックされた優先度レベルの割り込みハンドラの実行を抑制します。 割り込みハンドラによって調査あるいは修正されたであろうデータ領域を 調査あるいは修正するドライバの “synchronous” 部分(ユーザープロセスを代表して実行される部分)で使用されます。

通常それぞれの割り込みを使用するドライバは、 config ファイルのキーワードによって 1 つの 割り込み優先度グループに割り当てられます。 例えば、

    device foo0 at isa? port 0x0815 irq 12 tty

は、割り込み 12 を “tty” 優先度グループに割り当てます。 システムは自動的に xxx グループの割り込みを優先度が splxxx () 以上の時に呼ばれるように準備します。

splx() 関数は割り込み優先度レベルを絶対的な数値に設定します。 これは別の割り込みレベル関数が返した値をローカルの変数に保存して、 後で元の優先度レベルに戻すために splx() を使用する事を意図しています。

spl0() 関数は全ての割り込みハンドラをブロックしない値に優先度を減少させます。 ただし、AST(非同期システムトラップ)はシステムが ユーザーモードに戻るまでの間はブロックされます。

いろいろなデバイスドライバの割り込み優先度グループの伝統的な割り当ては、 おおよそ次のように分類できます。

splnet()
    全てのネットワークインターフェイスドライバ。

splbio()
    全ての バッファ入出力 (つまりディスクなど)のドライバ。

spltty()
    基本的にはネットワーク以外の通信デバイスですが、 事実上はネットワークとディスク以外の全てのドライバ。

戻り値
splx() および spl0() 以外の全ての関数は、操作前の優先度の値を返します。

使用例
以下は、標準的な使用例です。

    struct foo_softc {
    	...
    	int flags;
    #define	FOO_ASLEEP	1
    #define	FOO_READY	2
    } foo_softc[NFOO];
    int
    foowrite(...)
    {
    	struct foo_softc *sc;
    	int s, error;
    	...
    	s = spltty();
    	if (!(sc->flags & FOO_READY)) {
    		/* 準備ができていません、待機しなければなりません */
    		sc->flags |= FOO_ASLEEP;
    		error = tsleep(sc, PZERO, "foordy", 0);
    		sc->flags &= ~FOO_ASLEEP;
    	}
    	sc->flags &= ~FOO_READY;
    	splx(s);
    	...
    }
    void
    foointr(...)
    {
    	struct foo_softc *sc;
    	...
    	sc->flags |= FOO_READY;
    	if (sc->flags & FOO_ASLEEP)
    		/* 誰かが我々を待っています、起こしてください */
    		wakeup(sc);
    	...
    }

割り込みハンドラは 絶対に 優先度レベルを減少させるべきではない、ということに注意してください。 自動的に、自分のレベルの割り込み優先度に増加させられます。 すなわち、同じグループの全ての割り込みはブロックされます。

歴史
割り込み優先度レベルは早期のバージョンの Unix で登場しました。 伝統的には名前ではなく数字が使われていて、そのレベルまでの全てを含んで (優先度 5 はレベル 5 までの全てをブロックします)いた事が知られています。 これは FreeBSD にはあてはまりません。 伝統的な名前 ‘level’ はいまだに文字 ‘l’ としてそれぞれの関数や変数の名前に反映されています。 しかし、実際にはもはやレベルではなく、 むしろ異なった(部分的に含まれた)関数群がシステムのある期間ブロックされます。 歴史的な番号による方法は単純で順番通りの 割り込み優先度レベルグループであるとみなす事ができます。

作者
このマニュアルページは Jörg Wunsch が書きました。