JavaScript is required to for searching.
ナビゲーションリンクをスキップ
印刷ビューの終了
デバイスドライバの記述     Oracle Solaris 10 8/11 Information Library (日本語)
search filter icon
search icon

ドキュメントの情報

はじめに

パート I Solaris プラットフォーム用デバイスドライバの設計

1.  Solaris デバイスドライバの概要

2.  Solaris カーネルとデバイスツリー

3.  マルチスレッド

4.  プロパティー

5.  イベントの管理とタスクのキュー

イベントの管理

イベントの概要

ddi_log_sysevent() を使用したイベントのロギング

ddi_log_sysevent() の構文

イベントロギング用のサンプルコード

イベント属性の定義

タスクのキュー

タスクキューの概要

タスクキューのインタフェース

タスクキューの使用

タスクキューの監視

タスクキューのカーネル統計カウンタ

タスクキューの DTrace SDT プローブ

6.  ドライバの自動設定

7.  デバイスアクセス: プログラム式入出力

8.  割り込みハンドラ

9.  ダイレクトメモリーアクセス (DMA)

10.  デバイスメモリーおよびカーネルメモリーのマッピング

11.  デバイスコンテキスト管理

12.  電源管理

13.  Solaris ドライバの強化

14.  階層化ドライバインタフェース (LDI)

パート II 特定の種類のデバイスドライバの設計

15.  文字デバイスのドライバ

16.  ブロックデバイスのドライバ

17.  SCSI ターゲットドライバ

18.  SCSI ホストバスアダプタドライバ

19.  ネットワークデバイスのドライバ

20.  USB ドライバ

パート III デバイスドライバの構築

21.  ドライバのコンパイル、ロード、パッケージ化、およびテスト

22.  デバイスドライバのデバッグ、テスト、およびチューニング

23.  推奨されるコーティング方法

パート IV 付録

A.  ハードウェアの概要

B.  Solaris DDI/DKI サービスの概要

C.  64 ビットデバイスドライバの準備

D.  コンソールフレームバッファードライバ

索引

タスクのキュー

この節では、タスクキューを使用して一部のタスクの処理を延期し、その実行を別のカーネルスレッドに委任する方法について説明します。

タスクキューの概要

カーネルプログラミングの一般的な操作は、タスクがあとで別のスレッドによって実行されるようにスケジュールすることです。次の例は、タスクを別のスレッドにあとで実行する理由をいくつか列挙したものです。

これらの各ケースでは、別のコンテキスト内でタスクが実行されます。別のコンテキストとは通常、異なる一連のロックを保持し、優先順位もおそらく異なる別のカーネルスレッドのことです。タスクキューは、非同期タスクをスケジュールするための汎用カーネル API を提供します。

タスクキューとは、タスクリストを処理するためのスレッドを 1 つ以上備えたタスクリストのことです。タスクキューのサービススレッドが 1 つの場合、リストに追加された順番ですべてのタスクが実行されることが保証されます。タスクキューのサービススレッドが複数存在する場合、タスクの実行順番は不明になります。


注 - タスクキューのサービススレッドが複数存在する場合には、あるタスクの実行がほかのどのタスクの実行にも依存しないことを確認してください。タスク間に依存関係があると、デッドロックが発生する可能性があります。


タスクキューのインタフェース

次の DDI インタフェースはタスクキューを管理します。これらのインタフェースは sys/sunddi.h ヘッダーファイル内で定義されています。これらのインタフェースの詳細については、taskq(9F) のマニュアルページを参照してください。

ddi_taskq_t
不透明なハンドル
TASKQ_DEFAULTPRI
システムのデフォルト優先順位
DDI_SLEEP
メモリーのためにブロックできる
DDI_NOSLEEP
メモリーのためにブロックできない
ddi_taskq_create()
タスクキューを作成する
ddi_taskq_destroy()
タスクキューを破棄する
ddi_taskq_dispatch()
タスクキューにタスクを追加する
ddi_taskq_wait()
保留中のタスクが完了するまで待つ
ddi_taskq_suspend()
タスクキューを一時停止する
ddi_taskq_suspended()
タスクキューが一時停止されているかどうかをチェックする
ddi_taskq_resume()
一時停止されたタスクキューを再開する

タスクキューの使用

ドライバでの典型的な使用方法は、attach(9E) でタスクキューを作成することです。taskq_dispatch() 呼び出しの大部分は、割り込みコンテキストから行われます。

Solaris ドライバで使用されるタスクキューについて学ぶには、http://hub.opensolaris.org/bin/view/Main/ にアクセスします。右上隅にある「Source Browser」をクリックします。検索領域の「Symbol」フィールドに ddi_taskq_create と入力します。「File Path」フィールドに amr と入力します。「Project」リストで onnv を選択します。「Search」ボタンをクリックします。検索結果に、Dell PERC 3DC/4SC/4DC/4Di RAID デバイス用の SCSI HBA ドライバ (amr.c) が表示されるはずです。

ファイル名 amr.c をクリックします。ddi_taskq_create () 関数は、amr_attach() エントリポイント内で呼び出されています。ddi_taskq_destroy() 関数は、amr_detach() エントリポイント内で呼び出されているほか、amr_attach() エントリポイントのエラー処理セクション内でも呼び出されています。ddi_taskq_dispatch() 関数は amr_done() 関数内で呼び出されていますが、この関数は amr_intr() 関数内で呼び出されています。amr_intr() 関数は割り込み処理関数であり、amr_attach() エントリポイント内で ddi_add_intr(9F) 関数の引数として渡されています。

タスクキューの監視

この節では、タスクキューで消費されるシステムリソースを監視するために使用可能な 2 つの手法について説明します。タスクキューは、タスクキュースレッドによるシステム時間の使用量に関する統計情報をエクスポートします。さらにタスクキューは、DTrace SDT プローブを使用してタスクキューがタスクの実行を開始した時刻と終了した時刻を判定します。

タスクキューのカーネル統計カウンタ

すべてのタスクキューに一連の kstat カウンタが関連付けられます。次の kstat(1M) コマンドの出力を確認してください。

$ kstat -c taskq
module: unix                            instance: 0     
name:   ata_nexus_enum_tq               class:    taskq
        crtime                          53.877907833
        executed                        0
        maxtasks                        0
        nactive                         1
        nalloc                          0
        priority                        60
        snaptime                        258059.249256749
        tasks                           0
        threads                         1
        totaltime                       0

module: unix                            instance: 0     
name:   callout_taskq                   class:    taskq
        crtime                          0
        executed                        13956358
        maxtasks                        4
        nactive                         4
        nalloc                          0
        priority                        99
        snaptime                        258059.24981709
        tasks                           13956358
        threads                         2
        totaltime                       120247890619

上で示した kstat 出力には、次の情報が含まれています。

次の例は、kstat コマンドを使用してあるカウンタ (スケジュールされたタスクの数) が時間の経過とともに増加する様子を監視する方法について示したものです。

$ kstat -p unix:0:callout_taskq:tasks 1 5
unix:0:callout_taskq:tasks      13994642

unix:0:callout_taskq:tasks      13994711

unix:0:callout_taskq:tasks      13994784

unix:0:callout_taskq:tasks      13994855

unix:0:callout_taskq:tasks      13994926

タスクキューの DTrace SDT プローブ

タスクキューは便利な SDT プローブをいくつか提供します。この節で説明するプローブはすべて、次の 2 つの引数を持ちます。

これらのプローブを使用すると、個々のタスクキューやそれらを通じて実行される個々のタスクに関する高精度のタイミング情報を収集できます。たとえば、次のスクリプトは、タスクキュー経由でスケジュールされた関数を 10 秒に 1 度出力します。

# !/usr/sbin/dtrace -qs

sdt:genunix::taskq-enqueue
{
  this->tq  = (taskq_t *)arg0;
  this->tqe = (taskq_ent_t *) arg1;
  @[this->tq->tq_name,
    this->tq->tq_instance,
    this->tqe->tqent_func] = count();
}

tick-10s
{
  printa ("%s(%d): %a called %@d times\n", @);
  trunc(@);
}

特定のマシン上で上の D スクリプトを実行すると、次のような出力が生成されます。

callout_taskq(1): genunix`callout_execute called 51 times
callout_taskq(0): genunix`callout_execute called 701 times
kmem_taskq(0): genunix`kmem_update_timeout called 1 times
kmem_taskq(0): genunix`kmem_hash_rescale called 4 times
callout_taskq(1): genunix`callout_execute called 40 times
USB_hid_81_pipehndl_tq_1(14): usba`hcdi_cb_thread called 256 times
callout_taskq(0): genunix`callout_execute called 702 times
kmem_taskq(0): genunix`kmem_update_timeout called 1 times
kmem_taskq(0): genunix`kmem_hash_rescale called 4 times
callout_taskq(1): genunix`callout_execute called 28 times
USB_hid_81_pipehndl_tq_1(14): usba`hcdi_cb_thread called 228 times
callout_taskq(0): genunix`callout_execute called 706 times
callout_taskq(1): genunix`callout_execute called 24 times
USB_hid_81_pipehndl_tq_1(14): usba`hcdi_cb_thread called 141 times
callout_taskq(0): genunix`callout_execute called 708 times