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