rt-linux里的泛rtmutex锁的调用链整体分析

一、背景

linux系统里有非常多的锁种类,除了spinlock,mutex,rwlock,rwsem,还有rcu及顺序锁,这里面还有不少锁变种,比如spinlock的带bh或者irq字样的lock/unlock,还有nmi里可以用的顺序锁,还有不同模式的rcu等等,可见linux里的锁或者说内核同步原语的细节是非常非常多的。

普通linux里已经有这么多的细节了,但是如果加上rt-linux的patch,锁的细节就更加多了,尤其是rt-linux里与提高实时性相关的重要的锁改动,也就是以rtmutex为核心的那些锁的改动。

在之前的博客 rcu的实例、注意事项及原理讲解_rcu使用实例-CSDN博客 里,我们已经详细介绍了rcu,另外,在之前的博客 顺序锁的原理和使用注意事项-CSDN博客 里,我们也详细介绍了顺序锁,这篇博客里就不涉及这两个锁了。

这篇博客里,我们基于rt-linux这个大前提,来分析rt-linux里所有用到rtmutex核心的那些锁的调用链情况,从而能整体上对rt-linux里的这些rtmutex的衍生品锁,所谓的泛rtmutex锁有一个整体的认知。

二、泛rtmutex锁的调用链完整图及整体介绍

2.1 泛rtmutex锁的调用链完整图

我有整理一个泛rtmutex锁的调用链完整图,在资源 https://download.csdn.net/download/weixin_42766184/90894722 里。

完整的图非常非常大,缩小以后完全看不清:

2.2 整体介绍

rt-linux系统为了提高整个系统的实时性,修改了spinlock的实现,除了raw_spin_lock_xx保持原来的实现之外,其他的不带raw的spinlock都改成了rtmutex为核心的实现。不带raw的spinlock里不再像普通linux里一直死锁乐观地一等到底,而是等一段时间后,变为了rtmutex的等待方式,交出cpu,这样做肯定会让系统的吞吐量下降,因为上下文切换变多了,但是好处就是让锁的逻辑里也增加了调度点,让系统里更高优先级的任务能更早地进行响应。

这篇博客并不会深入到具体某个锁的实现细节里去,主要看的是rt-linux下rtmutex核心的这些锁的调用链关系,看里面哪些逻辑是公用的,是如何使用rtmutex核心的逻辑,各个锁之间的调用链关系上。

在第三章里的分类介绍之前,我们对整理出的图里的共性内容做一些简要说明。

2.2.1 CONFIG_DEBUG_LOCK_ALLOC和CONFIG_LOCKDEP

可以从图里看到,mutex系列、rt_mutex系列、down_read/up_read/down_write/up_write系列、rt读写锁系列、读写锁系列、rt自旋锁系列、自旋锁系列都有关于CONFIG_DEBUG_LOCK_ALLOC编译选项开和不开的一些分叉,在开了CONFIG_DEBUG_LOCK_ALLOC时,会多出一些xx_nested函数和宏,这些是用于调试lock的,用于检查内核是否错误地释放被持有的锁,什么意思呢?就是检测使用中的锁是否被意外释放,或者使用中的锁被重新初始化,或者在进程退出时有持有锁。另外,图里还有一些与CONFIG_LOCKDEP编译选项有关的宏或者函数的定义分叉,CONFIG_LOCKDEP是整个lockdep的总开关,更多的关于lockdep的编译选项的描述就不在这里展开了。

2.2.2 rtmutex核心逻辑函数

另外一点重点需要说明的是,图里列出来的这些锁,无论是哪个系列的锁,最终都会或多或少的使用到rtmutex核心逻辑的一些实现的接口函数,所以rtmutex核心逻辑的实现的接口函数还是非常多的,其实现在rtmutex.c里,在图里并没有列全,列了一部分,为的是有一个直观的认知,是最终用到了rtmutex的核心函数,如下:

这块rtmutex的核心逻辑函数主要是处理一些与优先级继承相关的一些功能,用于防止优先级反转等影响系统实时性而加的一些逻辑。

我们以__rt_mutex_slowlock来做一个展开,这个函数里的实现大致有下图里的这些内容:

可以看到,__rt_mutex_slowlock的实现里的这些函数大部分都是被其他函数如__rwbase_read_unlock,rt_mutex_slow_unlock、rt_mutex_slowunlock等函数所复用的。

2.2.3 rwbase_rt.c里被同时两个.c包含呈现两种不同的实现形态

rwbase_rt.c以及使用rwbase_rt.c的rwsem.c和spinlock_rt.c是一个有点类似C++基类继承的关系,就是说rwbase_rt.c是实现了一个基类,rwbase_rt.c的这个基类的实现里用到了一些纯虚接口,而这些用到的纯虚接口是在rwsem.c和spinlock_rt.c里各自定义自己的实现的。

这其实就是linux内核里,用C来模拟出C++的继承的方式,进行的一种抽象的实现,和内核里大量存在ops函数的用法不一样,但是核心的思想是一样的。

下图就是图里的上面说的rwsem.c和spinlock_rt.c里同一个函数rwbase_rtmutex_slowlock_locked的不同的呈现形态(实际有了不同的实现):

三、分类介绍

我们按照图里的从上到下的顺序进行依次介绍。

3.1 mutex系列和rt_mutex系列

mutex系列指的是调用的函数是mutex_开头的这些锁,如下图:

 rt_mutex系列指的是调用的函数是ww_mutex_开头的这些锁,如下图:

在rt-linux系统上,mutex系列和rt_mutex系列虽然在函数定义上来说并没有马上画等号的指代,但是,很快就逻辑上合并了,如下图,mutex_xx系列用到的__mutex_lock_common继而就马上用到了__rt_mutex_lock,而rt_mutex_xx系列用到的_rt_mutex_lock_common继而马上也用到了__rt_mutex_lock:

对于mutex_trylock直接用的就是__rt_mutex_trylock来实现的。

3.2 ww_mutex系列

ww_mutex系列指的是调用的函数是ww_mutex_开头的这些锁,如下图:

ww_mutex系列是用于处理AB-BA死锁情形的一个锁,但是这种处理其实也只是说是为了避免系统严重的死锁崩溃,即,当检测到发生死锁时,让其中一个锁先unlock。

ww-mutex里ww表示wound-wait,是受伤地等待的意思,一方受伤地等待比让系统直接崩溃看起来会好一些,但是这可能也隐藏了问题,当前系统里使用ww_mutex系列的锁的人并不多。

需要说明的是ww_mutex系列的锁最终用到的还是rt_mutex_slowlock这样的rtmutex核心逻辑函数来实现的。

3.3 down_read/up_read/down_write/up_write系列

down_read/up_read/down_write/up_write系列指的是调用的函数是down_read_开头和up_read/down_write_开头/up_write的这些锁,如下图:

down_read/up_read/down_write/up_write系列其实也就是rwsem系列,rwsem和读写spinlock锁都是有读和写两个角色的,都是为了照顾多读少写场景下的并发性能,前者rwsem是会睡眠的,这是很显然的,后者读写spinlock锁在普通linux下是乐观地死等的,而在rt-linux下,则是会进行睡眠的。

回到这里说的rwsem,这个down_read/up_read/down_write/up_write系列的核心实现在rwsem.c里,而rwsem.c刚 2.2.3 里也讲到,是用到了rwbase_rt.c里的“基类”实现。

3.4 rt读写锁系列和读写锁系列

rt读写锁系列指的是调用的函数是rt_write_开头和rt_read_开头的这些锁,如下图:

读写锁系列指的是调用的函数是write_开头和read_开头的这些锁,如下图:

rt-linux里rt读写锁和读写锁在实现是很快就合并到用rt_write_xx和rt_read_xx这些rt_开头的接口里了:

rt_write_xx和rt_read_xx的具体实现,是在spinlock_rt.c里,而spinlock_rt.c刚 2.2.3 里也讲到,是用到了rwbase_rt.c里的“基类”实现。

3.5 rt自旋锁系列和自旋锁系列

rt自旋锁系列指的是调用的函数是rt_spin_开头的这些锁,如下图:

自旋锁系列指的是调用的函数是spin_开头的这些锁,如下图:

与 3.4 差不多,这里的 rt自旋锁系列和自旋锁系列很快也在实现上合并了,都是用的rt_spin_xx开头的这些的实现,这些的实现里,用到了rt_mutex_slowtrylock、rtlock_slowlock等rtmutex里的核心实现函数,这些核心函数的使用在实现上和rt_mutex_系列接口相比,在使用rtmutex核心逻辑函数上,也是比较接近的。

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

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

相关文章

LLM多平台统一调用系统-LiteLLM概述

概述 在当今快速发展的AI领域,大语言模型(LLM)已成为技术创新的核心驱动力。然而,随着市场上涌现出越来越多的LLM提供商(如OpenAI、Anthropic、Google Gemini、AWS Bedrock等),开发者面临着一个日益复杂的问题&#x…

C#实现MCP Client 与 LLM 连接,抓取网页内容功能!

该专栏优先在飞书发布,欢迎收藏关注! https://www.feishu.cn/community/article?id7507084665509904403 前面的课程,我们已经用C#实现了,自己的MCP Client。 下面我们一起来实现,MCP Client与LLM 对接。 一、添加依…

并发编程(6)

指令重排序 指令重排序是指在程序执行过程中,为了提高性能,编译器或处理器会对指令的执行顺序进行重新排列。 指令重排序导致可见性消失 在多线程环境下,每个线程都有自己的工作内存,线程对变量的操作是在工作内存中进行的&…

鸿蒙仓颉开发语言实战教程:页面跳转和传参

前两天分别实现了商城应用的首页和商品详情页面,今天要分享新的内容,就是这两个页面之间的相互跳转和传递参数。 首先我们需要两个页面。如果你的项目中还没有第二个页面,可以右键cangjie文件夹新建仓颉文件: 新建的文件里面没什…

Java 学习笔记:注解、泛型与 IO 流

目录 课程目标 Java 注解(Annotation) 1. 概念与作用 2. 自定义注解示例 3. JDK 内置注解 4.注释 Java 泛型(Generics) 1. 基本语法 2. 通配符与上下限 3. 常见应用场景 Java IO 流 1. 流的分类1.File文件类 2. 字节流与字符流 3. 经典示例:文件拷贝 总结与…

git仓库代码操作

1、从gitee下载代码提交到本地github仓库,保留提交记录 # 查看当前分支 git branch# 查看当前远程仓库 git remote -v# 确保所有更改已提交 git add . git commit -m "准备提交到GitLab"# 添加GitLab远程仓库 git remote add gitlab https://gitlab.com/…

Thinkphp6使用token+Validate验证防止表单重复提交

htm页面加 <input type"hidden" name"__token__" value"{:token()}" /> Validate 官方文档 ThinkPHP官方手册

Mcu_Bsdiff_Upgrade

系统架构 概述 MCU BSDiff 升级系统通过使用二进制差分技术&#xff0c;提供了一种在资源受限的微控制器上进行高效固件更新的机制。系统不传输和存储完整的固件映像&#xff0c;而是只处理固件版本之间的差异&#xff0c;从而显著缩小更新包并降低带宽要求。 该架构遵循一个…

Spring Boot微服务架构(四):微服务的划分原则

微服务划分原则&#xff08;CRM系统案例说明&#xff09; 一、微服务划分的核心原则 单一职责原则&#xff08;SRP&#xff09; 每个微服务只负责一个明确的业务功能服务边界清晰&#xff0c;避免功能混杂便于独立开发、测试和部署 业务领域驱动设计&#xff08;DDD&#xff0…

基于CNN卷积神经网络的带频偏QPSK调制信号检测识别算法matlab仿真

目录 1.算法运行效果图预览 2.算法运行软件版本 3.部分核心程序 4.算法理论概述 5.算法完整程序工程 1.算法运行效果图预览 (完整程序运行后无水印) 2.算法运行软件版本 matlab2024b 3.部分核心程序 &#xff08;完整版代码包含详细中文注释和操作步骤视频&#xff09…

从机械应答到深度交互,移远通信如何让机器人“灵魂觉醒”?

你是否还在因机器人的“答非所问”而无奈&#xff0c;为它们的“反应慢半拍”而抓狂&#xff1f;别慌&#xff01;一场引领机器人实现“灵魂觉醒”的技术革命&#xff0c;正如同暗夜中悄然绽放的繁星&#xff0c;彻底颠覆人们对机器人的传统认知。 5月20日&#xff0c;移远通信…

软件的技术架构、应用架构、业务架构、数据架构、部署架构

一、各架构定义 1. 技术架构&#xff08;Technical Architecture&#xff09; 定义&#xff1a;技术架构关注的是支撑系统运行的底层技术基础设施和软件平台&#xff0c;包括硬件、操作系统、中间件、编程语言、框架、数据库管理系统等技术组件的选择和组合方式。它描述了系统…

HTML-前端

目录 开始学习HTML 什么是 HTML? 剖析一个 HTML 元素 嵌套元素 块级元素和内联元素 空元素 属性 为元素添加属性 布尔属性 省略包围属性值的引号 使用单引号还是双引号&#xff1f; 剖析 HTML 文档 HTML 中的空白 实体引用&#xff1a;在 HTML 中包含特殊字符 HT…

多态的总结

什么是多态&#xff1f; 答&#xff1a;多态是多种形态&#xff0c;是为了完成某种行为时&#xff0c;不同对象会产生不同的形态&#xff08;结合车票例子解释&#xff09; 2. 什么是重载、重写(覆盖)、重定义(隐藏)&#xff1f; 答&#xff1a;重载的条件是&#xff1a;在同一…

VBA 读取指定范围内的单元格数据,生成csv文件

目录 一. 需求二. 宏代码三. 添加按钮 一. 需求 ⏹有如下表格&#xff0c;现在想在Excel中添加一个按钮 点击按钮之后&#xff0c;读取该表格中的数据&#xff0c;生成csv文件将csv文件输出到和Excel同级目录 二. 宏代码 Application.PathSeparator&#xff1a;路径分隔符Cr…

【Code Agent Benchmark】论文分享No.15:TAU-Bench

论文名称&#xff1a;τ-bench: A Benchmark for Tool-Agent-User Interaction in Real-World Domains 论文&#xff1a;https://arxiv.org/abs/2406.12045 机构&#xff1a;Sierra Github 链接&#xff1a;https://github.com/sierra-research/tau-bench# 简介 相比于Swe-ben…

Linux下 使用 SSH 完成 Git 绑定 GitHub

文章目录 1、检查 SSH2、生成 SSH key3、添加 SSH key4、验证绑定是否成功 1、检查 SSH Git Bash 中输入ssh命令&#xff0c;查看本机是否安装 SSH&#xff1a; 2、生成 SSH key &#xff08;1&#xff09;输入 ssh-keygen -t rsa 命令&#xff0c;表示我们指定 RSA 算法生…

Java 8 Stream 流操作全解析

文章目录 **一、Stream 流简介****二、Stream 流核心操作****1. 创建 Stream****2. 中间操作&#xff08;Intermediate Operations&#xff09;****filter(Predicate<T>)&#xff1a;过滤数据****1. 简单条件过滤****2. 多条件组合****3. 过滤对象集合****4. 过滤 null 值…

Java——设计模式(Design Pattern)

设计模式&#xff08;Design Pattern&#xff09;是软件开发中针对常见问题的经典解决方案&#xff0c;由 GoF&#xff08;Gang of Four&#xff09;在《设计模式&#xff1a;可复用面向对象软件的基础》一书中归纳为23 种模式&#xff0c;分为三大类&#xff1a;创建型模式、结…

python语法学习

1.python的类的定义 class Memory_Manager: 2.__init__ 方法 __init__ 是类的构造方法&#xff0c;用于初始化类的实例。 self 是类实例的引用&#xff0c;用于访问类的属性和方法。 3.方法定义 类中的方法是类的功能实现&#xff0c;通过 def 定义。 4.if __name__ __ma…