中断上下文中的preempt count
参考博客:
Linux上下文切换[转]_thonmin的博客-CSDN博客_linux 上下文切换
中断子系统
1. 背景
<linux kernel的中断子系统之八:softirq>中讲到:
softirq在同一个CPU上是串行的,这点体现在代码的哪里呢?
./kernel/softirq.c
wowo科技的文章中讲了两种场景,其中中断嵌套由于Linux不支持,所以暂时不讨论,只讨论下面的一个场景: softirq中的中断
假设一个中断下半部softirq(随便什么类型的softirq)正在执行,在调用softirq的hander之前,也就是__do_softirq()中一定会调用__local_bh_disable_ip(_RET_IP_, SOFTIRQ_OFFSET)然后打开CPU中断local_irq_enable(),最后执行softirq handler
就在执行softirq handler的时候在同一个CPU上发生了外部中断,此时CPU能够响应这个外部中断,并同样走到了irq_exit()的Line408处,由于之前调用了 __local_bh_disable_ip,所以此时if条件为假,invoke_softirq()得不到调用导致新的softirq无法执行
第二个中断结束,退出到被中断的softirq处继续执行,依靠__do_softirq()中的restart标签机制,将没有处理的softirq处理完毕
似乎一切很合理,但是这里有一个隐藏很深的问题: in_interrupt()的实现与preempt count有关系,但是程序在我上述描述的场景中用到的所有preempt count都是在中断上下文,而我们又知道Linux的中断上下文不存在struct task_struct结构,那么这里的preempt count是哪里的?
2. 中断栈
相关资料请见以下博客:
linux kernel中的栈的介绍_代码改变世界ctw的博客-CSDN博客
中断子系统
ARM32的IRQ STACK
./arch/arm/kernel/setup.c
arm32的中断栈很小,只有12byte,在系统初始化的时候,cpu_init()函数会进行中断模式stack的设定,在此不详细介绍
为什么arm32的中断栈如此小呢?这与arm32架构下中断处理的模式有关系,参考如下描述:
简单说来就是在arm32架构下,真正的中断处理都在svc mode,发生中断时,先进入irq mode,再进入svc mode完成大部分工作,而进入svc mode,也伴随着栈切换,也就是说,arm32的irq handler是运行在被中断进程的内核栈上面的
ARM64的IRQ STACK
./arch/arm64/kernel/irq.c
arm64架构专门设计了中断栈用于irq handler,可以看到代码中中断栈是基于per-cpu的,中断栈可能是静态分配的,也可能是vmalloc动态分配的,大小为THREAD_SIZE
小总结:
linux kernel arm32中定义的irq栈,其实就在一个static struct stack结构体变量中,大小为12bytes. irq_hander使用svc栈
linux kernel arm64中定义的irq栈,在内存"首地址"处,大小16k. irq_hander使用irq栈
为什么arm64要引入特别的IRQ STACK?
具体可以看看下面这个patch的描述:arm64: Introduce IRQ stack [LWN.net]
3. 中断栈的切换
根据上一小节描述,arm32架构下,中断最开始会进入IRQ mode,但是它稍纵即逝,最终进入SVC mode处理具体的中断,所以irq handler是运行在被中断的进程的内核栈上面的。具体栈切换请参考中断子系统的四小节
在arm64架构下,irq handler运行在cpu独立的IRQ stack中,可以参考中断向量表arch/arm64/kernel/entry.S,精简后的大概流程如下,可以看到实际上中断上半部和中断底半步都是在IRQ STACK上完成的
4. 猜想-中断上下文中的preempt count究竟是什么
参考:Linux内核进程栈的两种架构_Andy Pines的博客-CSDN博客
在中断上下文中一定会有这样的代码片段:
最终都是去操作preempt_count这个成员来通过软件的方式去标识运行上下文
ARM32架构,thread_info在内核栈中,获取preempt_count的途径如下:
通过sp找到栈底,自然也就找到了thread_info,进而找到preempt_count
在了解了arm32中断栈切换的原理后,由于irq handler是运行在SVC模式的内核栈上的,所以sp就是被中断的内核栈顶指针,preempt_count属于被中断进程
ARM64架构,thread_info不在内核栈中,thread_info在struct task里面,获取preempt_count的途径如下:
arm64架构下,进程描述符是用寄存器来承载的,在了解了arm64中断栈切换原理后,我们并没有发现sp_el0有什么变化,所以sp_el0仍然是被中断进程的进程描述符,所以preempt_count属于被中断进程
5. 思考
综上所述,在中断上下文中操作到的preempt_count实际上是属于被中断进程的(仍然是推测+猜想,无实证),这也就能解释本文最开始提到的问题:如何保证softirq在同一个CPU上的串行执行?这下就很简单了,不管是因为中断嵌套也好,还是softirq被中断也好,前者用于标识运行上下文操作的preempt_count与后者用于检测的preempt_count是同一个变量,也都是被中断进程的那个preempt_count
同样,这里又会引申出另一个深层次的问题: 中断上下文为什么不能睡眠?
通过查找各种资料,大概归于两类原因:
a. Linux中断的设计要求
从中断设计目标看,它应该尽快完成处理返回现场,甚至为此还特意分出了下半部,调用阻塞函数,不可避免得增加了时延,显然违背初衷
b.与进程调度相关
从Linux的设计规则上看,中断上下文不是调度实体,调用阻塞函数使中断上下文参与调度,打破了设计规则,而且有很大程度上可能无法返回原来的现场,如果可以靠的也是运气
关于第二点,<深入Linux设备驱动程序内核机制>有如下描述:
我们再看看引起睡眠的schedule函数,先取得当前cpu上的进程运行队列,再从该队列中取出当前运行的进程,而在中断上下文中的rq->curr就是被中断的进程,进而让被中断的进程参与调度,在arm32架构下,被中断的进程可能在以后的调度中又被中断,导致内核栈被改写,被调度出去的中断下下文就再也回不去了;在arm64架构下,调度器根本就看不到中断栈,所以一旦中断中出现了调度,就有可能再也回不去了。
中断上下文中的preempt count相关推荐
- 为什么可能导致睡眠的函数都不能在中断上下文中使用呢?【转】
转自:http://www.cnblogs.com/hoys/archive/2012/06/28/2567622.html 转自:http://blog.chinaunix.net/u1/49093 ...
- linux多进程通过中断实现,Linux驱动中断上下文中会发生什么结果实验测试
一.前言 每一个Linux驱动工程师都知道这样一个准则:在中断上下文中不能睡眠.但是为什么interrupt context中不能调用导致睡眠的kernel API呢?如果驱动这么做会导致什么样的后果 ...
- linux内核的中断上下文,Linux操作系统中中断上下文中的互斥
UP(单CPU系统)上的中断处理 互斥 如果一个中断处理程序的代码访问或者更新了由非中断的代码(通常称为基准代码)使用的同一数据结构,那么就会出现竞争条件. 幸运的是,得到允许的以内核态执行的进程会临 ...
- arm Linux 中断管理机制
关键词:GIC.IAR.EOI.SGI/PPI/SPI.中断映射.中断异常向量.中断上下文.内核中断线程.中断注册. 1.1 ARM支持中断类型 ARM GIC-v2支持三种类型的中断: SGI:软件 ...
- 进程上下文、中断上下文及原子上下文
谈论进程上下文 .中断上下文 . 原子上下文之前,有必要讨论下两个概念: a -- 上下文 上下文是从英文context翻译过来,指的是一种环境.相对于进程而言,就是进程执行时的环境: 具体来说就是各 ...
- linux 中断子系统
linux 中断子系统 1,异常和中断 1.1 中断引入的必要性 1.2 同步异常 1.2.1 同步异常 1.2.2 同步异常的种类 1.3 异步异常 1.3.1 异步异常 1.3.2 异步异常的种类 ...
- 嵌入式之linux用户空间与内核空间,进程上下文与中断上下文
文章目录 前言 用户空间与内核空间 内核态与用户态 进程上下文和中断上下文 上下文 原子 进程上下文 中断上下文 进程上下文VS中断上下文 原子上下文 前言 之前在学习嵌入式linux系统的时候,一直 ...
- Linux中断子系统(三)之GIC中断处理过程
Linux中断子系统(三)之GIC中断处理过程 备注: 1. Kernel版本:5.4 2. 使用工具:Source Insight 4.0 3. 参考博客: Linux中断子系统(一)中 ...
- Linux 中断子系统之softirq
Linux 中断子系统之softirq 1 前言 对于中断处理而言,linux将其分成了两个部分,一个叫做中断handler(top half),是全程关闭中断的,另外一部分是deferable ta ...
- 进程上下文和中断上下文
1.进程上下文 进程上下文实际上是进程执行活动全过程的静态描述.我们把已执行过的进程指令和数据在相关寄存器与堆栈中的内容称为上文,把正在执行的指令和数据在寄存器和堆栈中的内容称为正文,把待执行的指令和 ...
最新文章
- C#编码实践:使用委托和特性调用指定函数
- 旋转卡壳——模板(对踵点)
- 用计算机制作演示文稿教案博客,制作演示文稿 教学反思
- android 之Activity间的相互跳转(通过intent构造函数)
- Coursera公开课笔记: 斯坦福大学机器学习第十一课“机器学习系统设计(Machine learning system design)”
- 汇编语言 DS段寄存器
- LeetCode 1362. 最接近的因数
- 如何学好Spring
- fatal error C1010: 是否忘记了向源中添加“#include stdafx.h”?
- 文件磁盘相关函数[11]-获取指定文件的版本号 GetFileVersion
- 【VRP】基于matlab遗传算法求解出租车网约车接送客车辆路径规划问题【含Matlab源码 YC003期】
- PixiJS学习(9)动画序列帧
- 谷歌浏览器扩展程序XDM_如何下载和安装扩展程序?
- 金色经典图案背景新中式PPT模板
- 误码率matlab怎么计算,PSK理论误码率与实际误码率MATLAB仿真程序(最新整理)
- 控制面板快捷键win10_Win10系统启动变慢怎么办,Win10系统启动变慢解决方法
- 杰奇php手机登陆自动跳转,杰奇cms电脑与手机自动判断跳转代码
- 2020年朋友圈天文大戏“日环食”大赏
- 什么是因果?什么是相关?
- Java异常处理的简单总结+文件操作
热门文章
- 妈妈计算机英语怎么说,妈妈的英文翻译,妈妈英语怎么说
- 网络教育本科统考计算机和英语作文,远程教育本科统考英语真题及答案
- 百度云重置服务器密码,单台或多台腾讯云服务器 CVM 重置实例密码教程
- Android实用视图动画及工具系列之九:漂亮的图片选择器,高性能防崩溃图片选择工具
- 解决Android图片剪切返回崩溃问题
- WPS新建文字分享微信.docx形式_这 3 个实用的文档「分享」技巧,很多人都不会用...
- 使用Euclid算法求最大公约数
- I love you
- 机械硬盘和固态硬盘之间的区别
- spring框架 -- IOC