您的位置:首页 > 其它

soft irq and tasklet

2013-09-17 15:16 190 查看

创建 ksoftirqd

early_initcall(spawn_ksoftirqd);

static __init int spawn_ksoftirqd(void)

{

void *cpu = (void *)(long)smp_processor_id();

int err = cpu_callback(&cpu_nfb, CPU_UP_PREPARE, cpu);

cpu_callback(&cpu_nfb, CPU_ONLINE, cpu);

register_cpu_notifier(&cpu_nfb);

return 0;

}

int __cpuinit cpu_callback(struct notifier_block *nfb,

unsigned long action,

void *hcpu)

{

int hotcpu = (unsigned long)hcpu;

struct task_struct *p;

switch (action) {

case CPU_UP_PREPARE:

case CPU_UP_PREPARE_FROZEN:

/*创建 Kthread 并绑定某个CPU,这里给出了 thread funcion 绑定到某个CPU的方法*/

p = kthread_create_on_node(run_ksoftirqd,

hcpu,

cpu_to_node(hotcpu),

"ksoftirqd/%d", hotcpu);

kthread_bind(p, hotcpu);

per_cpu(ksoftirqd, hotcpu) = p;

break;

/*唤醒并绑定某个CPU的Kthread */

case CPU_ONLINE:

case CPU_ONLINE_FROZEN:

wake_up_process(per_cpu(ksoftirqd, hotcpu));

break;

}

kthread function: run_ksoftirqd

/*ksoftirqd thread的当有pending的softirq时,调用处理函数

*没有pending 事件,则睡眠

**/

int run_ksoftirqd(void * __bind_cpu)

{

__set_current_state(TASK_RUNNING);

while (local_softirq_pending()) {

__do_softirq();

}

set_current_state(TASK_INTERRUPTIBLE);

}

下面的问题是怎样pending位和怎样唤醒ksoftirqd, 当然还有怎样设置一个softirq

struct tasklet_struct

{

struct tasklet_struct *next;

unsigned long state;

atomic_t count;

void (*func)(unsigned long);

unsigned long data;

};

定义一个 named tasklet_strct:

#define DECLARE_TASKLET(name, func, data) \

struct tasklet_struct name = { NULL, 0, ATOMIC_INIT(0), func, data }

tasklet_schedule

/*

*test_and_set_bit(int nr, long* addr)

*将*addr 的第n位设置成1,并返回原来这一位的值

**/

static inline void tasklet_schedule(struct tasklet_struct *t)

{

if (!test_and_set_bit(TASKLET_STATE_SCHED, &t->state))

__tasklet_schedule(t);

}

/*将tasklet_struct提交到tasklet_vec*/

void __tasklet_schedule(struct tasklet_struct *t)

{

*__this_cpu_read(tasklet_vec.tail) = t;

__this_cpu_write(tasklet_vec.tail, &(t->next));

raise_softirq_irqoff(TASKLET_SOFTIRQ);

}

/*设置pending并唤醒ksoftirqd thread*/

inline void raise_softirq_irqoff(unsigned int nr)

{

__raise_softirq_irqoff(nr);

if (!in_interrupt())

wakeup_softirqd();

}

static void wakeup_softirqd(void)

{

/* Interrupts are disabled: no need to stop preemption */

struct task_struct *tsk = __this_cpu_read(ksoftirqd);

if (tsk && tsk->state != TASK_RUNNING)

wake_up_process(tsk);

}

何时调用do_softirq

/*

* Exit an interrupt context. Process softirqs if needed and possible:

*/

void irq_exit(void)

{

if (!in_interrupt() && local_softirq_pending())

invoke_softirq();

}

static inline void invoke_softirq(void)

{

if (!force_irqthreads)

do_softirq();

}

asmlinkage void do_softirq(void)

{

__u32 pending;

pending = local_softirq_pending();

if (pending)

__do_softirq();

}

__do_softirq唤醒kthread: ksoftirqd

在函数__do_softirq调用所有 pending 的action后,再次判断是否又有新的pending,

如果有则再次处理,但是这个过程最多循环MAX_SOFTIRQ_RESTART :10次。

如果还有则唤醒 进程: ksoftirqd

#define MAX_SOFTIRQ_RESTART 10

asmlinkage void __do_softirq(void)

{

struct softirq_action *h;

__u32 pending;

int max_restart = MAX_SOFTIRQ_RESTART;

int cpu;

pending = local_softirq_pending();

h = softirq_vec;

do {

if (pending & 1) {

unsigned int vec_nr = h - softirq_vec;

h->action(h);

}

h++;

pending >>= 1;

} while (pending);

pending = local_softirq_pending();

if (pending && --max_restart)

goto restart;

if (pending)

wakeup_softirqd();

}

总结:

刚看代码有点疑惑,还以为所有的action 都是 ksoftirqd处理的,其实不然,是在中断退出的时候调用的 __do_softirq,在该函数中满足某些条件的时候才调用 kthread.

当然,可以强制使用 kthread的 macro:#define force_irqthreads (0).
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: