• include/linux/list.h的简要分析


    struct list_head结构体是linux实现数据结构双向链表的基础。其定义:

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

     可见链表里面的成员还是链表,每个链表都指向了前面和后面的链表。

    一般将struct list_head作为一个成员,放到一个结构体中,其作用是可以从当前的结构体指针,获取到下一个链表元素的地址。一般用list_entry()来实现。具体按照下面的链接:

    http://www.cnblogs.com/bastard/archive/2012/10/19/2731107.html

    ok,下面来看看list_head为我们提供的一些接口:

    先看一个基础的:

    添加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的next,一个是添加到prev。对应的函数分别为:list_add和list_add_tail.

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

    如果不好理解的话,自己画个图,应该就能明白了。

    删除delet:

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

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

    static inline void list_del_init(struct list_head *entry)
    {
     __list_del_entry(entry);
     INIT_LIST_HEAD(entry);
    }

    删除就是把某一节点从链表中删除。entry->next = LIST_POISON1; entry->prev = LIST_POISON2; LIST_POISON1/2在linux/poison.h中定义。删除后,为什么还要设置删除掉的节点指针呢?因为删除后,该选节点已不在链表当中,因此不会再使用。LIST_POISON1/2是两个不会存在于内核空间的地址,如果使用,就会报错。因此,设置指针,是强制禁用该节点。

    inline void list_del_init 把entry从链表中delete,并将其初始化为一个空的链表。

    替代replace:

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

    移动move:

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

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

    从原链表中删除,并添加到新的链表中。list_move添加到head后面,list_move_tail添加到head的前面。

    //将head和它的next互换

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

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

     链表一分为二cut:

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

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

    注意这个是从entry处分开,list到entry为新的链表。head、entry->next、、、为老的链表。

    举例:原来的链表是 head->1->2->3->4->5(只列出next方向,previous方向就是反过来),如果entry是2,那么新的链表是list->1->2,原来的链表则变为head->3->4->5。

    看代码的一些小心得:一,阅读英文注释,不要害怕。二,静下心。

    合并:

    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放到放到prev和next之间。

    主要的函数接口有:

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

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

    上面都比较简单,不细谈,不行可以去看看函数的解释。

    下面是一些获取指针的操作:

    基础:

    #define list_entry(ptr, type, member)
     container_of(ptr, type, member)

    container_of这个函数,一定要牢记,它是通过已知的指针ptr,去获取它存在于那个type类型的结构体的指针,它在这个type结构体里面的成员名叫member。

       之前说了一般链表的第一个是做连接用的,没什么实际意义,因此衍生的函数有:

    #define list_first_entry(ptr, type, member)
     list_entry((ptr)->next, type, member) 

    获取第一个链表成员的指针。

    遍历链表:

    正向:

    #define list_for_each(pos, head)
     for (pos = (head)->next; pos != (head); pos = pos->next)

    #define list_for_each_safe(pos, n, head)
     for (pos = (head)->next, n = pos->next; pos != (head);
      pos = n, n = pos->next)

    反向:

    #define list_for_each_prev(pos, head)
     for (pos = (head)->prev; pos != (head); pos = pos->prev)

    #define list_for_each_prev_safe(pos, n, head)
     for (pos = (head)->prev, n = pos->prev;
          pos != (head);
          pos = n, n = pos->prev)

    关于safe的说明:如果是list_for_each,在处理的过程中,将pos的节点给删除了,那就引起了错误,因为pos->next就成了我们上面说的LISTPOISON1,操作的时候就引起页错误。(list_del(pos)将pos的前后指针指向undefined state,导致kernel panic,list_del_init(pos)将pos前后指针指向自身,导致死循环)

    safe机制在于提供了一个临时存放区,可以对其进行操作后,再返回到原链表中。思考:如果在处理过程中,删除了n,那是不是也会引起错误呢?????

                         

  • 相关阅读:
    华为云文字识别服务关键技术、能力和产品落地需要注意的事宜(OCR系列二)
    【华为云技术分享】大数据容器化,头部玩家尝到了甜头
    【华为云技术分享】9 个Java 异常处理的规则!
    【华为云技术分享】一统江湖大前端DOClever—你的Postman有点Low
    【华为云技术分享】大前端的自动化工厂— babel
    非编程人学Python,要注意哪些隐秘的错误认知?
    【华为云技术分享】【一统江湖的大前端】PPT制作库impress.js
    【鲲鹏来了】鲲鹏迁移过程案例分享
    【华为云技术分享】圣诞特别版 | 数据库频频出现OOM问题该如何化解?
    HBuilder开发App
  • 原文地址:https://www.cnblogs.com/cyc2009/p/4160503.html
Copyright © 2020-2023  润新知