linux 内核常用数据结构及算法——list(循环双向链表)

在linux内核中,应用到链表的地方非常多,所以在内核代码中,专门有一个list.h文件,定义了常用的链表操作,由于该文件的长度太长,这里就不将整个文件都粘出来了,如果没有下载代码,可以在如下网址阅读http://lxr.linux.no/linux+v3.17.3/include/linux/list.h

list.h中,定义了一个链表结点结构体list_head,

struct list_head {
	struct list_head *next, *prev;
};
在程序中,需要将list_head作为结构体的指针,然后通过这个指针连接前驱、后继,比如以下的代码:

struct cat{
	int color;
	int weight;
	int age;
	struct list_head catList;
};
通过结构体的catList成员可以将多个对象连入链表

主要的函数

INIT_LIST_HEAD   初始化链表头

list_add(struct list_head *new, struct list_head *head)加入一个新的结点

list_add_tail(struct list_head *new, struct list_head *head)在链表的尾部加入新的结点

list_del(struct list_head *entry) 删除一个结点,删除结点后,还要将其后继设为LIST_POISON1、前驱设为LIST_POISON2,目的是以防程序仍然按照错误的地址访问链表

list_replace(struct list_head *old,
struct list_head *new)
用新的结点替换旧的结点

list_replace_init(struct list_head *old,
struct list_head *new)
用新的结点替换旧的结点,然后将旧的结点初始化为另一个链表头

list_del_init(struct list_head *entry) 将一个结点从链表上删除,然后将其初始化为另一个

list_move(struct list_head *list, struct list_head *head)将结点从一个位置换到另一个位置(移动到head之后)

list_move_tail(struct list_head *list,
 struct list_head *head)
将结点移动链表尾部(移动到head之前)

list_is_last(const struct list_head *list,
const struct list_head *head)
判断一个结点是否为链表的尾部

list_empty(const struct list_head *head) 判空(只有head)

list_empty_careful(const struct list_head *head)判空,会检查其他cpu有无正在修改该结点

list_is_singular(const struct list_head *head) 判断链表中是否只有head一个结点

list_cut_position(struct list_head *list,
struct list_head *head, struct list_head *entry)
将一个链表拆成两个,其中,list为新产生链表的头,entry为head链表上的一个结点。拆分后的head到entry之间的部分,被从原有链表中移除,放到新链表list中。

linux 内核常用数据结构及算法——list(循环双向链表)_第1张图片

拆分前

linux 内核常用数据结构及算法——list(循环双向链表)_第2张图片

拆分后


list_splice(const struct list_head *list,
struct list_head *head)
将链表list合并到结点head之后(list中不包括list结点的所有结点加入head之后)

static inline void list_splice_tail(struct list_head *list,
struct list_head *head)
将链表list合并到结点head之前(list中不包括list结点的所有结点加入head之前)

list_splice_init(struct list_head *list,
   struct list_head *head)
将链表list合并到结点head之后(list中不包括list结点的所有结点加入head之后),之后重新初始化list结点

list_splice_tail_init(struct list_head *list,
struct list_head *head)
将链表list合并到结点head之前(list中不包括list结点的所有结点加入head之前),之后重新初始化list结点


宏函数

1

#define list_entry(ptr, type, member) \
	container_of(ptr, type, member)

通过链表的指针,获得结构体的地址,实际上是由container_of宏实现的,可以参考上一篇博客

2

#define list_first_entry(ptr, type, member) \
	list_entry((ptr)->next, type, member)

获得ptr指针后第一个链表结点对应的结构体地址

3

#define list_for_each(pos, head) \
	for (pos = (head)->next; prefetch(pos->next), pos != (head); \
        	pos = pos->next)

从head结点处开始,向后遍历整个链表,pos作为遍历的游标(链表结点list_head的指针),作为后续操作的参数,通常需要与list_entry协同使用,获得遍历链表上所有的结构体地址,典型的用法如下:

	list_for_each (tmp, &cam_list) {
		cpia = list_entry(tmp, struct cam_data, cam_data_list);
                 ......
        }

4

#define list_for_each_prev(pos, head) \
	for (pos = (head)->prev; prefetch(pos->prev), pos != (head); \
        	pos = pos->prev)

head结点处开始,向遍历整个链表

5

#define list_for_each_safe(pos, n, head) \
	for (pos = (head)->next, n = pos->next; pos != (head); \
		pos = n, n = pos->next)

list_for_each的安全版本,多了一个临时变量n,用来存储链表结点的下一个结点,可以防止另一个cpu同时操作链表造成的断链问题。通常配合删除链表中的结点时使用,比如:

	list_for_each_safe (list, next, &bus_info_head ) {
		bus_info = list_entry (list, struct bus_info, bus_info_list);
		kfree (bus_info);
	}

6

#define list_for_each_prev_safe(pos, n, head) \
	for (pos = (head)->prev, n = pos->prev; \
	     prefetch(pos->prev), pos != (head); \
	     pos = n, n = pos->prev)

list_for_each_prev的安全版本

7

#define list_for_each_entry(pos, head, member)				\
	for (pos = list_entry((head)->next, typeof(*pos), member);	\
	     prefetch(pos->member.next), &pos->member != (head); 	\
	     pos = list_entry(pos->member.next, typeof(*pos), member))

member参数为list_head在数据结构中的名字。功能与list_for_each相似,只是pos游标为结构体的指针而不是list_head的指针

8

#define list_for_each_entry_reverse(pos, head, member)			\
	for (pos = list_entry((head)->prev, typeof(*pos), member);	\
	     prefetch(pos->member.prev), &pos->member != (head); 	\
	     pos = list_entry(pos->member.prev, typeof(*pos), member))
member参数为list_head在数据结构中的名字。功能与list_for_each_prev相似,只是pos游标为结构体的指针而不是list_head的指针

9

#define list_for_each_entry_continue(pos, head, member) 		\
	for (pos = list_entry(pos->member.next, typeof(*pos), member);	\
	     prefetch(pos->member.next), &pos->member != (head);	\
	     pos = list_entry(pos->member.next, typeof(*pos), member))
继续遍历链表,其中pos为结构体的指针。与list_for_each_entry相比,不同的是,这里的pos需要有初值,即从pos结构体所在的list_head指针开始向后遍历链表,直到list_head指针与head相同

10

#define list_for_each_entry_continue_reverse(pos, head, member)		\
	for (pos = list_entry(pos->member.prev, typeof(*pos), member);	\
	     prefetch(pos->member.prev), &pos->member != (head);	\
	     pos = list_entry(pos->member.prev, typeof(*pos), member))

从pos结构体所在的list_head指针开始向遍历链表,直到list_head指针与head相同

11

#define list_for_each_entry_from(pos, head, member) 			\
	for (; prefetch(pos->member.next), &pos->member != (head);	\
	     pos = list_entry(pos->member.next, typeof(*pos), member))
从指针pos对应的结构体开始向后遍历链表,直到链表结点的指针与head相同。它与list_for_each_entry_continue不同之处就在于,进入list_for_each_entry_continue循环,第一次pos的值为pos初值对应的下一个结构体,而该函数第一次循环,pos值就是pos的初值

12

#define list_for_each_entry_safe(pos, n, head, member)			\
	for (pos = list_entry((head)->next, typeof(*pos), member),	\
		n = list_entry(pos->member.next, typeof(*pos), member);	\
	     &pos->member != (head); 					\
	     pos = n, n = list_entry(n->member.next, typeof(*n), member))
list_for_each_entry函数的安全版本

13

#define list_for_each_entry_safe_continue(pos, n, head, member) 		\
	for (pos = list_entry(pos->member.next, typeof(*pos), member), 		\
		n = list_entry(pos->member.next, typeof(*pos), member);		\
	     &pos->member != (head);						\
	     pos = n, n = list_entry(n->member.next, typeof(*n), member))
list_for_each_entry_continue的安全版本

14

#define list_for_each_entry_safe_from(pos, n, head, member) 			\
	for (n = list_entry(pos->member.next, typeof(*pos), member);		\
	     &pos->member != (head);						\
	     pos = n, n = list_entry(n->member.next, typeof(*n), member))
list_for_each_entry_from的安全版本

15

#define list_for_each_entry_safe_reverse(pos, n, head, member)		\
	for (pos = list_entry((head)->prev, typeof(*pos), member),	\
		n = list_entry(pos->member.prev, typeof(*pos), member);	\
	     &pos->member != (head); 					\
	     pos = n, n = list_entry(n->member.prev, typeof(*n), member))
list_for_each_entry_reverse的安全版本






你可能感兴趣的:(linux 内核常用数据结构及算法——list(循环双向链表))