Go to main content
Oracle® Solaris 11.3 デバイスドライバの記述

印刷ビューの終了

更新: 2016 年 11 月
 
 

ロック構成の選択

ほとんどのデバイスドライバで、ロック構成を簡潔に保つことをお勧めします。追加のロックを使用すると並行性が向上しますが、オーバーヘッドが増加します。ロックの使用数を減らすと消費時間が減少しますが、並行性は低下します。一般的な目安として、データ構造ごとに 1 つの mutex を、ドライバが待機する必要があるイベントまたは条件ごとに 1 つの条件変数を、ドライバ単位でグローバルな主要データセットごとに 1 つの mutex を使用します。長期間にわたって mutex を保持しないでください。ロック構成を選択するときは次のガイドラインを使用します。

  • エントリポイントのマルチスレッド動作のうち、十分な利点が得られるものを使用します。

  • すべてのエントリポイントを再入可能にします。静的変数を自動変数に変更することにより、共有データの量を減らすことができます。

  • ドライバで複数の mutex を取得する場合は、すべてのコードパスで、同じ順序で mutex を取得および解放します。

  • 同じ関数空間の内部でロックを保持および解放します。

  • KM_SLEEP を指定した kmem_alloc(9F) のように、ブロックの可能性がある DDI インタフェースを呼び出すときはドライバ mutex を保持しないようにします。

ロックの使用状態を確認するには、lockstat(1M) を使用します。lockstat(1M) はすべてのカーネルロックイベントを監視し、イベントの頻度およびタイミングデータを収集し、データを表示します。

マルチスレッド操作の詳細は、Multithreaded Programming Guideを参照してください。

ロックの潜在的な危険性

mutex は同じスレッドによって再入可能ではありません。mutex をすでに保有している場合、この mutex をもう一度取得しようとすると次のパニックが発生します。

panic: recursive mutex_enter. mutex %x caller %x

現在のスレッドが保持していない mutex を解放すると、次のパニックが発生します。

panic: mutex_adaptive_exit: mutex not held by thread

次のパニックは単一プロセッサ環境でのみ発生します。

panic: lock_set: lock held and only one CPU

lock_set パニックは、ほかの CPU がスピン mutex を解放できないため、この mutex が保持されてスピンし続けることを示します。ドライバが特定のコードパスで mutex を解放しなかった場合や、mutex の保持中にドライバがブロックされた場合に、この状況に陥る可能性があります。

lock_set パニックのよくある原因は、割り込みレベルの高いデバイスが、cv_wait(9F) のようにブロック処理を行うルーチンを呼び出したときに発生します。別の一般的な原因は、mutex_enter(9F) を呼び出すことによって適応型 mutex を獲得する高レベルハンドラです。

スレッドがシグナルを受信できない

スレッドがシグナルを受信したときに、sema_p_sig()cv_wait_sig()、および cv_timedwait_sig() の各関数を復帰させることができます。一部のスレッドがシグナルを受信できないことが原因で問題が起きる可能性があります。たとえば、アプリケーションが close(2) を呼び出した結果として close(9E) が呼び出されたときは、シグナルの受信が可能です。一方、開いているすべてのファイル記述子を閉じる exit(2) 処理の内部から close(9E) が呼び出されたとき、スレッドはシグナルを受信できません。スレッドがシグナルを受信できないとき、sema_p_sig()sema_p() として、cv_wait_sig()cv_wait() として、cv_timedwait_sig()cv_timedwait() としてそれぞれ動作します。

発生しない可能性があるイベントで、スリープし続けないように注意する必要があります。決して発生しないイベントは、強制終了できない (機能停止した) スレッドを作成し、システムをリブートするまでデバイスを使用不能にします。機能停止したプロセスはシグナルを受信できません。

現在のスレッドがシグナルを受信できるかどうかを検出するには、ddi_can_receive_sig(9F) 関数を使用します。ddi_can_receive_sig() 関数が B_TRUE を返す場合、受信したシグナルによって前述の関数を復帰させることができます。ddi_can_receive_sig() 関数が B_FALSE を返す場合、受信したシグナルによって前出の関数群を復帰させることはできません。ddi_can_receive_sig() 関数が B_FALSE を返す場合、デバイスドライバではtimeout(9F) 関数などの代替手段を使用して、再度復帰処理を行うべきです。

この問題が発生する重要なケースの 1 つはシリアルポートです。リモートシステムがフロー制御を表明し、出力データの排出を試みる間 close(9E) 関数がブロックする場合、フロー制御条件が解決されるか、システムがリブートされるまでポートがスタックする可能性があります。そのようなドライバでは、このケースを検出し、フロー制御条件の持続時間が長すぎるときに排出操作を中止するためのタイマーを設定するべきです。

この問題は、STREAMS Programming Guide の 第 7 章, STREAMS Framework – Kernel Levelで説明する qwait_sig(9F) 関数にも影響します。