Linux抢占调度
目录
抢占流程
抢占时机
用户态抢占时机
1、 从系统调用返回用户空间
2、 从中断返回用户空间
内核态抢占时机
1、中断处理程序返回内核空间
可以看到最终是到了 preempt_schedule_irq
2、当内核从non-preemptible(禁止抢占)状态变成preemptible(允许抢占)的时候;
3、内核主动进行任务切换
备注
https://blog.csdn.net/heyangge/article/details/134666931
https://zhuanlan.zhihu.com/p/519030765
17 | 调度(下):抢占式调度是如何发生的?-CSDN博客
抢占式调度和非抢占式调度是操作系统中两种不同的进程调度方式。
在抢占式调度中,操作系统可以在任何时候中断正在运行的进程,并将 CPU分配给另一个处于就绪状态的进程。这意味着,一个高优先级的进程可以随时抢占正在运行的低优先级进程的 CPU时间片。这种方式可以保证高优先级进程得到更快的响应时间,但可能会导致低优先级进程的运行时间不确定。
相反,在非抢占式调度中,一个进程只有在自愿放弃CPU或者因为等待某个事件而被阻塞时,操作系统才会将 CPU分配给另一个进程。这种方式可以保证低优先级进程得到更稳定的运行时间,但可能会导致高优先级进程得不到及时响应。总的来说,抢占式调度适用于实时系统或需要快速响应的场景,而非抢占式调度适用于一些需要稳定运行的应用,如批处理系统
- 抢占式内核:当一个进程在内核模式下运行时,如果有一个更高优先级的任务出现,内核可以强制将当前任务挂起,执行更高优先级的任务。这种内核总是执行准备运行的最高优先级任务,除非函数是互斥的,否则不能使用非可重入函数。
- 非抢占式内核:也称为合作式内核,进程必须显式地放弃CPU才能让另一个进程运行。这种内核不会中断正在运行的进程,直到它自愿释放CPU。
对于非抢占内核:就是内核线程能一直运行下去,除非自己主动调用schedule或者进行了会休眠的动作,才会让出cpu 。即使当前执行流被中断/软中断打断,当其执行完成后,也必须回到打断的线程继续执行。这种内核解决异常问题稍微简单点,但是如果代码里面有啥死循环或者死锁之类的,那这个核就废了。
对于抢占式内核:感觉可能在中断触发后,可能就会切换到其他进程了,回不来了。这点用户态和内核态应该都是一样的。(没有用过。。)
抢占流程
Linux抢占(PREEMPTION)_linux preempt-CSDN博客
抢占的过程分两步,第一步触发抢占,第二步执行抢占,这两步中间不一定是连续的,有些特殊情况下甚至会间隔相当长的时间:
1、触发抢占:给正在CPU上运行的当前进程设置一个请求重新调度的标志(TIF_NEED_RESCHED),仅此而已,此时进程并没有切换。
2、执行抢占:在随后的某个时刻,内核会检查TIF_NEED_RESCHED标志并调用schedule()执行抢占。
抢占时机
如果是抢占式的,它应该在何时进行抢占呢?
用户态抢占时机
有两种情况,分别是从系统调用返回用户空间和从中断处理程序返回用户空间
1、 从系统调用返回用户空间
https://zhuanlan.zhihu.com/p/363148708 //这个是用户态抢占调度的地方
1、内核态抢占是可以关闭的,用户态抢占是无法关闭的。
2、如果内核编译配置是“CONFIG_PREEMPT_NONE=y”。这就意味着一个正处于内核态的进程是不能被抢占的,无论它运行的时间有多长,也无论其他进程的优先级比它高多少,都只能等它回到用户态才能抢占。(这个意思就是非抢占内核的情况下,即使是一个用户态进程,如果其进行了系统调用陷入内核,在内核里面执行的这段时间也是无法被抢占的。如果是内核线程,那就永远无法被抢占)
Linux抢占(PREEMPTION)_linux preempt-CSDN博客 //这个文章写了用户态的抢占是无法关闭的
用户态进行系统调用的时候会进入到vector_swi,在该函数里面会跳转到内核系统调用接口里面去,并且设置返回值为ret_fast_syscall ,其实现如下(其实它有两种实现)(参考文章arm系统调用过程_arm系统调用号-CSDN博客)
#define _TIF_WORK_MASK (_TIF_NEED_RESCHED | _TIF_SIGPENDING | \_TIF_NOTIFY_RESUME | _TIF_UPROBE)ret_fast_syscall:UNWIND(.fnstart )UNWIND(.cantunwind )str r0, [sp, #S_R0 + S_OFF]! @ save returned r0disable_irq_notrace @ disable interruptsldr r2, [tsk, #TI_ADDR_LIMIT]cmp r2, #TASK_SIZEblne addr_limit_check_failedldr r1, [tsk, #TI_FLAGS] @ re-check for syscall tracingtst r1, #_TIF_SYSCALL_WORK | _TIF_WORK_MASKbeq no_work_pending //如果没有设置need sch或者是有信号待处理,则跳转到no_work_pending返回用户空间,如果相等,我感觉应该是继续往下执行UNWIND(.fnend )
ENDPROC(ret_fast_syscall)/* Slower path - fall through to work_pending */
#endiftst r1, #_TIF_SYSCALL_WORKbne __sys_trace_return_nosave
slow_work_pending:mov r0, sp @ 'regs'mov r2, why @ 'syscall'bl do_work_pendingcmp r0, #0beq no_work_pendingmovlt scno, #(__NR_restart_syscall - __NR_SYSCALL_BASE)ldmia sp, {r0 - r6} @ have to reload r0 - r6b local_restart @ ... and off we go
ENDPROC(ret_fast_syscall)
tst r1, #_TIF_SYSCALL_WORK | _TIF_WORK_MASK //如果不为0,则跳转到slow_work_pending去进行抢占或者下信号处理(上面提到根据定义的宏的不同ret_fast_syscall有两种实现,但是最终都会走到slow_work_pending)
slow_work_pending:mov r0, sp @ 'regs'mov r2, why @ 'syscall'bl do_work_pendingcmp r0, #0beq no_work_pendingmovlt scno, #(__NR_restart_syscall - __NR_SYSCALL_BASE)ldmia sp, {r0 - r6} @ have to reload r0 - r6b local_restart @ ... and off we go
ENDPROC(ret_fast_syscall)
slow_work_pending-->do_work_pending:可以看到这就是为什么用户态无法禁止抢占了。只要你设置了_TIF_NEED_RESCHED标记,走到这里就会无条件进行任务切换了
asmlinkage int
do_work_pending(struct pt_regs *regs, unsigned int thread_flags, int syscall)
{
...............................trace_hardirqs_off();do {/* 如果设置可以抢占的标记,就会直接进行调度了 */if (likely(thread_flags & _TIF_NEED_RESCHED)) {schedule();} else {...............................}local_irq_disable();thread_flags = current_thread_info()->flags;} while (thread_flags & _TIF_WORK_MASK);return 0;
}
2、 从中断返回用户空间
vector_irq-->__irq_usr(被打断的是用户态)
__irq_usr:usr_entrykuser_cmpxchg_checkirq_handlerget_thread_info tskmov why, #0b ret_to_user_from_irqUNWIND(.fnend )
ENDPROC(__irq_usr)
可以看到在中断处理完以后会走到ret_to_user_from_irq,在该函数里面也是调用的slow_work_pending。所以用户态无论是通过系统调用还是中断陷入内核,抢占都是在这里发生的。主要的一个中断就是时钟中断
ENTRY(ret_to_user_from_irq)ldr r2, [tsk, #TI_ADDR_LIMIT]cmp r2, #TASK_SIZEblne addr_limit_check_failedldr r1, [tsk, #TI_FLAGS]tst r1, #_TIF_WORK_MASKbne slow_work_pending
no_work_pending:asm_trace_hardirqs_on save = 0/* perform architecture specific actions before user return */arch_ret_to_user r1, lrct_user_enter save = 0restore_user_regs fast = 0, offset = 0
ENDPROC(ret_to_user_from_irq)
内核态抢占时机
内核为了支持抢占,为每个进程的thread info引入了preempt_count计数器。该计数初始为0,每当加锁(还得看代码具体代码实现)或者是显示禁止抢占preempt_disable等操作会加1,反之释放锁或者是开启抢占则减1。当计数器为0的时候表示内核允许抢占
可以通过CONFIG_PREEMPT_COUNT=y开启抢占计数器。这样内核就能在切换时检查preempt_count计数是否为0,是否运行进行抢占切换
1、中断处理程序返回内核空间
中断处理程序返回内核空间之前会检查TIF_NEED_RESCHED标志,如果置位则调用preempt_schedule_irq()执行抢占。preempt_schedule_irq()是对schedule()的包装
中断发生在内核__irq_svc(CONFIG_PREEMPT开启了表示内核运行抢占)。中断返回时会去检查TIF_NEED_RESCHED,如果设置表示可以抢占
__irq_svc:@将中断现场保存到内核栈中svc_entry@中断处理过程irq_handler@如果开启了抢占功能,则中断返回时会检查是否可以抢占发生中断时的进程
@检查thread_info->preempt_count是否为0
#ifdef CONFIG_PREEMPTget_thread_info tskldr r8, [tsk, #TI_PREEMPT] @ get preempt countldr r0, [tsk, #TI_FLAGS] @ get flagsteq r8, #0 @ if preempt count != 0movne r0, #0 @ force flags to 0tst r0, #_TIF_NEED_RESCHEDblne svc_preempt
#endifsvc_exit r5, irq = 1 @ return from exceptionUNWIND(.fnend )
ENDPROC(__irq_svc)
#ifdef CONFIG_PREEMPT
svc_preempt:mov r8, lr
1: bl preempt_schedule_irq @ irq en/disable is done insideldr r0, [tsk, #TI_FLAGS] @ get new tasks TI_FLAGStst r0, #_TIF_NEED_RESCHEDreteq r8 @ go againb 1b
#endif
可以看到最终是到了 preempt_schedule_irq
schedule前调用preempt_disable禁止抢占原因:因为调度前开启了中断,如果不禁止抢占,那么可能被中断打断,这样在中断退出时preemp_cout又是0,并且TIF_NEED_RESCHED未清除,又能够走到这里 来回套娃
asmlinkage __visible void __sched preempt_schedule_irq(void)
{enum ctx_state prev_state;/* Catch callers which need to be fixed */BUG_ON(preempt_count() || !irqs_disabled());prev_state = exception_enter();do {/*不明白在切换之前为什么还需要将抢占计数加1,这样不是不能抢占了吗?看了网上说调用__schedule都会显示禁用抢占然后schedule_debug就判断是preempt_count是不是1,不是1就打印原子上下文调度告警*/preempt_disable();local_irq_enable();__schedule(true);local_irq_disable();sched_preempt_enable_no_resched();} while (need_resched());exception_exit(prev_state);
}
2、当内核从non-preemptible(禁止抢占)状态变成preemptible(允许抢占)的时候;
- 在preempt_enable()中,会最终调用 preempt_schedule 来执行抢占。preempt_schedule()是对schedule()的包装。
asmlinkage __visible void __sched notrace preempt_schedule(void)
{if (likely(!preemptible()))return;preempt_schedule_common();
}
static void __sched notrace preempt_schedule_common(void)
{do {preempt_disable_notrace();preempt_latency_start(1);__schedule(true);preempt_latency_stop(1);preempt_enable_no_resched_notrace();/** Check again in case we missed a preemption opportunity* between schedule and now.*/} while (need_resched());
}
3、内核主动进行任务切换
其实这个感觉不算抢占了
备注
1、开启了CONFIG_PREEMPT_COUNT,抢占计数器才会生效,即preempt_disable/preempt_enablec才会修改preempt_count,否则这些操作只是等价于barrier()
2、CONFIG_PREEMPT配置了内核才开启抢占,否则就算是计数器生效了,内核也无法进行抢占,只是会任务切换的时候打告警,告诉切换时preempt_count不为1,可能有风险
相关文章:

Linux抢占调度
目录 抢占流程 抢占时机 用户态抢占时机 1、 从系统调用返回用户空间 2、 从中断返回用户空间 内核态抢占时机 1、中断处理程序返回内核空间 可以看到最终是到了 preempt_schedule_irq 2、当内核从non-preemptible(禁止抢占)状态变成pr…...

k8s中,为什么把pod的服务以deployment的形式通过nodeport对外发布,以及容器和虚拟机的一些区别
deployment是个控制器 主要负责管理pod,来代表k8s集群向外提供稳定的服务。 说,k8s有很多优点。 说k8s的优点,可能先需要说容器提供的便利。 同样的硬件资源 跑几个虚拟机,每个虚拟机上跑几个服务。 就挺重了。风扇呼呼叫 …...

PMP--一模--解题--41-50
文章目录 14.敏捷--方法--回顾--回顾是最重要的一个实践,原因是它能让团队学习、改进和调整其过程。41、 [单选] 新项目中的所有团队成员都希望通过尽快交付价值来获得客户的信任。项目经理了解到一个资源已经在其他项目中与发起人一起工作。某资源似乎在使用个人影…...

Kafka启动关闭及其相关命令kafka启动、状态监控、日常操作
开启zookeeper命令(备注:先进入zookeeper的bin目录) ./zkServer.sh start 关闭zookeeper命令(备注:先进入zookeeper的bin目录) ./zkServer.sh stop Kafka启动命令(备注:先进入kafka目录) 常规模式启动kafka bin/kafka-server-start.sh config/server.properties 进程守…...

CentOS 系统设置与维护教程
CentOS 系统设置与维护教程 在这篇博客中,我们将介绍在 CentOS 系统上进行的一些常见操作,包括停止和禁用防火墙服务、配置 SELinux。我们还将展示如何切换到 root 用户以执行这些操作。通过这些操作,你可以更好地管理和配置你的 CentOS 环境…...

流量牵引技术与传统防火墙的区别
在网络安全领域,流量牵引技术和传统防火墙都起着重要的作用,但它们在很多方面存在着明显的区别。 一、工作原理不同 传统防火墙主要是通过设置访问控制规则来过滤网络流量。它基于预先设定的策略,对进入和离开网络的数据包进行检查…...

【Python爬虫系列】_020.异步协程asyncio
课 程 推 荐我 的 个 人 主 页:👉👉 失心疯的个人主页 👈👈入 门 教 程 推 荐 :👉👉 Python零基础入门教程合集 👈👈虚 拟 环 境 搭 建 :👉👉 Python项目虚拟环境(超详细讲解) 👈👈PyQt5 系 列 教 程:👉👉 Python GUI(PyQt5)文章合集 👈👈…...

ubuntu22安装docker
1、查看服务器系统信息 uname -a:显示内核名称、主机名、内核版本、处理器类型等信息。 lsb_release -a:显示有关 Ubuntu 发行版的详细信息,包括版本号、代号等。 free -h:查看系统内存使用情况。 df -h:查看磁盘空间使…...

【拥抱AI】如何使用Pandas进行数据分段
安装Pandas库 如果您的环境中尚未安装Pandas库,可以使用pip命令进行安装: pip install pandas导入Pandas库 在Python脚本中,导入Pandas库以便使用其数据处理功能: import pandas as pd读取文本文件 使用Pandas的read_csv函数…...

Docker Compose version v2.29.2 提示 exited with code 0 解决方案
问题描述: 使用 docker-compose up 启动容器时,老是报错exited with code 0,容器要么处于退出,要么处于重启阶段,查明原因后,是因为docker容器执行任务完成后就会处于exited状态,必须强制状态。…...

深度学习速通系列:依存分析
依存分析(Dependency Parsing)是自然语言处理(NLP)中的一项任务,目的是确定句子中单词之间的依存关系,并将这些关系表示为一个有向图,通常称为依存树。在依存树中,每个节点代表一个单…...

玩转扩展库,温湿度传感器篇!—合宙Air201资产定位模组LuatOS快速入门05
随着LuatOS快速入门系列教程的推出,小伙伴们学习热情高涨。 合宙Air201不仅支持三种定位方式,还具有丰富的扩展功能,通过外扩BTB链接方案,最多可支持21个IO接口:SPI、I2C、UART等多种接口全部支持。 本期,…...

【人工智能】人工智能领域中的线性回归算法原理、应用场景及代码示例。
🏆🏆欢迎大家来到我们的天空🏆🏆 🏆🏆如果文章内容对您有所触动,别忘了点赞、关注,收藏! 🏆 作者简介:我们的天空 🏆《头衔》&#x…...

day18JS-微任务、宏任务和node.js
1. 代码的执行流程 代码的执行流程分为同步与异步。 2. 什么样子的是宏任务? 1. setTimeout 和 setInterval 定时器: 没有写时间(传参的),代表下一帧执行,如果没有其他任务1ms后执行。 // 没有写时间(传参的),代表下…...

Mega Stamp Bundle 地形合集捆绑包峡谷沙丘山脉
终极套装,满足所有地形雕刻需求! 自2015年Gaia发布以来,我们团队就发明了印章技术,欢迎来到Mega Stamp Bundle! 本套装包含14个印章包,单次购买即可享受大幅折扣,共获得140个专业设计的印章。 这些印章可与Unity Terrain Tools、Gaia以及任何使用印章高度图图像的工具…...

基于SpringBoot+Vue+MySQL的明星周边产品销售网站系统
系统展示 用户前台界面 管理员后台界面 系统背景 在当今数字化消费时代,粉丝经济蓬勃发展,明星周边产品作为连接明星与粉丝的重要纽带,市场需求日益增长。为了满足广大粉丝对明星周边产品的热情追求,并提升购物体验,我…...

websocket 和sip 在协议层面有哪些区别,为什么要各自这样设置协议
WebSocket 和 SIP(Session Initiation Protocol)在协议层面有显著区别,因为它们各自的设计目标和用途不同。让我们从协议的定义、工作方式和用途来讨论这些区别: 1. 协议定义与用途 WebSocket: WebSocket 是一种通信协议,旨在通过单个 TCP 连接实现全双工通信。它用于在客…...

Miracast/WifiDisplay开发相关的深入调研分析-android投屏实战开发
Miracast/WifiDisplay概念介绍 Miracast Miracast是由Wi-Fi联盟于2012年所制定,以Wi-Fi直连(Wi-Fi Direct)为基础的无线显示标准。支持此标准的消费性电子产品(又称3C设备)可透过无线方式分享视频画面,例如…...

linux入门到实操-4 linux系统网络配置、连接测试、网络连接模式、修改静态IP、配置主机名
教程来源:B站视频BV1WY4y1H7d3 3天搞定Linux,1天搞定Shell,清华学神带你通关_哔哩哔哩_bilibili 整理汇总的课程内容笔记和课程资料(包含课程同版本linux系统文件等内容),供大家学习交流下载:…...

【kubernetes】Ingress和Ingress-Controller介绍,高可用应用案例
一,Ingress介绍 Ingress是k8s中一种重要的资源对象,它主要用于定义从集群外部到集群内部服务的HTTP(S)路由规则。用于管理代理 Ingress-Controller的配置文件。 kubectl explain ingress二,Ingress-Controller介绍 Ingress Controller 是 …...

C# 使用Socket通信,新建WinForm服务端、客户端程序
一、新建WinForm Socket服务端程序 注:rtbReceviceMsg为RichTextBox控件 服务端程序、界面 服务端代码 public partial class Form1 : Form {public Form1(){InitializeComponent();}public virtual void TriggerOnUpdateUI(string message){if (this.InvokeRequir…...

Kamailio-基于Homer与heplify的SIP信令监控-2
接上篇,我们已经顺利地完成了服务的安装,下面就来看看如何配置并启动。 跟着我,你将学会: 下载并安装 踩坑:按照官方步骤来,可是网络条件不允许 获取YUM源下载RPM包手动解压安装避坑 配置并启动…...

unity3d入门教程四
unity3d入门教程四 10.1坐标与旋转10.2物体的运动10.3(练习)掉头飞行11.1向量11.2向量间运算11.3向量夹角11.4物体的指向11.5(练习)飞向目标12.1屏幕坐标12.2屏幕的边界 10.1坐标与旋转 比如,节点的坐标用 Vector3 类型…...

无人机飞控的原理!!!
一、传感器系统 陀螺仪:用于检测无人机的角速度和角度,帮助确定无人机的姿态。 加速度计:用于检测无人机的加速度和倾斜角度,进一步辅助姿态判断。 磁力计(或罗盘):用于检测无人机的方向&…...

深入解析代理模式:静态代理、JDK 动态代理和 CGLIB 的全方位对比!
代理模式(Proxy Pattern)是一种结构型设计模式,它提供了对象的替身,即代理对象来控制对实际对象的访问。通过代理对象,可以在不修改目标对象的情况下,扩展或控制其功能。例如,代理模式可以用于延…...

51单片机快速入门之独立按键
51单片机快速入门之独立按键 这里我们需要用上一个仿真软件,只因不想硬件焊接:PROTEUS DESIGN SUITE PROTEUS DESIGN SUITE: PROTEUS DESIGN SUITE是一款由LabCenter Electronics开发的电子设计自动化(EDA)软件,广泛应用于电气工程和电子工…...

设计模式之工厂模式(通俗易懂--代码辅助理解【Java版】)
文章目录 设计模式概述1、工厂模式概述1)特点:2)主要角色:3)工作流程:4)优点5)缺点6)适用场景 2、简单工厂模式(静态工厂模式)1) 在简单工厂模式中,有三个主要…...

速盾:高防 cdn 分布式防御攻击?
在当今数字化时代,网络安全问题日益凸显,各种网络攻击手段层出不穷。为了保护企业和个人的网络资产安全,高防 CDN(Content Delivery Network,内容分发网络)成为了一种重要的防御手段。其中,分布…...

Unity3D类似于桌面精灵的功能实现
前言: 由于最近在做游戏魔改,很多功能在游戏里面没法实现(没错,说的就是排行榜),所以准备用Unity3D开发一个类似于桌面精灵的功能部件,实现效果如下: PS:有需要定制的老…...

Audio Over IP的PTP时钟初探
Audio Over IP的PTP时钟初探 这几天参加省局举办的技术能手比赛,第一次接触并了解AOIP(Audio Over IP)相关的理论和实践相关的知识。其中AoIP的时钟同步采用的是IEEE 1588 标准的PTP(Precision Time Protocol)基于网络…...