当前位置: 首页 > 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…...

设计模式和设计原则回顾

设计模式和设计原则回顾 23种设计模式是设计原则的完美体现,设计原则设计原则是设计模式的理论基石, 设计模式 在经典的设计模式分类中(如《设计模式:可复用面向对象软件的基础》一书中),总共有23种设计模式,分为三大类: 一、创建型模式(5种) 1. 单例模式(Sing…...

k8s从入门到放弃之Ingress七层负载

k8s从入门到放弃之Ingress七层负载 在Kubernetes&#xff08;简称K8s&#xff09;中&#xff0c;Ingress是一个API对象&#xff0c;它允许你定义如何从集群外部访问集群内部的服务。Ingress可以提供负载均衡、SSL终结和基于名称的虚拟主机等功能。通过Ingress&#xff0c;你可…...

【入坑系列】TiDB 强制索引在不同库下不生效问题

文章目录 背景SQL 优化情况线上SQL运行情况分析怀疑1:执行计划绑定问题?尝试:SHOW WARNINGS 查看警告探索 TiDB 的 USE_INDEX 写法Hint 不生效问题排查解决参考背景 项目中使用 TiDB 数据库,并对 SQL 进行优化了,添加了强制索引。 UAT 环境已经生效,但 PROD 环境强制索…...

centos 7 部署awstats 网站访问检测

一、基础环境准备&#xff08;两种安装方式都要做&#xff09; bash # 安装必要依赖 yum install -y httpd perl mod_perl perl-Time-HiRes perl-DateTime systemctl enable httpd # 设置 Apache 开机自启 systemctl start httpd # 启动 Apache二、安装 AWStats&#xff0…...

Python爬虫(一):爬虫伪装

一、网站防爬机制概述 在当今互联网环境中&#xff0c;具有一定规模或盈利性质的网站几乎都实施了各种防爬措施。这些措施主要分为两大类&#xff1a; 身份验证机制&#xff1a;直接将未经授权的爬虫阻挡在外反爬技术体系&#xff1a;通过各种技术手段增加爬虫获取数据的难度…...

Spring Boot+Neo4j知识图谱实战:3步搭建智能关系网络!

一、引言 在数据驱动的背景下&#xff0c;知识图谱凭借其高效的信息组织能力&#xff0c;正逐步成为各行业应用的关键技术。本文聚焦 Spring Boot与Neo4j图数据库的技术结合&#xff0c;探讨知识图谱开发的实现细节&#xff0c;帮助读者掌握该技术栈在实际项目中的落地方法。 …...

ardupilot 开发环境eclipse 中import 缺少C++

目录 文章目录 目录摘要1.修复过程摘要 本节主要解决ardupilot 开发环境eclipse 中import 缺少C++,无法导入ardupilot代码,会引起查看不方便的问题。如下图所示 1.修复过程 0.安装ubuntu 软件中自带的eclipse 1.打开eclipse—Help—install new software 2.在 Work with中…...

Maven 概述、安装、配置、仓库、私服详解

目录 1、Maven 概述 1.1 Maven 的定义 1.2 Maven 解决的问题 1.3 Maven 的核心特性与优势 2、Maven 安装 2.1 下载 Maven 2.2 安装配置 Maven 2.3 测试安装 2.4 修改 Maven 本地仓库的默认路径 3、Maven 配置 3.1 配置本地仓库 3.2 配置 JDK 3.3 IDEA 配置本地 Ma…...

Java线上CPU飙高问题排查全指南

一、引言 在Java应用的线上运行环境中&#xff0c;CPU飙高是一个常见且棘手的性能问题。当系统出现CPU飙高时&#xff0c;通常会导致应用响应缓慢&#xff0c;甚至服务不可用&#xff0c;严重影响用户体验和业务运行。因此&#xff0c;掌握一套科学有效的CPU飙高问题排查方法&…...

springboot整合VUE之在线教育管理系统简介

可以学习到的技能 学会常用技术栈的使用 独立开发项目 学会前端的开发流程 学会后端的开发流程 学会数据库的设计 学会前后端接口调用方式 学会多模块之间的关联 学会数据的处理 适用人群 在校学生&#xff0c;小白用户&#xff0c;想学习知识的 有点基础&#xff0c;想要通过项…...