Boqun Feng spoke at Kangrejos 2025 about adding a frequently needed API for Rust drivers that need to handle interrupts: interrupt-aware spinlocks. Most drivers will need to communicate information from interrupt handlers to main driver code, and this exchange is frequently synchronized with the use of spinlocks. While his first attempts ran into problems, Feng's ultimate solution could help prevent bugs in C code as well, by tracking the number of nested scopes that have disabled interrupts. The patch set, which contains work from Feng and Lyude Paul, is still under review.
馮博羣在 2025 年的 Kangrejos 會議上介紹了一個 Rust 驅動程序經常需要的新 API:可感知中斷的自旋鎖(interrupt-aware spinlocks)。大多數驅動程序都需要在中斷處理程序與主驅動代碼之間交換信息,而這種交換通常應該通過自旋鎖來同步。儘管他最初的嘗試遇到了一些挑戰,但他最終的解決方案不僅能幫助 Rust 驅動,還能防止 C 代碼中出現 bug——通過追蹤禁用中斷的嵌套層級數量。包含馮博羣和 Lyude Paul 工作的補丁集目前仍在審查中。
Code that acquires a spinlock needs to disable preemption: otherwise, if it were preempted, everything else contending for the lock would just pointlessly burn CPU time. The same thing (almost) applies to using spinlocks in interrupts, Feng said. If kernel code acquires a spinlock in process context, and then an interrupt arrives, the handler for which tries to acquire the same lock, the system will deadlock. The simple rule in the kernel is that if a lock is ever used in both interrupt handler and process context, the lock must be "irq-safe" (meaning that the acquirer disables interrupts when appropriate). The kernel's lockdep tool will check that this rule is followed.
獲取自旋鎖的代碼必須禁用搶佔;否則,如果該代碼在持鎖期間被搶佔,其他試圖獲得同一鎖的線程將會白白浪費 CPU 時間。馮博羣指出,在中斷中使用自旋鎖時幾乎也是同樣的道理。如果內核代碼在進程上下文中獲取了一個自旋鎖,而此時發生中斷且中斷處理程序嘗試獲取同一個鎖,那麼系統將陷入死鎖。內核中有一個簡單的規則:假如某個鎖既在中斷上下文又在進程上下文中使用,那麼該鎖必須是“irq-safe”的,也就是説,在合適的時機禁用中斷。內核的 lockdep 工具會檢查此規則是否被遵守。
Every sufficiently complex driver will need an interrupt handler, Feng continued. In order to write drivers in Rust, kernel programmers will need an abstraction to deal with interrupts and irq-safe locks. The existing irq-safe spinlocks in C use either spin_lock_irq()/spin_unlock_irq() or spin_lock_irqsave()/spin_lock_irqrestore(), depending on whether the code is expected to run in an interrupt-enabled context or not. The former pair of functions leaves interrupts unconditionally enabled after the lock is released, while