關於Linux核心代碼的真正接觸還是最近2個月,首先接觸這個最簡單的就是雙向鏈表了,這個鏈表可謂真的短小。原來有些時候,看這種經典代碼也是一種享受。在大學裡面寫的那些雙向鏈表那隻不過是學習而已。
#ifndef _LINUX_LIST_H<br />#define _LINUX_LIST_H</p><p>#ifdef __KERNEL__</p><p>struct list_head {<br />struct list_head *next, *prev;<br />};</p><p>#define LIST_HEAD_INIT(name) { &(name), &(name) }</p><p>#define LIST_HEAD(name) /<br />struct list_head name = LIST_HEAD_INIT(name)</p><p>#define INIT_LIST_HEAD(ptr) do { /<br />(ptr)->next = (ptr); (ptr)->prev = (ptr); /<br />} while (0)</p><p>static __inline__ void __list_add(struct list_head * new,<br />struct list_head * prev,<br />struct list_head * next)<br />{<br />next->prev = new;<br />new->next = next;<br />new->prev = prev;<br />prev->next = new;<br />}</p><p>static __inline__ void list_add(struct list_head *new, struct list_head *head)<br />{<br />__list_add(new, head, head->next);<br />}</p><p>static __inline__ void list_add_tail(struct list_head *new, struct list_head *head)<br />{<br />__list_add(new, head->prev, head);<br />}</p><p>static __inline__ void __list_del(struct list_head * prev,<br /> struct list_head * next)<br />{<br />next->prev = prev;<br />prev->next = next;<br />}</p><p>static __inline__ void list_del(struct list_head *entry)<br />{<br />__list_del(entry->prev, entry->next);<br />}</p><p>static __inline__ void list_del_init(struct list_head *entry)<br />{<br />__list_del(entry->prev, entry->next);<br />INIT_LIST_HEAD(entry);<br />}</p><p>static __inline__ int list_empty(struct list_head *head)<br />{<br />return head->next == head;<br />}</p><p>static __inline__ void list_splice(struct list_head *list, struct list_head *head)<br />{<br />struct list_head *first = list->next;</p><p>if (first != list) {<br />struct list_head *last = list->prev;<br />struct list_head *at = head->next;</p><p>first->prev = head;<br />head->next = first;</p><p>last->next = at;<br />at->prev = last;<br />}<br />}</p><p>#define list_entry(ptr, type, member) /<br />((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member)))</p><p>#define list_for_each(pos, head) /<br />for (pos = (head)->next; pos != (head); pos = pos->next)</p><p>#endif /* __KERNEL__ */</p><p>#endif<br />
這些鏈表結構體只能在核心使用,但其實我們在平時寫鏈表時,可以仿照這樣,精簡。
如果我們需要某種資料結構的隊列,就在這種結構內部放上list_head結構即可。例如:
typedef struct page {
struct list_head list;
.....
struct list_head lru;
....
}page_t;
這裡面放了了2個list_head結構體(list和lru),這代表page結構體可以存在兩個隊列中,如下面圖所示:
在這鏈表裡面最關鍵的地方在
#define list_entry(ptr, type, member) /
((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member)))
通過它才可以訪問鏈表裡面真正的元素
例如:
list_head pstList;
struct page *page;
page = list_entry(pstList, struct page, list); 其中pstList 指向一個page結構體。
list_entry的原理的,通過這個結構體鏈表頭在結構體中的位移來擷取 某個結構體的地址。
(unsigned long)(&((type *)0)->member)),這個是擷取結構鏈表頭的位移值,如在page中,list位移page的值
然後再把該地址減去該位移才真正得到我們想要的結構體地址。