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,那是不是也会引起错误呢?????

 

 

                     

 

posted on 2014-12-12 23:40  tiger_chen  阅读(2381)  评论(0编辑  收藏  举报

导航