你应该知道Linux内核softirq

说起这个softirq ,很多人还是一头雾水,觉得这个是什么东西,跟tasklets 和 workqueue有什么不同。

每次谈到这个,很多人,包括我,都是有点紧张,特别是面试的时候,因为你一旦说错了什么,那么你这次面试估计就歇菜了。

谈到这个,我们不得不说中断,中断处理,我相信很多人都是知道的,中断分为上半部和下半部,原来的Linux 内核是没有下半部的,中断来了,就在中断里处理事件,说白了,就是执行一些函数操作,但是这个会导致一个问题,就是系统调度慢了,对于用户来说,你用手机的时候,感觉到十分卡顿,真想摔了这个手机,所以,后来就出现了中断下半部。

中断下半部的机制有很多种。例如:softirq、tasklet、workqueue或是直接创建一个kernel thread来执行bottom half(这在旧的kernel驱动中常见,现在,一个理智的driver厂商是不会这么做的

tasklet 是基于softirq实现的,所以我们讨论tasklet的时候,其实也是在说softirq,他们都是运行在中断上下文的。

workqueue和softirq不同的是,它运行是进程上下文。

为什么需要这么多机制来实现中断下半部呢?

你可以理解,我如果要去纽约,我可以坐飞机,可以坐轮船,也可以开小汽车,甚至,我还可以骑自行车,中断下半部也是一样,tasklet的出现,是因为把softirq封装起来,更加方便别人使用。workqueue的话,紧急程度就没有softirq那么紧急,可以说优先级没有那么高,如果是非常紧急的事情,比如网络事件,我们还是优先使用softirq来实现。

Linux 内核里面可以有多少种softirq呢?

softirq是一种非常紧急的事件,所以说,不是你想用就用的,内核里面定义了一个枚举变量来说明softirq支持的类型。

/* PLEASE, avoid to allocate new softirqs, if you need not _really_ high
frequency threaded job scheduling. For almost all the purposes
tasklets are more than enough. F.e. all serial device BHs et
al. should be converted to tasklets, not to softirqs.
*/

enum
{
HI_SOFTIRQ=0,
TIMER_SOFTIRQ,
NET_TX_SOFTIRQ,
NET_RX_SOFTIRQ,
BLOCK_SOFTIRQ,
BLOCK_IOPOLL_SOFTIRQ,
TASKLET_SOFTIRQ,
SCHED_SOFTIRQ,
HRTIMER_SOFTIRQ, /* Unused, but kept as tools rely on the
numbering. Sigh! */
RCU_SOFTIRQ, /* Preferable RCU should always be the last softirq */

NR_SOFTIRQS
};

看到上面的那段英文了没,它说,「大部分情况下,tasklets已经满足你的要求,就不要只想着用softirq

软中断是什么时候执行的呢?

软中断和workqueue存在非常大的区别,我们在上面说过,软中断是在中断上下文的,但是中断上半部已经脱离了中断了,它如何跟中断上下文存在千丝万缕的联系呢?说到这里,我们不拿出代码来说,那就是耍流氓了。

/*
* Exit an interrupt context. Process softirqs if needed and possible:
*/
void irq_exit(void)
{
#ifndef __ARCH_IRQ_EXIT_IRQS_DISABLED
local_irq_disable();
#else
WARN_ON_ONCE(!irqs_disabled());
#endif

account_irq_exit_time(current);
preempt_count_sub(HARDIRQ_OFFSET);
if (!in_interrupt() && local_softirq_pending())
//此处判断是否从中断上下文退出,并判断是否有软中断任务挂起待处理
invoke_softirq();
//启用,排程软中断处理

tick_irq_exit();
rcu_irq_exit();
trace_hardirq_exit(); /* must be last! */
}

我们看看irq_exit()这个函数,这个函数是在什么时候调用?就是中断上半部执行结束后,需要跳出中断上半部的时候,我们需要执行irq_exit(),然后在里面有一个判断。

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

tick_irq_exit();
rcu_irq_exit();
trace_hardirq_exit(); /* must be last! */
}

这几行代码就是判断当前是否需要执行软中断,说白了,就是CPU需要执行一段优先级非常高的代码,这段代码需要在中断结束,关闭中断后马上执行。

#define local_softirq_pending() this_cpu_read(irq_stat.__softirq_pending)

那我们在中断上半部执行结束后,如何设置需要执行softirq呢?使用这个函数

#define set_softirq_pending(x) __this_cpu_write(irq_stat.__softirq_pending, (x))

softirq相关的代码都在 softirq.c 这个文件里面,如果想有更深入了解的同学,可以一睹源码风采,不吹,C语言的源码真是一个宝藏,细细评味,可以挖掘出非常多的好东西。

我们分析下 invoke_softirq

这个函数是执行softirq的函数,里面也有一些判断的东西,我看了下源码,理解了下,顺便解读下自己的看法,如果有疑问或者问题的,请读者们指出来,只有不断的探讨,大家才可能收获更多的东西。

static inline void invoke_softirq(void)
{
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();
}
}

不会看注释的码农不是好码农,不写注释的码农就不是码农,如果你想写代码,就一定要会写注释,同时,你也要会看别人的注释,好吧,这类源码都是老外写的,所以我们一定要习惯看英文注释,慢慢看,不要着急,学会上下文推敲,这样才像一个大神嘛。

我不是大神,所以,我就瞎说一下上面使用一个 force_irqthreads 来区分一个东西,就是软中断上下文,软中断上下文是不能睡眠的,你知道的,你要是在中断里面睡眠,那系统调度就起不来了,起不来的原因那可真是五花八门,因为你不知道进入中断的时候做了什么事情,在中断里面的时候,我们只有更高优先级的中断才能打断当前中断,现在新版本的Linux内核取消了中断嵌套,那你要是在中断里面睡觉,就没有人叫你起床了,那就只能出现panic,挂机了。用我的话来说,那就是睡死了。

如果你的softirq里面执行很多东西,在软中断上文没有执行完,那你就需要用到软中断线程把剩下的事情做完,然后就出现了wakeup_softirqd(),这个就是处理软中断下半部的。

看看__do_softirq()里面做的事情吧

asmlinkage __visible void __softirq_entry __do_softirq(void)
{
unsigned long end = jiffies + MAX_SOFTIRQ_TIME; //最大处理时间:2毫秒
unsigned long old_flags = current->flags;
int max_restart = MAX_SOFTIRQ_RESTART; //最大回圈次数:10次
struct softirq_action *h;
bool in_hardirq;
__u32 pending;
int softirq_bit;

/*
* Mask out PF_MEMALLOC s current task context is borrowed for the
* softirq. A softirq handled such as network RX might set PF_MEMALLOC
* again if the socket is related to swap
*/
current->flags &= ~PF_MEMALLOC;

pending = local_softirq_pending(); //获取本地CPU上等待处理的软中断掩码
account_irq_enter_time(current);

__local_bh_disable_ip(_RET_IP_, SOFTIRQ_OFFSET);
in_hardirq = lockdep_softirq_start();

restart:
/* Reset the pending bitmask before enabling irqs */
set_softirq_pending(0); //清除本地CPU上等待处理的软中断掩码

local_irq_enable(); // 开中断状态下处理软中断

h = softirq_vec; // h指向软中断处理函式阵列首元素

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;
}

rcu_bh_qs();
local_irq_disable(); //关中断,判断在处理上次软中断期间,硬中断处理函式是否又排程了软中断

pending = local_softirq_pending();
if (pending) { //软中断再次被排程
if (time_before(jiffies, end) && !need_resched() &&
--max_restart) //没有达到超时时间,也不需要被排程,并且排程次数也没有超过10次
goto restart; //重新执行软中断

wakeup_softirqd(); //否则唤醒软中断核心执行绪处理剩下的软中断,当前CPU退出软中断上下文
}

lockdep_softirq_end(in_hardirq);
account_irq_exit_time(current);
__local_bh_enable(SOFTIRQ_OFFSET);
WARN_ON_ONCE(in_interrupt());
current_restore_flags(old_flags, PF_MEMALLOC);
}

这段代码主要是展示了软中断上下文的处理策略,一次处理所有等待的软中断,处理轮训结束或者时间超过2ms,就跳出软中断上下文,跑到软中断线程里面去执行,避免系统响应过慢。

如何加入新的软中断?

说了那么多,这个应该是重点了,一直强调,不要加软中断,使用tasklet就够了,但是无法避免就是有人要用啊。

内核使用下面函数来新增一个软中断

void open_softirq(int nr, void (*action)(struct softirq_action *))
{
softirq_vec[nr].action = action;
}

当然了,你可以新增一个枚举变量

内核里面是这样使用下面这个函数调用

open_softirq(RCU_SOFTIRQ, rcu_process_callbacks);

好了,就说这么多~

右下角,你懂的ʕ•̫͡•ʕ*̫͡*ʕ•͓͡•ʔ-̫͡-ʕ•̫͡•ʔ*̫͡*ʔ-̫͡-ʔ

—————END—————

扫码或长按关注

回复「 加群 」进入技术群聊

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

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

相关文章

linux 查看磁盘分区,文件系统,使用情况的命令和相关工具介绍,Linux 查看磁盘分区、文件系统、使用情况的命令和相关工具介绍...

Linux 查看磁盘分区、文件系统、使用情况的命令和相关工具介绍作者:北南南北来自:http://doc.xuehai.net提要:Linux 磁盘分区表、文件系统的查看、统计的工具很多,有些工具是多功能的,不仅仅是查看磁盘的分区表&#x…

C语言,链表

定义一个链表的节点之前说到树,里面也有一个节点,节点是用来存数据的,不管是树还是其他什么数据结构,最终的目的都是用来处理数据的,所以节点里面包含两个东西,一个是指针,指针可以指向其他位置…

linux hosts文件如何修改_3 种方法教你在 Linux 中修改打开文件数量限制

当文件被打开访问时,操作系统临时分配一个名为文件句柄的数字。主内存的一个特殊区域是为文件句柄预留的,这个区域的大小决定了一次可以打开多少个文件。Linux上的进程受到许多限制,这些限制也阻碍它们正确地执行,而且每个进程都有…

10个高效Linux技巧及Vim命令对比

写在前面:今天没来得及唱歌~一个多星期没更新了,今天记录下我自己用得比较多的Linux命令行快捷键,小伙伴们别嘲笑我哈~不知道为啥,每次发文就有好几个小伙伴取消关注离开之前,可以告诉我为什么吗~~Vim的很多命令和功能…

python 微信机器人_Python 微信机器人

一、写在前边的话 如何做一个自动回复的微信机器人?机器人的功能有,自动加好友,关键字回复,等等,它甚至可以成为你的私人管家,只要你的代码到位。今天,主要讲解下,微信机器人-图灵版…

linux 控制台存储,技术|使用 Stratis 从命令行管理 Linux 存储

通过从命令行运行它,得到这个易于使用的 Linux 存储工具的主要用途。正如本系列的第一部分和第二部分中所讨论的,Stratis 是一个具有与 ZFS 和 Btrfs 相似功能的卷管理文件系统。在本文中,我们将介绍如何在命令行上使用 Stratis。安装 Strati…

你想要的江湖,可能不在这时候笑傲

昨天看知识星球看到的一个码农的经历,然后我看了,也回答了,想把回答分享给大家,我觉得这应该是很多人都会遇到的。困扰的问题潜水这么久,有一个问题想问一下,帅张。可能有点啰嗦。就是在一家公司做开发&…

mysql binlog 备份_MySQL的binlog知识梳理

1、binlog概念:binlog是一个二进制格式的文件,用于记录“修改数据或可能引起数据变更”的SQL语句(查询的SQL不会记录)。2、binlog功能:(1)恢复: 利用binlog日志恢复数据库数据。(2)复制: 主从架构通过binlog同步数据。(3)审计: 可以用binlog中的信息进行审计&#x…

你需要知道的Linux 系统下外设时钟管理

嵌入式系统一般要求低功耗,出于这个原因,一般只把需要使用到的外设时钟源打开,其他不需要使用到的模块,则默认关闭它们。LCD 模块,上电时候默认情况是关闭的,所以,要想使用 LCD 模块&#xff0c…

千万级大表如何更快速的创建索引_分享一份生产环境mysql数据库大表归档方案,值得收藏...

概述分享下最近做的一个mysql大表归档方案,仅供参考。整体思路一、明确哪些大表需做归档1、数据库表概要信息统计SELECTt1.table_schema,t1.table_name,ENGINE,table_rows,CAST( data_length / 1024.0 / 1024.0 AS DECIMAL ( 10, 2 ) ) data_size(M),CAST( index_le…

载波和LoRa

最近lora这个很火,火的原因是因为国家出了一个政策,这个政策呢,有很多人解读了,我身边也有好几个朋友做这方面的,然后我今天找他们聊了下,得到的结果是,这个政策肯定是或多或少对现在的行情和市…

imread函数 matlab_【MATLAB图像处理学习】1.读取和显示图片

CHAPTER2 图像处理的基础函数【使用的教材:冈萨雷斯 数字图像处理MATLAB(Digital image processing with Matlab】【原书图片下载地址:点这里】先介绍三个MATLAB中图片基本操作:imread imshow imwrite2.2读取图片imread(filename)imread是读取…

一场不能只看结果的较量

林书豪的比赛看得真的很舒服,虽然输掉了比赛,但是看到两边不断改变打法,不断试图侵犯对方的夺取分数,就好比看了一场战争电影,过程酣畅淋漓,结果差点令人满意。第一节广东的双后卫给北京制造了非常多的麻烦…

嘻哈帝国第一季/全集Empire迅雷下载

英文译名Empire,第1季(2015-01-08)FOX.本季看点:《嘻哈帝国》卢西奥斯莱恩是一名超级音乐明星兼Empire娱乐公司的创始人,故事讲述了他如何在困境和失败中运营公司的故事。拥有庞大帝国的老板得了绝症,于是他决定培养继承人&#x…

cassandra可视化工具_一位数据科学家的私房工具清单

作为一位万人敬仰的数据科学家,不但需要培育一棵参天技能树,私人武器库里没有一票玩得转的大火力工具也是没法在江湖中呼风唤雨的。近日北卡来罗纳大学CTO,一位数据科学家Jefferson Heard分享了多年来收集沉淀的数据分析工具集:处…

Dev C++,一个好玩的猜数字游戏

周末了,看了一点代码,发现有一个好玩的数字游戏,贡献给大家,个人觉得还是挺好玩的。说个题外话,之前写的文章,都是零散的,主要是时间的原因,最近事情有点杂,一说到这个事…

[BZOJ 2500] 幸福的道路

照例先贴题面(汪汪汪) 2500: 幸福的道路 Time Limit: 20 Sec Memory Limit: 256 MBSubmit: 368 Solved: 145[Submit][Status][Discuss]Description 小T与小L终于决定走在一起,他们不想浪费在一起的每一分每一秒,所以他们决定每天早上一同晨练来享受在一…

你手上的PCB怎么制作的?几张动图揭晓工厂生产流程

在PCB出现之前,电路是通过点到点的接线组成的。这种方法的可靠性很低,因为随着电路的老化,线路的破裂会导致线路节点的断路或者短路。绕线技术是电路技术的一个重大进步,这种方法通过将小口径线材绕在连接点的柱子上,提…

linux开发板作为蓝牙音箱,USB 蓝牙适配器在ARM 开发板下的使用

4、可能出现的问题和解决方案:4.1 编译dbus 时出现:1checking for accept4... yeschecking abstract socket namespace... nochecking for pkg-config... (cached) /usr/local/bin/pkg-configchecking pkg-config is at least version 0.9.0... yescheck…

细丝极恐的华为251事件

事情的来龙去脉我就不再详细描述了,我提几个问题点,觉得有点疑惑,也是自己对这个事件的看法。1、李洪元于2005年入职华为,2018年1月离职,在2016年11月21日向公司的投诉邮箱发了一份匿名邮件,至于发邮件的东…