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;
}
原文地址:https://www.cnblogs.com/bspp1314/p/9455419.html