关闭 x
IT技术网
    技 采 号
    ITJS.cn - 技术改变世界
    • 实用工具
    • 菜鸟教程
    IT采购网 中国存储网 科技号 CIO智库

    IT技术网

    IT采购网
    • 首页
    • 行业资讯
    • 系统运维
      • 操作系统
        • Windows
        • Linux
        • Mac OS
      • 数据库
        • MySQL
        • Oracle
        • SQL Server
      • 网站建设
    • 人工智能
    • 半导体芯片
    • 笔记本电脑
    • 智能手机
    • 智能汽车
    • 编程语言
    IT技术网 - ITJS.CN
    首页 » HTML5 »Linux 内核的软中断深入解析

    Linux 内核的软中断深入解析

    2015-05-12 00:00:00 出处:linux.cn
    分享

    软中断介绍

    把可以延迟的处理从硬中断处理程序独立出来,这样这个处理可以在开中断的情况下运行,这个处理就是软中断。可见,软中断的这种脱离可以大大缩短硬中断的响应时间,对于很多实时应用来说及其重要。

    我们本文只谈软中断,至于tasklet、workqueue等我们以后再谈。我们在讲述软中断流程(参考linux kernel 4.0)时会尝试深入理解其中的各个细节之处,分享我们自己的理解(假如不正,还望指出,谢谢)。

    理解 linux 内核的软中断

    (题图来自:techvark.com)

    软中断数据结构的定义

    软中断目前有10(由NR_SOFTIRQS定义)个,通过softirq_vec[NR_SOFTIRQS]数组来管理这些软中断,全部cpu共用。

    软中断的注册

    通过open_softirq()将具体的软中断处理函数和软中断编号绑定。如网络系统注册了收发包的软中断处理函数:

    open_softirq(NET_TX_SOFTIRQ, net_tx_action);
    open_softirq(NET_RX_SOFTIRQ, net_rx_action);

    软中断的激活

    每个cpu都有一个32bit的位图(即__softirq_pending)来维护本cpu上的软中断是否激活。

    typedef struct {
        unsigned int __softirq_pending;
        #ifdef CONFIG_SMP
        unsigned int ipi_irqs[NR_IPI];
        #endif
    } ____cacheline_aligned irq_cpustat_
    
    irq_cpustat_t irq_stat[NR_CPUS] ____cacheline_aligned;

    软中断的激活时机之一:irq_exit

    irq_exit函数里可能会激活软中断,激活条件是:

    不在硬中断里并且不在软中断里并且本cpu的__softirq_pending中有置位。

    if (!in_interrupt() && local_softirq_pending())
        invoke_softirq();

    由这个条件,我们可以知道,软中断和硬中断在这里是同等对待(在in_interrupt里)的,体现都是中断处理这一个本质。不能在硬中断里的条件,表明必须优先性,必须硬中断全部处理完,才考虑软中断;不能在软中断里的条件,表明屏蔽了软中断的嵌套。

    invoke_softirq函数的处理是,要么(先唤醒ksoftirqd)将软中断交由ksoftirqd专门线程处理,要么直接调用__do_softirq即时处理(当然,即时处理要区分是在哪个栈上:是当前栈上还是在独立的软中断栈上)。

    我们看看即时处理这个流程。local_softirq_pending前肯定会清除preempt_count中的硬中断位,假如此时preempt_count里没有软中断位则可以被抢占(即时关闭硬中断)。在进入到__do_softirq处理各个软中断期间,肯定是禁止抢占了。在硬(软)中断上下文里的抢占是众所周知不被允许的:会让被中断的进程执行时间不确定,也是不公平的(也就是说,不要在硬中断和软中断的处理中有调度离开的意向)。

    软中断的激活时机之二:raise_softirq

    网卡收包方式从非NAPI进化到NAPI方式,就充分展示了软中断的优点:把收报任务最大程度地交给软中断处理,最大程度简化硬中断处理。这种进化,我们以后再讲。

    raise_softirq函数会调用__raise_softirq_irqoff函数,在指定cpu的__softirq_pending位图上置位相应的软中断。raise_softirq_irqoff函数和raise_softirq函数的区别是关中断的操作是否已经完成了。置位位图是一个竞争操作,所有硬中断里都可能做,所以得保证在关中断的情况下完成。

    软中断的激活之三:ksoftirqd

    每个cpu都有一个ksoftirqd线程在软中断量大时专门处理软中断:

    DEFINE_PER_CPU(struct task_struct *, ksoftirqd);

    ksoftirqd线程的核心函数run_ksoftirqd的(循环)处理是:关中断看本cpu的__softirq_pending的置位情况,如有则执行__do_softirqd(),执行完开中断)。这个执行很顺畅,因为是在该线程自己的栈上,不会有影响用户进程的问题。

    这里有个疑问,此处以前是关抢占保护,现在是关中断的保护了(参考2012年的patch 3e339b,softirq: Use hotplugthread infrastructure)?我们的理解是:关抢占的保护方式,会让后续更多的软中断由ksoftirqd处理,不符合ksoftirqd的辅助地位。就处理软中断的地位而言,应该是irq_exit的为主,ksoftirqd的为辅。)

    ksoftirqd里也可以看到,在执行软中断前是可以被抢占的,但是一旦开始执行就不能被抢占了(和上面的调度之一:irq_exit中的讲述的思想是一致的)。就是说,软中断和硬中断的处理思想是一致的:执行期间不允许发生调度!

    上述不能抢占的原因其实就是类似事务性的一个原则:一旦开始不能停止。另外一个原因是,执行的是用户自定义的硬(软)中断程序,操作具有不确定性,假如让这些操作期间具有调度可能,则会脱离内核的控制范围。

    软中断的激活之四:其他地方

    比如netif_rx_ni(),执行do_softirq前关抢占,不能在执行软中断期间调度。

    软中断的激活之五:local_bh_enable

    if (unlikely(!in_interrupt() && local_softirq_pending()))
        do_softirq();

    想想,假如异常和软中断有共享数据的话,异常处理走到此共享数据的临界区时需要关软中断,但不需要关硬中断。那么当走完临界区时,需要开软中断,此时就是一个激活时机(看preempt_count了,其实可能也是一个抢占时机)。

    用“激活”而不是“调用”的原因是外围处理仅修改本cpu的__softirq_pending位图,最后由核心机制(比如ksoftirqd、能通过in_interrupt检查的软中断处理)真正处理,而这就是软中断的理念:让硬中断(或者其它)更快执行,所以不会采用直接调用的方式。

    “激活”的原则是谁激活,谁处理,哪个cpu上的硬中断带来的软中断就由哪个cpu处理(或者说,归属cpu是软中断跟着硬中断走)。这样,充分发挥smp的优势,均衡到各个cpu上。至于硬中断和cpu之间的关系,我们以后讲到硬中断时再讨论。每个cpu维护自己的软中断机制就行了,各个cpu是互不相关的。注意,还是有相关性的:各个cpu并行处理同一类型的软中断时,该类型软中断处理需要为共享数据做保护,这是软中断可重入性需要付出的代价。

    软中断核心函数处理之do_softirq

    do_softirq先检查软中断重入条件:必须不在硬中断里并且不在软中断里,符合条件之后就可以开始做如下的软中断处理了:

    pending = local_softirq_pending();
    if (pending)
        __do_softirq();

    这个处理是在关中断的保护下完成的,毕竟软中断和硬中断本质上是一样的,都是中断体系的(当然,进入到硬/软中断内部再开则另当别论了)。也可以看到,局部变量pending没有传入__do_softirq内部,所以此处仅是判断,不是使用,此处判断值和内部使用值可能有差异,位图中置位位数会少一些。

    我们再深究一下这个检查条件。我们的理解是:

    这个条件达到了两个效果:同一个cpu上的软中断不嵌套;嵌套硬中断中不处理软中断。就同一个cpu而言,__do_softirq函数的执行是串行的,非重入的(do_softirq函数可以说是可重入的);就多个cpu而言,__do_softirq函数是可重入的,即使是同一个类型的软中断。也就是说,软中断通过这个检查条件做到了本cpu上的软中断处理串行化,当然,多cpu之间的还是并行的,所以同一类型软中断处理还是需要保护自己的相关共享数据结构的。

    软中断核心函数处理之__do_softirq

    __do_softirq函数处理是尽量(虽然可能还是执行不完)执行所有被激活的软中断(由本cpu上的__softirq_pending位图标识)处理。我们分三个阶段分析。

    准备处理阶段:关闭软中断(效果是让上面提到的检查条件为真,从而达到禁止本cpu上的软中断嵌套的目的)。

    核心处理阶段:关硬中断,获得本cpu的__softirq_pending位图并存储起来,清空位图,开硬中断(仅在读写位图时需要关硬中断,防止其它硬中断同时操作)。执行本cpu的所有软中断(由存储起来的位图获得)。这个核心处理是个循环,最多10次(MAX_SOFTIRQ_RESTART),毕竟此时用的是用户进程的栈,不能借用太久。退出循环的条件是:总时间超出或者被抢占(开中断就会有被抢占)或者达到10次了。

    结尾处理阶段:关硬中断,开软中断。

    另外,假如10次循环都解决不完软中断,说明期间发生的硬中断很多,带来的额外的软中断也很多。那么就不继续影响借用的用户进程栈了,直接交给专门的ksoftirqd内核线程处理。这也就说明了循环的含义:处理软中断期间时还会进入新的硬中断,从而带进新的软中断(当然,仅仅是在本cpu的__softirq_pending上置位,不会有实际处理),所以需要反复去处理(处理的目标很明确,就是要清空本cpu上的__softirq_pending位图)。

    再看看那个防止软中断嵌套的流程。关软中断中肯定有一句原子地加1的关键语句,假如当前内核路径A在该原子操作之前被另一个内核路径B打断,则B执行完硬中断和软中断后,返回到A的此处,A接着执行该原子操作,之后的软中断处理应该是空转,因为肯定已经被B处理完了。假如在该原子操作之后被B打断,则B执行完硬中断,不会执行自己的软中断而是会直接退出(因为软中断嵌套了),返回到A的此处,A接着执行,这次A除了处理自己软中断,还会额外地处理B的软中断。

    对于preempt_count中的软中断位,由上述可以知道,它的作用有两个:防止软中断在单cpu上嵌套;保证了在执行软中断期间不被抢占。

    最后,还得重复一句:这里讲的__do_softirq函数都是在一个cpu上的处理,多个cpu上的并行是不受任何控制的。

    总结

    关于中断的时序貌似很复杂,但其实都逃不过两个原则:硬中断会打断硬中断(当然是不同类型的);硬中断会打断软中断(同样地:软中断不会打断硬中断,软中断也不会打断软中断)。所有貌似复杂的时序其实都只是这两个的叠加而已。

    上一篇返回首页 下一篇

    声明: 此文观点不代表本站立场;转载务必保留本文链接;版权疑问请联系我们。

    别人在看

    帝国CMS7.5编辑器上传图片取消宽高的三种方法

    帝国cms如何自动生成缩略图的实现方法

    Windows 12即将到来,将彻底改变人机交互

    帝国CMS 7.5忘记登陆账号密码怎么办?可以phpmyadmin中重置管理员密码

    帝国CMS 7.5 后台编辑器换行,修改回车键br换行为p标签

    Windows 11 版本与 Windows 10比较,新功能一览

    Windows 11激活产品密钥收集及专业版激活方法

    如何从 Windows 11 中完全删除/卸载 OneNote?无解!

    抖音安全与信任开放日:揭秘推荐算法,告别单一标签依赖

    ultraedit编辑器打开文件时,总是提示是否转换为DOS格式,如何关闭?

    IT头条

    华为Pura80系列新机预热,余承东力赞其复杂光线下的视频拍摄实力

    01:28

    阿里千问3开源首战告捷:全球下载破千万,国产AI模型崛起新高度!

    01:22

    DeepSeek R1小版本试升级:网友实测编程能力已达到国际一线水平

    23:15

    NVIDIA 与 Dell 合作,大规模交付 Blackwell AI 系统

    20:52

    Cerebras 以最快的 Llama 4 Maverick 性能引领 LLM 推理竞赛

    20:51

    技术热点

    PHP中的随机性——你觉得自己幸运吗?

    搞定Ubuntu Linux下WPA无线上网

    Java使用内存映射实现大文件的上传

    MySQL安全性指南

    MySQL两项性能的基本测试浅谈

    教您使用UniqueIdentifier选取SQL Server主键

      友情链接:
    • IT采购网
    • 科技号
    • 中国存储网
    • 存储网
    • 半导体联盟
    • 医疗软件网
    • 软件中国
    • ITbrand
    • 采购中国
    • CIO智库
    • 考研题库
    • 法务网
    • AI工具网
    • 电子芯片网
    • 安全库
    • 隐私保护
    • 版权申明
    • 联系我们
    IT技术网 版权所有 © 2020-2025,京ICP备14047533号-20,Power by OK设计网

    在上方输入关键词后,回车键 开始搜索。Esc键 取消该搜索窗口。