linux 软中断入门

在 linux 中,任务执行的载体有很多,包括线程,中断,软中断,tasklet,定时器等。但是从本质上来划分的话,任务执行的载体只有两个:线程和中断。软中断和 tasklet 的执行可能在中断中,也可能在线程中,定时器的执行可能在中断、软中断或者线程中。

在讨论中断和软中断的时候,经常以网卡收包为例子来理解。如下是网卡收包的主要环节,分别说明每个环节:

① 网卡从链路上收包,网卡的作用是成帧,网卡在链路上收到的是字节流,根据前导码,帧开始界定符,帧间隙来界定一个帧,这就是成帧。

② 网卡界定一帧报文之后,将这一帧报文通过 dma 保存到内存中。

③ 网卡触发中断,收包中断有对应的处理程序,对于现在的大多网卡来说,在中断处理程序中做的事情是触发收包软中断。

④ 收包的主要工作是在软中断中处理,而不是在硬中断中处理。

中断是硬件和软件进行通信的一种方式。中断具有异步,响应快的特点。在 linux 中,中断可以打断当前正在运行的程序,并且在处理一个中断的时候,往往需要关闭本地中断。

在网络收包的过程中,从网卡驱动,到链路层代码,再到 ip 层,tcp 层,报文的处理过程比较长,所需要花费的时间往往是比较长的。如果在中断处理程序中把收包的工作都做了,那么很可能会导致本地关中断时间太长,进而影响系统的响应。所以在网卡收包时,往往采用中断和软中断结合的方式,在中断处理程序中做的工作比较简单,只是触发一个软中断,后边的处理过程在软中断中进行。中断处理程序中触发软中断之后立即返回,此时,就可以打开本地中断了。

软中断处理函数是 __do_softirq(),从这个函数中也可以看出来,在处理软中断之前调用函数 local_irq_enable(),也就说在处理软中断的时候,是开中断的。

asmlinkage __visible void __softirq_entry __do_softirq(void)
{...local_irq_enable();h = softirq_vec;while ((softirq_bit = ffs(pending))) {unsigned int vec_nr;int prev_count;h += softirq_bit - 1;vec_nr = h - softirq_vec;prev_count = preempt_count();kstat_incr_softirqs_this_cpu(vec_nr);trace_softirq_entry(vec_nr);h->action(h);trace_softirq_exit(vec_nr);if (unlikely(prev_count != preempt_count())) {pr_err("huh, entered softirq %u %s %p with preempt_count %08x, exited with %08x?\n",vec_nr, softirq_to_name[vec_nr], h->action,prev_count, preempt_count());preempt_count_set(prev_count);}h++;pending >>= softirq_bit;}if (__this_cpu_read(ksoftirqd) == current)rcu_softirq_qs();local_irq_disable();...
}

1 软中断种类

如下是软中断的种类,当前定义了 10 种软中断,其中 NET_TX_SOFTIRQ 和 NET_RX_SOFTIRQ  用于网卡发包和收包。从定义可以看出来,软中断的种类是静态的,确定的,不能动态改变。从注释可以看出来,不到万不得已,不要新增软中断,大部分情况下使用 tasklet 已经足够了。

/* PLEASE, avoid to allocate new softirqs, if you need not _really_ highfrequency threaded job scheduling. For almost all the purposestasklets are more than enough. F.e. all serial device BHs etal. should be converted to tasklets, not to softirqs.*/enum
{HI_SOFTIRQ=0,TIMER_SOFTIRQ,NET_TX_SOFTIRQ,NET_RX_SOFTIRQ,BLOCK_SOFTIRQ,IRQ_POLL_SOFTIRQ,TASKLET_SOFTIRQ,SCHED_SOFTIRQ,HRTIMER_SOFTIRQ,RCU_SOFTIRQ,    /* Preferable RCU should always be the last softirq */NR_SOFTIRQS
};

 

2 开启软中断和触发软中断

以网卡软中断为例来说明。

通过函数 open_softirq() 来打开软中断,也叫注册这个软中断,在内核初始化的时候会调用函数 net_dev_init() 完成网络相关的初始化,在该函数中打开了网络收发包软中断。

static int __init net_dev_init(void)
{...open_softirq(NET_TX_SOFTIRQ, net_tx_action);open_softirq(NET_RX_SOFTIRQ, net_rx_action);...
}

软中断使用一个数组来维护,数组是 softirq_vec,数组的下标是软中断的中断号,数组的元素struct softirq_action 类型,这个结构体中只有一个成员,就是软中断的处理函数。网卡发包和收包软中断的处理函数分别是 net_tx_action 和 net_rx_action。

struct softirq_action
{void	(*action)(struct softirq_action *);
};static struct softirq_action softirq_vec[NR_SOFTIRQS] __cacheline_aligned_in_smp;

在网卡中断处理程序中,一般会调用函数 __raise_softirq_irqoff() 触发软中断。触发软中断就是在一个全局的变量中设置一个标志,标志有软中断了。在 linux 中,这个全局变量是 per cpu 的。

void __raise_softirq_irqoff(unsigned int nr)
{lockdep_assert_irqs_disabled();trace_softirq_raise(nr);or_softirq_pending(1UL << nr);
}

3 处理软中断

3.1 中断返回时

中断返回时,最终会调用到函数 __irq_exit_rcu(),在这个函数中会进行判断,如果当前不是处于中断上下文并且有软中断需要处理,那么就会调用 invoke_softirq() 来处理软中断。

static inline void __irq_exit_rcu(void)
{
#ifndef __ARCH_IRQ_EXIT_IRQS_DISABLEDlocal_irq_disable();
#elselockdep_assert_irqs_disabled();
#endifaccount_irq_exit_time(current);preempt_count_sub(HARDIRQ_OFFSET);if (!in_interrupt() && local_softirq_pending())invoke_softirq();tick_irq_exit();
}

在函数 invoke_softirq() 中进行判断,如果软中断处理线程当前正在运行,那么直接返回。如果 force_irqthreads 是 false 的话,那么就调用 __do_softirq() 或者 do_softirq_onwn_stack() 处理软中断;如果强制让软中断处理线程来处理软中断,那么意思是在中断返回的时候不处理软中断,会将线程唤醒。

static inline void invoke_softirq(void)
{if (ksoftirqd_running(local_softirq_pending()))return; if (!force_irqthreads) {
#ifdef CONFIG_HAVE_IRQ_EXIT_ON_IRQ_STACK/** We can safely execute softirq on the current stack if* it is the irq stack, because it should be near empty* at this stage.*/__do_softirq();
#else/** Otherwise, irq_exit() is called on the task stack that can* be potentially deep already. So call softirq in its own stack* to prevent from any overrun.*/do_softirq_own_stack();
#endif} else {wakeup_softirqd();}
}

3.2 ksoftirqd

除了在中断返回的时候处理软中断,还有专门的线程来处理。在内核中,每个 cpu 核上都会创建一个 ksoftirqd 线程用来处理这个核上的软中断。

ksoftirqd 的信息维护在 softirq_threads 中。

static struct smp_hotplug_thread softirq_threads = {.store            = &ksoftirqd,.thread_should_run    = ksoftirqd_should_run,.thread_fn        = run_ksoftirqd,.thread_comm        = "ksoftirqd/%u",
};

 

在 ksoftirqd 中,最终也是调用函数 __do_softirq() 来处理软中断。

static void run_ksoftirqd(unsigned int cpu)
{local_irq_disable();if (local_softirq_pending()) {/** We can safely run softirq on inline stack, as we are not deep* in the task stack here.*/__do_softirq();local_irq_enable();cond_resched();return;}local_irq_enable();
}

什么时候在中断返回时处理软中断 ?

中断返回时会进行判断,如果当前不是处于中断上下文,并且有软中断需要处理,并且这个时候 ksofrirqd 没有在运行,那么这个时候就会处理软中断。

什么时候在 ksoftirqd 中处理软中断 ?

① 中断返回的时候, 判断 force_irqthreads 为 true,那么只能在 ksoftirqd 中处理软中断,这个时候会通过 wakeup_softirqd() 来唤醒 ksoftirqd。

② 使用 raise_softirq_irqoff() 触发软中断时,如果当前不是处于中断上下文,也会唤醒 ksoftirqd

inline void raise_softirq_irqoff(unsigned int nr)
{__raise_softirq_irqoff(nr);/** If we're in an interrupt or softirq, we're done* (this also catches softirq-disabled code). We will* actually run the softirq once we return from* the irq or softirq.** Otherwise we wake up ksoftirqd to make sure we* schedule the softirq soon.*/if (!in_interrupt())wakeup_softirqd();
}

4 软中断处理时为什么不能睡眠

软中断的处理,可能在中断返回的时候,也可能在 ksoftirq 线程中。在中断返回的时候,虽然通过 in_interrupt() 判断,当前不是处于中断上下文,但是这个时候中断处理程序还没有真正返回,还不是进程上下文,所以此时也是不能睡眠。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/784172.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

DevSecOps安全工具链介绍

目录 一、概述 二、安全工具链在平台中的定位 2.1 概述 2.2 分层定位 2.2.1 不同阶段的安全工具 2.2.2 安全工具金字塔 2.3 安全流水线集成概览 2.3.1 概述 2.3.2 标准流水线集成安全工具链概览图 三、安全工具链分类 3.1 概述 3.2 威胁建模类 3.2.1 威胁建模的概念…

计算机网络:数据链路层 - 封装成帧 透明传输 差错检测

计算机网络&#xff1a;数据链路层 - 封装成帧 & 透明传输 & 差错检测 数据链路层概述封装成帧透明传输差错检测 数据链路层概述 从数据链路层来看&#xff0c;主机 H1 到 H2 的通信可以看成是在四段不同的链路上的通信组成的&#xff0c;所谓链路就是从一个节点到相邻…

Android设备无线连接电脑及QXDM、QACT等工具的方法

首先样机和笔记本电脑连接同一wifi网络 adb root adb shell ifconfig复制inet addr地址 ping inet addr地址 adb tcpip 5555 adb connect (inet addr地址):5555 此时adb和机器使用wifi连接好了&#xff0c;可以拔出usb线 ipconfig查询电脑的IP地址 ipconfig使用adb在主机上…

canvas+javascript 实现贪吃蛇游戏

引言 在当今数字化时代&#xff0c;编程已经成为一种极具创造力和趣味性的活动。通过编写代码&#xff0c;我们可以创造出各种各样的应用程序和游戏&#xff0c;其中包括经典的贪吃蛇游戏。本文将向您介绍如何使用 JavaScript 编程语言制作一个简单而有趣的贪吃蛇游戏&#xf…

动态内存管理-错题合集讲解

空指针的解应用操作&#xff08;错误信息合集&#xff09; 越界访问 首先我们上一个代码&#xff0c;看看这个的代码的问题 这个代码的问题显而易见 &#xff0c;就是在循环里面&#xff0c;产生了越界访问的问题&#xff0c;这里你开辟了10个整形空间&#xff0c;但是从0-1…

【javaWeb 第九篇】功能接口开发流程以及常用注解

常用注解 准备-环境搭建开发规范开发流程 注解补充 准备-环境搭建 准备数据库表&#xff08;dept,emp&#xff09;准备后端SpringBoot环境 需要依赖&#xff1a; Web起步依赖&#xff0c;数据库驱动依赖&#xff0c;Mybatis依赖&#xff0c;lombok依赖配置文件application.pr…

9.Python类与对象

1 面向对象 类和对象都是面向对象中的重要概念。面向对象是一种编程思想&#xff0c; 即按照真实世界的思维方式构建软件系统。 例如&#xff0c;在真实世界的校园里有学生和老师&#xff0c;学生有学号、姓名、所 在班级等属性&#xff08;数据&#xff09;&#xff0c;还有…

MySQL核心命令详解与实战,一文掌握MySQL使用

文章目录 文章简介演示库表创建数据库表选择数据库删除数据库创建表删除表向表中插入数据更新数据删除数据查询数据WHERE 操作符聚合函数LIKE 子句分组 GROUP BY HAVINGORDER BY(排序) 语句LIMIT 操作符 分页查询多表查询-联合查询 UNION 操作符多表查询-连接的使用-JOIN语句编…

本地GPU调用失败问题解决3重新配置anaconda环境(成功)

1、右键“以管理员身份”打开anaconda prompt conda create -n python 3.9 2、使用官方下载源的配置 3、修改conda下载超时 conda config --set remote_connect_timeout_secs 60 conda config --set remote_read_timeout_secs 100 查看配置结果conda config --show 配置内…

122、内网安全——域信息收集应用网络凭据CS插件AdfindBloodHound

文章目录 理解域域信息搜集 理解域 假设有1000台计算机&#xff0c;运维人员需要为每一台计算机进行软件的安装、环境部署&#xff0c;实际上运维人员不可能亲自对每一台计算机进行软件的安装和环境部署。实际&#xff0c;将所有1000台计算机放入一个域中&#xff0c;域内有一…

多传感器标定——相机内参标定

文章目录 一、前言二、内参标定流程三、如何提升标定精度四、精度验证五、内外参联合标定 一、前言 之前写过一篇文章&#xff08;相机内参、外参、畸变系数简介&#xff09;&#xff0c;感觉应该把这几个东西说的还算明白&#xff0c;但是里边并没有深究该如何进行标定&#…

牛客NC153 信封嵌套问题【中等 动态规划,最长递增子序列 Java,Go,PHP】

题目 题目链接&#xff1a; https://www.nowcoder.com/practice/9bf77b5b018d4d24951c9a7edb40408f 相同的题目&#xff1a; https://www.lintcode.com/problem/602 思路 本质是求最长子序列问题envelopes 先按 w 升序排序&#xff0c;再按 h 降序 排序&#xff0c;只需考虑h…

一条SQL在MySQL中的执行过程

图解&#xff1a; 第⼀步&#xff1a;连接器 过程 1. 建⽴连接&#xff1a;与客户端进⾏ TCP 三次握⼿建⽴连接&#xff1b; 2. 校验密码&#xff1a;校验客户端的⽤户名和密码&#xff0c;如果⽤户名或密码不对&#xff0c;则会报错&#xff1b;3. 权限判断&#xff1a…

手机无线投屏到windows11电脑

1 安装无线投影组件 2 电脑端打开允许其他设备投影的开关 3 手机找到投屏选项 4 手机搜索可用设备连接即可 这里的官方文档给的不太好,给了一些让人眼花撩乱的信息,以下是经过整合的有效信息

金融衍生品市场

金融衍生品市场 衍生金融品的作用衍生金融工具远期合约期货合约期权 衍生金融品的作用 套期保值&#xff08;Hedging&#xff09; 组合多头头寸(long position)与空头头寸(short position)例&#xff1a;股票与股指期货 投机 衍生金融工具 远期合约 定义&#xff1a;在将来…

翻译: 硅谷软件工程师面试:准备所需的一切

没有人有时间去做成百上千道LeetCode题目&#xff0c;好消息是你实际上并不需要做那么多题目就能够在FAANG公司找到工作&#xff01; 我曾经在Grab工作&#xff0c;这是东南亚的一家共享出行公司&#xff0c;但我对工作感到沮丧&#xff0c;想要进入FAANG公司&#xff0c;但我…

【opencv】教程代码 —features2D(5)旋转相机的基本全景拼接

基本全景拼接 panorama_stitching_rotating_camera.cpp 将第二张图像进行透视变换后与第一张图像拼接 #include <iostream> // 包含了一些用于输入输出的函数 #include <opencv2/core.hpp> // 包含了OpenCV核心库的一些常用类和函数 #include <opencv2/imgpro…

Android视角看鸿蒙第十课-鸿蒙的布局之线性布局

Android视角看鸿蒙第十课-鸿蒙的布局之线性布局 导读 这篇文章开始&#xff0c;依次学习鸿蒙的八大布局&#xff0c;这是第一篇&#xff0c;所以顺带也会聊聊通用属性。 文档地址 文档地址 如何定义一个线性布局 Android中是使用LinearLayout来构建线性布局的&#xff0c…

ChatGPT chrome扩展下载与安装

官方下载地址 https://chromewebstore.google.com/detail/lpbhmlbicmgjpacbofijdfpcplfhakeo 截图 安装 离线安装 下载地址 https://static.xutongbao.top/app/chatgpt-chrome-crx-v0.0.7.zip 打开链接 chrome://extensions/ 人工智能学习网站 https://chat.xutongbao.to…

谷粒商城——RabbitMQ

0. 消息中间件 1.RabbitMQ的核心概念 2. 工作流程 整体架构&#xff1a; 相关细节&#xff1a; 上述要注意的是&#xff1a; 路由键包含在message的头中&#xff0c;其作用是用于指定该消息存储与哪个消息队列中。 信道是客户端&#xff08;包括生产者和消费者&#xff09;用…