第三十七期-ARM Linux内核的中断(7)

本文介绍了ARM Linux内核中的底半机制,包括中断的上半部分(硬中断)和下半部分(软中断)。软中断分为三种类型:软中断、小任务和工作队列,其中软中断处理流程涉及软中断注册表、raise_softirq()函数、__do_softirq()函数等关键步骤。文章还讨论了软中断线程化的情况和处理限制。
摘要由CSDN通过智能技术生成

作者:罗宇哲,中国科学院软件研究所智能软件研究中心

上一期中我们介绍了ARM Linux内核中与中断相关的常用函数,这一期我们将介绍ARM Linux内核中的底半机制。

一、ARM Linux内核中底半机制

Linux系统内核在处理中断时,为避免复杂的中断嵌套,通常采用关闭中断的策略,例如使用上一期中提到的local_irq_disable()和local_irq_save()函数。但是系统关闭中断的时间不能过长,这是因为用户敲击鼠标和键盘等外设中断的响应时间关系到用户体验。为了减少关闭中断的时间,Linux系统内核将中断的处理按重要性分为两个部分:上半部分和下半部分。

中断的上半部分又称为硬中断,Linux内核在关闭中断的情况下处理上半部分的工作,它包括中断中对响应时间要求较高或与硬件相关的部分;中断的下半部分则包括软中断(softirq)、小任务(tasklet)和工作队列(work queue)三种类型,Linux内核在开中断的情况下处理中断的下半部分。

三种类型的中断下半部分的区别如下表所示[1]:

是否可睡眠 是否要求可重入 是否可动态添加删除
软中断
小任务
工作队列

软中断和小任务的处理函数中不允许睡眠,而工作队列的处理函数运行在内核线程上,可以睡眠。可重入函数指该函数的不同副本可以由多个线程同时运行,该函数要么没有使用共享资源从而有相互分离的函数栈,要么使用锁保护了临界区中的共享资源。同一种软中断的处理函数可能会在多个处理器上执行,从而要求处理函数是可重入的。同一个小任务只能在一个处理器上执行,从而不要求函数是可重入的。在后文我们将看到,工作队列添加工作项时,将会把正在运行的工作留在原工作池,以保证任务的不可重入性。软中断的种类是在静态编译时确定的,因此不能动态添加和删除。而小任务和工作队列中的工作项都是可以动态添加和删除的。

二、ARM Linux内核中软中断的处理流程

软中断在中断的下半部分执行,可以被硬中断抢占。openEuler内核中定义了10种软中断,定义代码可以在openEuler源码仓库的openeuler/kernel/blob/kernel-4.19/include/linux/interrupt.h文件中可以找到[1,2]:

enum

{
   

HI_SOFTIRQ=0, /* 高优先级tasklet */

TIMER_SOFTIRQ, /* 时钟相关的软中断 */

NET_TX_SOFTIRQ, /* 网络栈发送报文的软中断 */

NET_RX_SOFTIRQ, /* 网络栈接收报文的软中断 */

BLOCK_SOFTIRQ, /* 块设备的软中断 */

IRQ_POLL_SOFTIRQ, /* 支持IO设备轮询的软中断 */

TASKLET_SOFTIRQ, /* 低优先级的tasklet */

SCHED_SOFTIRQ, /* 调度软中断,用于处理器间的负载均衡 */

HRTIMER_SOFTIRQ, /* 高精度定时器,未使用 */

RCU_SOFTIRQ, /* RCU软中断,该中断最好总是为最后一个软中断*/

NR_SOFTIRQS /* 软中断数,为10 */

};

枚举类型中软中断的编号也表现了它们的优先级,编号较小的软中断优先级较高。

与软中断相关的关键代码大部分都能在openEuler源码仓库的openeuler/kernel/blob/kernel-4.19/kernel/softirq.c 文件中找到,下面的源代码没有特别说明的部分都在softirq.c文件中可以找到。

软中断首先定义了软中断的注册表,用来记录软中断号和软中断处理函数的对应关系,它是一个softirq_action结构体的数组:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-NSKH3pim-1591269381858)(media/df4c095a00a4a21a78ed9bc234ff904a.png)]
softirq_action结构体的定义在openeuler/kernel/blob/kernel-4.19/include/linux/interrupt.h文件中:
在这里插入图片描述
成员action为指向软中断处理函数的函数指针。该函数指针的注册在open_softirq()函数中完成:
在这里插入图片描述
若要触发软中断号对应的软中断,可以调用raise_softirq()函数。
在这里插入图片描述
在已经禁止中断的场景下也可以直接调用raise_softirq_irqoff()函数。在中断处理程序的下半部分,通过调用函数irq_exit()退出中断上下文,并在需要且可能时处理该软中断:
在这里插入图片描述
该函数调用函数invoke_softirq()来处理软中断。invoke_softirq()函数首先判断软中断线程是否处于就绪或运行状态,如果是就调用软中断线程执行软中断[1]。没有强制中断线程化(force_irqthreads变量控制,详情见后文)时,根据是否定义了CONFIG_HAVE_IRQ_EXIT_ON_IRQ_STACK有两种情况:

  • 软中断运行在中断栈上,当中断没有复杂的嵌套时,中断处理程序的函数调用并不复杂,中断栈几乎是空的,因此软中断可以安全地运行,调用__do_softirq()函数;
  • irq_exit()函数是在当前任务栈上被调用的,当前任务可能会进行复杂的函数调用,因此这个栈可能已经非常深了,为了防止过载,就在软中断自己的栈上处理软中断,调用do_softirq_own_stack()函数;

如果强制中断线程化那么调用wakeup_softirqd()函数唤醒处理软中断的线程。

static inline 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值