2020年5月10日 星期日

Linux Method Dispatch

一種在 C 實作 Object 的方式是宣告一個 struct,含有一些函數指標,這些函數運作在 struct 自己 (也就是第一個參數是 struct 自己),但這不是 Linux 主要採用的樣式。
就同樣 class 的 Object,Method 不像狀態一般不會變,通常收集在另一個 struct,有時稱為「virtual function table (vtable)」,原本 struct 只需要一個指標到這個 table 而節省記憶體。

pure vtable:都是函數指標的 struct,這些函數的第一個引數指到一個 struct,其包含一個指標指到此 vtable。
例如:file_lock_operations 包含兩個函數指標,運作在 struct file_lock
例如:seq_operations 包含四個函數指標,運作在 struct seq_file
vtable 取名習慣是運作的 struct 名稱或 abbreviated 加上「_operations」,在 Linux 2.6.39 大約有 30 個「*_operations」。此外有超過 100 個「*_ops」,大部分也是。但也有幾個如 struct mdk_personality,並沒有規則。

函數指標為 NULL:
  • 呼叫前要檢查。
  • 與其間接執行一個沒功能的函數,檢查是否 NULL 較有效率。
  • 如果 NULL 只是少數例外,檢查 NULL 確實浪費程式空間及執行時間。
  • 可能有別的方式得知為 NULL,不用實際去檢查,也節省了 memory fetch。
原因:持續發展的結果。新加一個函數指標,舊有程式預設初始化為 NULL,不好一一指定一個存在、但沒實際動作的函數。 
原因:特定 Method 對有些使用情況是無意義的,測試為 NULL 需回傳錯誤。例如:在 inode_operations 的 create() 只有在 inode 是目錄才有意義,所以執行 vfs_create() 檢查為 NULL 而回傳 -EACCES。

原因:界面函數轉換。例如:file_operations 的 ioctl(),在 2.6.11 新增 unlocked_ioctl() 不用 big kernel lock,在 2.6.36 所有驅動程式和檔案系統完成轉換而移除 ioctl()。轉換過程中,一個檔案系統一般只有二者之一,讓另一個為 NULL。

例如:file_operations 的 read()/write() 和 aio_read()/aio_write() 只需要二者之一。aio_read() 用來支援 asynchronous IO,此時 the regular synchronous read() 是不需要的 (實際上是透過 do_sync_read() 使用 aio_read()),但似乎沒有移除 read() 的打算,有些情況 async IO 是 not relevant,例如特殊檔案系統 procfs 和 sysfs。

不純的 vtable:含有其它成員。

例如:struct mdk_personality 提供 particular software RAID level 操作,包含了「owner」、「name」、以及「list」「owner」是提供實作的模組,「name」只是識別(有些 vtable 是字串、有些數字,有些稱作「版本」、「family」、「drvname」、或「level」。)

Object-oriented design patterns in the kernel, part 1

沒有留言:

張貼留言

SIP header Via

所有 SIP 訊息 都要有 Via,縮寫 v。一開始的 UAC 和後續途經的每個 proxy 都會疊加一個 Via 放傳送的位址,依序作為回應的路徑。 格式 sent-protocol sent-by [ ;branch= branch ][ ; 參數 ...] s...