zoukankan      html  css  js  c++  java
  • Linux内核数据结构list_head

    1、list_head的简单说明

    在Linux内核中,提供了一个用来创建的双向循环链表的结构list_head。

    其在内核中的定义如下:

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

    使用list_head的内存结构如下所示:

    在数据结构的课本中,链表的经典定义方式通常是这样的

    struct list_node {
        struct list_node *next;
        struct list_node *pre;
        ElemType    data;
    };

    我们知道在一般的双链表中,链表节点一般是含有数据域。而list_head这个结构模型和一般的链表结构模型最大的不同在于,list_head是没有数据域。在linux内核链表中不是在链表结构中包含数据,而是在数据中包含链表节点。

     2、list_head提供的一些接口

     2.1 初始化头结点

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

     2.2 遍历双向链表

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

    2.3  插入操作

    对链表的插入操作有两种:在表头插入和在表尾插入。Linux为此提供了两个接口。实际上我们可以看出来,这两个接口的差别并不大,一个从表头插入一个从表尾插入。

    static inline void list_add(struct list_head *new, struct list_head *head)
    static inline void list_add_tail(struct list_head *new, struct list_head *head)
     
    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);
    }
    
    
    
    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;
    }

    2.3 删除操作

    static inline void list_del(struct list_head *entry);
    被删除的dentry的pre,next指针分别指向被设定为LIST_POSITION2和LIST_POSITION1两个特殊值,这样设置是为了保证不在链表中的节点项不可访问--对LIST_POSITION1和LIST_POSITION2的访问都将引起页故障。与之相对应,
    list_del_init()函数将节点从链表中解下来之后,调用LIST_INIT_HEAD()将节点置为空链状态。
    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(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);
    }

    2.4 迁移操作

    将节点list从其所在的链表迁移到head所在的链表。

    static inline void list_move(struct list_head *list, struct list_head *head);

    static inline void list_move_tail(struct list_head *list, struct list_head *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);
    }
    
    /**
     * 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);
    }

    2.5 合并 

    static inline void list_splic(struct list_head *list,struct list_head *head)

    static inline void list_splice_init(struct list_head *list,struct list_head *head)

    static inline void list_splic_tail(struct list_head *list,struct list_head *head)

    static inline void list_splice_tail_init(struct list_head *list,struct list_head *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);
    }
    
    /**
     * 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);
    }
    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);
      }
    }
    
    /**
     * 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);
      }
    }

    3 例子

    #define MAX_NAME_LEN 32
    #define MAX_ID_LEN 10
    
    typedef struct student{
      struct list_head list;
      char name[MAX_NAME_LEN];
      char id[MAX_ID_LEN];
    }student_t;
    
    static int  list_test_init(void)
    {
      struct list_head head;
      struct list_head *p; 
      student_t stu_1;
      student_t stu_2;
      student_t *entry;
    
      INIT_LIST_HEAD(&head);
      strcpy(stu_1.name,"lisi");
      strcpy(stu_1.id,"001");
      strcpy(stu_2.name,"linyp");
      strcpy(stu_2.id,"002");
    
      list_add(&stu_1.list,&head);
      list_add(&stu_2.list,&head);
    
      list_for_each(p,&head)
      {
        entry = list_entry(p,student_t,list);
        printk("name:%s
    ",entry->name);
        printk("id:%s
    ",entry->id);
      }
    
      list_del(&stu_1.list);
      printk("del student 1
    ");
      list_for_each(p,&head)
      {
        entry = list_entry(p,student_t,list);
        printk("name:%s
    ",entry->name);
        printk("id:%s
    ",entry->id);
      }
      return 0;
    }
  • 相关阅读:
    看看优酷是怎么做网络投票的?
    CURL的学习和应用
    PHP生成word的三种方式
    感谢
    网站后台权限设计
    ORACLE 11g 导出数据
    第一份blog
    查看tomcat的内存情况
    执行sshadd时出现Could not open a connection to your authentication agent
    读取SSDT当前函数地址
  • 原文地址:https://www.cnblogs.com/bspp1314/p/9455419.html
Copyright © 2011-2022 走看看