総合手引 | セクション 9 | オプション |
#include <sys/param.h>
#include <sys/kernel.h>
#include <sys/malloc.h>
#include <sys/queue.h>
#include <sys/taskqueue.h>
typedef void (*task_fn)(void *context, int pending);typedef void (*taskqueue_enqueue_fn)(void *context);
struct task { STAILQ_ENTRY(task) ta_link; /* キューのためのリンク */ int ta_pending; /* キューに入った回数 */ int ta_priority; /* キュー内タスク優先度 */ task_fn ta_func; /* タスクハンドラ */ void *ta_context; /* ハンドラの引数 */ };
関数 taskqueue_create() は新しいキューを作成するために使用されます。 taskqueue_create() への引数は、唯一であるべき名前、 malloc() の呼び出しがスリープを認めるかどうかを指定する malloc(9) フラグの組、タスクがキューに追加されたときに taskqueue_enqueue() から呼び出される関数を含みます。 これは、(たとえば、ソフトウェア割り込みによるスケジューリングまたは カーネルスレッドが起こされることによって) キューが後で実行されるために 準備されることができるようにするためです。
関数 taskqueue_free() はキューのグローバルなリストからそのキューを取り除くためと、 キューによって使用されたメモリを開放するために使用されるべきです。 キュー上の全てのタスクはこのとき実行されます。
システムは、 taskqueue_find() を使用して検索されることが可能な、全てのキューのリストを管理します。 名前が一致する最初のキューが返され、そうでなければ NULL が返されます。
タスクキュー上のキューに入れられたタスクのリストに、タスクを追加するためには、 キューへのポインタとタスクへのポインタを指定して taskqueue_enqueue() を呼び出します。 タスクの ta_pending フィールドが 0 でない場合には、タスクがキューに入れられた回数に反映するために 単純にインクリメントされます。 そうでない場合には、そのタスクはより低い ta_priority 値を持つ最初のタスクの前に、またはより低い優先度持つタスクがない場合は リストの最後に、追加されます。 タスクをキューに入れることは、割り込みハンドラの中から呼び出されることに 適応するために、メモリの割り当てを実行しません。 この関数は、そのキューが開放されようとしている場合には、 EPIPE を返します。
関数 taskqueue_enqueue_fast() は、高速割り込みハンドラからキューに入れることが発生するときには、 taskqueue_enqueue() の代わりに使用されるべきです。 このメソッドは高速割り込みコンテキスト内でスリープの可能性を避けるために スピンロックを使用します。
キュー上の全てのタスクを実行するには、 taskqueue_run() を呼び出します。 タスクが実行されるときには、先ずそのタスクがキューから取り除かれ、 ta_pending の値が記録されそれからそのフィールドが 0 でクリアされます。 task 構造体の ta_func 関数は ta_context フィールドの値を最初の引数として、 ta_pending の値を 2 番目の引数として、呼び出されます。
便利なマクロ TASK_INIT(task, priority, func, context) は task 構造体を初期化するために提供されています。 priority, func および context の値は単純に task 構造体のフィールドにコピーされ、 ta_pending フィールドはクリアされます。
3 つのマクロ TASKQUEUE_DECLARE(name), TASKQUEUE_DEFINE(name, enqueue, context, init) および +.Fn TASKQUEUE_DEFINE_THREAD "name" は、グローバルなキューへの参照の宣言、そのキューの実装の定義、 および所有するスレッドを使用するキューを宣言するために使用されます。 TASKQUEUE_DEFINE() マクロは name, enqueue および context 引数の値で、システムの初期化の間に taskqueue_create() を呼び出すための手配を行います。 taskqueue_create() の呼び出しの後で、(割り込みハンドラの登録などの) その他の初期化が 実行されることを可能にするために、このマクロへの init 引数が C のステートメントとして実行されます。
TASKQUEUE_DEFINE_THREAD() マクロはタスクを取り扱う自身が所有するカーネルスレッドで 新しいタスクキューを定義します。 変数 struct proc *taskqueue_name_proc はタスクを取り扱うカーネルスレッドを含んで定義されます。 変数 struct taskqueue *taskqueue_name はそのキューにタスクを追加するために使用されます。
システムは 3 つのグローバルなタスクキュー taskqueue_swi, taskqueue_swi_giant, および taskqueue_thread を提供します。 swi タスクキューはソフトウェア割り込みの仕組みを介して実行されます。 taskqueue_swi キューは Giant カーネルロックの保護無しで実行し、 taskqueue_swi_giant キューは Giant カーネルロックの保護有りで 実行します。 スレッドタスクキューはカーネルスレッドコンテキストで実行され、このスレッド から実行されるタスクは、Giant カーネルロック下で実行されません。 呼び出し側が Giant ロック下で実行したい場合には、呼び出し側の タスクキューハンドラルーチンの中で、呼び出し側が明確に Giant ロックの 獲得および解放を行なうべきです。
このキューを使用するためには、使用したいキュー ( taskqueue_swi, taskqueue_swi_giant または taskqueue_thread ) のためのグローバルタスクキュー変数の値で taskqueue_enqueue() を呼び出します。
ソフトウェア割り込みキューは、例えば、ハンドラの中で著しい量の処理を実行 しなければならない割り込みハンドラを実装するために、使用されることが可能です。 ハードウェア割り込みハンドラは、その割り込みの最小の処理を実行し、それから 作業を完了させるためにタスクをキューに入れます。 これは、割り込みが無効化されて費やされる時間を最小量にまで縮小します。
スレッドキューは、例えば、スレッドコンテキストからのみ実行することが可能な 何かを行なうカーネル関数を呼び出すことが必要な、割り込みレベルのルーチンに よって使用されることが可能です。 (例えば、M_WAITOK フラグを伴った malloc の呼び出しです。)
TASKQUEUE (9) | May 12, 2000 |
総合手引 | セクション 9 | オプション |
このマニュアルページサービスについてのご意見は Ben Bullock にお知らせください。 Privacy policy.
“ | Using Unix is the computing equivalent of listening only to music by David Cassidy | ” |
— Rob Pike |