RT-Mutex-1——内核文档翻译——rt-mutex.rst & pi-futex.rst

一、rt-mutex.rst

翻译:kernel-5.10\Documentation\locking\rt-mutex.rst

==================================
支持 PI 的 RT-mutex 子系统
==================================

具有优先级继承的 RT-mutexes 用于支持 PI-futexes,它启用 pthread_mutex_t 优先级继承属性 (PTHREAD_PRIO_INHERIT)。 [有关 PI-futex 的更多详细信息,
请参阅 Documentation/locking/pi-futex.rst。]

该技术是在 -rt 树中开发的,并针对 pthread_mutex 支持进行了简化。


基本原则:
------------------

RT 互斥体通过优先级继承协议扩展了简单互斥体的语义。

rt-mutex 的低优先级所有者(owner)继承高优先级等待者(waiter)的优先级,直到 rt-mutex 被释放。 如果临时提升的所有者又被其它 rt-mutex 阻塞,它会将优
先级提升继续传播给阻塞它的其他 rt_mutex 的所有者。 一旦 rt_mutex 被释放,优先级提升会立即被移除。

这种方法使我们能够缩短保护共享资源的互斥锁上的高优先级任务块。 优先级继承对于设计不佳的应用程序来说不是灵丹妙药,但它允许设计良好的应用程序在高
优先级线程的关键部分使用用户空间锁,而不会失去确定性。

将等待者排队到 rtmutex 等待者树中是按优先顺序完成的。 对于相同的优先级,选择 FIFO 顺序。 对于每个 rtmutex,只有最高优先级的waiters被排入owner的优
先级waiter树中。 这棵树也按优先顺序排队。 每当任务的最高优先级等待者发生变化(例如超时或收到信号)时,owner task的优先级就会被重新调整。 优先级排
队由“pi_waiters”处理。

RT-mutexes 针对快速路径操作进行了优化,并且在无竞争时锁定互斥锁或在没有等待者的情况下解锁互斥锁都没有内部开销。 优化的快速路径操作需要 cmpxchg 支
持。
[如果不可用,则使用 rt-mutex 内部自旋锁]

rt-mutex 的状态通过 rt-mutex 结构的 owner 字段进行跟踪:

lock->owner 持有 owner 的 task_struct 指针。 位 0 用于跟踪“锁有等待者”状态:

============ ======= ================================================
所有者       bit0    注释
============ ======= ================================================
NULL         0       锁是空闲的(可以快速获取)
NULL         1       锁是空闲的,有等待者,top waiter要拿锁[1]_
taskpointer  0       锁被持有(可以快速释放)
taskpointer  1       锁被持有并且有等待者 [2]_
============ ======= ================================================

只有当 lock->owner 的 bit 0 为 0 时,基于快速原子比较交换的获取和释放才有可能

.. [1] 当持有 ->wait_lock 的状态下获取锁时,它也可能是一个过渡状态。 为了防止 cmpxchg 到锁的任何快速路径,我们需要在查看锁之前设置 bit0,并且所有
者在这段时间内可能为 NULL,因此这可以是一个过渡状态。

.. [2] 位 0 被设置但没有waiters的时间是很短的。 在慢速路径上抢锁时可能会发生这种情况。 为了防止所有者的 cmpxchg 释放锁,我们需要在查看锁之前设置该位。

顺便说一句,技术上仍然有一个“Pending Owner”,只是不再那样称呼了。 pending owner恰好是一个没有owner的锁的top_waiter,已经被唤醒去抢锁。

 

二、pi-futex.rst

翻译:kernel-5.10\Documentation\locking\pi-futex.rst

======================
轻量级 PI-futex
======================

我们称它们为轻量级的原因有 3 个:

- 在用户空间快速路径中,启用 PI 的 futex 根本不涉及内核工作(或任何其他 PI 复杂操作)。 没有注册,没有额外的内核调用 - 只是用户空间中的纯快速原子操作。

- 即使在慢速路径中,系统调用和调度模式也与普通的 futex 非常相似。

- 内核 PI 实现围绕互斥锁抽象进行了简化,严格的规则使实现相对简单:只有一个所有者可以拥有锁(即不支持读写锁),只有所有者可以解锁锁, 没有递归锁定等。


优先继承——为什么?
--------------------------

简短回复:用户空间 PI 有助于实现/改进用户空间应用程序的确定性。 在最好的情况下,它可以帮助实现确定性和良好的延迟。 即使在最坏的情况下,PI 也会改善与锁定
相关的应用程序延迟的统计分布。


较长的回复
------------------

首先,在多个任务之间共享锁是一种常见的编程技术,通常无法用无锁算法代替。 正如我们在内核中看到的那样[这本身就是一个相当复杂的程序],无锁结构与其说是常态,
倒不如说是一种例外 —— 目前共享数据结构的无锁代码与有锁代码的比率介于 1:10 和 1:100 之间 。 无锁很难,无锁算法的复杂性通常会危及对所述代码进行稳健审查的能
力。 IE。 关键 RT 应用程序通常选择锁结构来保护关键数据结构,而不是无锁算法。 此外,在某些情况下(如共享硬件或其他资源限制),无锁访问在数学上是不可能的。

媒体播放器(如 Jack)是合理的应用程序设计的一个例子,多个任务(具有多个优先级)共享短期锁:例如,高优先级音频播放线程与中等优先级构造音频数据线程和低优先级
显示颜色线程相结合。 将视频和解码添加到组合中,我们获得了更多的优先级。

因此,一旦我们接受同步对象(锁)是生活中不可避免的事实,并且一旦我们接受多任务用户空间应用程序对能够使用锁有非常公平的期望,我们就必须考虑如何提供用户空间
的确定性锁定实现选项。

大多数反对优先级继承的技术的反驳仅适用于内核空间锁。 但是用户空间锁不同,我们不能在关键部分禁用中断或使任务不可抢占,因此'使用自旋锁'参数不适用(用户空间自
旋锁与其他用户空间自旋锁具有相同的优先级反转问题- 空间锁定结构)。 事实上,目前几乎唯一能够为用户空间锁(例如基于 futex 的 pthread 互斥锁)提供良好确定性的
技术是优先级继承:

目前(没有 PI),如果一个高优先级任务和一个低优先级任务共享一个锁 [这对于大多数重要的 RT 应用程序来说是一个很常见的场景],即使所有关键部分都被仔细编码为确定
性的(即所有临界区的持续时间很短并且只执行有限数量的指令),内核不能保证高优先级任务的任何确定性执行:任何中优先级任务都可以在低优先级任务持有共享锁并执行关
键部分时抢占低优先级任务,并可能无限期地延迟它。


执行
--------------

如前所述,启用 PI 的 pthread 互斥体的用户空间快速路径根本不涉及内核工作——它们的行为与普通的基于 futex 的锁非常相似:0 值表示解锁,value==TID 表示锁定。 (这
与基于列表的健壮 futex 使用的方法相同。)用户空间使用原子操作来锁定/解锁这些互斥锁,而无需进入内核。

为了处理慢速路径,我们添加了两个新的 futex 操作:

- FUTEX_LOCK_PI
- FUTEX_UNLOCK_PI

如果锁定获取快速路径失败,[即 从 0 到 TID 的原子转换失败],然后调用 FUTEX_LOCK_PI。 内核完成所有剩余的工作:如果还没有 futex 队列附加到 futex 地址,那么代码
查找拥有 futex 的任务[它已将自己的 TID 放入 futex 值],并附加一个 'PI state' 结构到 futex 队列。 pi_state 包括一个 rt-mutex,它是一个 PI 感知的、基于内核的同
步对象。 “其他”任务成为 rt-mutex 的所有者,FUTEX_WAITERS 位自动设置在 futex 值中。 然后这个任务会尝试锁定它阻塞的 rt-mutex。 一旦它返回,它就获得了互斥锁,并
将 futex 值设置为它自己的 TID 并返回。 用户空间没有其他工作可执行 - 它现在拥有锁,并且 futex 值包含 FUTEX_WAITERS|TID。

如果解锁侧的快速路径成功,[即 用户空间设法完成 futex 值的 TID -> 0 原子转换],就不会触发任何内核工作。

如果解锁快速路径失败(因为设置了 FUTEX_WAITERS 位),则调用 FUTEX_UNLOCK_PI,内核代表用户空间解锁 futex - 它还解锁附加的 pi_state->rt_mutex,从而唤醒任何潜在
的等待者。

请注意,在这种方法下,与以前的 PI-futex 方法相反,没有 PI-futex 的事先“注册”。 [由于 pthread 互斥锁的现有 ABI 属性,无论如何,这不太可能。]

此外,在该方案下,'robustness' 和 'PI' 是 futex 的两个正交属性,并且所有四种组合都是可能的:futex、robust-futex、PI-futex、robust+PI-futex。

有关优先级继承的更多详细信息,请参见 Documentation/locking/rt-mutex.rst。

 

posted on 2022-12-25 15:45  Hello-World3  阅读(187)  评论(0编辑  收藏  举报

导航