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_lockrt_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委托的更多相关文章

  1. linux 内核的futex

    futex是linux内核为用户空间实现锁等同步机制而设计的同步排队(队列queueing)服务.在futex.c的注释中,futex起源于"Fast Userspace Mutex&quo ...

  2. linux 内核的各种futex

    futex 设计成用户空间快速锁操作,由用户空间实现fastpath,以及内核提供锁竞争排队仲裁服务,由用户空间使用futex系统调用来实现slowpath.futex系统调用提供了三种配对的调用接口 ...

  3. 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 ...

  4. linux内核级同步机制--futex

    在面试中关于多线程同步,你必须要思考的问题 一文中,我们知道glibc的pthread_cond_timedwait底层是用linux futex机制实现的. 理想的同步机制应该是没有锁冲突时在用户态 ...

  5. linux内核数据结构学习总结

    目录 . 进程相关数据结构 ) struct task_struct ) struct cred ) struct pid_link ) struct pid ) struct signal_stru ...

  6. [中英对照]Linux kernel coding style | Linux内核编码风格

    Linux kernel coding style | Linux内核编码风格 This is a short document describing the preferred coding sty ...

  7. Linux内核编程规范与代码风格

    source: https://www.kernel.org/doc/html/latest/process/coding-style.html translated by trav, travmym ...

  8. 嵌入式Linux内核+根文件系统构建工具-Buildroot 快速入手指导【转】

    本文转载自:https://my.oschina.net/freeblues/blog/596448 嵌入式Linux内核+根文件系统构建工具-Buildroot 快速入手指导 buildroot 是 ...

  9. C 语言代码风格之 Linux 内核代码风格

    GitHub: https://github.com/storagezhang Emai: debugzhang@163.com 华为云社区:https://bbs.huaweicloud.com/b ...

随机推荐

  1. [.NET] 一步步打造一个简单的 MVC 网站 - BooksStore(一)

    一步步打造一个简单的 MVC 网站 - BooksStore(一) 本系列的 GitHub地址:https://github.com/liqingwen2015/Wen.BooksStore 简介 主 ...

  2. Zkui安装

    是一个允许在zookeeper上进行增删查改操作的图形管理工具,与zkdash类似. 1.拉取代码 #git clone https://github.com/DeemOpen/zkui.git 2. ...

  3. ng自定义一个过滤器

    ng允许我们自定义指令 下面来我们自己来定义一个过滤指令:filter,返回一个函数的形式 filter(name,callback(){//name:过滤器的名字,callback:匿名函数 ret ...

  4. 老李分享:Android -自动化埋点 3

    又一个问题,代码中的writeLog方法到底要记录哪些数据作为log信息呢?log信息中最重要的是能让开发者看出来哪个界面被打开或者哪个控件被点 击.对于界面,可以记录其类名:对于控件,一般没有确定的 ...

  5. WebApp框架

    我所知道的webapp开发框架,欢迎补充, Framework7包含ios和material两种主题风格并且有vue版和react版, vue发现一个vue-material, react有一款mat ...

  6. Java -- 浅入Java反射机制

    1,Java 反射是Java语言的一个很重要的特征,它使得Java具体了"动态性". Java 反射机制主要提供了以下功能: 在运行时判断任意一个对象所属的类. 在运行时构造任意一 ...

  7. 实现全局同一编码:Filter

    request.setCharacterEncoding("UTF-8");只对POST方式提交有用 对于GET方式 ,可以有装饰模式和适配器模式,对获取参数的函数进行重写. 对所 ...

  8. vue实现简单表格组件

    本来想这一周做一个关于vuex的总结的,但是由于朋友反应说还不知道如何用vue去写一个组件,所以在此写写一篇文章来说明下如何去写vue页面或者组件.vue的核心思想就是组件,什么是组件呢?按照我的理解 ...

  9. 构造函数与普通函数的区别还有关于“new”操作符的一些原理

    有一种创建对象的方法叫做工厂模式,例如: function person(name,age){ var o=new Object(); o.name=name; o.age=age; return o ...

  10. UEFI+GPT下安装Win10+Ubuntu16.04双系统

    安装环境 SSD+HDD双盘,Win10安装在SSD里,HDD分出来60G安装Ubuntu. 自行百度你的主板是否支持UEFI启动方式. Win10 下载Win10安装镜像.烧盘等步骤就不说了,重启后 ...