• 链表的操作


    Linux内核链表的操作定义在kernel/include/linux/list.h中,我们将逐一分析此文件中关于链表操作的接口。

    1,struct list_head的定义在kernel/include/linux/types.h中:

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

    struct list_head类型的结构体包含了两个指向struct list_head结构类型的成员指针next和prev,因此我们可以看出struct list_head类型的变量可以进行双向链表的操作。

    2,静态初始化链表头节点:

    /*
     * Simple doubly linked list implementation.
     *
     * Some of the internal functions ("__xxx") are useful when
     * manipulating whole lists rather than single entries, as
     * sometimes we already know the next/prev entries and we can
     * generate better code by using them directly rather than
     * using the generic single-entry routines.
     */
    
    #define LIST_HEAD_INIT(name) { &(name), &(name) }
    
    #define LIST_HEAD(name) 
            struct list_head name = LIST_HEAD_INIT(name)

    LIST_HEAD宏根据传进来的参数定义了一个的struct list_head类型的变量name,并根据LIST_HEAD_INIT宏将name的成员变量next、prev分别赋值指向自身所在结构体变量的首地址&name。

    3,INIT_LIST_HEAD用于将list的成员next、prev分别指向其所在的结构体变量本身list。这个宏在后面会经常用到,主要用于初始化从链表中被删除的节点。

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

    4,__list_add用于将一个new节点插入到prev之后,next之前,此函数只用于已知prev/next的内部链表操作:

    /*
     * 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

    5,list_add用于将一个new节点添加到链表头head之后和第一个节点head->next之前:

    /**
     * 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);
    }

    6,list_add_tail用于将一个new节点添加到最后一个节点head->prev之后和头节点head之前:

    /**
     * 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);
    }

    7,__list_del用于删除一个链表节点项,其表现方式是将要删除节点前后节点的指针互相连上:

    /*
     * 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;
    }

    8,list_del用于删除一个链表的节点项entry,通过其调用__list_del函数我们可以看出,传到__list_del的参数为entry的上一个节点和下一个节点的指针,这样也就实现了在__list_del中entry的prev和next互相操作,而越过了entry这个节点。而后面的操作entry->next = LIST_POISON1;   entry->prev = LIST_POISON2; LIST_POISON1和LIST_POISON2用于确保没人能够使用未初始化的列表项,在正常情况下使用这两个非空指针时将会导致Page Fault页故障。

    /**
     * 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

     9,list_del_init同样是删除一个节点,并将这个被删除节点的prev、next指针指向entry变量本身。

    /**
     * list_del_init - deletes entry from list and reinitialize it.
     * @entry: the element to delete from the list.
     */
    static inline void list_del_init(struct list_head *entry)
    {
            __list_del_entry(entry);
            INIT_LIST_HEAD(entry);
    }

    10,list_replace用于将old节点替换成new,list_replace_init多加了一个将old节点的prev、next指向old本身的操作。

    /**
     * list_replace - replace old entry by new one
     * @old : the element to be replaced
     * @new : the new element to insert
     *
     * If @old was empty, it will be overwritten.
     */
    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);
    }

    11,list_move用于将一个节点项list删除,然后将节点项list添加到另一个链表头head的后面。

    /**
     * list_move - delete from one list and add as another's head
     * @list: the entry to move
     * @head: the head that will precede our entry
     */
    static inline void list_move(struct list_head *list, struct list_head *head)
    {
            __list_del_entry(list);
            list_add(list, head);
    }

     12,list_move_tail用于将一个节点项list删除,然后将节点项list添加到另一个链表头head的前面。

    /**
     * list_move_tail - delete from one list and add as another's tail
     * @list: the entry to move
     * @head: the head that will follow our entry
     */
    static inline void list_move_tail(struct list_head *list,
                                      struct list_head *head)
    {
            __list_del_entry(list);
            list_add_tail(list, head);
    }

     13,list_is_last用于测试节点list是否是链表head中的最后一项。

    /**
     * list_is_last - tests whether @list is the last entry in list @head
     * @list: the entry to test
     * @head: the head of the list
     */
    static inline int list_is_last(const struct list_head *list,
                                    const struct list_head *head)
    {
            return list->next == head;
    }

     14,list_empty用于判断一个链表是否为空,也就是说链表头节点的next是否指向了头head本身,是则代表链表中除了head没有其他项。

    /**
     * list_empty - tests whether a list is empty
     * @head: the list to test.
     */
    static inline int list_empty(const struct list_head *head)
    {
            return head->next == head;
    }
    

     15,list_empty_careful用于判断一个链表是否为空,同时检测链表的prev、next成员没有被其他CPU修改。注意:只有其他CPU在使用list_del_init()来操纵同一个链表时list_empty_careful才能保证安全,否则多核CPU对链表的操作仍需使用锁机制。

    /**
     * list_empty_careful - tests whether a list is empty and not being modified
     * @head: the list to test
     *
     * Description:
     * tests whether a list is empty _and_ checks that no other CPU might be
     * in the process of modifying either member (next or prev)
     *
     * NOTE: using list_empty_careful() without synchronization
     * can only be safe if the only activity that can happen
     * to the list entry is list_del_init(). Eg. it cannot be used
     * if another CPU could re-list_add() it.
     */
    static inline int list_empty_careful(const struct list_head *head)
    {
            struct list_head *next = head->next;
            return (next == head) && (next == head->prev);
    }

    16,list_rotate_left用于将链表的第一个节点移到头结点的左边,即最后一个节点。

    /**
     * list_rotate_left - rotate the list to the left
     * @head: the head of the list
     */
    static inline void list_rotate_left(struct list_head *head)
    {
        struct list_head *first;
    
        if (!list_empty(head)) {
            first = head->next;
            list_move_tail(first, head);
        }
    }

    17,list_is_singular用于测试链表是否只含有一个节点。

    /**
     * list_is_singular - tests whether a list has just one entry.
     * @head: the list to test.
     */
    static inline int list_is_singular(const struct list_head *head)
    {
        return !list_empty(head) && (head->next == head->prev);
    }
    

    18,__list_cur_position用于将一个链表一分为二:

    @head表示将要被cut链表的链表头,我称之为原始链表;

    @list指向原始链表的第一个节点,并以第@entry个节点为尾节点,组成一个以@list为头@entry为尾的新链表。

    @head指向原始链表中@entry后面的一个节点,这个节点作为@head新链表中的第一个节点,同时@head的prev节点不变,仍为原始链表中的尾节点(假使原始链表是循环链表的话)。

    从而就构成了两个以@entry为分界点,@list指向前半部,@head指向后半部的2个新链表。

    原始链表

    @head<--->N1<--->N2<--->N3<--->N4<--->N5<--->N6<--->N7<--->N8<--->N9<----------

        ^                                        |      

        |_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _|  

    假使@entry为第N5个节点,

    @list新链表

    @list<--->N1<--->N2<--->N3<--->N4<--->N5<----------

        ^                          |      

        |_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ __ _ _ _ _|  

    @head新链表:

    @head<--->N6<--->N7<--->N8<--->N9<----------

        ^                    |      

        |_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _|  

    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;
    }
    
    /**
     * list_cut_position - cut a list into two
     * @list: a new list to add all removed entries
     * @head: a list with entries
     * @entry: an entry within head, could be the head itself
     *    and if so we won't cut the list
     *
     * This helper moves the initial part of @head, up to and
     * including @entry, from @head to @list. You should
     * pass on @entry an element you know is on @head. @list
     * should be an empty list or a list you do not care about
     * losing its data.
     *
     */
    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);
    }

     19,__list_splice用于拼接两个链表:

    @list为要插入链表的链表头;

    @prev为被插入链表的一个节点;

    @next为被插入链表的一个节点;

    整体就是将@list链表拼接到被插入链表的prev和next之间。

    被插入链表

    @head<--->H1<--->H2<--->H3<--->H4<--->H5<----------

        ^                             |      

        |_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _   _ _ _ _|  

     要插入链表

    @list<--->L1<--->L2<--->L3<----------

        ^                    |      

        |_ _ _ _ _ _ _ _ _ _ _ _ _   _ _ _|

    假设prev为H1,next为H2,则拼接后的链表为:

            @list 

                

                 

    @head<--->H1<--->L1<--->L2<--->L3<--->H2<--->H3<--->H4<--->H5<----------

        ^                                  |      

        |_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _  _ _ _ _ _|

    @list仍然指向L1,这里没法斜着画 >,我就不画了。

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

     20,list_splice用于将@list链表插入到head和head的下一个节点head->next之间。

    /**
     * list_splice - join two lists, this is designed for stacks
     * @list: the new list to add.
     * @head: the place to add it in the first list.
     */
    static inline void list_splice(const struct list_head *list,
                    struct list_head *head)
    {
        if (!list_empty(list))
            __list_splice(list, head, head->next);
    }

     21,list_splice_tail用于将@list插入到head的前一个节点head->prev和head之间。

    /**
     * list_splice_tail - join two lists, each list being a queue
     * @list: the new list to add.
     * @head: the place to add it in the first list.
     */
    static inline void list_splice_tail(struct list_head *list,
                    struct list_head *head)
    {
        if (!list_empty(list))
            __list_splice(list, head->prev, head);
    }

     22,list_splice用于将@list链表插入到head和head的下一个节点head->next之间,由于@list拼接到@head中后,@list的头节点将会从拼接好的链表中掉出,所以调用INIT_LIST_HEAD将@list的头list的成员变量prev、next指向其自身。

    /**
     * list_splice_init - join two lists and reinitialise the emptied list.
     * @list: the new list to add.
     * @head: the place to add it in the first list.
     *
     * The list at @list is reinitialised
     */
    static inline void list_splice_init(struct list_head *list,
                        struct list_head *head)
    {
        if (!list_empty(list)) {
            __list_splice(list, head, head->next);
            INIT_LIST_HEAD(list);
        }
    }

     23,list_splice_tail用于将@list插入到head的前一个节点head->prev和head之间,由于@list拼接到@head中后,@list的头节点将会从拼接好的链表中掉出,所以调用INIT_LIST_HEAD将@list的头list的成员变量prev、next指向其自身。

    /**
     * list_splice_tail_init - join two lists and reinitialise the emptied list
     * @list: the new list to add.
     * @head: the place to add it in the first list.
     *
     * Each of the lists is a queue.
     * The list at @list is reinitialised
     */
    static inline void list_splice_tail_init(struct list_head *list,
                         struct list_head *head)
    {
        if (!list_empty(list)) {
            __list_splice(list, head->prev, head);
            INIT_LIST_HEAD(list);
        }
    }

     

    链表头数据结构

  • 相关阅读:
    gateway 实现接口日志保存
    Spring Boot应用的Controller返回的集合类数据是XML格式的可能原因
    json 转list
    观察者模式
    Quartz定时任务整理
    java通过word模板生成word文档
    基于mysql的单据号生成(前缀+日期+自增id+后缀)
    Rabbitmq详解
    java.sql.SQLException: connection holder is null 问题处理
    为什么要用消息队列或消息队列的优缺点
  • 原文地址:https://www.cnblogs.com/watson/p/3592178.html
Copyright © 2020-2023  润新知