之前说过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 }    

 

 

 

 

 

未完待续.........................................