Linux内核软中断线程对于通用内核线程的启示

Linux 2.6.11版本的内核软中断线程ksoftirqd代码如下,下面框架可以看出对于,吞吐量与处理延迟两者之间的权衡。

软中断线程处理概括:

1、如果没有活干(没有软中断等待处理)就 schedule()切出,并从运行队列里面删除(由于任务状态已经变成TASK_INTERRUPTIBLE)

2、如果有活儿干,就把当前pending的软中断处理完,处理过程中检查如果本线程运行时间过长,则 schedule()切出(cond_resched()完成这一切),避免其他线程饿死。但切出时任务状态是TASK_RUNNING,不会移出运行队列(线程还有活儿没干完,得赶紧回来),由于移出前,关闭了内核抢占,很快就会重新调度到本线程的。

3、系统调度让其他进程运行一段时间后,本进程重新切换回来运行,重复第2步,一直到该处理得软中断处理完

4、一批软中断处理完后,设置任务状态是TASK_INTERRUPTIBLE,为无软新的软中断过来时切出去并移出运行队列准备。

假如:一次来了8个软中断要处理,需要连续处理完8个软中断,期间可以会切出;如果处理完这组最后一个软中断后正好切出(调用 cond_resched()时里面检查时间片到),然后一段时间后切换回来,发现切出的这段时间有新的软中断等待处理,则有继续处理。

static int ksoftirqd (void * __bind_cpu)
{
    set_user_nice(current, 19);             <---软中断线程按照优先级最低运行
    current->flags |= PF_NOFREEZE;

set_current_state(TASK_INTERRUPTIBLE);   <---进入主循环前,先设置任务状态为TASK_INTERRUPTIBLE

while (!kthread_should_stop()) {               <---这个while循环内部处理时,线程可以切出,但仍处与运行队列
        if (!local_softirq_pending())                     <---如果不存在需要处理的软中断,则线程切出并移出运行队列
            schedule();

__set_current_state(TASK_RUNNING);   <---如果有活儿干,则恢复线程的状态为TASK_RUNNING

while (local_softirq_pending()) {            <---这个循环是干活的主循环
            preempt_disable();                              <---关闭内核抢占,目的是为了保证能连续处理完pending的软中断
            if (cpu_is_offline((long)__bind_cpu))
                goto wait_to_die;
            do_softirq();                                       <---处理软中断(转发、报文收发处理)
            preempt_enable();
            cond_resched();                                 <---运行“指定时间片”后本线程强行切出,切出时任务状态还是TASK_RUNNING
        }

set_current_state(TASK_INTERRUPTIBLE);   <---设置任务状态为TASK_INTERRUPTIBLE,为重新循环开始时,发现如果没活儿干任务切出,并移出运行队列准备
    }
    __set_current_state(TASK_RUNNING);
    return 0;

wait_to_die:   <---出错的时候才会走入这个处理
    preempt_enable();
    set_current_state(TASK_INTERRUPTIBLE);
    while (!kthread_should_stop()) {
        schedule();
        set_current_state(TASK_INTERRUPTIBLE);
    }
    __set_current_state(TASK_RUNNING);
    return 0;
}

int __sched cond_resched (void)
{
    if (need_resched()) {
        __cond_resched();
        return 1;
    }
    return 0;
}

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/24287.html