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

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 环境…...

流量牵引技术与传统防火墙的区别

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

【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等多种接口全部支持。 本期&#xff0c…...

【人工智能】人工智能领域中的线性回归算法原理、应用场景及代码示例。

🏆🏆欢迎大家来到我们的天空🏆🏆 🏆🏆如果文章内容对您有所触动,别忘了点赞、关注,收藏! 🏆 作者简介:我们的天空 🏆《头衔》&#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 是 …...

挑战杯推荐项目

“人工智能”创意赛 - 智能艺术创作助手:借助大模型技术,开发能根据用户输入的主题、风格等要求,生成绘画、音乐、文学作品等多种形式艺术创作灵感或初稿的应用,帮助艺术家和创意爱好者激发创意、提高创作效率。 ​ - 个性化梦境…...

R语言AI模型部署方案:精准离线运行详解

R语言AI模型部署方案:精准离线运行详解 一、项目概述 本文将构建一个完整的R语言AI部署解决方案,实现鸢尾花分类模型的训练、保存、离线部署和预测功能。核心特点: 100%离线运行能力自包含环境依赖生产级错误处理跨平台兼容性模型版本管理# 文件结构说明 Iris_AI_Deployme…...

.Net框架,除了EF还有很多很多......

文章目录 1. 引言2. Dapper2.1 概述与设计原理2.2 核心功能与代码示例基本查询多映射查询存储过程调用 2.3 性能优化原理2.4 适用场景 3. NHibernate3.1 概述与架构设计3.2 映射配置示例Fluent映射XML映射 3.3 查询示例HQL查询Criteria APILINQ提供程序 3.4 高级特性3.5 适用场…...

ServerTrust 并非唯一

NSURLAuthenticationMethodServerTrust 只是 authenticationMethod 的冰山一角 要理解 NSURLAuthenticationMethodServerTrust, 首先要明白它只是 authenticationMethod 的选项之一, 并非唯一 1 先厘清概念 点说明authenticationMethodURLAuthenticationChallenge.protectionS…...

Spring Boot面试题精选汇总

🤟致敬读者 🟩感谢阅读🟦笑口常开🟪生日快乐⬛早点睡觉 📘博主相关 🟧博主信息🟨博客首页🟫专栏推荐🟥活动信息 文章目录 Spring Boot面试题精选汇总⚙️ **一、核心概…...

WEB3全栈开发——面试专业技能点P2智能合约开发(Solidity)

一、Solidity合约开发 下面是 Solidity 合约开发 的概念、代码示例及讲解,适合用作学习或写简历项目背景说明。 🧠 一、概念简介:Solidity 合约开发 Solidity 是一种专门为 以太坊(Ethereum)平台编写智能合约的高级编…...

CSS设置元素的宽度根据其内容自动调整

width: fit-content 是 CSS 中的一个属性值&#xff0c;用于设置元素的宽度根据其内容自动调整&#xff0c;确保宽度刚好容纳内容而不会超出。 效果对比 默认情况&#xff08;width: auto&#xff09;&#xff1a; 块级元素&#xff08;如 <div>&#xff09;会占满父容器…...

C++使用 new 来创建动态数组

问题&#xff1a; 不能使用变量定义数组大小 原因&#xff1a; 这是因为数组在内存中是连续存储的&#xff0c;编译器需要在编译阶段就确定数组的大小&#xff0c;以便正确地分配内存空间。如果允许使用变量来定义数组的大小&#xff0c;那么编译器就无法在编译时确定数组的大…...

佰力博科技与您探讨热释电测量的几种方法

热释电的测量主要涉及热释电系数的测定&#xff0c;这是表征热释电材料性能的重要参数。热释电系数的测量方法主要包括静态法、动态法和积分电荷法。其中&#xff0c;积分电荷法最为常用&#xff0c;其原理是通过测量在电容器上积累的热释电电荷&#xff0c;从而确定热释电系数…...

基于Java Swing的电子通讯录设计与实现:附系统托盘功能代码详解

JAVASQL电子通讯录带系统托盘 一、系统概述 本电子通讯录系统采用Java Swing开发桌面应用&#xff0c;结合SQLite数据库实现联系人管理功能&#xff0c;并集成系统托盘功能提升用户体验。系统支持联系人的增删改查、分组管理、搜索过滤等功能&#xff0c;同时可以最小化到系统…...