首页 > 其他分享 >RT-Mutex-3——实现分析-pi-futex与rt-mutex

RT-Mutex-3——实现分析-pi-futex与rt-mutex

时间:2023-04-20 22:46:56浏览次数:30  
标签:RT rt task waiter futex mutex PI

一、rt-mutex 的原理

PI-futex是通过rt mutex来实现的,因此我们这里简单的聊一聊内核的这个PI-aware mutex。

从rt mutex的视角看任务:

rt_mutex_waiter 用来抽象一个阻塞在 rt mutex 的任务:task 成员指向这个任务,lock 成员指向对应的 rt mutex 对象,tree_entry 是挂入 blocker 红黑树的节点,rt mutex 对象的 waiters 成员就是这颗红黑树的根节点(wait_lock 成员用来保护红黑树的操作)。而 owner 则指向持锁的任务。需要特别说明的是 waiters 这个红黑树是按照任务优先级排序的,left most 节点就是对应该锁的 top waiter。

从任务 task_struct 结构的视角来看 rt mutex:

为了支持 rt mutex,task struct 也增加了若干的成员,最重要的就是 pi_waiters。由于一个任务可以持有多把锁,每把锁都有 top waiter,因此和一个任务关联的 top waiter 也有非常多,这些 top waiter 形成了一个红黑树(同样也是按照优先级排序),pi_waiters 成员就是这颗红黑树的根节点。这颗红黑树的 left most 的任务优先级就是实现优先级继承协议中规定要临时提升的优先级。pi_top_task 成员指向了 left most 节点对应的任务对象,我们称之 top pi waiter。Task struct 的 pi_blocked_on 成员则指向其阻塞的 rt_mutex_waiter 对象。

有了上面的基本概念之后,我们讲一下 PI chain 的概念。首先看看任务和锁的基本关系,如下图所示:

在上面的图片中,task 1 持有了 Lock A 和 Lock B,阻塞在 Lock C 上。一个任务只能阻塞在一个锁上,所以红色箭头只能是从任务到锁,不能分叉。由于一个任务可以持有多把锁,所以黑色箭头会有多个锁指向一个任务,即多把锁汇聚于任务。有
了这个基本的关系图之后,我们可以形成更加复杂的任务和锁的逻辑图,如下:

在上面这张图中有四条PI chain:

(1) Lock D ---> task 2

(2) task 4 ---> Lock C ---> task 2

(3) Lock A ---> task 1 ---> Lock C ---> task 2

(4) task 3 ---> Lock B ---> task 1---> Lock C ---> task 2

为了能够让 PI 正常起作用,PI chain 中的任务必须维持这样的关系:处于 PI chain 中右端的任务的优先级必须大于等于 PI chain 中左端的任务们。我们以第四条 PI chain 为例,任务2的优先级必须大于等于任务1和任务3的优先级,
而任务1的优先级必须要大于等于任务3的优先级。


二、PI futex 和 rt mutex 的关系

熟悉Linux的工程师都了解内核中的mutex互斥锁以及支持PI的互斥锁版本rt mutex。如果想让用户空间的互斥锁实现优先级继承的功能,那么其实不需要futex模块实现复杂的PI chain,实际上对PI状态的跟踪是通过rt mutex代理来完成的,原理图如下:

我们先看接口部分,normal futex 使用 FUTEX_WAIT 和 FUTEX_WAKE 操作码来完成阻塞和唤醒的动作。对于 PI futex 而言,FUTEX_LOCK_PI 用来执行上锁,而 FUTEX_UNLOCK_PI 用来完成解锁。这里的 lock 和 unlock 其实是对 futex 的代
理 rt mutex 而言的。

无论是 normal futex 还是 PI futex,阻塞于 futex 的任务都会有一个 futex_q 对象与之对应。对于 normal futex,有了 futex_q 对象,挂入等待队列和将其唤醒的功能都能轻松实现。对于 PI futex,我们不仅仅需要挂入队列和唤醒任务,最重要的是我们需要根据 PI chain 完成任务优先级的调整。为了完成这个功能,需要两个额外的对象,一个是 rt_mutex_waiter 表示一个阻塞在 rt mutex 的任务,其 rt mutex 指针指向了其阻塞在哪个 rt mutex 上。另外一个是 futex_pi_state 对象,它记录了优先级翻转的信息,包括该用户空间上层锁对应的内核态的 rt mutex,rt mutex 的 owner 任务的信息等。


三、Pi futex逻辑过程

Pi futex 主要有两个逻辑过程:通过 FUTEX_LOCK_PI 上锁,通过 FUTEX_UNLOCK_PI 完成释放锁的逻辑。

这里的“上锁”有点误导,不是“试图持锁”的意思,而是竞争上层锁失败之后,陷入内核准备进入阻塞状态。这里为了记录 PI state,所以需要对代理 rt mutex 执行上锁的动作(基本上也是会阻塞在 rt mutex 上)。对于 pi futex 的正常 futex 的部分,例如 get hash key、找 futex 对应的 hash bucket、插入 hash 队列等操作,这里不再描述,主要看 PI futex 特有的部分。

第一次 futex lock pi 稍微复杂一点,需要完成 owner 持锁和 current task 的阻塞在锁上这两个动作。注意:这里的锁指的是 rt mutex。当线程持上层锁成功的时候,我们并不能同时对 rt mutex 持锁成功并设置 owner,因此这时候并不会有 futex 系统调用进入内核。当第一次阻塞的时候,会通过 futex 系统调用把 owner id 传递给内核,这时候我们需要分配一个 futex pi state 对象创建一个 rt mutex,同时建立这个 rt mutex 和 owner task 的关系:

(1) 挂入 owner task 的 futex pi state 链表。一个任务可以持有多把上层锁,所以需要链表管理,当然不一定每一个任务持有的上层锁都有对应的 futex pi state 对象,没有竞争也就不会陷入内核调用 FUTEX_LOCK_PI。

(2) futex pi state 对象的 owner 成员指向对应的 owner task


第二个重要的动作就是让 current task 去获取 rt mutex,上面刚刚设定了 owner,这里 current task 持锁的结果大概率就是会阻塞,不过我们本来就是通过这个阻塞关系来完成 PI 状态的跟踪的。rt_mutex_waiter 对象抽象了一个阻塞在 rt mutex 上的任务,我们需要建立 rt_mutex_waiter 对象、阻塞任务和 rt mutex 的关系,具体包括:

(1) rt_mutex_waiter 对象的 lock 成员指向对应于的 rt mutex,表示该任务阻塞在这个锁上。rt_mutex_waiter 对象的 task 成员指向当前要阻塞的任务对象。

(2) 将 rt_mutex_waiter 对象插入 rt mutex 的 waiters 红黑树。

(3) task struct 的 pi_blocked_on 设置为该 rt_mutex_waiter 对象。

(4) 对于 rt mutex 而言,有了新的阻塞任务,如果优先级比目前该 rt mutex 的 top waiter 更高的话,那么需要更新 owner task 的 top waiter,将旧的 top waiter 节点从红黑树中删除,将新的 top waiter 插入 owner task 的 top waiter 红黑树

(5) 根据新的 top waiter 更新 owner task 的动态优先级。一旦修改了 owner task 的优先级,那么其相关的 PI chain 都需要进行优先级调整。

第二次以及后续的 FUTEX_LOCK_PI 会简单一点,因为不需要新建 rt mutex 对象了,只需要在 bucket 找到第一个 futex_q 对象,通过其 pi state 指针就可以定位 rt mutex 了。有了 rt mutex,通过上锁即可让自己阻塞在这个 rt mutex 上了。

FUTEX_UNLOCK_PI 的流程留给读者自行分析了。


四、总结

1. 上层也可以通过 pi-futex 使用内核中 rt-mutex 的逻辑。

 


参考:
futex基础问答:http://www.wowotech.net/kernel_synchronization/futex.html

 

标签:RT,rt,task,waiter,futex,mutex,PI
From: https://www.cnblogs.com/hellokitty2/p/17338589.html

相关文章

  • JetBrains IntelliJ支持自动切换输入法插件 smart input,写代码如丝般顺滑
    对于母语为中文的开发者,写代码过程中经常需要在中/英输入法之间进行切换,而且由于不清楚当前处于哪种输入状态,有时输入到一半发现输入法错了,删除重新输入,有时切换了好几次都没有成功,实在太影响写代码了。其实,在哪个位置需要使用哪种输入法是可以确定的,既然这样就可以让IDE帮助我......
  • C#基础 Process Start 运行浏览器打开指定页面
     .NETFramework:4.7.2       IDE:VisualStudioCommunity2019        OS:Windows10x64    typesetting:Markdown codeusingSystem;usingSystem.Diagnostics;namespaceConsoleApp{classProgram{staticvoidMain(stri......
  • C#基础 Math Pow Sqrt 幂与平方根
     .NETFramework:4.7.2       IDE:VisualStudioCommunity2019        OS:Windows10x64    typesetting:Markdown codeusingSystem;namespaceConsoleApp{classProgram{staticvoidMain(string[]args){......
  • Linux 安装 Node Exporter
    1.下载安装cdsrcwgethttps://github.com/prometheus/node_exporter/releases/download/v1.5.0/node_exporter-1.5.0.linux-amd64.tar.gztarxfnode_exporter-1.5.0.linux-amd64.tar.gzmvnode_exporter-1.5.0.linux-amd64/node_exporter/usr/binuseradd-s/sbin/nologin......
  • vue全家桶进阶之路46:Vue3 Axios拦截器和globalProperties全局设置
    在Vue.js3中,使用Axios与Vue.js2.x中类似,但是需要进行一些修改和更新,下面是Vue.js3中Axios的定义和使用方式:首先,你需要安装Axios和Vue.js3.x,可以使用npm或yarn等包管理工具安装:npminstallaxiosvue@next然后,在你的Vue.js3应用程序中,你可以使用以下代码来导入和使用Axio......
  • Layer-Dependent Importance Sampling for Training Deep and Large Graph Convolutio
    目录概符号说明MotivationLADIES代码ZouD.,HuZ.,WangY.,JiangS.,SunY.andGuQ.Layer-dependentimportancesamplingfortrainingdeepandlargegraphconvolutionalnetworks.NIPS,2019.概本文在以往的mini-batch的快速算法上进行了改进.符号说明\(\m......
  • ONVIF网络摄像头(IPC)客户端开发—RTSP RTCP RTP加载H264视频流
    前言:RTSP,RTCP,RTP一般是一起使用,在FFmpeg和live555这些库中,它们为了更好的适用性,所以实现起来非常复杂,直接查看FFmpeg和Live555源代码来熟悉这些协议非常吃力,这里将它们独立出来实现,以便更好的理解协议。本文主要介绍RTSP,RTCP,RTP加载H264数据流。说明:(1)大华IPC摄像头作为服......
  • ONVIF网络摄像头(IPC)客户端开发—最简RTSP客户端实现
    前言:网上对于RTSP协议客户端的表述和实现非常不清晰,在实际使用中,FFMPEG和live555这些软件已经实现了RTSP客户端和服务端的所有功能,但是它们并没有将RTSP协议独立出来,通过看live555或是FFMPEG这些第三方库的源码来学习rtsp协议还是非常吃力。这里根据协议自己现实一个RTSP客户端程......
  • ONVIF网络摄像头(IPC)客户端开发—RTSP RTCP RTP加载AAC音频流
    前言:RTSP,RTCP,RTP一般是一起使用,在FFmpeg和live555这些库中,它们为了更好的适用性,所以实现起来非常复杂,直接查看FFmpeg和Live555源代码来熟悉这些协议非常吃力,这里将它们独立出来实现,以便更好的理解协议。本文主要介绍RTSP,RTCP,RTP加载AAC音频流。说明:(1)大华IPC摄像头作为服......
  • GE RTT Desktop Test Set
    通用电气RTT桌面测试集是一个工具,帮助测试继电器,仪表和PLC的能力,提供单相电压和电流,驱动数字输入,并控制RTD。  海拔最大2000米控制权标称6va;最大14伏安规模长7.5英寸×宽5.75英寸×深3.25英寸干式数字输入接触电阻<10mΩ脉冲磁场抗扰度标准上午1000点......