Linux內核鏈表 ——list相關內容

1  鏈表數據結構的定義:

struct list_head {
struct list_head *next, *prev;
};

list_head結構包含兩個指向list_head結構的指針prev和next,內核的鏈表具備雙鏈表功能,實際上,通常它都組織成雙循環鏈表。
這裏的list_head沒有數據域。在Linux內核鏈表中,不是在鏈表結構中包含數據,而是在數據結構中包含鏈表節點

2   聲明和初始化鏈表

#define LIST_HEAD_INIT(name) { &(name), &(name) }
#define LIST_HEAD(name) struct list_head name = LIST_HEAD_INIT(name)
LIST_HEAD_INIT初始化鏈表next、prev指針都爲指向自己,因爲Linux用頭指針的next是否指向自己來判斷鏈表是否爲空:

static inline int list_empty(const struct list_head *head)
{
	return head->next == head;
}
3  宏定義操作


#define list_entry(ptr, type, member) /  
    container_of(ptr, type, member)  

#define container_of(ptr, type, member) ({                      /  
        const typeof( ((type *)0)->member ) *__mptr = (ptr);    /  
        (type *)( (char *)__mptr - offsetof(type,member) );})  
先把0強制類型轉換成爲指向一個type型數據空間的指針,然後取其中的成員member,通過typeof得到這個成員member的類型,然後定義一個指向這個類型數據的指針命名爲__mptr,並賦值爲ptr;

把上面得到的__mptr減去成員member的偏移量,然後在強制類型轉換成指向type型空間的指針,也就是地址,也就是得到了type類型的首地址,也就得到了一個指針,可以用它做“->”運算,得到其結構體中的任意一個值

#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)  

先把0強制類型轉換成爲指向一個TYPE型數據的指針,然後取其中的MEMBER成員,再取它的地址,最後再強制類型轉換成size_t型,就是unsigned long型,也就是MEMBER成員的地址,而該TYPE型數據的首地址爲0,所以這個地址也就是MEMBER成員的偏移量,所以offsetof得到的是TYPE類型數據中成員MEMBER的地址偏移量

list_entry,ptr從一個結構的成員指針找到其容器的指針,ptr是找容器的那個變量的指針,把它減去自己在容器中的偏移量的值就應該 得到容器的指針。(容器就是包含自己的那個結構)

#define list_first_entry(ptr, type, member) /  
    list_entry((ptr)->next, type, member) 
它是調用了list_entry來定義的,就是找到ptr->next的地址,也就是第一節點的地址

下面給出一些定義,根據上面的內容很容易看懂

#define list_for_each(pos, head) /  
    for (pos = (head)->next; prefetch(pos->next), pos != (head); /  
            pos = pos->next)  
#define __list_for_each(pos, head) /  
    for (pos = (head)->next; pos != (head); pos = pos->next) 

#define list_for_each_prev(pos, head) /  
    for (pos = (head)->prev; prefetch(pos->prev), pos != (head); /  
            pos = pos->prev)  



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章