SX(9)

名称
sx, sx_init, sx_destroy, sx_slock, sx_xlock, sx_try_slock, sx_try_xlock, sx_sunlock, sx_xunlock, sx_try_upgrade, sx_downgrade, sx_assert, sx_unlock, SX_SYSINIT - カーネルの共有/排他ロック

書式
<sys/param.h> <sys/lock.h> <sys/sx.h> void sx_init(struct sx *sx, const char *description) void sx_destroy(struct sx *sx) void sx_slock(struct sx *sx) void sx_xlock(struct sx *sx) int sx_try_slock(struct sx *sx) int sx_try_xlock(struct sx *sx) void sx_sunlock(struct sx *sx) void sx_xunlock(struct sx *sx) int sx_try_upgrade(struct sx *sx) void sx_downgrade(struct sx *sx) void sx_assert(struct sx *sx, int what)

  Ss ユーティリティマクロ
sx_unlock(struct sx *sx) SX_SYSINIT(name, struct sx *sx, const char *description)

  カーネルオプション
options INVARIANTS options INVARIANT_SUPPORT

解説
共有/排他ロックは書き込まれるよりも、読み込まれる方が非常に多いデータを 保護するために使用されます。 mutex は本質的に共有/排他ロックよりも能率的なので、共有/排他ロックは 用心深く使用されるべきです。

共有/排他ロックは sx_init() を使用して作成されます。 ここで sx は struct sx のための領域へのポインタで、 description はその共有/排他ロックを説明するヌルで終端された文字列へのポインタです。 共有/排他ロックは sx_destroy() を使用して破壊されます。 スレッドは sx_slock() または sx_try_slock() および sx_sunlock() または sx_unlock() の呼び出しによって共有ロックを獲得および解放します。 スレッドは sx_xlock() または sx_try_xlock() および sx_xunlock() または sx_unlock() の呼び出しによって排他ロックを獲得および解放します。 スレッドは sx_try_upgrade() の呼び出しによって、現在保有している共有ロックから排他ロックへの アップグレードを試みることが可能です。 排他ロックを持っているスレッドは、 sx_downgrade() の呼び出しによってその排他ロックから共有ロックへのダウングレードが可能です。

sx_try_slock() および sx_try_xlock() は共有/排他ロックがすぐに獲得できなかった場合には 0 を返し、 そうでない場合には共有/排他ロックが獲得され 0 ではない値が返されます。

sx_try_upgrade() は共有ロックをすぐに排他ロックにアップグレードできない場合には 0 を返し、 そうでない場合には排他ロックが獲得され 0 ではない値が返されます。

options INVARIANTS および options INVARIANT_SUPPORT 付きでコンパイルされたときには、 sx_assert() 関数は what に指定されたアサートのために sx をテストし、それらが合わなかった場合には panic します。 以下のアサートがサポートされています。

SX_LOCKED
    現在のスレッドが、最初の引数によって指されている sx ロック上に、共有または排他ロックのいずれかを持っていることをアサートします。

SX_SLOCKED
    現在のスレッドが、最初の引数によって指されている sx ロック上に、共有ロックを持っていることをアサートします。

SX_XLOCKED
    現在のスレッドが、最初の引数によって指されている sx ロック上に、排他ロックを持っていることをアサートします。

SX_UNLOCKED
    現在のスレッドが、最初の引数によって指されている sx ロック上に、ロックを持っていないことをアサートします。

プログラミングを簡単にするために、 sx_sunlock() および sx_xunlock() 各々の関数へのフロントエンドマクロとして sx_unlock() が提供されています。 ロックがどの状態になっているかを知っているアルゴリズムは、 小さなパフォーマンスの利益のために各々の 2 つの特定の関数を使用すべきです。

SX_SYSINIT() マクロはシステムスタートアップ時に与えられた sx ロックを初期化するために sx_sysinit() の呼び出しを生成します。 引数は sx_init() と同様ですが、 そのロックと sysinit ルーチンに関連付けられた構造体に関連した唯一の 変数名を生成する際に使用される追加の引数として name を持ちます。

スレッドは同じロック上に共有ロックと排他ロックを同時には持つことができません。 同時に持つことはデッドロックを引き起こすことになるためです。

コンテキスト
スリープしている間に sx ロック上に共有ロックまたは排他ロックを所有することは許可されます。 その結果、ミューテックスを保持している間、 sx ロックは獲得されないかもしれません。 そうでなければ、ミューテックスを獲得した後に同じ sx ロック上で別のスレッドがブロックされる間に、 一つのスレッドが sx ロックを保持している間にスリープするなら、 事実上、2 番目のスレッドは最後には許可されていないミューテックスを 保持している間にスリープすることになるでしょう。

関連項目
condvar(9), mtx_pool(9), mutex(9), panic(9), sema(9)

バグ
現在、ロックが保持されていないことをアサートする方法がありません。 WITNESS ではない場合には、このスレッドが共有ロックを保持していないことを アサートすることは不可能です。 WITNESS ではない場合には、 SX_LOCKED および SX_SLOCKED のアサートは、あるスレッドが共有ロックを保持していることを 単にチェックするに過ぎません。 これらは、現在のスレッドが共有ロックを保持していることを保証しません。