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的地址偏移量
#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)