7.链表合并
1>function:
实现将list链表(不包括list结点)插入到head链表中
2>Linux内核链表提供了四个函数接口
static inline void list_splice(const struct list_head *list,struct list_head *head)
static inline void list_splice_init(struct list_head *list,struct list_head *head)
static inline void list_splice_tail(struct list_head *list,struct list_head *head)
static inline void list_splice_tail_init(struct list_head *list,struct list_head *head)
list:新添加的链表
head:将list链表添加到head链表中
3>函数实现
static inline void __list_splice(const struct list_head *list, struct list_head *prev, struct list_head *next)
{
struct list_head *first = list->next;
struct list_head *last = list->prev;
first->prev = prev;
prev->next = first;
last->next = next;
next->prev = last;
}
static inline void list_splice(const struct list_head *list, struct list_head *head)
{
if (!list_empty(list))
__list_splice(list, head, head->next);
}
static inline void list_splice_tail(struct list_head *list, struct list_head *head)
{
if (!list_empty(list))
__list_splice(list, head->prev, head);
}
static inline void list_splice_init(struct list_head *list, struct list_head *head)
{
if (!list_empty(list)) {
__list_splice(list, head, head->next);
INIT_LIST_HEAD(list);
}
}
static inline void list_splice_tail_init(struct list_head *list, struct list_head *head)
{
if (!list_empty(list)) {
__list_splice(list, head->prev, head);
INIT_LIST_HEAD(list);
}
}
(1)四个函数都调用了__list_splice()函数来实现添加链表。
(2)list_splice和list_splice_init表示将新添加的链表用头插法插入在head链表中.他们之间的区别是.list_splice中的list结点没有被初始化,list_splice_init将list结点进行了初始化。
(3) list_splice_tail和list_splice_init表示将新添加的链表list用尾插入法插入在head链表中。他们之间的区别是list_splice_tail和list_splice_init的区别是list_splice_tail中的list结点没有被初始化,而list_splice_tail_init将list结点进行了初始化。
(4)list_splice和list_splice_tail都调用了__list_splice实现将整个list链表(不包括list结点)添加到head链表中,他们的区别是list_splice将list链表添加到head结点之后,list_splice_tail将list链表添加尾结点之后
五.内核链表的遍历操作
遍历链表常用操作。为了方便核心应用遍历链表,linux链表将遍历操作抽象成几个宏。在分析遍历宏之前,先分析下如何从链表中访问到我们所需要的数据项
1.list_entry(ptr,type,member)
1>function:
通过成员指针获得整个结构体的指针
Linux链表中仅保存了数据项结构中list_head成员变量的地址,可以通过list_entry宏通过list_head成员访问到作为它的所有者的结点数据
2>接口:
list_entry(ptr,type,member)
ptr:ptr是指向该数据结构中list_head成员的指针,即存储该数据结构中链表的地址值。
type:是该数据结构的类型。
member:改数据项类型定义中list_head成员的变量名。
3>list_entry宏的实现
#define list_entry(ptr, type, member) \
container_of(ptr, type, member)
list_entry宏调用了container_of宏,关于container_of宏的用法见:
2.list_first_entry(ptr,type,member)
1>function:
这里的 ptr是一个链表的头结点,这个宏就是取的这个链表第一元素所指结构体的首地址。
2>接口:
list_first_entry(ptr,type,member)
ptr:ptr是指向该数据结构中list_head成员的指针,即存储该数据结构中链表的地址值。此处的ptr是一个链表的头结点
type:是该数据结构的类型。
member:该数据项类型定义中list_head成员的变量名。
3>list_entry宏的实现
#define list_first_entry(ptr, type, member) \
list_entry((ptr)->next, type, member)
list_first_entry调用了list_entry来获取ptr链表结点后的第一个结点其结构体的地址。