内核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 即可