zoukankan      html  css  js  c++  java
  • linux list

    一篇介绍链表不错的文章:

    1. 玩转C链表

    2. openwrt使用list

    3. 深入分析 Linux 内核链表 https://www.ibm.com/developerworks/cn/linux/kernel/l-chain/

    include/linux/list.h

    双向链表--双指针(无头链表,需外部指定头部

    /*
     * 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.
     */
    struct list_head {
        struct list_head *next, *prev;
    };
    
    #define LIST_HEAD_INIT(name) { &(name), &(name) }
    
    #define LIST_HEAD(name) 
        struct list_head name = LIST_HEAD_INIT(name)
    
    static inline void INIT_LIST_HEAD(struct list_head *list)
    {
        list->next = list;
        list->prev = list;
    }
    #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);
    }
    static inline void __list_del(struct list_head * prev, struct list_head * next)
    {
        next->prev = prev;
        prev->next = next;
    }
    
    被剔除下来的list,prev、next指针分别被设为LIST_POSITION2和LIST_POSITION1两个特殊值,这样设置是为了保证不在链表中的节点项不可访问--对LIST_POSITION1和LIST_POSITION2的访问都将引起页故障。
    与之相对应,list_del_init()函数将节点从链表中解下来之后,调用LIST_INIT_HEAD()将节点置为空链状态。
    /** * 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(struct list_head *entry) { __list_del(entry->prev, entry->next); entry->next = LIST_POISON1; entry->prev = LIST_POISON2; } #else extern void list_del(struct list_head *entry); #endif
    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->prev, entry->next);
        INIT_LIST_HEAD(entry);
    }
    static inline void list_move(struct list_head *list, struct list_head *head)
    {
        __list_del(list->prev, list->next);
        list_add(list, head);
    }
    static inline void list_move_tail(struct list_head *list,
                      struct list_head *head)
    {
        __list_del(list->prev, list->next);
        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;
    }
    
    /**
     * 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;
    }
    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;
    }
    
    /**
     * 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);
    }
    static inline void list_splice_tail(struct list_head *list,
                    struct list_head *head)
    {
        if (!list_empty(list))
            __list_splice(list, head->prev, head);
    }
    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);
        }
    }
    当list1被挂接到list2之后,作为原表头指针的list1的next、prev仍然指向原来的节点,为了避免引起混乱,Linux提供了一个list_splice_init(),在将list合并到head链表的基础上,调用INIT_LIST_HEAD(list)将list设置为空链。
    /** * 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); } }

    -------------------------------------------------------------------------------------------------------------------

    Linux链表中仅保存了数据项结构中list_head成员变量的地址,那么我们如何通过这个list_head成员访问到作为它的所有者的节点数据呢?
    Linux为此提供了一个list_entry(ptr,type,member)宏,其中ptr是指向该数据中list_head成员的指针,也就是存储在链表中的地址值,type是数据项的类型,member则是数据项类型定义中list_head成员的变量名。
    /*
    * * list_entry - get the struct for this entry * @ptr: the &struct list_head pointer. * @type: the type of the struct this is embedded in. * @member: the name of the list_struct within the struct. */ #define list_entry(ptr, type, member) container_of(ptr, type, member)
    /**
     * list_first_entry - get the first element from a list
     * @ptr:    the list head to take the element from.
     * @type:   the type of the struct this is embedded in.
     * @member: the name of the list_struct within the struct.
     *
     * Note, that list is expected to be not empty.
     */
    #define list_first_entry(ptr, type, member) 
        list_entry((ptr)->next, type, member)
    /**
     * 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; prefetch(pos->next), pos != (head); 
                pos = pos->next)
    /**
     * __list_for_each  -   iterate over a list
     * @pos:    the &struct list_head to use as a loop cursor.
     * @head:   the head for your list.
     *
     * This variant differs from list_for_each() in that it's the
     * simplest possible list iteration code, no prefetching is done.
     * Use this for code that knows the list to be very short (empty
     * or 1 entry) most of the time.
     */
    #define __list_for_each(pos, head) 
        for (pos = (head)->next; pos != (head); pos = pos->next)
    
    /**
     * list_for_each_prev   -   iterate over a list backwards
     * @pos:    the &struct list_head to use as a loop cursor.
     * @head:   the head for your list.
     */
    #define list_for_each_prev(pos, head) 
        for (pos = (head)->prev; prefetch(pos->prev), pos != (head); 
                pos = pos->prev)
    /**
     * list_for_each_safe - iterate over a list safe against removal of list entry
     * @pos:    the &struct list_head to use as a loop cursor.
     * @n:      another &struct list_head to use as temporary storage
     * @head:   the head for your list.
     */
    #define list_for_each_safe(pos, n, head) 
        for (pos = (head)->next, n = pos->next; pos != (head); 
            pos = n, n = pos->next)
    
    /**
     * list_for_each_prev_safe - iterate over a list backwards safe against removal of list entry
     * @pos:    the &struct list_head to use as a loop cursor.
     * @n:      another &struct list_head to use as temporary storage
     * @head:   the head for your list.
     */
    #define list_for_each_prev_safe(pos, n, head) 
        for (pos = (head)->prev, n = pos->prev; 
             prefetch(pos->prev), pos != (head); 
             pos = n, n = pos->prev)
    /**
     * list_for_each_entry  -   iterate over list of given type
     * @pos:    the type * to use as a loop cursor.
     * @head:   the head for your list.
     * @member: the name of the list_struct within the struct.
     */
    #define list_for_each_entry(pos, head, member)              
        for (pos = list_entry((head)->next, typeof(*pos), member);  
             prefetch(pos->member.next), &pos->member != (head);    
             pos = list_entry(pos->member.next, typeof(*pos), member))
    /**
     * list_for_each_entry_reverse - iterate backwards over list of given type.
     * @pos:    the type * to use as a loop cursor.
     * @head:   the head for your list.
     * @member: the name of the list_struct within the struct.
     */
    #define list_for_each_entry_reverse(pos, head, member)          
        for (pos = list_entry((head)->prev, typeof(*pos), member);  
             prefetch(pos->member.prev), &pos->member != (head);    
             pos = list_entry(pos->member.prev, typeof(*pos), member))
    /**
     * list_prepare_entry - prepare a pos entry for use in list_for_each_entry_continue()
     * @pos:    the type * to use as a start point
     * @head:   the head of the list
     * @member: the name of the list_struct within the struct.
     *
     * Prepares a pos entry for use as a start point in list_for_each_entry_continue().
     */
    #define list_prepare_entry(pos, head, member) 
        ((pos) ? : list_entry(head, typeof(*pos), member))
    
    /**
     * list_for_each_entry_continue - continue iteration over list of given type
     * @pos:    the type * to use as a loop cursor.
     * @head:   the head for your list.
     * @member: the name of the list_struct within the struct.
     *
     * Continue to iterate over list of given type, continuing after
     * the current position.
     */
    #define list_for_each_entry_continue(pos, head, member)         
        for (pos = list_entry(pos->member.next, typeof(*pos), member);  
             prefetch(pos->member.next), &pos->member != (head);    
             pos = list_entry(pos->member.next, typeof(*pos), member))
    /**
     * list_for_each_entry_continue_reverse - iterate backwards from the given point
     * @pos:    the type * to use as a loop cursor.
     * @head:   the head for your list.
     * @member: the name of the list_struct within the struct.
     *
     * Start to iterate over list of given type backwards, continuing after
     * the current position.
     */
    #define list_for_each_entry_continue_reverse(pos, head, member)     
        for (pos = list_entry(pos->member.prev, typeof(*pos), member);  
             prefetch(pos->member.prev), &pos->member != (head);    
             pos = list_entry(pos->member.prev, typeof(*pos), member))
    
    /**
     * list_for_each_entry_from - iterate over list of given type from the current point
     * @pos:    the type * to use as a loop cursor.
     * @head:   the head for your list.
     * @member: the name of the list_struct within the struct.
     *
     * Iterate over list of given type, continuing from current position.
     */
    #define list_for_each_entry_from(pos, head, member)             
        for (; prefetch(pos->member.next), &pos->member != (head);  
             pos = list_entry(pos->member.next, typeof(*pos), member))
    /**
     * list_for_each_entry_safe - iterate over list of given type safe against removal of list entry
     * @pos:    the type * to use as a loop cursor.
     * @n:      another type * to use as temporary storage
     * @head:   the head for your list.
     * @member: the name of the list_struct within the struct.
     */
    #define list_for_each_entry_safe(pos, n, head, member)          
        for (pos = list_entry((head)->next, typeof(*pos), member),  
            n = list_entry(pos->member.next, typeof(*pos), member); 
             &pos->member != (head);                    
             pos = n, n = list_entry(n->member.next, typeof(*n), member))
    
    /**
     * list_for_each_entry_safe_continue - continue list iteration safe against removal
     * @pos:    the type * to use as a loop cursor.
     * @n:      another type * to use as temporary storage
     * @head:   the head for your list.
     * @member: the name of the list_struct within the struct.
     *
     * Iterate over list of given type, continuing after current point,
     * safe against removal of list entry.
     */
    #define list_for_each_entry_safe_continue(pos, n, head, member)         
        for (pos = list_entry(pos->member.next, typeof(*pos), member),      
            n = list_entry(pos->member.next, typeof(*pos), member);     
             &pos->member != (head);                        
             pos = n, n = list_entry(n->member.next, typeof(*n), member))
    /**
     * list_for_each_entry_safe_from - iterate over list from current point safe against removal
     * @pos:    the type * to use as a loop cursor.
     * @n:      another type * to use as temporary storage
     * @head:   the head for your list.
     * @member: the name of the list_struct within the struct.
     *
     * Iterate over list of given type from current point, safe against
     * removal of list entry.
     */
    #define list_for_each_entry_safe_from(pos, n, head, member)             
        for (n = list_entry(pos->member.next, typeof(*pos), member);        
             &pos->member != (head);                        
             pos = n, n = list_entry(n->member.next, typeof(*n), member))
    
    /**
     * list_for_each_entry_safe_reverse - iterate backwards over list safe against removal
     * @pos:    the type * to use as a loop cursor.
     * @n:      another type * to use as temporary storage
     * @head:   the head for your list.
     * @member: the name of the list_struct within the struct.
     *
     * Iterate backwards over list of given type, safe against removal
     * of list entry.
     */
    #define list_for_each_entry_safe_reverse(pos, n, head, member)      
        for (pos = list_entry((head)->prev, typeof(*pos), member),  
            n = list_entry(pos->member.prev, typeof(*pos), member); 
             &pos->member != (head);                    
             pos = n, n = list_entry(n->member.prev, typeof(*n), member))
    /**
     * list_safe_reset_next - reset a stale list_for_each_entry_safe loop
     * @pos:    the loop cursor used in the list_for_each_entry_safe loop
     * @n:      temporary storage used in list_for_each_entry_safe
     * @member: the name of the list_struct within the struct.
     *
     * list_safe_reset_next is not safe to use in general if the list may be
     * modified concurrently (eg. the lock is dropped in the loop body). An
     * exception to this is if the cursor element (pos) is pinned in the list,
     * and list_safe_reset_next is called after re-taking the lock and before
     * completing the current iteration of the loop body.
     */
    #define list_safe_reset_next(pos, n, member)                
        n = list_entry(pos->member.next, typeof(*pos), member)

     ---------------------------------------------------------------------------------------------------------------------

    双向链表--单指针,hlist

    精益求精的Linux链表设计者(因为list.h没有署名,所以很可能就是Linus Torvalds)认为双头(next、prev)的双链表对于HASH表来说"过于浪费",因而另行设计了一套用于HASH表应用的hlist数据结构--单指针表头双循环链表。

    从上图可以看出,hlist的表头仅有一个指向首节点的指针,而没有指向尾节点的指针,这样在可能是海量的HASH表中存储的表头就能减少一半的空间消耗。

    因为表头和节点的数据结构不同,插入操作如果发生在表头和首节点之间,以往的方法就行不通了:表头的first指针必须修改指向新插入的节点,却不能使用类似list_add()这样统一的描述。

    为此,hlist节点的prev不再是指向前一个节点的指针,而是指向前一个节点(可能是表头)中的next(对于表头则是first)指针(struct list_head **pprev),从而在表头插入的操作可以通过一致的"*(node->pprev)"访问和修改前驱节点的next(或first)指针。

    /*
     * Double linked lists with a single pointer list head.
     * Mostly useful for hash tables where the two pointer list head is
     * too wasteful.
     * You lose the ability to access the tail in O(1).
     */
    *
     * Double linked lists with a single pointer list head.
     * Mostly useful for hash tables where the two pointer list head is
     * too wasteful.
     * You lose the ability to access the tail in O(1).
     */
    
    struct hlist_head {
        struct hlist_node *first;
    };
    
    struct hlist_node {
        struct hlist_node *next, **pprev;
    };
    #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_HLIST_NODE(struct hlist_node *h)
    {
        h->next = NULL;
        h->pprev = NULL;
    }
    
    static inline int hlist_unhashed(const struct hlist_node *h)
    {
        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;
        struct hlist_node **pprev = n->pprev;
        *pprev = next;
        if (next)
            next->pprev = pprev;
    }
    
    static inline void hlist_del(struct hlist_node *n)
    {
        __hlist_del(n);
        n->next = LIST_POISON1;
        n->pprev = LIST_POISON2;
    }
    
    static inline void hlist_del_init(struct hlist_node *n)
    {
        if (!hlist_unhashed(n)) {
            __hlist_del(n);
            INIT_HLIST_NODE(n);
        }
    }
    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 */
    static 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;
    }
    
    static inline void hlist_add_after(struct hlist_node *n,
                        struct hlist_node *next)
    {
        next->next = n->next;
        n->next = next;
        next->pprev = &n->next;
    
        if(next->next)
            next->next->pprev  = &next->next;
    }
    /*
     * Move a list from one list head to another. Fixup the pprev
     * reference of the first entry if it exists.
     */
    static inline void hlist_move_list(struct hlist_head *old,
                       struct hlist_head *new)
    {
        new->first = old->first;
        if (new->first)
            new->first->pprev = &new->first;
        old->first = NULL;
    }
    #define hlist_entry(ptr, type, member) container_of(ptr,type,member)
    
    #define hlist_for_each(pos, head) 
        for (pos = (head)->first; pos && ({ prefetch(pos->next); 1; }); 
             pos = pos->next)
    
    #define hlist_for_each_safe(pos, n, head) 
        for (pos = (head)->first; pos && ({ n = pos->next; 1; }); 
             pos = n)
    
    /**
     * hlist_for_each_entry - iterate over list of given type
     * @tpos:   the type * to use as a loop cursor.
     * @pos:    the &struct hlist_node to use as a loop cursor.
     * @head:   the head for your list.
     * @member: the name of the hlist_node within the struct.
     */
    #define hlist_for_each_entry(tpos, pos, head, member)            
        for (pos = (head)->first;                    
             pos && ({ prefetch(pos->next); 1;}) &&          
            ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); 
             pos = pos->next)
    /**
     * hlist_for_each_entry_continue - iterate over a hlist continuing after current point
     * @tpos:   the type * to use as a loop cursor.
     * @pos:    the &struct hlist_node to use as a loop cursor.
     * @member: the name of the hlist_node within the struct.
     */
    #define hlist_for_each_entry_continue(tpos, pos, member)         
        for (pos = (pos)->next;                      
             pos && ({ prefetch(pos->next); 1;}) &&          
            ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); 
             pos = pos->next)
    
    /**
     * hlist_for_each_entry_from - iterate over a hlist continuing from current point
     * @tpos:   the type * to use as a loop cursor.
     * @pos:    the &struct hlist_node to use as a loop cursor.
     * @member: the name of the hlist_node within the struct.
     */
    #define hlist_for_each_entry_from(tpos, pos, member)             
        for (; pos && ({ prefetch(pos->next); 1;}) &&            
            ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); 
             pos = pos->next)
    /**
     * hlist_for_each_entry_safe - iterate over list of given type safe against removal of list entry
     * @tpos:   the type * to use as a loop cursor.
     * @pos:    the &struct hlist_node to use as a loop cursor.
     * @n:      another &struct hlist_node to use as temporary storage
     * @head:   the head for your list.
     * @member: the name of the hlist_node within the struct.
     */
    #define hlist_for_each_entry_safe(tpos, pos, n, head, member)        
        for (pos = (head)->first;                    
             pos && ({ n = pos->next; 1; }) &&               
            ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); 
             pos = n)

    安全性考虑

    在并发执行的环境下,链表操作通常都应该考虑同步安全性问题,为了方便,Linux将这一操作留给应用自己处理。Linux链表自己考虑的安全性主要有两个方面:

    a) list_empty()判断

    基本的list_empty()仅以头指针的next是否指向自己来判断链表是否为空,Linux链表另行提供了一个list_empty_careful()宏,它同时判断头指针的next和prev,仅当两者都指向自己时才返回真。这主要是为了应付另一个cpu正在处理同一个链表而造成next、prev不一致的情况。但代码注释也承认,这一安全保障能力有限:除非其他cpu的链表操作只有list_del_init(),否则仍然不能保证安全,也就是说,还是需要加锁保护。

    b) 遍历时节点删除

    前面介绍了用于链表遍历的几个宏,它们都是通过移动pos指针来达到遍历的目的。但如果遍历的操作中包含删除pos指针所指向的节点,pos指针的移动就会被中断,因为list_del(pos)将把pos的next、prev置成LIST_POSITION2和LIST_POSITION1的特殊值。

    当然,调用者完全可以自己缓存next指针使遍历操作能够连贯起来,但为了编程的一致性,Linux链表仍然提供了两个对应于基本遍历操作的"_safe"接口:list_for_each_safe(pos, n, head)、list_for_each_entry_safe(pos, n, head, member),它们要求调用者另外提供一个与pos同类型的指针n,在for循环中暂存pos下一个节点的地址,避免因pos节点被释放而造成的断链。

    附:

    #define offsetof(TYPE, MEMBER)   ((size_t) &((TYPE *)0)->MEMBER)
    
    /**
     * container_of - cast a member of a structure out to the containing structure
     * @ptr:    the pointer to the member.
     * @type:    the type of the container struct this is embedded in.
     * @member:    the name of the member within the struct.
     *
     */
    #define container_of(ptr, type, member) (type *)((char *)ptr -offsetof(type,member))
  • 相关阅读:
    为什么 PCB 生产时推荐出 Gerber 给工厂?
    Fedora Redhat Centos 有什么区别和关系?
    【KiCad】 如何给元件给元件的管脚加上划线?
    MCU ADC 进入 PD 模式后出现错误的值?
    FastAdmin 生产环境升级注意
    EMC EMI 自行评估记录
    如何让你的 KiCad 在缩放时不眩晕?
    KiCad 5.1.0 正式版终于发布
    一次单片机 SFR 页引发的“事故”
    java基础之集合
  • 原文地址:https://www.cnblogs.com/embedded-linux/p/5494283.html
Copyright © 2011-2022 走看看