SX(9) | FreeBSD Kernel Developer's Manual | SX(9) |
名称
sx, sx_init, sx_init_flags, sx_destroy, sx_slock, sx_xlock, sx_slock_sig, sx_xlock_sig, sx_try_slock, sx_try_xlock, sx_sunlock, sx_xunlock, sx_unlock, sx_try_upgrade, sx_downgrade, sx_sleep, sx_xholder, sx_xlocked, sx_assert, SX_SYSINIT — カーネルの共有/排他ロック書式
#include < sys/param.h>#include < sys/lock.h>
#include < sys/sx.h>
void
sx_init( struct sx *sx, const char *description);
void
sx_init_flags( struct sx *sx, const char *description, int opts);
void
sx_destroy( struct sx *sx);
void
sx_slock( struct sx *sx);
void
sx_xlock( struct sx *sx);
int
sx_slock_sig( struct sx *sx);
int
sx_xlock_sig( 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);
void
sx_unlock( struct sx *sx);
int
sx_try_upgrade( struct sx *sx);
void
sx_downgrade( struct sx *sx);
int
sx_sleep( void *chan, struct sx *sx, int priority, const char *wmesg, int timo);
struct thread *
sx_xholder( struct sx *sx);
int
sx_xlocked( const struct sx *sx);
options INVARIANTS
options INVARIANT_SUPPORT
void
sx_assert( const struct sx *sx, int what);
#include < sys/kernel.h>
SX_SYSINIT( name, struct sx *sx, const char *description);
解説
共有/排他ロックは、書き込まれるよりも、読み込まれる方が非常に多いデータを保護するために使用されます。共有/排他ロックは、優先権の反転を防ぐために mutex と読み込み/書き込みロックのような優先権の伝搬を実装しないので、共有/排他ロックは、用心深く使用されるべきです。共有/排他ロックは、 sx_init() または sx_init_flags() のいずれかで作成され、ここで sx は、 struct sx, のための空間へのポインタであり、 description は、共有/排他ロックを説明するヌル文字で終了する文字列へのポインタです。 sx_init_flags() への opts 引数は、 sx の振る舞いを変更するために 1 組のオプションのフラグを指定します。それは、1 つ以上の次のフラグを含んでいます:
- SX_NOADAPTIVE
- カーネルが options NO_ADAPTIVE_SX でコンパイルされないなら、 sx のためのロック操作は、排他ロックの所有者が別の CPU で実行している間にスリープする代わりにスピン (回転) します。
- SX_DUPOK
- witness は、獲得される複製されたロックに関するメッセージをログ記録するべきではありません。
- SX_NOWITNESS
- このロックを無視するために witness(4) に指示します。
- SX_NOPROFILE
- このロックのプロファイルを行いません。
- SX_RECURSE
- スレッドは、 sx のために排他ロックを再帰的に獲得することができます。
- SX_QUIET
- ktr(4) を通してこのロックのための任意の操作をログ記録しません。
共有/排他ロックは、 sx_destroy() を使用して破壊されます。ロック sx は、それが破壊されるとき、どんなスレッドによってもロックされてはいけません。
スレッドは、 sx_slock(), sx_slock_sig() または sx_try_slock() と sx_sunlock() または sx_unlock() の呼び出しによって共有ロックを獲得および解放します。スレッドは、 sx_xlock(), sx_xlock_sig() または 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 ではない値が返されます。
sx_slock_sig() と sx_xlock_sig() は、割り込み可能なスリープを実行しますが、それらの通常のバージョンと同じように行います。スリープがシグナルまたは割り込みによって割り込まれるなら、0 以外の値を返し、そうでなければ、0 を返します。
スレッドは、 sx_sleep() の呼び出しによってイベントを待っている間に、共有/排他ロックを不可分に解放できます。この関数へのパラメータに関するより詳しい情報については、 sleep(9) を参照してください。
options INVARIANTS と options INVARIANT_SUPPORT 付きでコンパイルされたときには、 sx_assert() 関数は、 what に指定されたアサートのために sx をテストし、それらが合わなかった場合には、panic します。次のアサートの 1 つが指定されるべきです:
- SA_LOCKED
- 現在のスレッドが、最初の引数によって指されている sx ロック上に、共有または排他ロックのいずれかを持っていることをアサートします。
- SA_SLOCKED
- 現在のスレッドが、最初の引数によって指されている sx ロック上に、共有ロックを持っていることをアサートします。
- SA_XLOCKED
- 現在のスレッドが、最初の引数によって指されている sx ロック上に、排他ロックを持っていることをアサートします。
- SA_UNLOCKED
- 現在のスレッドが、最初の引数によって指されている sx ロック上に、ロックを持っていないことをアサートします。
さらに、次の省略可能なアサーションの 1 つは、 SA_LOCKED, SA_SLOCKED または SA_XLOCKED アサーションのいずれかに含まれます:
- SA_RECURSED
- 現在のスレッドが sx で繰り返えされるロックがあることをアサートします。
- SA_NOTRECURSED
- 現在のスレッドが sx で繰り返えされるロックがないことをアサートします。
sx_xholder() は、現在 sx で排他ロックを保持しているスレッドへのポインタを返します。スレッドが sx, で排他ロックを保持していないなら、代わりに NULL が返されます。
sx_xlocked() は、現在のスレッドが排他的なロックを保持しているなら、0 以外を返します。そうでなければ、0 を返します。
プログラミングを簡単にするために、 sx_sunlock() と sx_xunlock() 各々の関数へのフロントエンドマクロとして sx_unlock() が提供されています。ロックがどの状態になっているかを知っているアルゴリズムは、小さなパフォーマンスの利益のために各々の 2 つの特定の関数を使用すべきです。
SX_SYSINIT() マクロは、システムスタートアップ時に与えられた sx ロックを初期化するために sx_sysinit() の呼び出しを生成します。引数は、 sx_init() と同様ですが、そのロックと sysinit ルーチンに関連付けられた構造体に関連した唯一の変数名を生成する際に使用される追加の引数として name を持ちます。
スレッドは、同じロック上に共有ロックと排他ロックを同時には持つことができません。同時に持つことは、デッドロックを引き起こすことになるためです。
コンテキスト
スリープしている間に sx ロック上に共有ロックまたは排他ロックを所有することは許可されます。その結果、ミューテックスを保持している間、 sx ロックは、獲得されないかもしれません。そうでなければ、ミューテックスを獲得した後に同じ sx ロック上で別のスレッドがブロックされる間に、一つのスレッドが sx ロックを保持している間にスリープするなら、事実上、2 番目のスレッドは、最後には許可されていないミューテックスを保持している間にスリープすることになるでしょう。バグ
現在、ロックが保持されていないことをアサートする方法がありません。 WITNESS ではない場合には、このスレッドが共有ロックを保持していないことをアサートすることは不可能です。 WITNESS ではない場合には、 SA_LOCKED と SA_SLOCKED のアサートは、あるスレッドが共有ロックを保持していることを単にチェックするに過ぎません。これらは、現在のスレッドが共有ロックを保持していることを保証しません。November 16, 2011 | FreeBSD |