linuxデバイス駆動下のtasklet
3826 ワード
デバイス駆動の割り込み処理ではtaskletがよく使われますが、linuxのソフト中断を前に少し見た後、taskletは分かりやすいです.Taskletもソフトブレークを使いますが、taskletの使い方はタイマーの使い方と似ています.
同じようにcでは、
start_kernel-->softirq_init
taskletの構造体定義を先に示します.
これでsoftirq_Init関数では、まずtasklet_を初期化します.vec
その後taskletソフト割り込みを登録し、割り込みサービスプログラムはtasklet_action
ソフトブレークの実行は、ksoftirqdカーネルスレッドによって処理されます.
taskletの初期化を見てみましょう.
Taskletのスケジュール:
ここでは先に初期化したtasklet_をstructはこのtaskletに参加しますvecベクトルテーブル
ここでraise_を呼び出しますsoftirq_irqoff(TASKLET_SOFTIRQ);
ソフトブレークをトリガーします.
では、前の割り込みサービスプログラムはtasklet_アクションが開始されました.
tasklet_を巡るvecベクトルテーブルは、taskletごとに登録時のt->func(t->data)を呼び出す.で行ないます.
これにより、taskletは、中断された頂部半部および底部半部に使用することができる.
割り込み処理の前半でtasklet_を呼び出すschedule関数
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処理関数は,割り込みの下半部処理である.