list.h 解析

来源:互联网 发布:sam软件和au 编辑:程序博客网 时间:2024/06/06 02:35

                                           内核数据结构list.h 解析

首先这个数据结构不同于我们我们设计的链表结构。

其实链表这种结构的各种操作就是改变链表的指针域而已,所以可以发现内核的链表结构在设计的时候其实只有指针域。

我的内核版本: 4.0.8-200.fc21.x86_6  此篇博客所有的源码都来自这个版本的内核。

节点的定义在./include/types.h 中

 

struct list_head {    struct list_head *next,*prev;};
 其实就是:

struct list_head{    struct list_head *next;    struct list_head *prev;};
可以看到链表的核心其实就是指针域的改变。

下面是两个头结点的初始化宏。

#define LIST_HEAD_INIT(name) { &(name),&(name) }#define LIST_HEAD(name)\        struct list_head name = LIST_HEAD_INIT(name)
这两句是源代码的头两个宏定义,作用是初始化一个链表节点的链接
例如申请一个变量head作为头结点
    LIST_HEAD(head) 等价于struct list_head head = {&(head),&(head)};
    就是对头节点的赋值了


同样有一个函数可以初始化

static inline void INIT_LIST_HEAD(struct list_head *list){    list->next = list;    list->prev = list;}
在已知的两个节点中插入一个节点,此处是已经知道这两个节点的情况:
static inline void __list_add(strcut list_head *new,strcut list_head *prev,                              strcut list_head *next){    next->prev = new;    new->next  = next;    new->prev  = prev;    prev->next = new;}
有了这个添加一个节点的函数,我们基本可以添加元素到任意位置了
例如添加一个节点进头结点之后
static inline void list_add_tail(struct list_head *new,                                struct list_head *head){    __list_add(new,head,head->next);}
添加一个节点到头指针之前

static inline void list_add_tail(struct list_head *new,                                struct list_head *head){    __list_add(new,head->prev,head);}
如果删除一个节点,其实本质上是两个节点之间的操作

static inline void list_del(struct list_head *prev,struct list_head *next){    next->prev = prev;    prev->next = next;}
如果需要删除一个具体存在的节点

static inline void __list_del_entry(struct list_head *entry){    __list_del(entry->prev,entry->next);}
删除一个节点并且给相应的节点处理

static inline void list_del(struct list_head *entry){    __list_del(entry->prev,entry->next);    entry->next = LIST_POISON1;    entry->prev = LIST_POISON2;}
使用一个新的节点替换一个旧的节点

static inline void list_replace(struct list_head *old,                               struct list_head *new){    new->next = old->next;    new->next->prev = new;    new->prev = old->prev;    new->prev->next = new;}

使用一个新的节点替换一个旧的节点并且将旧的节点置空

static inline void list_replace_init(struct list_head *old,                                    struct list_head *new){    list_replace(old,new);    INIT_LIST_HEAD(old);}

删除一个结点从链表中,并且重新初始化

static inline void list_del_init(struct list_head *entry){    __list_del_entry(entry);    INIT_LIST_HEAD(entry);}


删除一个节点并且在这个位置上增加一个其它的节点

static inline void list_move(struct list_head *list,                            struct list_head *head){    __list_del_entry(list);    list_add(list,head);}
//删除一个节点的前一个节点,并且插入一个新节点

static inline void list_move_tail(struct list_head *list                                 struct list_head *head){    __list_del_entry(list);    list_add_tail(list,head);}
/测试一个节点是不是其头节点

static inline int list_is_last(const struct list_head *list,                               const struct list_head *head){    return list->next == head;}

测试一个链表是不是空的

static inline int list_empty(const struct list_head *head){    return head->next == head;}

测试一个链表是否非空

static inline int list_empty_careful(const struct list_head *head){    struct list_head *next = head->next;    return (next == head) && (next == head->next);}

反转一个节点

static inline void list_roate_left(struct list_head *head){    struct list_head *first;    if(!list_empty(head)){        first = head->next;        list_move_tail(first,head);    }}

测试一个链表是不是仅仅只有一个节点

static inline int list_is_singular(const struct list_head *head){    return !list_empty(head) && (head->next == head->prev);}

链表分割函数一共有三个参数,list :新的链表头结点;head:裁剪剩下的链表
entry:包含在链表head内并且是开始裁剪的结尾

static inline void __list_cut_position(struct list_head *list,                struct list_head *head,struct list_head *entry){    struct list_head *new_first = entry->next;    list->next = head->next;    list->next->prev = list;    list->prev = entry;    entry->next = list;    head->next = new_first;    new_first->prev = head;}

一个分割链表的实际操作

static inline void list_cut_position(struct list_head *list,                    struct list_head *head,struct list_head *entry){    if(list_empty(head))        return;    if(list_is_singular(head) && (head->next != entry && head != entry))        return ;    if(entry == head)        INIT_LIST_HEAD(list);    else        __list_cut_position(list,head,entry);}
合并操作,这里主要看下核心步骤,就是将list领头的这个链表插入到
prev 和 next 之间不包含list 节点

static inline void __list_splice(const struct listg_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);    }}
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

链表的宏遍历再说这个之前,需要看几个必须的宏,不然,难以理解,

这是通过一个已经知道的指针地址,得到这个结构体的首地址,这样做封装性更好,适用范围更广。

#define list_entry(ptr, type, member)                  \container_of(ptr, type , member)
这个宏的详细代码再下边

#define  container_of(ptr, type, member) ({             \const typeof(((type *)0)->member ) * __mptr  = (ptr);    \(type *)((char *)__mptr  - offsetof(type, member)) ; })

offsetof 的代码还在下边

#define offsetof(type, member)     ((unsigned int )&((type *)0)->member)
一般人看到这样的C代码肯定是一头雾水难以理解这是为什么,甚至根本看不明白是什么意思,毕竟是内核代码,看不懂也是正常的。首先第一个宏有三个参数  list_head *   指针,最终它会是这个链表节点的首地址,就可以通过访问它的其它成员变量了。  ptr 传入时的类型,也就是list_head * 这个结构体中    list_head  的变量名<其次是一个运算符 typeof 这是 C 语言的扩展。可以得到一个结构体的类型。((type *)0)->member ) * __mptr  = (ptr); 
这一句,就是声明一个type 的member 类型的指针 __mptr  并且赋值ptr.

#define offsetof(type, member)     ((unsigned int )&((type *)0)->member)

这个宏可以得到member 相对于结构体首地址的相对地址。

(type *)((char *)__mptr  - offsetof(type, member)) ; })
这一句,就可以得到这个结构体的首地址了,就是地址相减,用member的地址减去它相对于首地址的偏移量就是这个结构体的首地址。


@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

这里ptr是一个链表的头结点,这个宏就是取得这个链表第一个元素的所指结构体的首地址

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

判断一个链表是否为空,且取首地址。

#define list_first_entry_or_null(ptr,type,member) \        (!list_empty(ptr) ? list_first_entry(ptr,type,member):null)

也可以根据变量的next与prev来确定结构体的地址

#define list_prev_entry(pos,member) \        list_entry((pos)->member.prev,typeof(*(pos)),member)#define list_next_entry(pos,member) \        list_entry((pos)->member.prev,typeof(*(pos)),member)

链表的遍历
#define list_for_each(pos,head)\    for(pos = (head)->next; pos != (head);pos = pos->next)

遍历一遍链表,使用entry方法

#define list_for_each_entry(pos,head,member) \        for(pos = list_first_entry(head,typeof(*pos),member)\           &pos->member != (head) \           pos = list_next_entry(pos,member))

pos 表示结构体变量,head 是头结点,member 是list_head 在结构体当中的名字,这个函数就是如果Pos 为非空,那么pos就是其本身,否则在链表头强制扩充一个虚指针,为了list_for_each_entry_continue()做准备

#define list_prepare_entry(pos,head,member)  \        ((pos) ? :list_entry(head,typeof(*pos),member))

可以指定链表的任意一个节点开始遍历

#define list_for_each_entry_continue(pos,head,member) \        for(pos = list_next_entry(pos,member);           \            &pos->member != (head);                   \            pos = list_next_entry(pos,member))
同上从前边遍历

#define list_for_each_continue_reverse(pos,head,member)   \        for(pos = list_prev_entry(pos,member);\           &pos->member != (head);              \           pos = list_prev_entry(pos,member))#define list_safe_reset_next(pos,n,member)       \        n = list_next_entry(pos,member)


内核哈希链表:

这个链表和我们平时常见的链表有很大的不同,哈希表的结构设计和普通的链表有很大的区别

首先哈希表的头结点和其它节点有很大的不同。

struct hlist_head{    struct hlist_node *first;};struct hlist_node{      struct hlist_node *next,**prev;};

这个链表首先使用的是hlist_head 节点做头结点,然后使用hlist_node 做其它节点,最后一个节点指向NULL
其中**prev 指向的是前一个节点的next.就是指向自己。


如果画成图就是这个样子的。

初始化以及判断是否为空#define HLIST_HEAD_INIT{ .first = NULL }#define HLIST_HEAD(name) struct hlist_head name = { .first = NULL }#define INIT_HLIST_HEAD(ptr)  ((ptr)->first = NULL)static inline void INIT_LIST_NODE(struct hlist_node *h){    h->next = NULL;    h->pprev = NULL;}static inline int hlist_unhashed(const struct hlist_node *n){    return !h->pprev;}static inline int hlist_empty(const struct hlist_head *h){    return !h->first;}


删除一个结点,看起来代码不多但是挺复杂的static inline void __hlist_del(struct hlist_node *n){    struct hlist_node *next = n->next;  //首先删除N节点,申请一个next 指向n的下一个节点;    struct hlist_node **prev = n->pprev;//申请一个二重指针开始指向n,    *pprev = next;                      //n前面的next指向了n后面的元素    if(next)                            //如果next非空,后一个元素赋值pprev        next->pprev = pprev;}

添加节点一共有三个函数第一个向链表头结点后边增加节点static inline void hlist_add_head(struct hlist_node *n,struct hlist_head *h){    struct hlist_node *first = h->first;    n->next = first;    if(first)        first->pprev = &n->next;   //注意符号优先级,二级指针    h->first = n;    n->pprev = &h->first;}//next must be != NULL,在next前边添加一个节点nstatic inline void hlist_add_before(struct hlist_node *n,struct hlist_node *next){    n->pprev = next->pprev;    n->next  = next;    next->pprev = &n->next;    *(n->pprev) = n;}//next must be != NULL ,在next后边添加一个节点nstatic inline void hlist_add_behind(struct hlist_node *n,struct hlist_node *prev){    n->next = prev->next;    prev->next = n;    n->pprev = &prev->next;    if(n->next)        n->next->pprev = &n->next;}


下面是hlist的宏遍历#define hlist_entry(ptr,type,member) \        container_of(ptr,type,member)#define hlist_for_each(pos,head)     \        for(pos = (head)->first;pos;pos= pos->next)//这是一个hlist的宏的安全遍历,其中添加了变量n,防止在遍历过程中//发生断链的情况#define hlist_for_each_safe(pos,n.head) \        for(pos = (head)->first;pos && ({n = pos->next;1;});\           pos = n) \

可能有人对pos && ({n = pos->next;1;})

这一句也不理解,这个for循环还是在判断pos这个东西是不是为空值于后边的部分,其实就是一个赋值操作,但是它必须返回1,

所以就写成<pre name="code" class="cpp" style="font-size:18px;"> ({n = pos->next;1;})

这个样子了,这个部分始终返回1.

#define hlist_entry_safe(ptr,type,member) \        ({typeof(ptr)___ptr = (ptr); \          ___ptr?hlist_entry(___ptr,type,member):NULL; \         })


遍历整个链表#define hlist_for_each_entry(pos,head,member) \        for(pos = hlist_entry_safe((head)->first),typeof(*(pos)),member); \        pos;\        pos = hlist_entry_safe((pos)->member.next,typeof(*(pos)),member)#define hlist_for_each_entry_continue(pos, member)pos\            for (pos = hlist_entry_safe((pos)->member.next, typeof(*(pos)), member);\                         pos;for\                         pos = hlist_entry_safe((pos)->member.next, typeof(*(pos)), member))#define hlist_for_each_entry_from(pos, member)hlist_for_each_entry_from\            for (; pos;typeof\                         pos = hlist_entry_safe((pos)->member.next, typeof(*(pos)), member))#define hlist_for_each_entry_safe(pos, n, head, member)         \            for (pos = hlist_entry_safe((head)->first, typeof(*pos), member);\                         pos && ({ n = pos->member.next; 1;  });pos\                         pos = hlist_entry_safe(n, typeof(*pos), member))


0 0