soft irq and tasklet


创建 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).


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值