linux內核鏈表是一個雙向循環鏈表,其實現與具體硬件平臺無關,理解了linux內核鏈表的實現機制,我們能夠把其移植到引用層程序設計當中。
linux內核鏈表相關的一些函數聲明在include/linux/list.h中。
首先是鏈表數據結構的定義
struct list_head {
struct list_head *next, *prev;
};
這個不需要做過多的解釋,就是這麼定義的,根據內核源代碼的說法是,使用這種next/prev entries的方式比使用一般的 single-entry routines所產生的代碼要好。
接着是鏈表的創建和初始化
從內存中開闢一個頭結點然後調用初始化函數就能完成鏈表的創建
在內核中,鏈表的初始化函數如下
static inline void INIT_LIST_HEAD(struct list_head *list)
{
list->next = list;
list->prev = list;
}
這是一個內聯函數,函數參數爲 list_head類型的頭結點。
通俗點講內核鏈表的初始化過程就是把前驅指針和後繼指針都指向了自己。
static inline void list_add(struct list_head *new, struct list_head *head)
{
__list_add(new, head, head->next);
}
static inline void list_add_tail(struct list_head *new, struct list_head *head)
{
__list_add(new, head->prev, head);
}
可以看到,其實現倒是調用__list_add函數,那麼__list_add函數函數又是如何實現的呢?
從內核中我們可以看到
static inline void __list_add(struct list_head *new,
struct list_head *prev,
struct list_head *next)
{
next->prev = new;
new->next = next;
new->prev = prev;
prev->next = new;
}
這個函數搞清楚了,添加結點也就沒有什麼問題了。這個函數的第一個參數是list_head類型的新的結點,第二個參數是它前面的那個list_head類型的結點,第三個參數是它後面的一個list_head類型的結點,這麼一說也許就清晰了
實際上這個函數可以理解爲圖上的畫線的過程,它總共畫了四條帶箭頭的線。