無料Wikiサービス | デモページ
検索

アクセス数
最近のコメント
kprobe - ななし
ksetの実装 - スーパーコピー
カーネルスレッドとは - ノース
カーネルスレッドとは - nbyst
asmlinkageってなに? - ノース
asmlinkageってなに? - よろしく
はじめ - ノース
はじめ - ノース
はじめ - 楽打連動ユーザー
はじめ - 楽打連動ユーザー
Adsense
広告情報が設定されていません。

タスクレット


タスクレットのサンプルです。invoke_virtual_irq()は実際は割り込みハンドラとしてコールされます。割り込み処理で負荷のある実装はタスクレットとして実装することで、割り込みの取りこぼしが防げます。
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/interrupt.h>

MODULE_LICENSE("GPL");

void hoge_fun(unsigned long data)
{
       printk("%s\n", (char *)data);
}

DECLARE_TASKLET(hoge_tasklet, hoge_fun, 0);

void    invoke_virtual_irq(void)
{
       hoge_tasklet.data = (unsigned long)"hoge by tasklet";
       tasklet_schedule(&hoge_tasklet);
}

int init_module(void)
{
       invoke_virtual_irq();
       printk("after tasklet_schedule\n");

       return 0;
}

void cleanup_module(void)
{
       tasklet_kill(&hoge_tasklet);
}
動作
[root@localhost lkm]# dmesg -C
[root@localhost lkm]# insmod tasklet.ko
[root@localhost lkm]# dmesg
[ 3626.655334] after tasklet_schedule
[ 3626.655346] hoge by tasklet
DECLARE_TASKLETマクロでt->state=0です。TASKLET_STATE_SCHEDは多重コール防止フラグです。
#define DECLARE_TASKLET(name, func, data) \
struct tasklet_struct name = { NULL, 0, ATOMIC_INIT(0), func, data }

struct tasklet_struct
{
       struct tasklet_struct *next;
       unsigned long state;
       atomic_t count;
       void (*func)(unsigned long);
       unsigned long data;
};
 
static inline void tasklet_schedule(struct tasklet_struct *t)
{
       if (!test_and_set_bit(TASKLET_STATE_SCHED, &t->state))
               __tasklet_schedule(t);
}
tasklet_vec.tailにtasklet_structをリストし、TASKLET_SOFTIRQでraise_softirq_irqoff()コールすることで、tasklet_action()がコールされます。
void __tasklet_schedule(struct tasklet_struct *t)
{
       unsigned long flags;

       local_irq_save(flags);
       t->next = NULL;
       *__this_cpu_read(tasklet_vec.tail) = t;
       __this_cpu_write(tasklet_vec.tail, &(t->next));
       raise_softirq_irqoff(TASKLET_SOFTIRQ);
       local_irq_restore(flags);
}
softirq_init()でopen_softirq(TASKLET_SOFTIRQ, tasklet_action)とし、tasklet_action()をタスクレットソフト割込みコールバックを設定します。
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);
}
tasklet_vec.headをヘッドとするリスト要素のtasklet_structのfuncを順次コールします。
static void tasklet_action(struct softirq_action *a)
{
       struct tasklet_struct *list;

       local_irq_disable();
       list = __this_cpu_read(tasklet_vec.head);
       __this_cpu_write(tasklet_vec.head, NULL);
       __this_cpu_write(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;
               *__this_cpu_read(tasklet_vec.tail) = t;
               __this_cpu_write(tasklet_vec.tail, &(t->next));
               __raise_softirq_irqoff(TASKLET_SOFTIRQ);
               local_irq_enable();
       }
}

最終更新 2015/04/13 17:08:14 - north
(2010/09/22 01:00:03 作成)