LWN:用戶空間的中斷!
關(guān)注了就能看到更多這么棒的文章哦~
User-space interrupts
By Jonathan Corbet
September 30, 2021
LPC
DeepL assisted translation
https://lwn.net/Articles/871113/
"interrupt(中斷)" 這個術(shù)語會讓人聯(lián)想到源自硬件的、由內(nèi)核所處理的那個中斷信號,甚至連軟中斷(software interrupt)也是屬于內(nèi)核的一個概念。但是,似乎有一個場景中會需要讓用戶空間的進(jìn)程互相之間直接來發(fā)送 interrupt。在 2021 年的 Linux Plumbers 大會上,Sohil Mehta 主持了一場關(guān)于 Linux 如何支持這個功能的內(nèi)核峰會。

Mehta 說,用戶空間中斷(user-spaceinterrupt,或簡稱 "user interrupt (用戶中斷)")這個功能的核心就是要以快速的方式來進(jìn)行 event signaling (事件通知)。它可以繞過內(nèi)核,直接向用戶空間來傳遞 signal,從而實(shí)現(xiàn)更低的 latency。他說,我們現(xiàn)有的進(jìn)程間通信機(jī)制都有一些局限。同步機(jī)制(synchronous mechanism)通常需要用一個專門的線程來做事,會有很高的延遲,而且通常效率很低。異步機(jī)制(比如說信號)的延遲甚至更高。所以往往我們唯一的選擇就是輪詢(polling),這種做法浪費(fèi)了 CPU 時間。如果能有一個快速、高效的替代方案就更好了。
用戶空間中斷就是一個很好的選擇,它將首先出現(xiàn)在英特爾的 "Sapphire Rapids" CPU 中。支持這一功能的 RFC patch 已于 9 月中旬發(fā)布了。這些 patch 支持 user-to-user 的信號發(fā)送,不需要經(jīng)過內(nèi)核,直接使用新的 SENDUIPI 指令就可以讓一個進(jìn)程直接向另一個進(jìn)程發(fā)送中斷了。未來的版本中還會包括 kernel-to-user 的信號發(fā)送,并最終支持讓設(shè)備直接發(fā)送中斷給到用戶空間進(jìn)程。
Mehta 提供了一些 benchmark 結(jié)果(可以在幻燈片中看到),數(shù)據(jù)顯示用戶空間中斷比使用 eventfd()快 9 倍,比使用管道(pipe)或信號(signal)快 16 倍。如果接收進(jìn)程在內(nèi)核中被阻塞了的話,這個優(yōu)勢就會降低,因?yàn)樵谶@種情況下無可避免地需要進(jìn)行上下文切換。即使如此,用戶空間中斷對接收方來說也要快 10%,而對發(fā)送方來說則要快得更多,因?yàn)榘l(fā)送方根本不需要進(jìn)入內(nèi)核了。Florian Weimer 問道,用戶空間中斷與 futexes 相比如何,但看起來這方面還沒有進(jìn)行過測試。
這個功能的使用場景當(dāng)然也會包括快速進(jìn)程間通信(fast interprocess communication)。那些 user-mode CPU scheduler 調(diào)度器可以從中受益,用戶空間的 I/O stack(例如 networking stack)也可以受益。要想充分利用這一特性,就需要對 libevent 和 liburing 等庫進(jìn)行修改。Mehta 說目前還沒有真正在使用這個功能的應(yīng)用,他很想聽聽大家的反饋看有哪些其他可能受益的應(yīng)用。Ted Ts'o 建議在虛擬化環(huán)境中用來進(jìn)行 host-to-guest 的喚醒;看起來這個用例正在進(jìn)行調(diào)查,但目前還沒有實(shí)際測試結(jié)果。
用戶空間的進(jìn)程出于各種原因不能隨意向他人發(fā)送中斷,這里需要進(jìn)行一些設(shè)置。在接收方,相關(guān)的工作都始于一個調(diào)用:
uintr_register_handler(handler, flags);
其中 handler() 是用來處理用戶空間中斷的函數(shù),flags 必須設(shè)為 0。handler 函數(shù)的定義需要特別注意,它的原型是這樣的:
void __attribute__ ((interrupt))
handler(struct __uintr_frame *frame, unsigned long long vector);
接下來需要創(chuàng)建至少一個跟這個 handler 關(guān)聯(lián)起來的文件描述符:
int uintr_create_fd(u64 vector, unsigned int flags);
這里,vector 是 0 到 63 之間的一個數(shù)字。每個 vector 都可以創(chuàng)建一個文件描述符。然后,該進(jìn)程將該文件描述符交給發(fā)送方。如果發(fā)送方是同一進(jìn)程中的另一個線程,那么這個傳遞就很簡單,否則的話就需要使用 Unix 里的 socket 來傳輸這個文件描述符了。然后,發(fā)送方要通過以下方式來進(jìn)行配置:
int uintr_register_sender(int fd, unsigned int flags);
其中 fd 是接收者傳遞過來的文件描述符,flags 和之前一樣需要是 0。返回值是一個 handle,可以與 GCC 11 支持的 _senduipi() intrinsic 一起使用來實(shí)際進(jìn)行中斷發(fā)送到接收者。
中斷的實(shí)際遞交時機(jī)要取決于接收方當(dāng)時正在做什么。如果該進(jìn)程正在用戶空間中運(yùn)行,那么 handler 函數(shù)將會被立即調(diào)用,并取得相應(yīng)的 vector 編號。一旦 handler 處理程序返回了,那么就會在之前被中斷的位置繼續(xù)執(zhí)行。如果接收者此時被阻塞在內(nèi)核的系統(tǒng)調(diào)用中,那么該中斷將會在返回到用戶空間時被觸發(fā),也就是說并不會打斷當(dāng)前正在進(jìn)行的系統(tǒng)調(diào)用。在 patch set 中有一個 uintr_wait() 系統(tǒng)調(diào)用,它的作用是一直阻塞到收到一個用戶空間中斷,然后就立即返回,但此函數(shù)目前的行為還是一個示意性質(zhì)的,需要等大家決定了這種情況下的理想行為之后再進(jìn)行修改。
Prakesh Sangappa 詢問大家是否真的有必要與所有相關(guān)的發(fā)送者來傳遞文件描述符。在一個可能有大量發(fā)送者的系統(tǒng)中,這個動作可能會耗費(fèi)不少資源。Mehta 回答說這里有幾個優(yōu)化方案正在研究中。Ts'o 詢問用戶空間中斷是否可以廣播給多個接收者,回答是不支持廣播。
Arnd Bergmann 想知道是否考慮過在老式 CPU 上模擬這一功能。答案似乎是肯定的,內(nèi)核將捕獲相關(guān)指令,并采取一種透明的方式來模擬實(shí)現(xiàn)它們的行為。Mehta 要求得到關(guān)于這個仿真機(jī)制的反饋,尤其是這個機(jī)制是否應(yīng)該在其他架構(gòu)上也實(shí)現(xiàn)。Bergmann 不贊成這個想法,他說,如果為這些架構(gòu)也實(shí)現(xiàn)了用戶空間中斷的話,它們肯定與仿真出來的版本不兼容。他說,對其他架構(gòu)的仿真應(yīng)該只有在這些架構(gòu)自己定義了它們自己的指令之后才能進(jìn)行。
Greg Kroah-Hartman 詢問 Clang 編譯器是否支持 _senduipi() intrinsic。這個支持目前正在進(jìn)行中,但尚未完成。Kroah-Hartman 還詢問了從該功能中受益的工作場景的更多細(xì)節(jié),Mehta 回答說他也還沒有什么具體的東西可以提供。
時間已經(jīng)不多了,結(jié)束這次會議之前,Mehta 問了一個問題,當(dāng)接收者在系統(tǒng)調(diào)用中被阻止時應(yīng)該發(fā)生什么。如前所述,目前的 patch set 在完成中斷傳遞之前會一直等待系統(tǒng)調(diào)用返回。我們是否應(yīng)該改變行為,使之更接近于信號,也就是立即會完成中斷傳遞,而系統(tǒng)調(diào)用則被打斷并返回 EINTR?沒有人對這個問題發(fā)表意見,會議就此結(jié)束了。
這個講座的視頻可以在 YouTube 上找到。
全文完
LWN 文章遵循 CC BY-SA 4.0 許可協(xié)議。
長按下面二維碼關(guān)注,關(guān)注 LWN 深度文章以及開源社區(qū)的各種新近言論~
