在linux核心中的佇列操作都是通過list_head來進行的,list_head稱為「宿主結構」的「連線件」,但是我們真正需要的是宿主結構,而不是這個連線件,如果我們順著乙個佇列取得了其中一項的list_head結構時,又怎樣找到其宿主結構呢?
剛開始看核心原始碼時,我對這個問題百思不得其解,後來看了浙大的那本《linux核心源**情景分析》之後,才找到答案。所以將關鍵部分摘錄出來,為有此苦惱的朋友解惑。
以記憶體頁面管理的page資料結構作為「宿主結構」為例,它的定義如下:
typedef struct page mem_map_t;
在核心源**中是通過list_entry()函式來解決這個問題的,例項**:
page = list_entry(curr, struct page, list);
如此就得到了其宿主結構。list_entry是乙個巨集,它的定義如下:
#define list_entry(ptr, type, member) /
((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member)))
和上面的例項**作比較,此巨集經過c預處理的文字替換,就成為:
page=((struct page*)((char *)(curr)-(unsigned long)(&((struct page*)0)->list)));
這裡的curr是乙個page結構的內部成員list的位址,而我們所需要的卻是那個page結構本身的位址,所以從位址curr減去乙個位移量,即成員list在page內部的偏移,才能達到要求。那麼,這位移量到底是多少呢?&((struct page *)0)->list表示當結構page正好在位址0上時其成員list的位址,這就是位移量。
在windows核心中也採用了類似的佇列操作,用ddk編寫過windows驅動程式的就知道,只不過換了個名字,將list_entry變成了containing_record,在ddk標頭檔案中也有此巨集的定義:
#define containing_record(address, type, field) ((type *)( /
(pchar)(address) - /
(ulong_ptr)(&((type *)0)->field)))
可見,它們是完全一樣的。
核心中重要的資料結構
任務鍊錶 task list 流程排程程式為每個活動的流程維護乙個資料塊。這些資料塊儲存在稱為任務列表的鏈結列表中。程序排程程式始終維護乙個指示當前活動程序的當前指標。記憶體對映 memry map 記憶體管理器基於每個程序儲存虛擬位址到實體地址的對映,還儲存有關如何獲取和替換特定頁面的其他資訊。此...
Linux核心中的資料結構與演算法(一)
一,序言 其實想寫這個系列很久了,因為本人工作的關係,平時接觸linux核心很多,從業後很多時候在網上查詢的東西是片面或者不系統的,打算給自己的知識庫進行個整理吧,打算開筆寫這個系列,再加上自己想考研了,算是重新學習,也算鞏固自己的知識吧。如果有什麼錯誤和疏漏,也請看客們給出批評意見,比心比心比心 ...
半原創 核心中的資料結構 SplayTree
核心中的資料結構 splay tree splay tree 伸展樹 是binary search tree 二叉搜尋樹 daniel sleator和robert e.tarjan發明。但此操作可能會花費o n 時間,但m次操作的最壞情況為o m log2 n splay tree是在節點訪問後,...