Skip to content

Latest commit

 

History

History
78 lines (66 loc) · 3.38 KB

2014-05-09-soft-irq-daemon-ksoftirqd.md

File metadata and controls

78 lines (66 loc) · 3.38 KB
layout title category description tags
post
软中断守护进程
中断和异常
软中断守护进程...
软中断 ksoftirqd

我们知道如果不在中断上下文中调用raise_softirq方法,则调用wakeup_softirq来唤醒软中断守护进程,这个守护进程会执行软中断。软中断的守护进程的任务是,与其余内核代码异步执行软中断,为此,系统中每个处理分配器都有自己的守护进程,名为ksoftirqd

内核中有两处调用了wakeup_softirq唤醒了该守护进程。

  1. do_softirq中。
  2. 在raise_softirq_irqoff末尾。

raise_softirq_irqoff函数由raise_softirq在内部调用,如果内核当前停用了中断,也可以直接使用。唤醒函数本身只需要几行代码,首先,借助于一些宏,从一个per-CPU变量读取指向当前CPU软中断守护进程的task_struct的指针。如果该进程当前的状态不是TASK_RUNNING的话,则通过wake_up_process将其置放到就绪进程列表的末尾。

尽管这并不会立即开始处理所有待决的软中断。但只要调度器没有更好的选择,就会选择用该守护进来执行。在系统启动时用initcall机制调用init不就,就创建了系统的软中断守护进程。代码如下:

<kernel/softirq.h>

{% highlight c++ %} static int ksoftirqd(void * __bind_cpu) { set_current_state(TASK_INTERRUPTIBLE);

current->flags |= PF_KSOFTIRQD;
while (!kthread_should_stop()) {
    // 禁止抢占
    preempt_disable();
    if (!local_softirq_pending()) {
        preempt_enable_no_resched();
        schedule();
        preempt_disable();
    }

    __set_current_state(TASK_RUNNING);

    while (local_softirq_pending()) {
        /*
           禁止抢占会停止让CPU下线,如果已经下线,那么就
           正在一个错误的CPU上,那么就不要执行
           goto wait_to_die
        */
        if (cpu_is_offline((long)__bind_cpu))
            goto wait_to_die;
        // 执行软中断
        do_softirq();
        // 可以抢占
        preempt_enable_no_resched();
        // 确保对当前进程设置了TIE_NEED_RESCHED
        // 因为所有这些函数执行时都启用了硬件中断
        cond_resched();
        // 禁止抢占
        preempt_disable();
        rcu_sched_qs((long)__bind_cpu);
    }
    preempt_enable();
    set_current_state(TASK_INTERRUPTIBLE);
}
__set_current_state(TASK_RUNNING);
return 0;

wait_to_die: preempt_enable(); /* 等待kthread_stop停止 */ set_current_state(TASK_INTERRUPTIBLE); while (!kthread_should_stop()) { schedule(); set_current_state(TASK_INTERRUPTIBLE); } __set_current_state(TASK_RUNNING); return 0; } {% endhighlight %}

每次被唤醒时,守护进程首先检查是否有标记出的待决软中断,否则明确地调用调度器,将控制软中断交给其他进程。如果有标记出的软中断,那么守护进程接下来将处理软中断。

进程在一个while循环中重复调用do_softirqcond_resched,直至没有标记出的软中断位置。con_resched确保在对当前进程设置了TIE_NEED_RESCHED标志的情况下调用调度器,这是可能的,因为所有这些函数执行时都启用了硬件中断。