深入分析Linux内核链表

1. 普通单链表

2. 内核链表

上图是本人从其他博客盗来的,差点被糊弄过去。

下图是本人自己用KeyNote画的(唉!!画图真的是让人心好累啊!!)。

差异是不是很明显啊?!

Read The Fucking Source Code

1. 初始化

/* include/linux/types.h */
struct list_head {
    struct list_head *next, *prev;
};

/* include/linux/list.h *//*××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××*/// 一. 如何初始化一个链表,初始化后的链表是什么鸟样?// 链表初始化的3个方法:// 1. #define LIST_HEAD_INIT(name) { &(name), &(name) }// 使用示例: struct list_head test_list = LIST_HEAD_INIT(test_list);

// 2. #define LIST_HEAD(name) \    struct list_head name = LIST_HEAD_INIT(name)// 使用示例: LIST_HEAD(module_bug_list);

// 3. static inline void INIT_LIST_HEAD(struct list_head *list){    list->next = list;    list->prev = list;}// 使用示例: struct list_head test_list;        INIT_LIST_HEAD(&test_list);
/*××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××*/

就连一个链表的初始化都想的这么周到!!真屌!!

初始化后,链表就是的鸟样:

2. 插入

/*
 * Insert a new entry between two known consecutive entries.
 *
 * This is only for internal list manipulation where we know
 * the prev/next entries already!
 */
#ifndef CONFIG_DEBUG_LIST
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;
}
#else
extern void __list_add(struct list_head *new,
                  struct list_head *prev,
                  struct list_head *next);
#endif

/**
 * list_add - add a new entry
 * @new: new entry to be added
 * @head: list head to add it after
 *
 * Insert a new entry after the specified head.
 * This is good for implementing stacks.
 */
static inline void list_add(struct list_head *new, struct list_head *head)
{
    __list_add(new, head, head->next);
}

/**
 * list_add_tail - add a new entry
 * @new: new entry to be added
 * @head: list head to add it before
 *
 * Insert a new entry before the specified head.
 * This is useful for implementing queues.
 */
static inline void list_add_tail(struct list_head *new, struct list_head *head)
{
    __list_add(new, head->prev, head);
}
/** *  list_add 和 list_add_tail的区别是: *  list_add 始终是在链表头后的的第一个位置进行插入:例如链表:head --> 数据1 --> 数据2 --> 数据3,插入新元素后:head --> new --> 数据1 --> 数据2 --> 数据3 *  list_add_tail 始终实在链表末尾插入新元素:例如链表:head --> 数据1 --> 数据2 --> 数据3,插入新元素后:head --> 数据1 --> 数据2 --> 数据3 --> new *//** * 仔细分析上述函数,可以发现其函数抽象的巧妙。 * __list_add 接收三个参数:分别是new, prev, next。任何位置的双链表插入操作,只需这3个参数。那么new元素一定是在prev和next之间进行插入。 * 所以很明显:list_add是在head和head->next之间插入,那就是链表的第一个元素。 *           list_add_tail实在head->prev和head之间插入,那就是链表的最后一个元素。*/

3. 删除

/*
 * Delete a list entry by making the prev/next entries
 * point to each other.
 *
 * This is only for internal list manipulation where we know
 * the prev/next entries already!
 */
static inline void __list_del(struct list_head * prev, struct list_head * next)
{
    next->prev = prev;
    prev->next = next;
}

/**
 * list_del - deletes entry from list.
 * @entry: the element to delete from the list.
 * Note: list_empty() on entry does not return true after this, the entry is
 * in an undefined state.
 */
#ifndef CONFIG_DEBUG_LIST
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;
}
#else
extern void __list_del_entry(struct list_head *entry);
extern void list_del(struct list_head *entry);
#endif

/*** 上述代码中存在两个宏,在include/linux/poison.h中的定义如下:*//* * These are non-NULL pointers that will result in page faults * under normal circumstances, used to verify that nobody uses * non-initialized list entries. * 是非空指针,在正常情况下会导致 page faults,用来验证没有人使用未初始化的链表项。 */#define LIST_POISON1  ((void *) 0x00100100 + POISON_POINTER_DELTA)#define LIST_POISON2  ((void *) 0x00200200 + POISON_POINTER_DELTA)

/* * __list_del_entry 和 list_del 的却别是显而易见的。*/

  

  至此,内核链表有了本质的认识,那么对于其他的链表操作的分析是非常容易的。

时间: 2024-12-19 07:45:35

深入分析Linux内核链表的相关文章

Linux 内核链表

一 . Linux内核链表 1 . 内核链表函数 1.INIT_LIST_HEAD:创建链表 2.list_add:在链表头插入节点 3.list_add_tail:在链表尾插入节点 4.list_del:删除节点 5.list_entry:取出节点 6.list_for_each:遍历链表 2.程序代码

例说Linux内核链表(二)

链表使用 我认为熟悉内核链表功能最好的方法就是看一些简单的实例,实例是一个非常好的素材去更好的理解链表. 下面是一个例子,包含创建,添加,删除和遍历链表. <span style="font-size:14px;"><span style="color:#330099;">#include <stdio.h> #include <stdlib.h> #include "list.h" struct

Linux 内核 链表 的简单模拟(2)

接上一篇Linux 内核 链表 的简单模拟(1) 第五章:Linux内核链表的遍历 /** * list_for_each - iterate over a list * @pos: the &struct list_head to use as a loop cursor. * @head: the head for your list. */ #define list_for_each(pos, head) for (pos = (head)->next; pos != (head);

例说Linux内核链表(一)

介绍 众所周知,Linux内核大部分是使用GNU C语言写的.C不同于其他的语言,它不具备一个好的数据结构对象或者标准对象库的支持.所以可以借用Linux内核源码树的循环双链表是一件很值得让人高兴的事. 在include/linux/list.h文件中用C实现了一个好用的循环链表.它是有效而且易于操作的,否则它也不会被内核使用(译者注:在kernel中大量的使用了循环双链表结构,比如在在进程描述符实体中我们就可以看到很多struct list_head的身影).不管何时,依靠这种结构,在内核中都

例说Linux内核链表(三)

经常使用的linux内核双向链表API介绍 linux link list结构图例如以下: 内核双向链表的在linux内核中的位置:/include/linux/list.h 使用双向链表的过程,主要过程包括创建包括struct link_head结构的结构体(item),建立链表头.向链表中加入item(自己定义数据结构.双向链表数据单元).删除链表节点.遍历链表,判空等. 1.建立自己定义链表数据结构 struct kool_list{ int to; struct list_head li

linux内核链表的使用

linux内核链表:链表通常包括两个域:数据域和指针域.struct list_head{struct list_head *next,*prev;};include/linux/list.h中实现了一套精彩的链表数据结构.传统的链表指针指向下一个节点的头部.linux链表指针指向下一个指针list_head结构(*next),双向循环.不会随着外部数据的变化而变化,使它具有通用性.? -------------------------------------------------------

linux内核链表的移植与使用

一.  Linux内核链表为双向循环链表,和数据结构中所学链表类似,具体不再细讲.由于在内核中所实现的函数十分经典,所以移植出来方便后期应用程序中的使用. /*********************************** 文件名:kernel link list of linux.h 作者:Bumble Bee 日期:2015-1-31 功能:移植linux内核链表 ************************************/ /*链表结点数据结构*/ struct lis

Linux 内核链表使用举例

链表数据结构的定义很简洁: struct list_head { struct list_head *next, *prev; }; list_head结构包含两个指向list_head结构的指针prev和next,该内核链表具备双链表功能,通常它都组织成双循环链表,这里的list_head没有数据域.在Linux内核链表中,不是在链表结构中包含数据,而是在数据结构中包含链表节点.下面是一个简单的内核模块的例子,包含了对链表进行插入.删除.遍历的一些函数: list.c: #include <l

链表的艺术——Linux内核链表分析

引言: 链表是数据结构中的重要成员之中的一个.因为其结构简单且动态插入.删除节点用时少的长处,链表在开发中的应用场景许多.仅次于数组(越简单应用越广). 可是.正如其长处一样,链表的缺点也是显而易见的.这里当然不是指随机存取那些东西,而是因为链表的构造方法(在一个结构体中套入其同类型指针)使得链表本身的逻辑操作(如添加结点,删除结点,查询结点等),往往与其应用场景中的业务数据相互混杂.这导致我们每次使用链表都要进行手工打造,做过链表的人肯定对此深有了解. 是否能将链表从变换莫測的业务数据中抽象出