前言:一起分析内核最重要的链表list_head
一、链表结构
struct list_head {
struct list_head *next, *prev;
};
二、链表初始化函数
list_head 链表的初始化只是把 *next, *prev连个指针指向链表头,形成双向循环链表;
#define LIST_HEAD_INIT(name) { &(name), &(name) }
#define LIST_HEAD(name) \
struct list_head name = LIST_HEAD_INIT(name)
static inline void INIT_LIST_HEAD(struct list_head *list)
{
WRITE_ONCE(list->next, list);
list->prev = list;
}
上面是各种不同的初始化或者定义并初始化链表的函数,我们都可以使用,
例如:
1)我们自己定义一个链表头,然后调用函数初始化:
struct list_head name;
LIST_HEAD_INIT(name);
//INIT_LIST_HEAD(name);
2)或者使用下面宏定义并初始化一个双向循环链表头;
LIST_HEAD(name)
三、增、删、遍历接口
我们都知道链表是用来保存一下有意义的字段的,但是list_haed结构中并没有其他字段,所以内核使用该链表时,总是把它嵌套到一个宿主结构中来使用。例如:
struct zj_list{
int val ;
struct list_head mylist;
};
3.1 增加节点
内核中提供了添加一个节点的接口,如下:
static inline void list_add(struct list_head *new, struct list_head *head);//首插入
static inline void list_add_tail(struct list_head *new, struct list_head *head);//尾插入
3.2 删除节点
static inline void list_del(struct list_head *entry)
3.3 遍历链表
内核是同过下面这个宏定义来完成对list_head链表进行遍历的,如下 :
#define list_for_each(pos, head) for (pos = (head)->next; pos != (head); pos = pos->next`) //从前往后
#define list_for_each_prev(pos, head) for (pos = (head)->prev; pos != (head); pos = pos->prev) //从后往前
3.4 定位宿主
上面的所有操作都是基于list_head这个链表进行的,涉及的结构体也都是该结构体,但是我们知道,这个结构体是嵌入到别的宿主中使用的,所以我们应该定位到该结构体的宿主位置,内核中有定义宏去直接得到宿主的地址,如下:
作用:已知某结构体的成员member和指向该成员的指针ptr(也就是member的地址),算出该结构体的起始地址。
#define container_of(ptr,type,member)
{const typeof(((type*)0)->member)* _myptr=(ptr);
(type*)((char*)_myptr-offsetof(type,member));})
#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE*)0)->MEMBER)
我们分析上面这个宏,发现有好些都不认识,这里一个一个分析:
( (TYPE *)0 ) 将零转型为TYPE类型指针;
((TYPE *)0)->MEMBER 访问结构中的数据成员;
&( ( (TYPE )0 )->MEMBER )取出数据成员的地址;,因为是从0开始的,所以就相当于该成员在结构体中的偏移量。
(size_t)(&(((TYPE)0)->MEMBER))结果转换类型;
typeof为C语言的关键字,用来由变量得到变量的类型,eg;typeof(a)得到变量a的类型。
经过上面分析可以看出来,其实现就是通过mem成员的地址减去mem的偏移量,来得到首地址,即宿主的地址。
3.5 宿主结构的遍历
宿主结构的遍历,它们的实现都是利用list_entry宏。
#define list_entry((ptr)->next, type, member) container_of(ptr,type,member)
#define list_for_each_entry(pos, head, member) \
for (pos = list_entry((head)->next, typeof(*pos), member); \
&pos->member != (head); \
pos = list_entry(pos->member.next, typeof(*pos), member))