Linux内核链表的研究与应用(5)

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链表结点后的第一个结点其结构体的地址。

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:http://www.heiqu.com/55d44a25386278bfb811a0069ff678d9.html