LWN:數(shù)據(jù)類型的命名差異!
關(guān)注了就能看到更多這么棒的文章哦~
What's in a (type) name?
By Jonathan Corbet
September 2, 2022
DeepL assisted translation
https://lwn.net/Articles/906496/
內(nèi)核的 manual pages (https://www.kernel.org/doc/man-pages/ )項目的地位比較特別。它是作為一個獨立的項目來管理的,沒有跟內(nèi)核的文檔放在一起,它的任務(wù)是記錄內(nèi)核中系統(tǒng)調(diào)用的接口,以及由 C 庫為這些接口所提供的 wrapper API。有時這兩個目的會有一些沖突,這可以從去年的一個關(guān)于是否使用 C 標準類型名稱(standard type names)來描述內(nèi)核定義的結(jié)構(gòu)的討論中就可以看到。
C 語言的 <stdint.h> 頭文件為那些需要準確規(guī)定如何表示整型變量的開發(fā)者定義了一些 type。例如,int16_t 是一個 16 位的有符號類型,而 uint64_t 是一個 64 位、無符號類型。在定義那些硬件實現(xiàn)的、通過通信協(xié)議交換的、或在用戶和內(nèi)核空間之間傳遞的數(shù)據(jù)結(jié)構(gòu)時,需要控制到這種程度。
然而,內(nèi)核并不使用這些類型來定義其系統(tǒng)調(diào)用接口。相反,內(nèi)核有自己的內(nèi)部定義的類型。例如,內(nèi)核的 API 定義不是使用 uint64_t,而是使用 __u64。這種情況已經(jīng)存在了很久,實際上在標準 C 類型出現(xiàn)之前就已經(jīng)存在了,這是 kernel 項目日常工作方式的一部分。
一般來說,man page 需要展示出內(nèi)核中對數(shù)據(jù)類型的定義。因此,例如,bpf()手冊中對 bpf_attr union 中的一部分的定義是:
struct { /* Used by BPF_MAP_*_ELEM and BPF_MAP_GET_NEXT_KEY
commands */
__u32 map_fd;
__aligned_u64 key;
union {
__aligned_u64 value;
__aligned_u64 next_key;
};
__u64 flags;
};
這些類型對于內(nèi)核開發(fā)者來說會非常熟悉,但對于用戶空間開發(fā)者來說,它們看起來就可能有點怪了。早在 2021 年 4 月,man-pages 的共同維護者 Alejandro Colomar 就決定來改寫 man pages,使用標準的 C 類型,讓這些內(nèi)容看起來更熟悉和正常一些。也許是因為他喜歡挑戰(zhàn),Colomar 是從 bpf() man page 開始的;在打上了他的 patch 后,上述結(jié)構(gòu)被定義為:
struct { /* Used by BPF_MAP_*_ELEM and BPF_MAP_GET_NEXT_KEY commands */
uint32_t map_fd;
uint64_t [[gnu::aligned(8)]] key;
union {
uint64_t [[gnu::aligned(8)]] value;
uint64_t [[gnu::aligned(8)]] next_key;
};
uint64_t flags;
};
這個 patch 立即被 BPF 維護者 Alexei Starovoitov 否決了,他說:"man page 應該按照.h 文件中的方式來描述內(nèi)核 api"。Colomar 回答說,無論哪種方式,實際使用的類型都是一樣的,而且他改動之后對用戶來說更好:
如果我們有一個固定寬度的整數(shù)類型的標準語法(實際上其他類型也一樣),那么 man page 就應該盡可能地遵循這個標準。任何背離標準(無論是 C 還是 POSIX)的做法都應該有一個強大的理由,否則就只會造成混亂。
但 Starovoitov 堅決反對這個做法,他說,man page 應該按照代碼所 include 的相關(guān)內(nèi)核頭文件里的定義來描述這些類型。
2021 年 5 月,Colomar 又回來提供了新版本的 patch,跟前一版本相比變化不大。同樣沒有變化的是人們對它的態(tài)度。這一次,Greg Kroah-Hartman 也表達了他的反對意見,他說所涉及的類型 "不一樣,它們生活在不同的命名空間和世界中,不可能在所有場景下都是可以直接交換的"。不過,GNU C 庫的開發(fā)者 Zack Weinberg 并不同意這個觀點:
C 結(jié)構(gòu)的手冊文檔 不應該 跟頭文件中的實際聲明一致。文檔中的字段類型通常是跟實際使用的類型在賦值時兼容(assignment-compatible),但并非總是如此。我們不能保證字段的順序與頭文件相同,也不能保證列出的字段的集合是完整的。
這個論點未能說服內(nèi)核社區(qū),他們?nèi)匀粡娏曳磳@一改動。這場討論后來平息了一年多。
2022 年 8 月,Colomar 又回來了,同樣是帶著一個新的 patch,修改了更多的文件;他提供了從三個不同的開發(fā)者那里得到的 Nacked-by tag。不出所料,這些開發(fā)者在風平浪靜的這一年間并沒有改變態(tài)度來同情這個做法。Starovoitov 重申了他的反對意見,并要求 Colomar 不要再發(fā)送 patch 了:
Colomar 的回應是繼續(xù)推進,并將該 patch 合入到 man-pages 倉庫中了。如果有一個內(nèi)核補丁遇到了這樣的反對,幾乎可以肯定永遠不會被合入,但 man-pages 不是 kernel 項目。Colomar 似乎是目前唯一活躍的 man-pages 維護者;自從 2021 年 8 月 man pages 5.13 發(fā)布后,長期維護者 Michael Kerrisk 似乎已經(jīng)從相關(guān)活動中消失了。因此,當涉及到這個領(lǐng)域的決定時,沒有人能夠推翻 Colomar 的決定。
這次討論的大部分內(nèi)容都跟之前類似,但這次 Linus Torvalds 也加入了討論。他指出,內(nèi)核的類型不可能與標準的 C 類型相同,否則會產(chǎn)生命名空間(namespaces)問題:內(nèi)核不能包括 <stdint.h> 來定義這些類型,但也不能在用戶空間使用的文件中定義這些類型且不產(chǎn)生沖突。Torvalds 同意其他人的意見,即文檔應該與實際使用的類型相匹配:
老實說,我不認為這有 很大 的區(qū)別,但是跟文檔來源不匹配的文檔最終只會讓人產(chǎn)生困惑。有人會說 "這不對",甚至可能修改 struct 的定義來跟文檔相符。
這條信息,加上 Kroah-Hartman 提出的 revert 這個改動的要求,說服 Colomar 退讓了。他的總結(jié)語是:
你說服了我。手冊將完全按照內(nèi)核中的類型來進行記錄。這樣更簡單。
由于這個 patch 在 Greg 要求我這么做的情況下最近被我 revert 掉了,所以我將保持這種方式。我想這可以結(jié)束 man-pages 的討論。
當然,有趣的是,內(nèi)核確實在內(nèi)部定義了許多標準類型(standard types),而且有成千上萬的變量都是用這些類型定義的。在內(nèi)核中使用標準 C 類型本身不是問題,只有在用戶空間的 API 定義中使用它們時,才會有問題。如果有足夠強的意愿,很可能是一個可以解決的問題,但這不是個不費吹灰之力的小工作。所以看起來 man-page 將繼續(xù)按照內(nèi)核的用戶空間 API 頭文件中實際使用的類型來進行記錄。
全文完
LWN 文章遵循 CC BY-SA 4.0 許可協(xié)議。
長按下面二維碼關(guān)注,關(guān)注 LWN 深度文章以及開源社區(qū)的各種新近言論~
