链表的操作

Linux内核链表的操作定义在kernel/include/linux/list.h中,我们将逐一分析此文件中关于链表操作的接口。

 

1,struct list_head的定义在kernel/include/linux/types.h中:

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

struct list_head类型的结构体包含了两个指向struct list_head结构类型的成员指针next和prev,因此我们可以看出struct list_head类型的变量可以进行双向链表的操作。

 

2,静态初始化链表头节点:

/*
 * 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.
 */

#define LIST_HEAD_INIT(name) { &(name), &(name) }

#define LIST_HEAD(name) \
        struct list_head name = LIST_HEAD_INIT(name)

LIST_HEAD宏根据传进来的参数定义了一个的struct list_head类型的变量name,并根据LIST_HEAD_INIT宏将name的成员变量next、prev分别赋值指向自身所在结构体变量的首地址&name。

 

3,INIT_LIST_HEAD用于将list的成员next、prev分别指向其所在的结构体变量本身list。这个宏在后面会经常用到,主要用于初始化从链表中被删除的节点。

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

 

4,__list_add用于将一个new节点插入到prev之后,next之前,此函数只用于已知prev/next的内部链表操作:

/*
 * Insert a new entry between two known consecutive entries.
 *
 * This is only for internal list manipulation where we know
 * the prev/next entries already!
 */
#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

 

5,list_add用于将一个new节点添加到链表头head之后和第一个节点head->next之前:

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

 

6,list_add_tail用于将一个new节点添加到最后一个节点head->prev之后和头节点head之前:

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

 

7,__list_del用于删除一个链表节点项,其表现方式是将要删除节点前后节点的指针互相连上:

/*
 * Delete a list entry by making the prev/next entries
 * point to each other.
 *
 * This is only for internal list manipulation where we know
 * the prev/next entries already!
 */
static inline void __list_del(struct list_head * prev, struct list_head * next)
{
        next->prev = prev;
        prev->next = next;
}

 

8,list_del用于删除一个链表的节点项entry,通过其调用__list_del函数我们可以看出,传到__list_del的参数为entry的上一个节点和下一个节点的指针,这样也就实现了在__list_del中entry的prev和next互相操作,而越过了entry这个节点。而后面的操作entry->next = LIST_POISON1;   entry->prev = LIST_POISON2; LIST_POISON1和LIST_POISON2用于确保没人能够使用未初始化的列表项,在正常情况下使用这两个非空指针时将会导致Page Fault页故障。

/**
 * 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_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;
}
#else
extern void __list_del_entry(struct list_head *entry);
extern void list_del(struct list_head *entry);
#endif

 

 9,list_del_init同样是删除一个节点,并将这个被删除节点的prev、next指针指向entry变量本身。

/**
 * list_del_init - deletes entry from list and reinitialize it.
 * @entry: the element to delete from the list.
 */
static inline void list_del_init(struct list_head *entry)
{
        __list_del_entry(entry);
        INIT_LIST_HEAD(entry);
}

 

10,list_replace用于将old节点替换成new,list_replace_init多加了一个将old节点的prev、next指向old本身的操作。

/**
 * list_replace - replace old entry by new one
 * @old : the element to be replaced
 * @new : the new element to insert
 *
 * If @old was empty, it will be overwritten.
 */
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);
}

 

11,list_move用于将一个节点项list删除,然后将节点项list添加到另一个链表头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);
}

 

 12,list_move_tail用于将一个节点项list删除,然后将节点项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);
}

 

 13,list_is_last用于测试节点list是否是链表head中的最后一项。

/**
 * list_is_last - tests whether @list is the last entry in list @head
 * @list: the entry to test
 * @head: the head of the list
 */
static inline int list_is_last(const struct list_head *list,
                                const struct list_head *head)
{
        return list->next == head;
}

 

 14,list_empty用于判断一个链表是否为空,也就是说链表头节点的next是否指向了头head本身,是则代表链表中除了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;
}

 

 15,list_empty_careful用于判断一个链表是否为空,同时检测链表的prev、next成员没有被其他CPU修改。注意:只有其他CPU在使用list_del_init()来操纵同一个链表时list_empty_careful才能保证安全,否则多核CPU对链表的操作仍需使用锁机制。

/**
 * list_empty_careful - tests whether a list is empty and not being modified
 * @head: the list to test
 *
 * Description:
 * tests whether a list is empty _and_ checks that no other CPU might be
 * in the process of modifying either member (next or prev)
 *
 * NOTE: using list_empty_careful() without synchronization
 * can only be safe if the only activity that can happen
 * to the list entry is list_del_init(). Eg. it cannot be used
 * if another CPU could re-list_add() it.
 */
static inline int list_empty_careful(const struct list_head *head)
{
        struct list_head *next = head->next;
        return (next == head) && (next == head->prev);
}

 

16,list_rotate_left用于将链表的第一个节点移到头结点的左边,即最后一个节点。

/**
 * list_rotate_left - rotate the list to the left
 * @head: the head of the list
 */
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);
    }
}

 

17,list_is_singular用于测试链表是否只含有一个节点。

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

 

18,__list_cur_position用于将一个链表一分为二:

@head表示将要被cut链表的链表头,我称之为原始链表;

@list指向原始链表的第一个节点,并以第@entry个节点为尾节点,组成一个以@list为头@entry为尾的新链表。

@head指向原始链表中@entry后面的一个节点,这个节点作为@head新链表中的第一个节点,同时@head的prev节点不变,仍为原始链表中的尾节点(假使原始链表是循环链表的话)。

从而就构成了两个以@entry为分界点,@list指向前半部,@head指向后半部的2个新链表。

原始链表

@head<--->N1<--->N2<--->N3<--->N4<--->N5<--->N6<--->N7<--->N8<--->N9<----------

    ^                                        |      

    |_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _|  

 

假使@entry为第N5个节点,

@list新链表

@list<--->N1<--->N2<--->N3<--->N4<--->N5<----------

    ^                          |      

    |_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ __ _ _ _ _|  

 

@head新链表:

@head<--->N6<--->N7<--->N8<--->N9<----------

    ^                    |      

    |_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _|  

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

/**
 * list_cut_position - cut a list into two
 * @list: a new list to add all removed entries
 * @head: a list with entries
 * @entry: an entry within head, could be the head itself
 *    and if so we won't cut the list
 *
 * This helper moves the initial part of @head, up to and
 * including @entry, from @head to @list. You should
 * pass on @entry an element you know is on @head. @list
 * should be an empty list or a list you do not care about
 * losing its data.
 *
 */
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);
}

 

 19,__list_splice用于拼接两个链表:

@list为要插入链表的链表头;

@prev为被插入链表的一个节点;

@next为被插入链表的一个节点;

整体就是将@list链表拼接到被插入链表的prev和next之间。

被插入链表

@head<--->H1<--->H2<--->H3<--->H4<--->H5<----------

    ^                             |      

    |_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _   _ _ _ _|  

 

 要插入链表

@list<--->L1<--->L2<--->L3<----------

    ^                    |      

    |_ _ _ _ _ _ _ _ _ _ _ _ _   _ _ _|

 

假设prev为H1,next为H2,则拼接后的链表为:

        @list 

             \

             \

@head<--->H1<--->L1<--->L2<--->L3<--->H2<--->H3<--->H4<--->H5<----------

    ^                                  |      

    |_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _  _ _ _ _ _|

@list仍然指向L1,这里没法斜着画 >,我就不画了。

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

 

 20,list_splice用于将@list链表插入到head和head的下一个节点head->next之间。

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

 

 21,list_splice_tail用于将@list插入到head的前一个节点head->prev和head之间。

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

 

 22,list_splice用于将@list链表插入到head和head的下一个节点head->next之间,由于@list拼接到@head中后,@list的头节点将会从拼接好的链表中掉出,所以调用INIT_LIST_HEAD将@list的头list的成员变量prev、next指向其自身。

/**
 * list_splice_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.
 *
 * The list at @list is reinitialised
 */
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);
    }
}

 

 23,list_splice_tail用于将@list插入到head的前一个节点head->prev和head之间,由于@list拼接到@head中后,@list的头节点将会从拼接好的链表中掉出,所以调用INIT_LIST_HEAD将@list的头list的成员变量prev、next指向其自身。

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

 

 

链表头数据结构

posted @ 2014-03-10 23:50  Watson  阅读(698)  评论(0编辑  收藏  举报