zoukankan      html  css  js  c++  java
  • 深入分析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 的却别是显而易见的。
    */

       

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

  • 相关阅读:
    自学Linux命令的四种方法
    POJ 1170 Shopping Offers -- 动态规划(虐心的六重循环啊!!!)
    九度OJ 1447 最短路 1008 最短路径问题
    九度OJ 1024 畅通工程 -- 并查集、贪心算法(最小生成树)
    PHPActiveRecord 学习三
    PHPUnit 组织测试
    PHPActiveRecord validates
    PHPActiveRecord 学习二
    PHPActiveRecord 学习一
    PHP ActiveRecord demo栗子中 关于类名 的问题
  • 原文地址:https://www.cnblogs.com/ronnydm/p/5547972.html
Copyright © 2011-2022 走看看