之前说过Linux内核中建立了一套内核链表体系,包括在内核中链表的定义和使用方法。由于内核中定义的对链表的操作方法太多了,限于时间和能力的问题,我将记录在学习过程
中所用到的操作方法。
内核中源文件位置:include\linux\list.h
1、list_entry宏
(1)原型: #define list_entry(ptr, type, member) container_of(ptr, type, member)
(2)作用:从上面可以看出来,list_entry宏其实就是container_of宏,这个宏之前说过,是内核中一个很重要的宏。可以通过结构体中的某一个变量的指针来获取
整个结构体变量的指针;ptr就是这个结构体中某个变量的指针,type就是这个结构体的类型,member就是ptr指针对应的变量的变量名。
(3)使用例子:
1 struct A{ 2 int a; 3 int b; 4 int c; 5 }; 6 struct A a = {0}; 7 struct A *ptr = list_entry(&a.a, struct A, a); // 或者是 container_of(&a.a, struct A, a)
2、list_for_each_entry宏
(1)原型:
#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))
(2)作用:这个宏就是内核中提供的遍历链表的宏,内核链表并不是单独使用,而是被其他的结构体包含,所有的同一类型的结构体变量通过内置的内核链表连接起来。
我们可以通过list_for_each_entry宏来遍历所有的连接在一起的结构体变量。 pos就是内置了内核链表的结构体变量的指针,head就是结构体内内置的内核链表
的链表头指针,member就是结构体内内置的内核链表的变量名。内部是通过for循环来实现的,
list_entry((head)->next, typeof(*pos), member) 其实就是获取内核链表头对应的结构体变量的指针,就是for循环的初始条件
prefetch(pos->member.next), &pos->member != (head) 就是for循环需要满足的条件
list_entry(pos->member.next, typeof(*pos), member) 返回下一个内核链表对应的结构体变量指针,就是for循环变量的跟新
(3)使用例子:
1 struct list { 2 2 int a; 3 3 struct list_head head; 4 4 }; 5 5 6 6 struct list *pList = NULL; 7 7 struct list list1 = {0}; 8 8 struct list list2 = {0}; 9 9 struct list list3 = {0}; 10 10 11 11 INIT_LIST_HEAD(&list1.head); // 初始化内置的内核链表,使得前向和后向指针都指向本身 12 12 INIT_LIST_HEAD(&list2.head); 13 13 INIT_LIST_HEAD(&list3.head); 14 14 15 15 list_add_tail(&list2.head, &list1.head); // 将list1变量中的内核链表作为链表头,将其他两个添加到list1.head后面 16 16 list_add_tail(&list3.head, &list1.head); 17 17 18 18 list_for_each_entry(pList, &list1.head, head) // 遍历 19 19 { 20 20 .................... // 操作 21 21 }
未完待续.........................................