內核list (雙向循環鏈表)
類型:
struct list_head {
struct list_head *next, *prev;
};
鏈表的初始化(兩種方式):
1. LIST_HEAD 定義一個頭,並且初始化爲循環鏈表
2. INIT_LIST_HEAD(內聯函數)初始化爲循環鏈表
#define LIST_HEAD_INIT(name) { &(name), &(name) }
#define LIST_HEAD(name) \
struct list_head name = LIST_HEAD_INIT(name)
static inline void INIT_LIST_HEAD(struct list_head *list)
{
list->next = list;
list->prev = list;
}
添加元素(兩種方式):
1. 頭插(list_add) :__list_add(new, head, head->next);
2. 尾插(list_add_tail) :__list_add(new, head->prev, head);
兩中方式本質相同往兩個元素中間插入元素。
(雙向循環鏈表特點的體現)
刪除元素(一種方式):
1. (list_del): __list_del(entry->prev, entry->next) 讓兩邊元素相互指向
讓被刪除元素指向LIST_POISON隊列,讓系統銷燬
2. (list_del_init):將被刪除元素初始化爲新的雙向循環列表
替換節點:
1. list_replace:修改新元素的指向即可
2. list_replace_init:修改新元素的指向即可,並將舊元素初始化爲新的雙向循環列表
list_move: 刪除一個頭部元素,在向頭部插入一個新元素
判斷是否爲最後一個元素:list_is_last
判空:list_empty 和 list_empty_careful
list_entry(找到某個節點的起始位置): 分析
#define list_entry(ptr, type, member) \
container_of(ptr, type, member)
#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
// 將值賦值給變量,並且用const修飾,可以防止無意修改變量的值
// offset也做了改動
#define container_of(ptr, type, member) ({ \
const typeof( ((type *)0)->member ) *__mptr = (ptr); \
(type *)( (char *)__mptr - offsetof(type,member) );})
之前版本使用的是:
#define list_entry(ptr, type, member) \
((type*)((char*)ptr – (unsigned long)(((type*)0)->member)))
一. 鏈表的for 循環頭部:
0. 遍歷時使用到的工具
1. 向後遍歷
1. 普通的for 循環,只適合遍歷,
注意pos的類型是struct list_head
list_for_each(pos, head) \
for (pos = (head)->next; pos != (head); pos = pos->next)
2. 在釋放的時候使用,其中的n 可以指向已釋放節點的下一個節點,
注意pos 和n 的類型都是struct list_head
list_for_each_safe(pos, n, head) \
for (pos = (head)->next, n = pos->next; pos != (head); \
pos = n, n = pos->next)
3. 普通的for 循環,只適合遍歷,
注意pos 的類型是用戶定義的結構體
list_for_each_entry (pos, head, member) \
for (pos = list_first_entry(head, typeof(*pos), member);
&pos->member != (head); \
pos = list_next_entry(pos, member))
4. 繼續遍歷鏈表,從pos 的下一個開始</span>
注意和3 中的一樣pos 的初始值是鏈表中的某個節點
#define list_for_each_entry_continue(pos, head, member)
for (pos = list_next_entry(pos, member);
&pos->member != (head);
pos = list_next_entry(pos, member))
5. 遍歷鏈表從pos 開始
和4 基本相似,
#define list_for_each_entry_from(pos, head, member)
for (; &pos->member != (head);
pos = list_next_entry(pos, member))
其他的就是給以上的加個safe
2. 向前遍歷
和上邊的一樣,實質將next 改成prev 即可