链表的删除
83/*
84 * Delete a list entry by making the prev/next entries
85 * point to each other.
86 *
87 * This is only for internal list manipulation where we know
88 * the prev/next entries already!
89 */
90static inline void __list_del(struct list_head * prev, struct list_head * next)
91{
92 next->prev = prev;
93 prev->next = next;
94}
该函数通过设置prev和next指针指向彼此,实现了删除二者之间节点的功能。但是这里我有个疑惑,删除的指针的释放在哪里实现。
96/**
97 * list_del - deletes entry from list.
98 * @entry: the element to delete from the list.
99 * Note: list_empty() on entry does not return true after this, the entry is
100 * in an undefined state.
101 */
102#ifndef CONFIG_DEBUG_LIST
103static inline void list_del(struct list_head *entry)
104{
105 __list_del(entry->prev, entry->next);
106 entry->next = LIST_POISON1;
107 entry->prev = LIST_POISON2;
108}
109#else
110extern void list_del(struct list_head *entry);
111#endif
该函数通过调用上面的内联函数实现节点的删除,这里的LIST_POISON1和LIST_POISON2是在linux/poison.h定义的。此处仍然是条件编译。
链表节点的置换
113/**
114 * list_replace - replace old entry by new one
115 * @old : the element to be replaced
116 * @new : the new element to insert
117 *
118 * If @old was empty, it will be overwritten.
119 */
120static inline void list_replace(struct list_head *old,
121 struct list_head *new)
122{
123 new->next = old->next;
124 new->next->prev = new;
125 new->prev = old->prev;
126 new->prev->next = new;
127}
128
129static inline void list_replace_init(struct list_head *old,
130 struct list_head *new)
131{
132 list_replace(old, new);
133 INIT_LIST_HEAD(old);
134}
静态内联函数list_replace接受两个参数:old和new,并通过new替换old。而list_replace_init函数则是通过调用list_replace进行替换,之后调用INIT_LIST_HEAD对被替换的old进行链表初始化。
链表的移动
146/**
147 * list_move - delete from one list and add as another’s head
148 * @list: the entry to move
149 * @head: the head that will precede our entry
150 */
151static inline void list_move(struct list_head *list, struct list_head *head)
152{
153 __list_del(list->prev, list->next);
154 list_add(list, head);
155}
List_move函数接受两个参数,第一个参数list为想要移动的节点指针,第二个参数为目的地节点指针。该函数通过调用__list_del函数实现list节点的prev和next两个指针互指实现删除list节点的效果,并且调用list_add将list节点插入到head之后。
157/**
158 * list_move_tail - delete from one list and add as another’s tail
159 * @list: the entry to move
160 * @head: the head that will follow our entry
161 */
162static inline void list_move_tail(struct list_head *list,
163 struct list_head *head)
164{
165 __list_del(list->prev, list->next);
166 list_add_tail(list, head);
167}
List_move_tail函数将指定节点移到指定链表的尾部,成为尾节点。并且由于链表是循环的,所以移动的节点指向该链表head节点。具体实现是通过目标节点的prev和next互指实现从原始链表中删除list节点,之后通过调用list_add_tail将list节点插入到以head为表首的链表尾部。
判断节点是否为链表的最后一个
169/**
170 * list_is_last - tests whether @list is the last entry in list @head
171 * @list: the entry to test
172 * @head: the head of the list
173 */
174static inline int list_is_last(const struct list_head *list,
175 const struct list_head *head)
176{
177 return list->next == head;
178}
通过判断节点的next指向是否为表首来确定是否为last。
判断链表是否为空
180/**
181 * list_empty - tests whether a list is empty
182 * @head: the list to test.
183 */
184static inline int list_empty(const struct list_head *head)
185{
186 return head->next == head;
187}
通过判断head节点是否指向自身来判断链表是否为空。
189/**
190 * list_empty_careful - tests whether a list is empty and not being modified
191 * @head: the list to test
192 *
193 * Description:
194 * tests whether a list is empty _and_ checks that no other CPU might be
195 * in the process of modifying either member (next or prev)
196 *
197 * NOTE: using list_empty_careful() without synchronization
198 * can only be safe if the only activity that can happen
199 * to the list entry is list_del_init(). Eg. it cannot be used
200 * if another CPU could re-list_add() it.
201 */
202static inline int list_empty_careful(const struct list_head *head)
203{
204 struct list_head *next = head->next;
205 return (next == head) && (next == head->prev);
206}
此处函数的作用并不十分理解,对于绿色注释说明部分的Description和NOTE部分也是一知半解。单纯地翻一下NOTE部分:如果没有经过同步化处理,那么如果要达到安全地使用list_empty_careful这个函数必须限定当前能对指定节点发生的操作仅仅为list_del_init(),比如当一个CPU对它进行add操作的时候不能使用该函数。
该函数能达到的效果是检查链表是否为空,并且检测是否有CPU在修改当前指定节点的prev和next指针。
这里引用一段解释,来自杨沙洲:
“Linux链表另行提供了一个list_empty_careful()宏,它同时判断头指针的next和prev,仅当两者都指向自己时才返回真。这主要是为了应付另一个cpu正在处理同一个链表而造成next、prev不一致的情况。但代码注释也承认,这一安全保障能力有限:除非其他cpu的链表操作只有list_del_init(),否则仍然不能保证安全,也就是说,还是需要加锁保护。”
判断链表是否只有唯一的一个节点
208/**
209 * list_is_singular - tests whether a list has just one entry.
210 * @head: the list to test.
211 */
212static inline int list_is_singular(const struct list_head *head)
213{
214 return !list_empty(head) && (head->next == head->prev);
215}
空表并不是一个节点都没有,唯一的节点也不是指只有一个节点,具体看函数代码我们便可以了解。当一个节点指针被执行LIST_HEAD了以后,它的prev和next指针都指向自身,这便称为空表;而如果它的prev和next指针都指向仅有的第二个节点,那么它便称为仅有一个节点。
链表的切割
217static inline void __list_cut_position(struct list_head *list,
218 struct list_head *head, struct list_head *entry)
219{
220 struct list_head *new_first = entry->next;
221 list->next = head->next;
222 list->next->prev = list;
223 list->prev = entry;
224 entry->next = list;
225 head->next = new_first;
226 new_first->prev = head;
227}
228
229/**
230 * list_cut_position - cut a list into two
231 * @list: a new list to add all removed entries
232 * @head: a list with entries
233 * @entry: an entry within head, could be the head itself
234 * and if so we won’t cut the list
235 *
236 * This helper moves the initial part of @head, up to and
237 * including @entry, from @head to @list. You should
238 * pass on @entry an element you know is on @head. @list
239 * should be an empty list or a list you do not care about
240 * losing its data.
241 *
242 */
243static inline void list_cut_position(struct list_head *list,
244 struct list_head *head, struct list_head *entry)
245{
246 if (list_empty(head))
247 return;
248 if (list_is_singular(head) &&
249 (head->next != entry && head != entry))
250 return;
251 if (entry == head)
252 INIT_LIST_HEAD(list);
253 else
254 __list_cut_position(list, head, entry);
255}
这里有三个参数,list,head,entry。
假设原先有链表:head <-> node1 <-> node2 <-> node3 <-> entry <-> node4 <-> head
那么最后会得到链表1:head <-> node4 <-> head 和链表2:list <-> node1 <-> node2 <-> node3 <-> entry <-> list。
这里最好自己画图模拟一下。
链表的合并
257static inline void __list_splice(const struct list_head *list,
258 struct list_head *prev,
259 struct list_head *next)
260{
261 struct list_head *first = list->next;
262 struct list_head *last = list->prev;
263
264 first->prev = prev;
265 prev->next = first;
266
267 last->next = next;
268 next->prev = last;
269}
假设有两条链表:head <-> node1 <-> node2 <-> node3 <-> head
和:last <-> list <-> first
那么合并的结果是取代了head:last <-> list <-> first <-> node1 <-> node2 <-> node3 <-> last
271/**
272 * list_splice - join two lists, this is designed for stacks
273 * @list: the new list to add.
274 * @head: the place to add it in the first list.
275 */
276static inline void list_splice(const struct list_head *list,
277 struct list_head *head)
278{
279 if (!list_empty(list))
280 __list_splice(list, head, head->next);
281}
282
283/**
284 * list_splice_tail - join two lists, each list being a queue
285 * @list: the new list to add.
286 * @head: the place to add it in the first list.
287 */
288static inline void list_splice_tail(struct list_head *list,
289 struct list_head *head)
290{
291 if (!list_empty(list))
292 __list_splice(list, head->prev, head);
293}
294
295/**
296 * list_splice_init - join two lists and reinitialise the emptied list.
297 * @list: the new list to add.
298 * @head: the place to add it in the first list.
299 *
300 * The list at @list is reinitialised
301 */
302static inline void list_splice_init(struct list_head *list,
303 struct list_head *head)
304{
305 if (!list_empty(list)) {
306 __list_splice(list, head, head->next);
307 INIT_LIST_HEAD(list);
308 }
309}
310
311/**
312 * list_splice_tail_init - join two lists and reinitialise the emptied list
313 * @list: the new list to add.
314 * @head: the place to add it in the first list.
315 *
316 * Each of the lists is a queue.
317 * The list at @list is reinitialised
318 */
319static inline void list_splice_tail_init(struct list_head *list,
320 struct list_head *head)
321{
322 if (!list_empty(list)) {
323 __list_splice(list, head->prev, head);
324 INIT_LIST_HEAD(list);
325 }
326}
以下的合并函数都是调用第一个合并内联函数__list_splice,区别只在于合并取代的位置以及是否对空出来的head进行初始化,即调用INIT_LIST_HEAD等宏。