linuxデバイス駆動下のtasklet

3826 ワード

デバイス駆動の割り込み処理ではtaskletがよく使われますが、linuxのソフト中断を前に少し見た後、taskletは分かりやすいです.Taskletもソフトブレークを使いますが、taskletの使い方はタイマーの使い方と似ています.         
同じようにcでは、
         start_kernel-->softirq_init
taskletの構造体定義を先に示します.
struct tasklet_struct
{
	struct tasklet_struct *next;
	unsigned long state;
	atomic_t count;
	void (*func)(unsigned long);
	unsigned long data;
};

struct tasklet_head
{
	struct tasklet_struct *head;
	struct tasklet_struct **tail;
};

static DEFINE_PER_CPU(struct tasklet_head, tasklet_vec);
static DEFINE_PER_CPU(struct tasklet_head, tasklet_hi_vec);

void __init softirq_init(void)
{
	int cpu;

	for_each_possible_cpu(cpu) {
		int i;

		per_cpu(tasklet_vec, cpu).tail =
			&per_cpu(tasklet_vec, cpu).head;
		per_cpu(tasklet_hi_vec, cpu).tail =
			&per_cpu(tasklet_hi_vec, cpu).head;
		for (i = 0; i < NR_SOFTIRQS; i++)
			INIT_LIST_HEAD(&per_cpu(softirq_work_list[i], cpu));
	}

	register_hotcpu_notifier(&remote_softirq_cpu_notifier);

	open_softirq(TASKLET_SOFTIRQ, tasklet_action);
	open_softirq(HI_SOFTIRQ, tasklet_hi_action);
}

これでsoftirq_Init関数では、まずtasklet_を初期化します.vec
その後taskletソフト割り込みを登録し、割り込みサービスプログラムはtasklet_action
 
ソフトブレークの実行は、ksoftirqdカーネルスレッドによって処理されます.
 
taskletの初期化を見てみましょう.
void tasklet_init(struct tasklet_struct *t,
		  void (*func)(unsigned long), unsigned long data)
{
	t->next = NULL;
	t->state = 0;
	atomic_set(&t->count, 0);
	t->func = func;
	t->data = data;
}

 
Taskletのスケジュール:
static inline void tasklet_schedule(struct tasklet_struct *t)
{
	if (!test_and_set_bit(TASKLET_STATE_SCHED, &t->state))
		__tasklet_schedule(t);
}

void __tasklet_schedule(struct tasklet_struct *t)
{
	unsigned long flags;

	local_irq_save(flags);
	t->next = NULL;
	*__get_cpu_var(tasklet_vec).tail = t;
	__get_cpu_var(tasklet_vec).tail = &(t->next);
	raise_softirq_irqoff(TASKLET_SOFTIRQ);
	local_irq_restore(flags);
}

 
ここでは先に初期化したtasklet_をstructはこのtaskletに参加しますvecベクトルテーブル
ここでraise_を呼び出しますsoftirq_irqoff(TASKLET_SOFTIRQ);
ソフトブレークをトリガーします.
 
では、前の割り込みサービスプログラムはtasklet_アクションが開始されました.
static void tasklet_action(struct softirq_action *a)
{
	struct tasklet_struct *list;

	local_irq_disable();
	list = __get_cpu_var(tasklet_vec).head;
	__get_cpu_var(tasklet_vec).head = NULL;
	__get_cpu_var(tasklet_vec).tail = &__get_cpu_var(tasklet_vec).head;
	local_irq_enable();

	while (list) {
		struct tasklet_struct *t = list;

		list = list->next;

		if (tasklet_trylock(t)) {
			if (!atomic_read(&t->count)) {
				if (!test_and_clear_bit(TASKLET_STATE_SCHED, &t->state))
					BUG();
				t->func(t->data);
				tasklet_unlock(t);
				continue;
			}
			tasklet_unlock(t);
		}

		local_irq_disable();
		t->next = NULL;
		*__get_cpu_var(tasklet_vec).tail = t;
		__get_cpu_var(tasklet_vec).tail = &(t->next);
		__raise_softirq_irqoff(TASKLET_SOFTIRQ);
		local_irq_enable();
	}
}

 
tasklet_を巡るvecベクトルテーブルは、taskletごとに登録時のt->func(t->data)を呼び出す.で行ないます.
 
 
これにより、taskletは、中断された頂部半部および底部半部に使用することができる.
割り込み処理の前半でtasklet_を呼び出すschedule関数
Taskletに関連付けられたtasklet処理関数は,割り込みの下半部処理である.