LINUX软中断-softirq

news2024/11/23 7:22:18

前言

关于linux的软中断的文章,在网上可以找到很多,但总觉着讲的都不够深入,打算自己写一下

软中断的感性认识

中断一旦被触发,本地cpu正在运行的不管是什么程序都要让路,让中断程序执行并且执行过程中不能被打断。在linux下,符合这种情景的中断有两种:

  1. 硬中断
    即硬件机制,GIC产生一个中断后通知cpu,cpu硬件会跳到特定的地址去执行程序,不能被打断, 这个程序就是中断服务程序。
  2. 软中断
    用软件编程的方式来模拟硬件中断的特性,当触发软中断任务执行时,此任务是不能被本core上的其他任务抢占,运行优先级最高,软中断任务执行结束后,才能执行其他任务,类似于硬中断的行为。但是毕竟是软件模拟的行为,所以软中断任务在执行的过程中是可以接收硬中断并优先执行中断服务程序(硬中断是老大,优先处理)。

那问题来了,软中断是如何做到不被本core上的其他任务抢占呢?我们先要说一下其他方面的知识

基础知识

运行上下文

大家都知道,在linux内核里用current_thread_info来表示本core上当前所运行程序的信息。

union thread_union {
	struct thread_info thread_info;
	unsigned long stack[THREAD_SIZE/sizeof(long)];
};
static inline struct thread_info *current_thread_info(void) __attribute_const__;

static inline struct thread_info *current_thread_info(void)
{
	register unsigned long sp asm ("sp");
	return (struct thread_info *)(sp & ~(THREAD_SIZE - 1));
}

从上面的定义可以看出,thread_info与栈共同占用一个page,thread_info从低地址开始存放,而栈从高地址往低地址增长。由于页对齐的缘故,栈指针sp & ~(THREAD_SIZE - 1)就是thread_info。
其次,内核程序在运行的过程中,需要有一个变量(preempt_count)

//#define preempt_count()	(current_thread_info()->preempt_count)
current_thread_info()->preempt_count

来标明目前此程序正在运行的环境(即上下文),在linux中,用不同的整数来代表不同的上下文。

//这里的 PREEMPT_SHIFT 是什么值就不做讨论了。
#define PREEMPT_OFFSET	(1UL << PREEMPT_SHIFT)
#define SOFTIRQ_OFFSET	(1UL << SOFTIRQ_SHIFT)
#define HARDIRQ_OFFSET	(1UL << HARDIRQ_SHIFT)
#define NMI_OFFSET	(1UL << NMI_SHIFT)

比如,来了个中断,当前任务被打断,那么这时候此任务应该被标识为正在运行在中断上下文中
比如来个硬中断,

//# define add_preempt_count(val)	do { preempt_count() += (val); } while (0)
//# define sub_preempt_count(val)	do { preempt_count() -= (val); } while (0)
add_preempt_count(HARDIRQ_OFFSET);

即把 preempt_count变量加上 HARDIRQ_OFFSET后的值,就表示当前current正运行在中断上下文。
随之而来的问题就出现了,preempt_count存在的意义是什么呢?,仅仅就是为了标识当前程序所运行的上下文吗?,我们接着说。

linux的抢占调度

上面的问题跟linux的调度器有关,我们都知道,linux内核是可抢占的,关于内核程序之间的抢占调度执行其实分为两个阶段。

  1. check点(检查当前线程是否需要被调度出去)
    比如说 tick时钟到了后, 通过某个调度算法(CFS)判断当前任务是否应该被调度(比如运行时间到了),然后将 current_thread_info()->flags = TIF_NEED_RESCHED
    通过代码感受一下流程
//sunxi_timer.c
//首先, 平台必须要注册一个定时器,用来触发tick中断用
clockevents_register_device(&sunxi_clockevent);
	clockevents_register_device(&sunxi_clockevent);
		clockevents_register_device
			list_add(&dev->list, &clockevent_devices);
			clockevents_do_notify(CLOCK_EVT_NOTIFY_ADD, dev);
				ret = nb->notifier_call(nb, val, v);
					tick_check_new_device
						tick_setup_device
							tick_setup_periodic
								tick_set_periodic_handler
									dev->event_handler = tick_handle_periodic;
//tick中断的ISR
sunxi_timer_interrupt
	evt->event_handler(evt);

//event_handler
//tick中断来到后,执行此函数
tick_handle_periodic
	tick_periodic
		update_process_times
			scheduler_tick
				//CFS算法
				curr->sched_class->task_tick(rq, curr, 0);
					task_tick_fair
						entity_tick
							//如果当前进程需要被调度出去的话,则flags置位:TIF_NEED_RESCHED
							check_preempt_tick
								resched_task
									set_tsk_need_resched
										set_tsk_thread_flag(tsk,TIF_NEED_RESCHED);
  1. 发生抢占(实际发生线程切换)
    实际发生线程切换,发生在中断函数要返回的时候,我们看一下
//GIC发生中断,会调到 __irq_svc(中断向量)这里执行
__irq_svc:
        svc_entry
        irq_handler //执行中断函数

#ifdef CONFIG_PREEMPT
        get_thread_info tsk //得到当前运行程序的thread_info 结构体
		//接下来就是重点,如果 thread_info 的结构体中的 preempt_count 的值不为0
		//并且flags的值是 TIF_NEED_RESCHED,则执行svc_preempt
        ldr     r8, [tsk, #TI_PREEMPT]          @ get preempt count
        ldr     r0, [tsk, #TI_FLAGS]            @ get flags
        teq     r8, #0                          @ if preempt count != 0
        movne   r0, #0                          @ force flags to 0
        tst     r0, #_TIF_NEED_RESCHED
        blne    svc_preempt
#endif

#ifdef CONFIG_PREEMPT
svc_preempt:
        mov     r8, lr
        //执行 preempt_schedule_irq 函数完成线程切换调度  
1:      bl      preempt_schedule_irq            @ irq en/disable is done inside
        ldr     r0, [tsk, #TI_FLAGS]            @ get new tasks TI_FLAGS
        tst     r0, #_TIF_NEED_RESCHED
        moveq   pc, r8                          @ go again
        b       1b
#endif

由上面的分析可知, 首先,完成线程切换,必须要满足

  1. 当前执行的线程是需要被调度的(flags == TIF_NEED_RESCHED)
  2. 当前执行的线程的是可被抢占(preempt_count == 0)

至此,我们发现, preempt_count 的作用,即在实际发生调度切换时,如果处在中断上下文中(硬中断,软中断),则当前进程是不能被调度的。

软中断的软件实现

在文章的最开始,我们说过这样的话

当触发软中断任务执行时,此任务是不能被本core上的其他任务抢占,运行优先级最高,软中断任务执行结束后,才能执行其他任务

那如何实现呢? 通过上面的知识,就不难分析出了, 当要执行软中断任务时,会调用__do_softirq函数,此函数刚开始就会调用 __local_bh_disable 函数将当前进程的上下文设置为 softirq环境(软中断环境)

add_preempt_count(SOFTIRQ_OFFSET);

实际上就是:preempt_count = SOFTIRQ_OFFSET;
设置preempt_count 变量后,在执行softirq的任务(运行在本core上的线程会执行特定的函数们,每个函数即为一个软中断的任务),即软中断任务在执行的过程中是处在preempt_count 变量 非0的状态下,所以此时本core上如果在来一个tick中断,中断返回时,因为preempt_count 不为0所以当前线程(正在执行软中断的任务)不会被调度出去,实现了在本core上不能被其他任务抢占的机制。
当软中断执行之后,会 __local_bh_enable,即 preempt_count -= SOFTIRQ_OFFSET,允许被抢占

顺便提一嘴spinlock

其实spinlock也是一样的机制,spinlock大家都知道,核之间硬件锁,核内锁调度。
其中核内锁调度,即不能在本core上被调度出去,也是通过preempt_count 设置了个不能于0的值来实现的。

基于代码,理解softirq

接下来进入正题,首先看一张图,了解下大概的软件脉络
在这里插入图片描述

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

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

相关文章

分布式事务问题

4.2 分布式事务问题 4.2.1 什么是分布式事务 一次课程发布操作需要向数据库、redis、elasticsearch、MinIO写四份数据&#xff0c;这里存在分布式事务问题。 什么是分布式事务&#xff1f; 首先理解什么是本地事务&#xff1f; 平常我们在程序中通过spring去控制事务是利用…

Linux---进程优先级

目录 基本概念 查看系统进程 PRI and NI 用top命令更改已存在进程的nice&#xff1a; 其他概念 基本概念 cpu资源分配的先后顺序&#xff0c;就是指进程的优先权&#xff08;priority&#xff09;。 优先权高的进程有优先执行权利。配置进程优先权对多任务环境的linux很…

JNPF 3.4.5 快速开发框架源码目录截图 Gitee代码托管和研发协作平台

Gitee Gitee 除了提供最基础的 Git 代码托管之外&#xff0c;还提供代码在线查看、历史版本查看、Fork、Pull Request、打包下载任意版本、Issue、Wiki 、保护分支、代码质量检测、PaaS项目演示等方便管理、开发、协作、共享的功能。 作为一个应用项目&#xff0c;一般会有一…

flink环境参数引起的错误

环境参数&#xff1a;flink使用的版本是1.13.5、CentOS Linux 8一&#xff0c;默认环境引起本地与集群的jar包冲突遇到的情况是在idea执行的时候是没有问题的&#xff0c;然后打成jar包用集群执行的时候就会遇到问题。报错的时候会不太一&#xff0c;总之顺着错误去找的话会找到…

【力学性能预测】基于人工神经网络的钢板力学性能预测(附完整代码和数据集,系列3)

写在前面: 首先感谢兄弟们的订阅,让我有创作的动力,在创作过程我会尽最大能力,保证作品的质量,如果有问题,可以私信我,让我们携手共进,共创辉煌。 Hello,大家好,我是augustqi。今天手把手带大家做一个机器学习实战项目:基于人工神经网络的钢板力学性能预测,或者称…

文本生成视频、AI临床知识理解、大模型有趣案例、智源社区《预训练周刊》第70期...

No.70智源社区预训练组预训练研究观点资源活动周刊订阅《预训练周刊》已经开启“订阅功能”&#xff0c;扫描下面二维码&#xff0c;进入《预训练周刊》主页&#xff0c;选择“关注TA”&#xff0c;即可收到推送消息。关于周刊本期周刊&#xff0c;我们选择了12篇来自国内外知名…

《机器人SLAM导航核心技术与实战》第1季:第4章_机器人传感器

视频讲解 【第1季】4.第4章_机器人传感器-视频讲解 【第1季】4.1.第4章_机器人传感器_惯性测量单元-视频讲解 【第1季】4.2.第4章_机器人传感器_激光雷达-视频讲解 【第1季】4.3.第4章_机器人传感器_相机-视频讲解 【第1季】4.4.第4章_机器人传感器_带编码器的减速电机-视频…

Python机器学习:数据探索与可视化(一)

什么是数据探索&#xff1f; 在前面我们说到&#xff0c;所谓机器学习&#xff0c;就是用已知的数据通过算法去预测未来未知的数据。但是这个过程进行的前提就是要保证已知数据的完成性。所以数据探索&#xff0c;就是检查数据是否完整&#xff0c;是否有缺失值。 什么是可视化…

【安全研究】基于OPA和Spring Security的外部访问控制

译者导读 CNCF的毕业项目Open Policy Agent&#xff08;OPA&#xff09;, 为策略决策需求提供了一个统一的框架与服务。它将策略决策从软件业务逻辑中解耦剥离&#xff0c;将策略定义、决策过程抽象为通用模型&#xff0c;实现为一个通用策略引擎&#xff0c;可适用于广泛的业…

阿里云对话 Tapdata:「开发者优先」正在影响商业化软件的开源选择

在刚刚过去的2022年&#xff0c;Tapdata 带着开源项目 PDK&#xff08;Plugin Development Kit&#xff09;及 Tapdata Community 和大家见面&#xff0c;兑现了我们对自己以及开发者们的开源承诺&#xff0c;同时与阿里云等生态伙伴联合&#xff0c;加速构建更加开放的数据生态…

Linux基础 - DNS服务进阶

‍‍&#x1f3e1;博客主页&#xff1a; Passerby_Wang的博客_CSDN博客-系统运维,云计算,Linux基础领域博主&#x1f310;所属专栏&#xff1a;『Linux基础』&#x1f30c;上期文章&#xff1a; Linux基础 - DNS服务基础&#x1f4f0;如觉得博主文章写的不错或对你有所帮助的话…

贪心策略(三)多机调度问题、活动选择(库函数sort的整理)

把sort库函数的使用总结一下&#xff1a; 1、头文件#include<algorithm> 时间复杂度nlog(n) 2、使用格式 sort&#xff08;arr.begin(), arr.end()&#xff09;&#xff1b; 3、默认使用升序排序&#xff0c;第三个参数默认使用less<T>() 4、如果需要进行降序排序…

springcloud + nacos多环境联调、本地联调(即灰度版本)

背景&#xff1a;当我们使用nacos为注册中心注册微服务时&#xff0c;想本地环境和测试环境公用一个nacos&#xff0c;即注册中心等基础服务共用。当我们在服务A开发时&#xff0c;本地服务和测试环境服务都是注册到同一个nacos&#xff0c;由于nacos自带负载均衡策略&#xff…

小程序开发经验分享(9)小程序快速上线汇总

微信小程序申请 开发中的Appid 需要从“微信公众平台”中获取 如果是直接从git上拉取的话 直接项目导入就可以了(名称可以是中文) 小程序基础配置 如果需要修改显示的名称和appid可以去生成的配置文件project.config.json里面修改

前端特效之毛玻璃-倾斜-日历

前端特效之毛玻璃-倾斜-日历描述项目效果index.htmlindex.css描述 项目描述开发语言HTML、JavaScript、CSS库dyCalendarJS、vanilla-tilt 该项目中需要使用到的库有&#xff1a; dyCalendarJS vanilla-tilt.js 是 JavaScript 中的一个平滑的 3D 倾斜库。vanilla-tilt dyCalen…

MS SQL Server 日志审核工具

手动审核数据库活动是一项艰巨的任务。有效实现这一目标的最佳方法是使用全面的解决方案来简化和自动化数据库和活动监控。该解决方案还应使数据库管理员能够监控、跟踪、即时识别任何操作问题的根本原因&#xff0c;并实时检测对机密数据的未经授权的访问。 审核 Microsoft S…

Bootstrap踩坑笔记(记录Bootstrap当中的核心知识点)

目录 1.Bootstrap官网 2.核心1:布局&#xff08;栅格系统&#xff09; 3.核心知识点3:响应式布局 A.容器 B.行 C.列 注意: D.案例: E.列偏移 F.列排序 4. 样式 A.按钮 B.图片 C.表格 5.组件 A.导航条 B.分页条 C.js插件 1.Bootstrap官网 Bootsrap官网 2.核心1…

docker入门(二):docker的常用命令

文章目录前言docker常用命令1 启停类/帮助 命令2镜像命令3 容器命令结语前言 大家好&#xff0c;这是我学习docker系列的笔记文章&#xff0c;目标是掌握docker,为后续学习K8s做准备。本文列举了docker的常用命令&#xff0c;感兴趣的朋友可以看一下以前的文章。 上一篇&#…

处理Springboot项目启动时streamBridge.send导致的卡住卡死问题

现象 我们的Spring Boot 项目启动时&#xff0c;偶现卡死的现象&#xff0c;启动到一半卡主不动了 2023-01-16 10:23:10.338 INFO 1 --- [ restartedMain] com.hazelcast.core.LifecycleService : [172.18.0.14]:5701 [dev] [4.2.4] [172.18.0.14]:5701 is STARTED 20…

Unity脚本 --- 常用API(常用类) --- Component类和Transform类

上面这个是Unity核心类图 第一部分 --- Component类 提供了查找组件的方法&#xff08;当前物体的&#xff0c;子物体&#xff0c;父物体的&#xff09; 1.颜色&#xff08;color&#xff09;是材质&#xff08;meterial&#xff09;控制的&#xff0c;meterial&#xff08…