EN JA
MUTEX(9)
MUTEX(9) FreeBSD Kernel Developer's Manual MUTEX(9)

名称

mutex, mtx_init, mtx_destroy, mtx_lock, mtx_lock_spin, mtx_lock_flags, mtx_lock_spin_flags, mtx_trylock, mtx_trylock_flags, mtx_unlock, mtx_unlock_spin, mtx_unlock_flags, mtx_unlock_spin_flags, mtx_sleep, mtx_initialized, mtx_owned, mtx_recursed, mtx_assert, MTX_SYSINITカーネル同期プリミティブ (基本関数)

書式

#include < sys/param.h>
#include < sys/lock.h>
#include < sys/mutex.h>

void
mtx_init( struct mtx *mutex, const char *name, const char *type, int opts);

void
mtx_destroy( struct mtx *mutex);

void
mtx_lock( struct mtx *mutex);

void
mtx_lock_spin( struct mtx *mutex);

void
mtx_lock_flags( struct mtx *mutex, int flags);

void
mtx_lock_spin_flags( struct mtx *mutex, int flags);

int
mtx_trylock( struct mtx *mutex);

int
mtx_trylock_flags( struct mtx *mutex, int flags);

void
mtx_unlock( struct mtx *mutex);

void
mtx_unlock_spin( struct mtx *mutex);

void
mtx_unlock_flags( struct mtx *mutex, int flags);

void
mtx_unlock_spin_flags( struct mtx *mutex, int flags);

int
mtx_sleep( void *chan, struct mtx *mtx, int priority, const char *wmesg, int timo);

int
mtx_initialized( const struct mtx *mutex);

int
mtx_owned( const struct mtx *mutex);

int
mtx_recursed( const struct mtx *mutex);


options INVARIANTS
options INVARIANT_SUPPORT
void
mtx_assert( const struct mtx *mutex, int what);

#include < sys/kernel.h>

MTX_SYSINIT( name, struct mtx *mtx, const char *description, int opts);

解説

ミューテックスは、スレッド同期の最も基本的で主要な方法です。ミューテックスのための重要な設計の検討項目は、次の通りです:
  1. 取得して解放する競合しないミューテックスは、できるだけ安く (リソース等を必要としない) あるべきです。
  2. それらは、優先権の伝播をサポートする情報と記憶域空間がなければなりません。
  3. スレッドは、ミューテックスが再帰をサポートするために初期化されること提供する、ミューテックスを繰り返し獲得できなければなりません。

現在、ミューテックスがブロックされるとき、コンテキストスイッチするものと、そうしない、2 つの特色があるミューテックスがあります。

デフォルトで、 MTX_DEF ミューテックスは、それらが既に保持されるとき、コンテキストスイッチします。最適化として、それらはコンテキストスイッチの前に若干の時間スピンするかもしれません。スレッドがいつでもプリエンプション (先取り) されるかもしれないので、ミューテックスを取得することによって導入される起こり得るコンテキストスイッチが既に壊れていないものを壊さないように保証されることを覚えていることは重要です。

コンテキストスイッチを行わないミューテックスは、 MTX_SPIN ミューテックスです。これらは、主要な割り込みコードで共有されたデータを保護するためにだけ使用されるべきです。これは、割り込みフィルタと低レベルスケジューリングコードを含んでいます。すべてのアーキテクチャで、競争しないスピンミューテックスの取得と解放は、非スピンミューテックスでの同じ操作より、より高価です。それ自体に対してブロックする割り込みサービスルーチンを保護するために、すべての割り込みは、スピンロックを保持している間に、プロセッサ上でブロックされるか延期されます。複数のスピンミューテックスを保持していることは許されます。

いったんスピンミューテックスが取得されると、ブロッキングミューテックスを取得するのは許されていません。

ミューテックスを実装するために必要な記憶域は struct mtx によって提供されます。一般的に、これは、不透明なオブジェクトとして取り扱われて、ミューテックスプリミティブでのみ参照されるべきです。

mtx_init() 関数は、他のミューテックス関数のどれかに渡す前にミューテックスを初期化するのに使用されなければなりません。 name オプションは、デバッグ出力などでロックを識別するために使用されます。 type オプションは、ロックの順序をチェックするとき、ミューテックスを区別するために、証言 (witness) コードによって使用されます。 typeNULL であるなら、 name は、その場所に使用されます。 nametype として渡されたポインタは、それが指されたデータよりむしろ保存されます。ミューテックスが破壊されるまで、指されたデータは安定した状態を保たなければなりません。 opts 引数は、ミューテックスのタイプを設定するために使用されます。それは、 MTX_DEF または MTX_SPIN のいずれかを含みますが、両方ではありません。追加初期化オプションに関しては下記を参照してください。複数の回の mtx_destroy() への呼び出しに介在なしに同じ mutexmtx_init() に渡すのは許されません。

mtx_lock() 関数は、現在実行しているカーネルスレッドの代わりに MTX_DEF 相互排除ロックを獲得します。別のカーネルスレッドがミューテックスを保持しているなら、ミューテックスが利用可能になるまで (すなわち、それはブロックしている)、呼び出し側は CPU から切り離されます。

mtx_lock_spin() 関数は、現在実行しているカーネルスレッドの代わりに MTX_SPIN 相互排除ロックを獲得します。別のカーネルスレッドがミューテックスを保持しているなら、ミューテックスが利用可能になるまで、呼び出し側はスピンします。割り込みは、スピンの間、無効にされ、次のロックの獲得は無効のまま残ります。

MTX_RECURSE ビットがミューテックスの初期化の間に、 mtx_init() に渡されたならば、同じスレッドは悪影響なしでミューテックスを再帰的に取得することは可能です。

mtx_lock_flags() と mtx_lock_spin_flags() 関数は、それぞれ MTX_DEF または MTX_SPIN ロックを獲得して、また、 flags 引数を受け付けます。いずれにしても、ロックの獲得のために現在利用可能な唯一のフラグは MTX_QUIETMTX_RECURSE です。 MTX_QUIET ビットが flags 引数でオンに変えられるなら、そして KTR_LOCK トレースが完了していたなら、それは、ロックの獲得の間に、沈黙します。 MTX_RECURSE ビットが flags 引数でオンにされるなら、ミューテックを再帰的に獲得することができます。

mtx_trylock() は、 mutex によって指された MTX_DEF ミューテックスを獲得することをを試みます。ミューテックスが直ちに獲得することができないなら、 mtx_trylock() は 0 を返し、そうでなければ、ミューテックスは獲得され、0 以外の値が返されます。

mtx_trylock_flags() 関数は、 mtx_trylock() と同じ振る舞いをしますが、呼び出し側が、 flags 値で渡すことを望んでいるとき、使用されるべきです。現在、 mtx_trylock() の場合での唯一の有効な値は、 MTX_QUIET で、その効果は上記の mtx_lock() で説明されたものと同じです。

mtx_unlock() 関数は MTX_DEF 相互排除ロックを解放します。より高い優先順位のスレッドがミューテックスを待っているなら、現在のスレッドは先取り (preempt) されるかもしれません。

mtx_unlock_spin() 関数は MTX_SPIN 相互排除ロックを解放します。

mtx_unlock_flags() と mtx_unlock_spin_flags() 関数は、上記の標準のミューテックスアンロックルーチンが行うのと全く同じ様に振る舞い、さらに、 MTX_QUIET を指定する flags 引数も許されます。 MTX_QUIET の振る舞いはミューテックスロックルーチンの振る舞いと同じです。

mtx_destroy() 関数は、 mutex を破壊するのに使用されます、それで、それに関連しているデータは解放されるか、またはそうでなければ上書きされます。破壊されるすべてのミューテックスは、以前に、 mtx_init() で初期化されていなければなりません。それが破壊されるとき、ミューテックスでの単一の保持カウントがあることは許されます。それが破壊されるとき、再帰的にミューテックスを保持するか、ミューテックスでのブロックされた別のスレッドがあることは許されていません。

mtx_sleep() 関数は、イベントを待っている間に不可分に mtx を解放するために使用されます。この関数のパラメータに関するより詳しい情報については sleep(9) を参照してください。

mtx_initialized() 関数は、 mutex が初期化されていれば 0 以外を返し、そうでなければ、0 を返します。

mtx_owned() 関数は、現在のスレッドが mutex を保持しているなら、0 以外を返します。現在のプロセスが mutex を保持していないなら、0 が返されます。

mtx_recursed() 関数は、 mutex が再呼び出しされたなら、0 以外を返します。このチェックは、実行しているスレッドが既に mutex を所有している場合にだけ、行われるべきです。

mtx_assert() 関数によって、 what で指定されたアサーションを mutex に関して行うことができます。アサーションが真でなく、カーネルが options INVARIANTSoptions INVARIANT_SUPPORT, でコンパイルされるなら、カーネルはパニックします。現在、次のアサーションがサポートされています:

MA_OWNED
現在のスレッドが、最初の引数によって指されたミューテックスを保持するアサート。
MA_NOTOWNED
現在のスレッドが、最初の引数によって指されたミューテックスを保持しないアサート。
MA_RECURSED
現在のスレッドが、最初の引数によって指されたミューテックスを再呼び出ししているアサート。このアサーションは MA_OWNED に関連しているときのみ有効です。
MA_NOTRECURSED
現在のスレッドが、最初の引数によって指されたミューテックスを再呼び出ししていないアサート。このアサーションは MA_OWNED に関連しているときのみ有効です。

MTX_SYSINIT() マクロは、与えられたミューテックスロックを初期化するためにシステム起動で mtx_sysinit() ルーチンへの呼び出しを生成するために使用されます。パラメータは mtx_init() と同じですが、ロックと sysinit ルーチンと関連している関連構造体のためにユニークな変数名を生成で使用される、追加の引数 name があります。

デフォルトのミューテックスタイプ

ほとんどのカーネルコードはデフォルトのロックタイプ MTX_DEF を使用するべきです。デフォルトロックタイプは、ロックが別のスレッドによって既に保持されているなら、CPU からスレッドを切り離すことができます。この実装は、いくつかの状況で短期間のスピンロックとしてロックを取り扱うことができます。しかしながら、同じ CPU 上で割り込まれたスレッド対してデッドロックの恐れなしで、割り込みスレッドのこれらの形式のロックを使用することは常に安全です。

スピンミューテックスタイプ

MTX_SPIN ミューテックスは、すぐに要求されたロックを取得できないとき、CPU を放棄しませんが、ミューテックスが別の CPU によって解放されるのを待って、ロープします。別のスレッドが、ミューテックスを保持して、次にミューテックスを取得しようとしたスレッドが割り込まれたなら、これはデッドロックの結果となることもあり得ます。この理由で、スピンロックはローカル CPU で、すべての割り込みを無効にします。

スピンロックは非常に短い期間に保持されることを目的としているかなり特殊化したロックです。それらの第一の目的は、デフォルトのミューテックスや、スレッドスケジューリングや、割り込みスレッドのような他の同期基本関数を実装するコードの部分を保護することです。

初期化オプション

mtx_init() の opts 引数で渡されたオプションは、ミューテックスタイプを指定します。 MTX_DEF または MTX_SPIN オプションの 1 つが、必要とされ、それらの 2 つのオプションの 1 つだけを指定することもできます。あり得るのは次の通りです:
MTX_DEF
デフォルトのミューテックス。サスペンドされる現在のスレッドは、常に、割り込みスレッドに対してデッドロック状態を避けることができます。このロックタイプの実装は、現在のスレッドがサスペンドされる前の少しの間スピンします。
MTX_SPIN
スピンミューテックス。 CPU を決して放棄しません。すべての割り込みは、任意のスピンロックが保持されている間、ローカル CPU で無効にされます。
MTX_RECURSE
初期化されたミューテックスが再呼び出しを許されることを指定します。このビットは、ミューテックスが再呼び出しすることが許可されるなら、存在していなければなりません。
MTX_QUIET
このロックのためにミューテックス操作を何もログ記録しません。
MTX_NOWITNESS
このロックを無視するように witness(4) に指示します。
MTX_DUPOK
witness は獲得される複製ロックに関するメッセージをログ記録するべきではありません。
MTX_NOPROFILE
このロックのプロファイルを行いません。

ロックとアンロックフラグ

mtx_lock_flags(), mtx_lock_spin_flags(), mtx_unlock_flags() と mtx_unlock_spin_flags() 関数に渡されたフラグは、呼び出し側にいくつかの基本的なオプションを提供し、ロックを変更するか、または振る舞いをアンロックするために特有の状況下でのみ、しばしば使用されます。標準のロックとアンロックは mtx_lock(), mtx_lock_spin(), mtx_unlock() と mtx_unlock_spin() 関数で実行されるべきです。フラグが要求される場合にだけ、対応するフラグ受け付けルーチンは使用されるべきです。

ミューテックスの振る舞いを変更するオプションは次の通りです:

MTX_QUIET
このオプションは、個々のミューテックス操作の間にメッセージのログ記録を行わないようにするために使用されます。これは、デバッグ目的のために余分なログ記録メッセージを削減するために使用することができます。

Giant

Giant を獲得しなければならないなら、他のミューテックスを獲得する前に、それは獲得されなければなりません。言い換えれば: 別のミューテックスを保持している間に Giant を非再帰的に獲得することは不可能です。 Giant を保持している間に、他のミューテックスを獲得することは可能で、他のミューテックスを保持している間に、 Giant を再帰的に獲得することは可能です。

スリープ

( Giant を除いて) ミューテックスを保持している間のスリープは、決して安全でなく、避けられるべきです。これが試みられるなら、失敗する多数のアサーションがあります。

ユーザ空間のメモリにアクセスする関数

( Giant を除いて) ミューテックスは、 copyin(9), copyout(9), uiomove(9), fuword(9), などのように、ユーザ空間でメモリにアクセスする関数にわたって保持されるべきではありません。これらの関数を呼び出すとき、ロックは必要ではありません。

歴史

これらの関数は、 BSD/OS 4.1FreeBSD 5.0 で登場しました。
November 16, 2011 FreeBSD