当前位置: 首页 > news >正文

Linux中断概述

Ref

https://zhuanlan.zhihu.com/p/88883239

    Linux的中断处理分为top half(关中断)以及bottom half(开中断、defer处理)。BH部分的机制包括:

softirqtaskletworkqueue

    其中,tasklet是基于softirq的。workqueue和softirq、tasklet有本质的区别:workqueue运行在process context(可以被中断,保存在进程栈),而softirq和tasklet运行在interrupt context(可以被中断,保存在中断栈)。

    softirq更倾向于性能,而tasklet更倾向于易用性

    为了性能,同一类型的softirq有可能在不同的CPU上并发执行,这给使用者带来了极大的痛苦,因为驱动工程师在撰写softirq的回调函数的时候要考虑重入,考虑并发,要引入同步机制。

    如果一个tasklet在processor A上被调度执行,那么它永远也不会同时在processor B上执行(在检查tasklet的状态的时候,如果发现该tasklet在其他processor上已经正在运行,那么该tasklet不会被处理,一直等到在processor A上的tasklet处理完),也就是说,tasklet是串行执行的(注:不同的tasklet还是会并发的),不需要考虑重入的问题。

preempt_count

struct thread_info {

    ……

    int            preempt_count;    /* 0 => preemptable, <0 => bug */

    ……

};

preempt_count本质上是一个per-CPU32位变量x86,它在各种处理器架构下的存放位置和命名不尽相同,但其值都可以使用preempt_count()函数统一获取。preempt_count逻辑相关的核心代码位于include/linux/preempt.h,虽然只是一个32位变量,但由于其和中断、调度/抢占密切相关,因此在系统中发挥的作用不容小觑。

注:

preempt_count定义的位置因架构不同,arm64定义在thread_info结构体中,x86则定义为percpu变量。

//arch/arm64/include/asm/preempt.h

static inline int preempt_count(void)

{

    return READ_ONCE(current_thread_info()->preempt.count);

}

//arch/x86/include/asm/preempt.h

DECLARE_PER_CPU(int, __preempt_count);

hardirq相关

preempt_count中的第16到19个bit表示hardirq count,它记录了进入hardirq/top half的嵌套次数,在这篇文章介绍的do_IRQ(x86,arm64为gic_handle_irq)中,irq_enter()用于标记hardirq的进入,此时hardirq count的值会加1。irq_exit()用于标记hardirq的退出,hardirq count的值会相应的减1。

如果hardirq count的值为正数,说明现在正处于hardirq上下文中,代码中可借助in_irq()宏实现快速判断。注意这里的命名是"in_irq"而不是"in_hardirq"

#define hardirq_count()         (preempt_count() & HARDIRQ_MASK)
#define in_irq()  (hardirq_count())

hardirq count占据4个bits,理论上可以表示16层嵌套,但现在Linux系统并不支持hardirq的嵌套执行,所以实际使用的只有1bit

之所以采用4个bits,一是历史原因,因为早期Linux并不是将中断处理的过程分为top half和bottom half,而是将中断分为fast interrupt handler和slow interrupt handler,而slow interrupt handler是可以嵌套执行的,二是某些 driver 代码可能在top half中重新使能hardirq

softirq相关

preempt_count中的第8到15个bit表示softirq count,它记录了进入softirq的嵌套次数,如果softirq count的值为正数,说明现在正处于softirq上下文中。由于softirq在单个CPU上是不会嵌套执行的,因此和hardirq count一样,实际只需要一个bit(bit 8)就可以了。但这里多出的7个bits并不是因为历史原因多出来的,而是另有他用。

这个"他用"就是表示在进程上下文中,为了防止进程被softirq所抢占,关闭/禁止softirq的次数,比如每使用一次local_bh_disable()softirq count7bits(bit 9bit 15)的值就会加1,使用local_bh_enable()则会让softirq count7bits的的值减1

代码中可借助in_softirq()宏快速判断当前是否在softirq上下文:

#define softirq_count()  (preempt_count() & SOFTIRQ_MASK)
#define in_softirq()         (softirq_count())

进入softirq是在softirq上下文,关闭softirq抢占也是在softirq上下文,但还是有办法区分的。办法就是使用in_serving_softirq()宏来确切地表示现在是在处理softirq(通过preempt_countbit8)。

#define SOFTIRQ_OFFSET  (1UL << 8)
#define in_serving_softirq()  (softirq_count() & SOFTIRQ_OFFSET)

上下文

不管是hardirq上下文还是softirq上下文,都属于我们俗称的中断上下文(interrupt context)

  • hardirq上下文:正在执行hardirq或关闭中断;
  • softirq上下文:正在执行softirq或关闭softirq抢占。

为此,有一个名为in_interrupt()的宏专门用来判断当前是否在中断上下文中。

#define irq_count()         (preempt_count() & (HARDIRQ_MASK | SOFTIRQ_MASK | NMI_MASK))                        
#define in_interrupt()  (irq_count())

与中断上下文相对应的就是俗称的进程上下文(process context),in_task()

#define in_task()  (!(preempt_count() & (HARDIRQ_MASK | SOFTIRQ_OFFSET | NMI_MASK)))

注意

  1. 这里使用SOFTIRQ_OFFSET,而不是SOFTIRQ_MASK,前面已经解释过;在进程上下文中可以通过local_bh_disable()来关闭软中断抢占;所以,这里进程上下文(in_task)和中断上下文(in_interrrupt)其实是有一个交集,即preempt_countbit9~bit15
  2. 并不是只有用户态进程才会处在process context,内核线程依然可以运行在process context。

中断上下文中,调度是关闭的,不会发生进程的切换,这属于一种隐式的禁止调度,而在代码中,也可以使用preempt_disable()来显示地关闭调度,关闭次数由第0到7个bits组成的preemption count(注意不是preempt count)来记录。

每使用一次preempt_disable(),preemption count的值就会加1,使用preempt_enable()则会让preemption count的值减1。preemption count占8个bits,因此一共可以表示最多256层调度关闭的嵌套

处于中断上下文,或者显示地禁止了调度,preempt_count()的值都不为0,都不允许睡眠/调度的发生,这两种场景被统称为atomic上下文,可由in_atomic()宏给出判断。

#define in_atomic()        (preempt_count() != 0)

中断上下文、进程上下文和atomic上下文的关系大概可以表示成这样:

http://www.dtcms.com/a/427977.html

相关文章:

  • 文安做网站的wordpress配置qq邮箱
  • kvmclock
  • 使用 Python 打造一个轻量级系统信息查看器
  • 旅游网站首页制作番禺核酸检测点有新调整
  • 最常用的js加解密之RSA-SHA256 加密算法简介与 jsjiami 的结合使用指南
  • 建站之星至尊版域名中的wordpress删除
  • 苹果软件混淆方式对比与场景化选择,源码混淆、成品包混淆与混合方案
  • 生产环境下oracle19c rac恢复节点2
  • 【VMware】VMware-workstation中,Ubuntu系统安装说明
  • 基于LMK04828的跨板级联时钟同步
  • 黄骅港客运站电话号码企业网站制作策划书
  • 图神经网络分享系列-transe(Translating Embeddings for Modeling Multi-relational Data) (二)
  • 安全的合肥网站建设中国建设银行移动门户
  • LVGL-UI工具
  • 长春网站建设推广网站建设佰金手指科杰二
  • 精益制造——解读麦肯锡集团精益生产与价值流图管理【附全文阅读】
  • 建站吗官方网站农产品网络营销模式
  • 苏宁易购网站设计怎么制作潍坊住房公积金个人查询入口
  • SeaTunnel 同步 KingBase 数据到 Easysearch
  • SSM基于Web的在线音乐网站935wk(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。
  • 自己做网站 需要哪些网站绑定别名好吗
  • 【设计模式】六大基本原则
  • dw做的手机端网站雄安网站建设单位
  • SpringBoot 统⼀功能处理
  • 建网站要多少费用南宁个人网站建设
  • JTCatch 缓存配置与使用
  • Android Jetpack 系列(六)WorkManager 任务调度实战详解
  • 1、docker入门简介
  • 个人小说网站怎么做娄底企业网站建设制作
  • 三层交换(h3c)