linux 内核的futex pi-support,即pi-futex使用rt_mutex委托
futex的pi-support,也就是为futex添加pi算法解决优先级逆转的能力,使用pi-support的futex又称为pi-futex。在linux内核的同步机制中,有一个pi算法的成例,就是rt_mutex实时锁。而futex的pi-support部分就是委托(代理)给rt_mutex进行实现的。
rtmutex,请参看前面的《linux 内核的rt_mutex (realtime互斥体)》。
non-pi futex,请参看前面的《linux 内核的futex》和《linux 内核的各种futex》。
为了让futex使用rt_mutex进行委托,futex设计中添加了一个futex_pi_state结构,这个结构组合了一个rt_mutex作为委托。并将futex_queue这个排队的entry结构添加对futex_pi_state和rt_mutex_waiter的关联,将futex的排队委托成rt_mutex的排队等待rt_mutex_waiter。同时 task_struct 也添加了pi_state_list链表,以维护确保进程(或线程)在持有pi-futex使用的rtmutex代理时退出,进行恢复。

图的上方为pi-futex添加的结构体,下方为non-pi futex使用的结构体。
pi-futex使用了robust-futex定义的锁规则,内核要求用户空间使用它所理解的锁规则,这样一来就可以将原本non-pi futex在用户空间进行的锁操作也委托给内核完成。所以在pi-support的futex系统调用操作 futex_lock_pi 以及 futex_unlock_pi ,还有pi-futex使用在requeue-pi中的futex系统调用操作 futex_wait_requeue_pi 都会在内核在修改用户空间的futex,完成锁操作。

正如这些操作的函数名称字面一样,futex_lock_pi 执行上锁操作(lock)和提供pi-support的排队(pi),而 futex_wait 只单单提供排队服务(wait)。futex_unlock_pi 执行解锁操作(unlock)和提供pi-support的排队唤醒(pi),而 futex_wake 只单单提供排队的唤醒(wake)。
当用户空间使用 futex_lock_pi 进行上锁的slowpath的场合中,内核从排队中唤醒后会尝试对pi-futex进行上锁(锁状态修改),失败后会再次到rt_mutex代理上排队等待。当内核对pi-futex上锁成功后就会返回用户空间,这时用户空间已经得到了内核上好的锁。
这里必须要注意,futex_lock_pi 和 futex_unlock_pi 都是临界区代码,必须被同步。释放pi-futex上的锁不能够像non-pi futex那样在用户空间任意自由地解锁,必须委托rt_mutex锁。由于pi-futex委托了rt_mutex,因此对pi-futex的trylock也不能non-pi futex那样简单地判断失败然后返回,必须进行rt_mutex的trylock委托,所以pi-futex的trylock在失败时,其开销比较大。
futex_lock_pi 和 futex_unlock_pi 在临界区同步使用的是futex_hash_bucket的保护锁,futex模块的共享等待队列。futex_lock_pi 只有在对rt_mutex进行委托调用(rt_mutex_timed_futex_lock或rt_mutex_trylock)时才会离开临界区,之后又重新回到临界区。虽然pi-futex排队在rt_mutex锁上,但是它的lock和unlock临界区却使用futex模块的共享等待队列的保护锁同步,也就是说,它与跟它共享相同的共享等待队列的futex,都同步地进行futex系统调用。
下面临界区图示

为什么pi-futex在rt_mutex锁上面委托了排队,还要在futex_hash_bucket->chain上入队呢?futex_queue代表着一个futex的waiter,而futex系统调用并不使用额外的映射表维护pi-futex与rt_mutex委托锁的对应关系,而是将同一个pi-futex的所有futex_queue(等待entry)关联到rt_mutex委托锁上,就可以通过futex_key在futex_hash_bucket->chain上找出futex_queue,从而得到这个pi-futex委托的rt_mutex锁。对于futex系统调用来说,它可见的futex等待就是futex_hash_bucket以及入队其中的futex_queue。从futex_hash_bucket搜索出的第一个futex_queue,已经不能看作是第一个唤醒的等待了,必须委托给它关联的rt_mutex进行仲裁。futex_queue除了多对一关联到rt_mutex外,还一对一关联到rt_mutex_waiter。这时wake_futex_pi不是依据futex_queue来唤醒任务,而使用委托的rt_mutex锁的等待队列waiters上的rt_mutex_waiter来唤醒任务。当pi-futex的阻塞任务唤醒后,才会将自己的futex_queue移出futex_hash_bucket。所以可以看到futex_lock_pi在委托rt_mutex进行排队的前后,也生成了一个futex_queue进行futex_hash_bucket的入队和出队。

linux 内核的futex pi-support,即pi-futex使用rt_mutex委托的更多相关文章
- linux 内核的futex
futex是linux内核为用户空间实现锁等同步机制而设计的同步排队(队列queueing)服务.在futex.c的注释中,futex起源于"Fast Userspace Mutex&quo ...
- linux 内核的各种futex
futex 设计成用户空间快速锁操作,由用户空间实现fastpath,以及内核提供锁竞争排队仲裁服务,由用户空间使用futex系统调用来实现slowpath.futex系统调用提供了三种配对的调用接口 ...
- How To Install Linux & Nginx & MySQL & PHP (LEMP) stack on Raspberry Pi 3,Raspberry Pi 3,LEMP,Nginx,PHP, LEMP (not LNMP)
1. How To Install Linux & Nginx & MySQL & PHP (LEMP) stack on Raspberry Pi 3 R ...
- linux内核级同步机制--futex
在面试中关于多线程同步,你必须要思考的问题 一文中,我们知道glibc的pthread_cond_timedwait底层是用linux futex机制实现的. 理想的同步机制应该是没有锁冲突时在用户态 ...
- linux内核数据结构学习总结
目录 . 进程相关数据结构 ) struct task_struct ) struct cred ) struct pid_link ) struct pid ) struct signal_stru ...
- [中英对照]Linux kernel coding style | Linux内核编码风格
Linux kernel coding style | Linux内核编码风格 This is a short document describing the preferred coding sty ...
- Linux内核编程规范与代码风格
source: https://www.kernel.org/doc/html/latest/process/coding-style.html translated by trav, travmym ...
- 嵌入式Linux内核+根文件系统构建工具-Buildroot 快速入手指导【转】
本文转载自:https://my.oschina.net/freeblues/blog/596448 嵌入式Linux内核+根文件系统构建工具-Buildroot 快速入手指导 buildroot 是 ...
- C 语言代码风格之 Linux 内核代码风格
GitHub: https://github.com/storagezhang Emai: debugzhang@163.com 华为云社区:https://bbs.huaweicloud.com/b ...
随机推荐
- Jdom读取XML文件
学习Spring时,我们经常看到很多xml配置文件,Spring通过在配置文件中的配置,使用IOC(控制反转),从而实现代码的灵活性,本篇我就为大家介绍一种解析xml方式--Jdom 首先我们到Jdo ...
- MyBatis极速入门开发手册(2017-2-6更新)
前言: 本篇文章对我的学习内容做一个归纳梳理,同时也记录一些学习过程中遇上的问题及注意事项等等,可以帮助新入门的朋友们消除一些误区与盲区,希望能帮上一些正在学习的朋友们.在编写时会引用一些mybati ...
- Windows 10 IoT Serials 7 – 如何用树莓派制作家庭流媒体播放器
Windows 10平台引入了AllJoyn开源软件框架,它提供了一组服务可以创建动态近端网络,让设备可以相互连接实现功能交互.目前,AllJoyn开源软件框架由AllSeen联盟负责管理.AllSe ...
- calendar.js(日历组件封装)
最近一直闲来无事,便寻思着做一下自己的个人项目,也想说能使用现在比较流行的一些mvvm框架来做,于是就选用了这样的一个技术栈vue2.0+vue-router+vuex+webpack来做,做得也是多 ...
- spring+mybatis之声明式事务管理初识(小实例)
前几篇的文章都只是初步学习spring和mybatis框架,所写的实例也都非常简单,所进行的数据访问控制也都很简单,没有加入事务管理.这篇文章将初步接触事务管理. 1.事务管理 理解事务管理之前,先通 ...
- window.onload 和 $(document).ready(function(){})的区别
这篇作为我的新的起点开始吧,发现年纪大了,记性就不好了,有些东西老是记了忘,忘了百度.在学一些新知识的时候也是这样的毛病,总是重复学习,这样效率真心差!所以决定开始认真写博客! 本来想封装一个预加载的 ...
- Unity无缝循环世界实现
一年前曾经碰到过已无限世界为题材的游戏开发比赛,虽然对比赛没有兴趣,但是对这个题材倒是有点想法.如何通过unity3d实现无缝的循环世界呢. 有一种想法是动态生成,一块场景一块场景进行动态加载.(做过 ...
- Eric的第一天
我叫刘志扬(ERIC),今天第一次来博客园,我是一个爱编程的小子,我使用开发工具Androidstudio(AS)我要把今后的问题记录在博客园里,欢迎大家点评,吐槽.
- Mybatis基础学习(四)—关系映射
一.模型分析 user和orders user---->orders 一个用户可以创建多个订单,一对多. orders--->user 一个订单只由一个用户创建,一对一. orders ...
- Struts2基础学习(二)—Action
一.ActionSupport 为了让用户开发的Action类更加规范,Struts2提供了一个Action接口,这个接口定义了Struts2的Action处理类应该实现的规范.下面是标准A ...