我对linux内核链表实现中的部分函数的理解——第一节

来源:互联网 发布:js数组遍历下标 编辑:程序博客网 时间:2024/05/17 22:15

linux内核链表是一个双向循环链表,其实现与具体硬件平台无关,理解了linux内核链表的实现机制,我们能够把其移植到引用层程序设计当中。

        

linux内核链表相关的一些函数声明在include/linux/list.h中。

首先是链表数据结构的定义

struct list_head {
          struct list_head *next, *prev;
 };

这个不需要做过多的解释,就是这么定义的,根据内核源代码的说法是,使用这种next/prev entries的方式比使用一般的 single-entry routines所产生的代码要好。

 

接着是链表的创建和初始化

从内存中开辟一个头结点然后调用初始化函数就能完成链表的创建

在内核中,链表的初始化函数如下

static inline void INIT_LIST_HEAD(struct list_head *list)
{
 list->next = list;
 list->prev = list;
}

这是一个内联函数,函数参数为 list_head类型的头结点。

通俗点讲内核链表的初始化过程就是把前驱指针和后继指针都指向了自己。

然后是链表添加结点函数,表头添加和表尾添加结点函数如下

static inline void list_add(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);
}

可以看到,其实现倒是调用__list_add函数,那么__list_add函数函数又是如何实现的呢?

从内核中我们可以看到

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

这个函数搞清楚了,添加结点也就没有什么问题了。这个函数的第一个参数是list_head类型的新的结点,第二个参数是它前面的那个list_head类型的结点,第三个参数是它后面的一个list_head类型的结点,这么一说也许就清晰了

实际上这个函数可以理解为图上的画线的过程,它总共画了四条带箭头的线。

          

      

0 0