linux软中断(linux中断处理流程)
Linux 中断( IRQ / softirq )基础:原理及内核实现
中断(IRQ),尤其是软中断(softirq)的广泛用途之一是网络数据包的接收与发送,但其应用场景并非单一。本文将全面整理中断(IRQ)与软中断(softirq)的基础知识,这些内容与网络数据包处理虽无直接联系,但整理本文旨在更深入地理解网络数据包处理机制。
什么是中断?
CPU通过时分复用处理多任务,其中包括硬件任务,如磁盘读写、键盘输入,以及软件任务,如网络数据包处理。CPU在任何时刻只能执行一个任务。当某个硬件或软件任务当前未被执行,但希望CPU立即处理时,会向CPU发送中断请求——希望CPU暂停手头工作,优先服务“我”。中断以事件形式通知CPU,因此常看到“在XX条件下会触发XX中断事件”的表述。
中断分为两类:
管理中断的设备:Advanced Programmable Interrupt Controller(APIC)。
硬中断的中断处理流程
中断随时发生,处理流程如下:
Maskable and non-maskable
Maskable interrupts在x64_64上可以通过sti/cli指令来屏蔽(关闭)和恢复:
在屏蔽期间,这种类型的中断不会触发新的中断事件。大部分IRQ都属于这种类型。例如,网卡的收发包硬件中断。
Non-maskable interrupts不可屏蔽,因此属于更高优先级的类型。
问题:执行速度与逻辑复杂性之间的矛盾
IRQ处理器的两个特点如下:
存在内在矛盾。
解决方式:中断的推迟处理(deferred interrupt handling)
传统解决方式是将中断处理分为两部分:
这种方式称为中断的推迟处理或延后处理。现在已是一个通用术语,涵盖各种推迟执行中断处理的方式。中断分为两部分处理:
在Linux中,有三种推迟中断(deferred interrupts):
具体细节将在后续介绍。
软中断与软中断子系统
软中断是内核子系统的一部分:
每个CPU上会初始化一个ksoftirqd内核线程,负责处理各种类型的softirq中断事件;
使用cgroup ls或ps-ef都能看到:
软中断事件的handler提前注册到softirq子系统,注册方式为open_softirq(softirq_id, handler)
例如,注册网卡收发包(RX/TX)软中断处理函数:
软中断占用了CPU的总开销:可以使用top查看,第三行倒数第二个指标是系统的软中断开销(si字段):
Linux内核源码分析学习地址:ke.qq.com/course/403254...
【文章福利】小编推荐自己的Linux内核源码分析交流群:【点击1095678385加入】整理了一些个人觉得比较好的学习书籍、视频资料共享在群文件里面,有需要的可以自行添加哦!
主处理
smpboot.c类似于事件驱动的循环,会调度ksoftirqd线程执行pending的软中断。ksoftirqd内部会进一步调用到__do_softirq,
避免软中断占用过多CPU
软中断的潜在影响:推迟执行的部分(如softirq)可能会占用较长时间,在这段时间内,用户空间线程只能等待。反映在top中,si占比。
不过softirq调度循环对此有所改进,通过budget机制来避免softirq占用过多CPU时间。
硬中断-软中断调用栈
softirq是一种推迟中断处理机制,将IRQ的大部分处理逻辑推迟在这里执行。有两条路径都会执行到softirq主处理逻辑__do_softirq():
1、CPU调度到ksoftirqd线程时,会执行到__do_softirq();
2、每次IRQ handler退出时:do_IRQ()->...
do_IRQ是内核中主要的IRQ处理方式。它执行结束时,会调用exiting_irq(),这会展开成irq_exit()。后者会检查是否pending有softirq,如果有,则唤醒:
进而会使CPU执行到__do_softirq。
软中断触发执行的步骤
总结,每个软中断会经过以下阶段:
以收包软中断为例,IRQ handler并不执行NAPI,只是触发它,在内部会执行到raiseNET_RX_SOFTIRQ;真正的执行在softirq,会调用网卡的poll()方法收包。IRQ handler中会调用napi_schedule(),然后启动NAPI poll()。
需要注意的是,虽然IRQ handler所做的工作很少,但处理这个包的softirq和IRQ在同一CPU上运行。这意味着,如果大量的包都放在同一个RX队列,虽然IRQ开销可能不多,但该CPU仍然会非常繁忙,都花费在softirq上。解决方式:RPS。它不会降低延迟,只是将包重新分配:RXQ->CPU。
三种推迟执行方式(softirq/tasklet/workqueue)
提到,Linux中的三种推迟中断执行方式:
其中:
前面已经看到,Linux在每个CPU上创建了一个ksoftirqd内核线程。
softirqs是在Linux内核编译时确定的,例如网络收包对应的NET_RX_SOFTIRQ软中断。因此是一种静态机制。如果想添加一种新softirq类型,需要修改并重新编译内核。
内部组织
内部由一个数组(或称为向量)管理,每个软中断号对应一个softirq handler。数组与注册:
在5.10中所有类型的softirq:
也就是在cat/proc/softirqs看到的哪些。
触发(唤醒)softirq
以收包软中断为例,IRQ handler并不执行NAPI,只是触发它,在内部会执行到raiseNET_RX_SOFTIRQ;真正的执行在softirq,会调用网卡的poll()方法收包。IRQ handler中会调用napi_schedule(),然后启动NAPI poll()。
如果对内核源码有一定了解,会发现softirq使用非常有限,原因之一是它是静态编译的,依赖内置的ksoftirqd线程来调度内置的9种softirq。如果想添加一种新功能,就得修改并重新编译内核,开发成本很高。
实际上,实现推迟执行的更常用方式是tasklet。它构建在softirq机制之上,具体来说就是使用了两种softirq:
换句话说,tasklet是在运行时(runtime)创建和初始化的softirq,
内核软中断子系统初始化了两个per-cpu变量:
tasklet再执行针对list的循环:
tasklet在内核中的使用非常广泛。不过,后面又出现了第三种方式:workqueue。
这也是一种推迟执行机制,与tasklet有些相似,但有显著不同。
使用场景
简而言之,workqueue子系统提供了一个接口,通过该接口可以创建内核线程来处理从其他地方enqueue过来的任务。这些内核线程称为worker threads,内置的per-cpu worker threads:
结构体
kworker线程调度workqueues,原理与ksoftirqd线程调度softirqs类似。然而,我们可以为workqueue创建新的线程,而softirq则不行。
参考资料引用链接
[1]
中断与中断处理:0xax.gitbooks.io/linux-...
作者:赵亚楠原文:arthurchiao.art/blog/li...来源:云原生实验室
linux内核中的软中断和threaded_irq(27)
软中断
软中断(Softirq)在Linux内核中是一种底半部处理机制,通常在顶半部返回时执行。软中断由softirq_action结构体表示,包含处理函数指针和参数。使用open_softirq()注册,raise_softirq()触发。软中断和tasklet运行于软中断上下文,属于原子上下文。工作队列运行于进程上下文,因此软中断和tasklet中禁止睡眠,而工作队列允许。
软中断执行的场景包括HI_SOFTIRQ、TIMER_SOFTIRQ、NET_TX_SOFTIRQ、NET_RX_SOFTIRQ、SCSI_SOFTIRQ、TASKLET_SOFTIRQ等。软中断与驱动编写无关,由内核自动管理。
软中断适度线程化,缓解高负载下的系统响应。内核会将大量软中断放入ksoftirqd线程执行。
硬中断、软中断、信号的区别:硬中断由外部设备触发,软中断是中断底半部处理机制,信号是内核或其他进程对进程的中断。软中断概念与通过软件指令引发的中断不同,后者与软中断不是一个概念。
threaded_irq
内核提供request_threaded_irq()和devm_request_threaded_irq()用于申请中断。这两个函数多了thread_fn参数,为中断号分配内核线程。中断上下文执行handler函数,内核线程执行thread_fn。如果handler结束时返回IRQ_WAKE_THREAD,内核调度thread_fn执行。支持IRQF_ONESHOT标记,自动屏蔽中断,避免中断服务程序退出后的中断洪泛。
handler参数可设为NULL,由内核使用默认处理函数和IRQF_ONESHOT标记。IRQF_ONESHOT在无法在上半部清除中断时特别有用。
GPIO按键中断
GPIO按键驱动通过request_any_context_irq()或devm_request_any_context_irq()申请中断,根据GPIO控制器的中断类型决定使用request_irq()或request_threaded_irq()。每个GPIO可能对应多个中断号,但共享一个中断控制器。
在GPIO按键驱动中,中断处理较为简单,不存在顶半部和底半部的明确划分。初始化时,通过INIT_WORK(&bdata->work,gpio_keys_gpio_work_func)初始化工作队列,用于处理按键事件。事件处理函数通过container_of()解析出对应的GPIO键数据结构。
Linux 内核网络中的软中断有什么作用
深入理解 Linux内核网络中的软中断机制:关键作用与实现
在Linux内核的复杂网络世界中,软中断(Soft Interrupts)作为关键的组件,扮演着不可或缺的角色。它们旨在优化中断处理流程,确保高效地响应网络事件,尤其是数据发送和接收。本文将详细探讨软中断的作用、实现方式以及与tasklet和工作队列的比较。
Linux内核的中断框架分为上半部和下半部,其核心在于提升中断处理效率。上半部中断处理函数迅速响应,保证了中断处理的实时性,而下半部则用于处理耗时较长的任务,避免中断处理被阻塞。当处理对时间敏感或与硬件紧密相关的任务时,上半部是首选;而其他情况,如需要睡眠或重新调度的工作,下半部则可以选择软中断或tasklet。
软中断,作为下半部处理的关键手段,通过内核的softirq_action结构体实现。Linux内核定义了10个软中断,如网络数据发送(NET_TX_SOFTIRQ)和接收(NET_RX_SOFTIRQ)等,这些中断通过open_softirq注册处理函数,并通过raise_softirq触发。为了保证中断处理的稳定性,软中断需要在编译时静态注册,通过softirq_init完成。
相比之下,tasklet是一种更高级的软中断实现,它利用软中断机制,通过tasklet_struct结构体来管理。tasklet允许在中断处理函数中通过tasklet_schedule调度,确保在合适的时间执行。tasklet相比软中断,更便于管理任务的执行,尤其是需要睡眠或重新调度的场景。
工作队列则是另一种在进程上下文中执行的工作调度机制,它将任务交给内核线程处理,支持睡眠和重新调度。如果工作需要这些特性,工作队列是理想的选择。例如,使用work_struct结构体定义工作,初始化后在中断处理函数中通过schedule_work调度。
总结来说,Linux内核网络中的软中断机制是确保高效处理网络事件的关键,通过灵活的上半部中断和下半部的软中断、tasklet和工作队列,内核能够优化中断响应,提升系统的整体性能和稳定性。理解这些机制对于深入开发网络驱动和优化系统性能至关重要。