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 ...
随机推荐
- 卸载php+apache+mysql
一.卸载删除 mysql 1 sudo apt-get autoremove --purge mysql-server-5.0 2 sudo apt-get remove mysql-server ...
- MIT 计算机科学及编程导论 Python 笔记 1
计算机科学及编程导论在 MIT 的课程编号是 6.00.1,是计算机科学及工程学院的经典课程.之前,课程一直使用 Scheme 作为教学语言,不过由于 Python 简单.易学等原因,近年来已经改用 ...
- ASP.NET MVC制作404跳转(非302和200)
前言:距离上次发文已经有几个月了! 这段时间李,制作了一个博客网站,现将博客文章选一些发表到博客园,顺便为自己网站打一下广告! 产生404的原因主要有以下: 1.浏览器和爬虫:某些浏览器会请求网站的f ...
- Android编码规范
Android-Code-Style 1.约定 Activity.onCreate(),Fragment.onActivityCreated(),紧跟成员变量后,方法内部保持简单,尽量只调用initX ...
- Iterator 的hasNext方法和next方法
这两个方法都有指向的移动,不同的是,一个返回boolean,一个返回对象: hasNext():判断当前元素是否存在,并没有指向的移动 next():返回当前元素, 并指向下一个元素 请看代码吧: L ...
- cookie技术简介
Cookie简介 众所周知,HTTP协议是一个无状态的协议.一个Web应用由很多个Web页面组成,每个页面都有唯一的URL来定义.用户在浏览器的地址栏输入页面的URL,浏览器就会向Web Server ...
- python selenium2示例 - 生成 HTMLTestRunner 测试报告
前言 在python selenium2自动化测试过程中,一个合适的报告是必须的,而HTMLTestRunner模块为我们提供了一个很好的报告生成功能. 什么是HTMLTestRunner HTMLT ...
- grep的用法笔记
1.grep搜索不保护字符串的命令格式如下: #带-v参数 jevan@df ~ grep "agc" -vRn ./
- 【Java进阶】——初识数据库连接池
[简介] 数据库连接池:程序启动时建立足够的数据库连接,并将这些连接组成一个连接池,由程序动态地对池中的链接进行申请,使用,释放. 相比之前的程序连接,减少了数据库的打开关闭次数,从而减少了程序响应的 ...
- Entity Framework Code First在Oracle下的伪实现
为什么要说是伪实现,因为还做不到类似MsSql中那样完全的功能.Oralce中的数据库还是要我们自己手动去创建的.这里,我们舍掉了Model First中的EDMX文件,自己在代码里面写模型与映射关系 ...