LWN:可以处理复杂死锁检测的依赖跟踪机制!

关注了就能看到更多这么棒的文章哦~

The dependency tracker for complex deadlock detection

By Jonathan Corbet
September 4, 2025
OSS EU
Gemini flash translation
https://lwn.net/Articles/1036222/

在并发环境中,共享数据带来的死锁(deadlock)是持续存在的威胁;因此,内核项目早已开发出工具来检测潜在的死锁,以便在它们影响生产环境用户之前进行修复,这并不令人意外。Byungchul Park 认为他开发了一种更优秀的工具,能够检测出更多容易发生死锁的情况。在 2025 年的 欧洲开源峰会上,他介绍了自己的依赖追踪器(dependency tracker,简称 DEPT)工具及其能够检测的问题类型。

Park 首先介绍了一个简单的 ABBA 死锁(ABBA deadlock)场景。设想有两个线程正在运行,每个线程都使用了两个锁,分别称为 A 和 B。第一个线程先获取 A,然后获取 B,最终持有这两个锁;与此同时,第二个线程获取同样的两个锁,但顺序相反,它首先获取 B。这种操作在正常情况下可以运行,直到某一天,两个线程都成功地获取了各自的第一个锁。这时,一个线程持有 A,另一个线程持有 B,并且每个线程都在等待对方释放它所需的第二个锁。它们将长时间地等待下去。

像这样的死锁可能难以重现,因此也难以追踪和修复;远不如提前检测出发生此类死锁的可能性。内核中有一个名为 lockdep(锁依赖追踪器)的工具,最初由 Ingo Molnar 编写,可以执行这种检测。每当一个线程获取一个锁时,lockdep 都会记住这次获取,以及当时的上下文——特别是,当时持有的任何其他锁。因此,它会注意到在第一个例子中,A 是在 B 之前获取的。当 lockdep 观察到第二个线程以相反的顺序获取锁时,它就会发出警报。问题随后可以得到修复,希望是在这个特定的死锁在生产系统上实际发生之前。

Park 接着展示了一个更复杂的例子,形式如下:

Thread X

Thread Y

Thread Z

mutex_lock(A)

mutex_lock(C)

mutex_lock(A)

mutex_lock(C)

wait_for_event(B)

mutex_unlock(A)

mutex_unlock(C)

mutex_unlock(A)

mutex_unlock(C)

event B

线程 Y 持有锁 C,将阻塞等待 A 变为可用。与此同时,线程 Z 被阻塞等待 C。线程 X 正在等待某种事件发生;这个事件本应由 Z 产生,但这永远不会发生,因为 Z 正在等待一个锁链,而这个锁链最终指向被 X 持有的 A。Park 在这里强调的是,死锁并不仅仅由锁驱动,其他类型的事件也可以成为死锁场景的一部分。lockdep 由于专注于锁,因此无法检测到这些情况。

Park 的 DEPT 工具目前已发布 第 16 个修订版,旨在解决这类问题。DEPT 背后的核心思想是对依赖关系有了新的定义;lockdep 将依赖关系视为锁的获取,而 DEPT 则更普遍地看待事件。如果一个事件在另一个事件之前发生,DEPT 就会注意到它们之间的依赖关系。在上面的例子中,A 的释放取决于事件 B 的发生,而事件 B 又取决于 C 的释放,C 的释放本身又取决于 A 的释放。这是一个可能导致死锁的依赖循环;DEPT 会如实报告这一情况。

早在 2023 年,内核开发者们曾为某个复杂的死锁问题绞尽脑汁,Linus Torvalds 曾问 DEPT 是否能够追查到这个问题。Park 利用 DEPT 成功定位了问题,其中涉及到对位锁(bit lock)的等待;而涉及位锁的事件对 lockdep 来说是不可见的。今年早些时候,Andrew Morton 也曾 面临一个类似的问题:

真是怀旧啊。一二十甚至三四十年前,我们很多人大部分时间都在盯着 ABBA 死锁。然后 lockdep 出现了,又过了几年,这一切都停止了。我一直希望 lockdep 能为像 folio_wait_bit_common() 这样的自定义锁提供解决方案,但至今仍未实现。

他也问 DEPT 能否找到这个问题;结果 DEPT 再次定位了死锁,以便进行修复。

Park 说,DEPT 具有多项优势,首先在于它采用了更普遍的依赖概念,而不仅仅关注特定的锁。它能够处理 lockdep 无法处理的涉及页帧锁(folio locks)、完成量(completions)或 DMA 栅栏(DMA fences)的情况。DEPT 也能够正确地处理读写锁(reader-writer locks)。他说,与 lockdep 相比,它产生误报(false-positive reports)的可能性更小,并且在首次报告问题后能够继续运行(而 lockdep 一旦发现问题就会停止运行)。

他承认,lockdep 更好的一点是它现在产生的误报报告少得多;他指出,内核开发者们为此付出了 20 年的努力。然而,它确实会遗漏一些死锁情况。他总结道,在死锁场景比 lockdep 能处理的更复杂的情况下,应该使用 DEPT。

我忍不住问,为什么 DEPT 经过 16 个修订版和三年多(第一个版本于 2022 年 2 月发布)仍未进入主线(upstream)。Park 回答说,真正的阻力来源是误报的数量。Lockdep 要安静得多。

另一位与会者表示,由于 DEPT 是一个编译时选项(build-time option),因此很难用于解决影响现场生产系统的问题;他建议或许采用 BPF(Berkeley Packet Filter,伯克利包过滤器)的方法会很有用。Park 表示同意,但似乎此前并未考虑过 BPF 方案;他说他会对此进行研究。

最后,另一位听众表示,他认为误报问题不应阻碍这段代码的合并;他问道, 真正 的问题是什么。Park 没有回答这个问题,但他声明会继续致力于代码开发,直到成功将其合并到主线。

讲座结束后,我手持啤酒,向一位内核核心开发者询问了 DEPT 遭遇阻力的原因。答案确实是误报;该工具产生了太多报告,以至于很难从这些噪音中提取出真正的信号。他们说,问题的根源在于 Park 试图通过一个大型补丁集一次性替换 lockdep。像 DEPT 这样的工具可能很有用且受欢迎,但它需要以一系列较小的更改形式进入主线(mainline),逐步将 lockdep 演进为具有 DEPT 依赖观念的工具,从而让内核在每一步都变得更好。在采取这种方法之前,将 DEPT 合并到主线的尝试不太可能成功。

感兴趣的读者可查阅 Park 讲座的幻灯片。

[感谢 Linux 基金会,LWN 的旅行赞助商,对此次活动差旅的支持。]

全文完
LWN 文章遵循 CC BY-SA 4.0 许可协议。

欢迎分享、转载及基于现有协议再创作~

长按下面二维码关注,关注 LWN 深度文章以及开源社区的各种新近言论~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值