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

Linux cond_resched()简介

文章目录

  • 简介
  • 一、cond_resched
    • 1.1 _cond_resched
    • 1.2 should_resched
      • 1.2.1 __preempt_count:
      • 1.2.2 函数说明
    • 1.3 preempt_schedule_common
      • 1.3.1 preempt_schedule_common
      • 1.3.2 preempt_latency_start/stop
    • 1.3.3 preempt_disable_notrace
  • 参考资料

简介

Linux 内核版本:4.19.90
处理器架构:x86_64
操作系统:Kylin Linux Advanced Server V10

一、cond_resched

CONFIG_PREEMPT_NONE=y
# CONFIG_PREEMPT is not set

该操作系统没有配置CONFIG_PREEMPT,配置CONFIG_PREEMPT_NONE,表示该系统在内核态是不可抢占的。

/** cond_resched() and cond_resched_lock(): latency reduction via* explicit rescheduling in places that are safe. The return* value indicates whether a reschedule was done in fact.* cond_resched_lock() will drop the spinlock before scheduling,*/
#ifndef CONFIG_PREEMPT
extern int _cond_resched(void);
#else
static inline int _cond_resched(void) { return 0; }
#endif#define cond_resched() ({			\___might_sleep(__FILE__, __LINE__, 0);	\_cond_resched();			\
})

cond_resched() 的目的是显式请求当前任务进行调度。它在可以安全地主动让出处理器给其他任务的位置使用。函数 _cond_resched() 在 cond_resched() 内部调用,以执行实际的调度操作。

由于配置了内核态是不可抢占的,在内核态运行的程序可调用cond_resched主动让出cpu,是为了在不可抢占内核的一些耗时的内核处理路径中增加主动抢占点,防止其在内核态执行时间过长导致可能发生的soft lockup或者造成较大的调度延迟。

1.1 _cond_resched

#ifndef CONFIG_PREEMPT
int __sched _cond_resched(void)
{if (should_resched(0)) {preempt_schedule_common();return 1;}rcu_all_qs();return 0;
}
EXPORT_SYMBOL(_cond_resched);
#endif

数 _cond_resched() 是一个具有 int 返回类型的函数,其参数列表为空。它的作用是进行条件调度,即根据一定的条件决定是否进行调度操作。

函数内部首先调用 should_resched(0) 来检查是否应该进行调度。should_resched() 是一个用于检查是否应该进行调度的函数,它的参数是一个整数(在此处传入了0)。如果 should_resched() 返回真值(非零),则表示应该进行调度。

如果应该进行调度,函数 _cond_resched() 调用 preempt_schedule_common() 来执行实际的调度操作。preempt_schedule_common() 是一个用于进行抢占式调度的函数,它会切换到其他可运行的任务。

如果不需要进行调度,函数 _cond_resched() 调用 rcu_all_qs() 函数。rcu_all_qs() 是一个用于处理 RCU(Read-Copy-Update)的函数,它用于等待所有的 RCU 队列完成。

最后,根据是否进行了调度操作,函数返回相应的值。如果进行了调度,返回值为1,否则返回0。

1.2 should_resched

// linux-4.19.90/arch/x86/include/asm/preempt.hDECLARE_PER_CPU(int, __preempt_count);/** Returns true when we need to resched and can (barring IRQ state).*/
static __always_inline bool should_resched(int preempt_offset)
{return unlikely(raw_cpu_read_4(__preempt_count) == preempt_offset);
}

1.2.1 __preempt_count:

在内核中只要没有持有锁,就可以就行内核抢占,锁是内核态是否抢占的标志,因此引入了一个preempt_count值,preempt_count初始值为0,每当使用锁时,该值就加1,释放锁时,该值就减1。preempt_count等于0代表内核可抢占。

因此对于内核态抢占来说,除了要判断是否设置了_TIF_NEED_RESCHED标志位,还需要判断preempt_count值是否等于0,内核中使用preempt_count来控制内核抢占。只有设置了_TIF_NEED_RESCHED标志位和preempt_count值等于0才能发起内核态抢占。

1.2.2 函数说明

该函数的目的是检查是否需要进行调度,并且在没有 IRQ(中断)发生的情况下可以进行调度。

函数内部使用 raw_cpu_read_4(__preempt_count) 来读取一个名为 __preempt_count 的全局变量的值。__preempt_count 是一个表示抢占计数的变量,用于跟踪当前任务的抢占状态。

unlikely() 宏用于提示编译器这个条件的结果通常是不成立的(即返回值为假)。这有助于编译器进行优化,以提高代码的执行效率。

函数比较 raw_cpu_read_4(__preempt_count) 的返回值与 preempt_offset(在这里也就是0,也就是判断__preempt_count的值是否为0) 参数是否相等。如果这两个值相等,意味着当前任务的抢占计数等于0,即需要进行调度。

如果相等,函数返回真值(非零),表示需要进行调度。否则,返回假值(零),表示不需要进行调度或者 IRQ 发生导致无法进行调度。

这个函数使用了 __always_inline 修饰符,表示建议编译器对该函数进行内联展开,以减少函数调用的开销。

在上面_cond_resched函数中调用should_resched函数时传入的参数是0,如果__preempt_count等于0,那么就发生调度(抢占式调度)。

1.3 preempt_schedule_common

static void __sched notrace preempt_schedule_common(void)
{do {/** Because the function tracer can trace preempt_count_sub()* and it also uses preempt_enable/disable_notrace(), if* NEED_RESCHED is set, the preempt_enable_notrace() called* by the function tracer will call this function again and* cause infinite recursion.** Preemption must be disabled here before the function* tracer can trace. Break up preempt_disable() into two* calls. One to disable preemption without fear of being* traced. The other to still record the preemption latency,* which can also be traced by the function tracer.*/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());
}

1.3.1 preempt_schedule_common

__schedule的参数preempt等于1表示是抢占调度,有处于运行态的任务发起的抢占调度。

preempt_schedule_common表示是抢占式调度。

函数内部使用一个循环,不断执行以下步骤:
(1)调用 preempt_disable_notrace(),禁用抢占,但不允许函数跟踪器(function tracer)对其进行跟踪。这是为了避免函数跟踪器在调用 preempt_enable_notrace() 时再次调用该函数,导致无限递归。
(2)调用 preempt_latency_start(1),开始记录抢占延迟时间,这也可以被函数跟踪器跟踪。
(3)调用 __schedule(true),进行实际的调度操作,切换到其他可运行的任务。
(4)调用 preempt_latency_stop(1),停止记录抢占延迟时间。
(5)调用 preempt_enable_no_resched_notrace(),启用抢占,但不允许函数跟踪器进行跟踪,并且不触发重新调度。

最后,在循环的末尾,通过调用 need_resched() 检查是否需要进行重新调度。如果需要重新调度,循环会继续执行上述步骤,直到不再需要重新调度为止。

这个函数的目的是在禁用抢占、记录抢占延迟、执行调度操作以及启用抢占的过程中,确保函数跟踪器的正常工作,并且避免出现无限递归的情况。同时,通过循环检查是否需要重新调度,确保不会错过可能的抢占机会。

1.3.2 preempt_latency_start/stop

preempt_latency_start() 和 preempt_latency_stop() 是用于记录抢占延迟时间的函数:

在多任务操作系统中,任务之间的切换是通过抢占机制实现的。当一个任务被抢占时,需要记录抢占的延迟时间,即从抢占开始到抢占结束的时间间隔。这个延迟时间对于性能分析和系统调优非常重要。

preempt_latency_start() 函数用于开始记录抢占延迟时间。它可能会调用系统计时器或其他相关机制来获取当前时间戳,并将其保存在某个数据结构中。通常,它会接收一个参数,用于标识抢占的类型或事件。

preempt_latency_stop() 函数用于停止记录抢占延迟时间。它也可能会使用系统计时器或其他机制获取当前时间戳,并将其与开始记录时的时间戳进行比较,以计算抢占的实际延迟时间。通常,它也会接收一个参数,用于标识抢占的类型或事件。

通过调用这两个函数,系统可以在抢占开始和结束时记录相关的时间戳,并计算抢占的延迟时间。这些延迟时间可以用于性能分析和诊断,以确定是否存在延迟问题,找出潜在的性能瓶颈,并进行系统调优。

1.3.3 preempt_disable_notrace

当需要禁用抢占且不被函数跟踪器追踪时,使用preempt_disable_notrace()函数。它用于禁用抢占,即当前任务不会被其他任务抢占。这个函数通常在代码的关键部分使用,确保当前任务能够无干扰地执行。

当需要重新启用抢占但不触发立即重新调度时,使用preempt_enable_no_resched_notrace()函数。它用于在禁用抢占后重新启用抢占。函数名中的no_resched表示不会立即重新调度。这意味着即使有更高优先级的任务可用,调度器也不会立即切换到其他任务。这在某些情况下非常有用,可以更加精确地控制调度行为。

总结一下,preempt_disable_notrace()用于禁用抢占且不被函数跟踪器追踪,确保当前任务不会被抢占。而preempt_enable_no_resched_notrace()用于重新启用抢占但不触发立即重新调度,从而更加精确地控制调度行为。这两个函数都用于关键代码区域,需要仔细管理抢占,同时避免受到函数跟踪器的干扰。

#define preempt_disable_notrace()		barrier()
#define preempt_enable_no_resched_notrace()	barrier()

barrier() 是一个预处理宏,用于插入一个内存屏障(memory barrier)。内存屏障是一种同步机制,用于确保在屏障之前和之后的操作按照特定的顺序执行,防止编译器或处理器对指令进行重排序。

在这种情况下,preempt_disable_notrace() 和 preempt_enable_no_resched_notrace() 宏被定义为 barrier(),是为了在禁用抢占和重新启用抢占之间插入内存屏障,以确保相关操作的顺序性。这可能是为了保证在禁用抢占和重新启用抢占之间的任何指令都不会被编译器或处理器进行重排序,从而确保这些操作的原子性和可预测性。

关于内存屏障用途(这段话的来自https://blog.csdn.net/orangeboyye 这个博主):
内存屏障有两种用途,一是设备内存,设备内存需要顺序执行,不能重排序。
二是多CPU,CPU乱序执行能保证单核逻辑的正确性,但是它不可能替你考虑多核逻辑的正确性,如果你的代码里有多核逻辑(多线程在多核并行运行),就需要考虑乱序执行带来的影响,就需要内存屏障了。为什么大部分情况你都没用过内存屏障,因为一般情况的多核逻辑你都会用锁,锁里面用的有内存屏障。

参考资料

Linux 4.19.90

Linux 调度器之抢占式调度
cond_resched的使用
深入理解Linux内核之主调度器(上)

相关文章:

Linux cond_resched()简介

文章目录 简介一、cond_resched1.1 _cond_resched1.2 should_resched1.2.1 __preempt_count:1.2.2 函数说明 1.3 preempt_schedule_common1.3.1 preempt_schedule_common1.3.2 preempt_latency_start/stop 1.3.3 preempt_disable_notrace 参考资料 简介 Linux 内核…...

初出茅庐的小李博客之认识编码器

编码器是什么: 一种将角位移或者角速度转换成一连串电数字脉冲的旋转式传感器,我们可以通过编码器测量到底位移或者速度信息。编码器通常由一个旋转部分和一个固定部分组成,旋转部分随着被测量的物体进行旋转,固定部分则保持不动…...

NVIDIA TX2 NX编译及更新设备树

在NVIDIA官网下载相关文件 官网网址:https://developer.nvidia.com/embedded/jetson-linux-archive 我选择的版本为R32.7.4 需要下载3个文件,BSP、根文件系统、BSP源码: 解压 将Tegra_Linux_Sample-Root-Filesystem_R32.7.4_aarch64文件夹下的内容提取到Jetson_Linux_R32.…...

从零开始学Python(二)运算符、if、循环结构

🥳🥳Welcome Huihuis Code World ! !🥳🥳 接下来看看由辉辉所写的关于Python的相关操作吧 目录 🥳🥳Welcome Huihuis Code World ! !🥳🥳 一.运算符 1.基本运算符 2.比较运算符 …...

Sentinel整合Spring Cloud Gateway、Zuul详解

Sentinel 支持对 Spring Cloud Gateway、Zuul 等主流的 API Gateway 进行限流。 Sentinel 1.6.0 引入了 Sentinel API Gateway Adapter Common 模块,此模块中包含网关限流的规则和自定义 API 的实体和管理逻辑: GatewayFlowRule:网关限流规则…...

wsl2安装mysql环境

安装完mysql后通过如下命令启动mysql service mysql start 会显示如下错误: mysql: unrecognized service 实际上上面显示的错误是由于mysql没有启动成功造成的 我们要想办法成功启动mysql才可以 1.通过如下操作就可以跳过密码直接进入mysql环境 2.如果想找到my…...

C#质检工具(StyleCop、SonarLint)

1、StyleCop StyleCop工具主要类似java中的checkStyle,是检查代码样式规范的工具。 1.1、StyleCop安装流程: 图1.1 图1.2 图1.3 安装StyleCop插件时可能会遇到下载特慢或卡住不动的情况,需注意: 1)网上说的关闭IPV6功能不管用 2)网上说的自动指定dns不管用 3)网上…...

PyTorch翻译官网教程-NLP FROM SCRATCH: GENERATING NAMES WITH A CHARACTER-LEVEL RNN

官网链接 NLP From Scratch: Generating Names with a Character-Level RNN — PyTorch Tutorials 2.0.1cu117 documentation 使用字符级RNN生成名字 这是我们关于“NLP From Scratch”的三篇教程中的第二篇。在第一个教程中</intermediate/char_rnn_classification_tutor…...

【C语言】结构体详解

现实生活中一个事物&#xff0c;会有许多属性连接起来。而C语言引入一种构造数据类型——结构体 将属于一个事物的多个数据组织起来以体现其内部联系。 一、结构体类型的定义 结构体类型 是一种 构造类型&#xff0c;它是由若干成员组成的&#xff0c;每个成员可以是一个基本…...

leetcode242. 有效的字母异位词

题目&#xff1a;leetcode242. 有效的字母异位词 描述&#xff1a; 给定两个字符串 s 和 t &#xff0c;编写一个函数来判断 t 是否是 s 的字母异位词。 注意&#xff1a;若 s 和 t 中每个字符出现的次数都相同&#xff0c;则称 s 和 t 互为字母异位词。 示例 1: 输入: s “…...

Unity 编辑器资源导入处理函数 OnPostprocessAudio :深入解析与实用案例

Unity 编辑器资源导入处理函数 OnPostprocessAudio 用法 点击封面跳转下载页面 简介 在Unity中&#xff0c;我们可以使用编辑器资源导入处理函数&#xff08;OnPostprocessAudio&#xff09;来自定义处理音频资源的导入过程。这个函数是继承自AssetPostprocessor类的&#xff…...

uniapp开发(由浅到深)

文章目录 1. 项目构建1.1 脚手架构建1.2 HBuilderX创建 uni-app项目步骤&#xff1a; 2 . 包依赖2.1 uView2.2 使用uni原生ui插件2.3 uni-modules2.4 vuex使用 3.跨平台兼容3.1 条件编译 4.API 使用4.1 正逆参数传递 5. 接口封装6. 多端打包3.1 微信小程序3.2 打包App3.2.1 自有…...

QT-基于Buildroot构建系统镜像下实现QT开发

QT-基于Buildroot构建系统镜像下实现QT开发 BuildRootUboot的仓库地址和commit idKernel 的仓库地址和commit id BuildRoot已编译库在Windows上的Create上创建项目编译QT项目 BuildRoot 这部分按照100ask官网的教程走即可: Uboot的仓库地址和commit id https://e.coding.net/…...

优雅地处理RabbitMQ中的消息丢失

目录 一、异常处理 二、消息重试机制 三、错误日志记录 四、死信队列 五、监控与告警 优雅地处理RabbitMQ中的消息丢失对于构建可靠的消息系统至关重要。下面将介绍一些优雅处理消息丢失的方案&#xff0c;包括异常处理、重试机制、错误日志记录、死信队列和监控告警等。…...

Vim入门教程vimtutor1.7总结

vimtutor命令可以打开教程文档 原文特别提示 ⬇⬇⬇ 特别提示&#xff1a;切记您要在使用中学习&#xff0c;而不是在记忆中学习 Vim模式 正常模式&#xff08;Normal Mode&#xff09;&#xff1a;默认模式&#xff0c;可以使用基础命令进行操作命令模式&#xff08;Command…...

Stephen Wolfram:让 ChatGPT 真正起作用的是什么?

What Really Lets ChatGPT Work? 让 ChatGPT 真正起作用的是什么&#xff1f; Human language—and the processes of thinking involved in generating it—have always seemed to represent a kind of pinnacle of complexity. And indeed it’s seemed somewhat remarkabl…...

CTF-Flask-Jinja2(持续更新)

放心&#xff0c;我会一直陪着你 一.知识一.在终端的一些指令1.虚拟环境2.docker容器二.SSTI相关知识介绍1.魔术方法2.python如何执行cmd命令3.SSTI常用注入模块(1)文件读取(2)内建函数eval执行命令(3)os模块执行命令(4)importlib类执行命令(5)linecache函数执行命令(6)subproc…...

linux文件I/O之 fcntl() 函数用法:设置文件的 flags、设置文件锁(记录锁)

头文件和函数声明 #include <unistd.h> #include <fcntl.h> int fcntl(int fd, int cmd, ... /* arg */ ); 函数功能 获取、设置已打开文件的属性 返回值 成功时返回根据 cmd 传递的命令类型的执行结&#xff0c;失败时返回 -1&#xff0c;并设置 errno 为相…...

黑马项目一完结后阶段面试45题 JavaSE基础部分20题(一)

一、Java数据类型 基本数据类型——四类八种 整数型 byte short int long 浮点型 float double 字符型 char 布尔型 boolean 引用数据类型 String字符串 类&#xff08;对象&#xff09; 接口类型 数组类型 枚举类型 二、面向对象的三大特性 1.封装 把同一类事物…...

(一)创建型设计模式:3、建造者模式(Builder Pattern)

目录 1、建造者模式含义 2、建造者模式的讲解 3、使用C实现建造者模式的实例 4、建造者模式的优缺点 5、建造者模式VS工厂模式 1、建造者模式含义 The intent of the Builder design pattern is to separate the construction of a complex object from its representatio…...

《Qt C++ 与 OpenCV:解锁视频播放程序设计的奥秘》

引言:探索视频播放程序设计之旅 在当今数字化时代,多媒体应用已渗透到我们生活的方方面面,从日常的视频娱乐到专业的视频监控、视频会议系统,视频播放程序作为多媒体应用的核心组成部分,扮演着至关重要的角色。无论是在个人电脑、移动设备还是智能电视等平台上,用户都期望…...

c#开发AI模型对话

AI模型 前面已经介绍了一般AI模型本地部署&#xff0c;直接调用现成的模型数据。这里主要讲述讲接口集成到我们自己的程序中使用方式。 微软提供了ML.NET来开发和使用AI模型&#xff0c;但是目前国内可能使用不多&#xff0c;至少实践例子很少看见。开发训练模型就不介绍了&am…...

成都鼎讯硬核科技!雷达目标与干扰模拟器,以卓越性能制胜电磁频谱战

在现代战争中&#xff0c;电磁频谱已成为继陆、海、空、天之后的 “第五维战场”&#xff0c;雷达作为电磁频谱领域的关键装备&#xff0c;其干扰与抗干扰能力的较量&#xff0c;直接影响着战争的胜负走向。由成都鼎讯科技匠心打造的雷达目标与干扰模拟器&#xff0c;凭借数字射…...

OpenLayers 分屏对比(地图联动)

注&#xff1a;当前使用的是 ol 5.3.0 版本&#xff0c;天地图使用的key请到天地图官网申请&#xff0c;并替换为自己的key 地图分屏对比在WebGIS开发中是很常见的功能&#xff0c;和卷帘图层不一样的是&#xff0c;分屏对比是在各个地图中添加相同或者不同的图层进行对比查看。…...

全面解析各类VPN技术:GRE、IPsec、L2TP、SSL与MPLS VPN对比

目录 引言 VPN技术概述 GRE VPN 3.1 GRE封装结构 3.2 GRE的应用场景 GRE over IPsec 4.1 GRE over IPsec封装结构 4.2 为什么使用GRE over IPsec&#xff1f; IPsec VPN 5.1 IPsec传输模式&#xff08;Transport Mode&#xff09; 5.2 IPsec隧道模式&#xff08;Tunne…...

MySQL用户和授权

开放MySQL白名单 可以通过iptables-save命令确认对应客户端ip是否可以访问MySQL服务&#xff1a; test: # iptables-save | grep 3306 -A mp_srv_whitelist -s 172.16.14.102/32 -p tcp -m tcp --dport 3306 -j ACCEPT -A mp_srv_whitelist -s 172.16.4.16/32 -p tcp -m tcp -…...

RNN避坑指南:从数学推导到LSTM/GRU工业级部署实战流程

本文较长&#xff0c;建议点赞收藏&#xff0c;以免遗失。更多AI大模型应用开发学习视频及资料&#xff0c;尽在聚客AI学院。 本文全面剖析RNN核心原理&#xff0c;深入讲解梯度消失/爆炸问题&#xff0c;并通过LSTM/GRU结构实现解决方案&#xff0c;提供时间序列预测和文本生成…...

.Net Framework 4/C# 关键字(非常用,持续更新...)

一、is 关键字 is 关键字用于检查对象是否于给定类型兼容,如果兼容将返回 true,如果不兼容则返回 false,在进行类型转换前,可以先使用 is 关键字判断对象是否与指定类型兼容,如果兼容才进行转换,这样的转换是安全的。 例如有:首先创建一个字符串对象,然后将字符串对象隐…...

项目部署到Linux上时遇到的错误(Redis,MySQL,无法正确连接,地址占用问题)

Redis无法正确连接 在运行jar包时出现了这样的错误 查询得知问题核心在于Redis连接失败&#xff0c;具体原因是客户端发送了密码认证请求&#xff0c;但Redis服务器未设置密码 1.为Redis设置密码&#xff08;匹配客户端配置&#xff09; 步骤&#xff1a; 1&#xff09;.修…...

2025季度云服务器排行榜

在全球云服务器市场&#xff0c;各厂商的排名和地位并非一成不变&#xff0c;而是由其独特的优势、战略布局和市场适应性共同决定的。以下是根据2025年市场趋势&#xff0c;对主要云服务器厂商在排行榜中占据重要位置的原因和优势进行深度分析&#xff1a; 一、全球“三巨头”…...