当前位置:   article > 正文

Linux 内核链表 list.h 的使用_如何引用linux内核的list.h库函数

如何引用linux内核的list.h库函数

C 语言本身并不自带集合(Collection)工具,当我们需要把结构体(struct)实例串联起来时,就需要在结构体内声明指向下一实例的指针,构成所谓的“链表”。而为了实现对链表的操作,我们需要另外实现一系列的函数,例如添加、删除、搜索、复制等等。而利用 Kernel 源代码中自带的 list.h,则可以方便地实现任意类型结构体的串联。

编程需求

假设我有一个表示学生资料的结构体:

  1. #define MAX_STRING_LENGTH 50
  2. typedef struct student {
  3. char first_name[MAX_STRING_LENGTH];
  4. char last_name[MAX_STRING_LENGTH];
  5. unsigned int age;
  6. } student_t;

传统的做法,当我们需要将一系列学生的数据串联起来,那我们需要在该结构体内部添加一枚指针:

  1. typedef struct student {
  2. char first_name[MAX_STRING_LENGTH];
  3. char last_name[MAX_STRING_LENGTH];
  4. unsigned int age;
  5. struct student *next; /* Look at dis ;p */
  6. } student_t;

几乎每位 C 语言学习者都有在教科书中见过此类实现方法。但是这样做的缺点是:我们需要额外编写一系列函数,实现对该类型链表的操作。然而,稍微复杂点的项目内,有个十几个结构体那是很平常的事情。如果我们想为它们都实现链表功能,那我们就需要为每个类型的结构体编写一套函数,然后我们就累 shi 了。

有没有一种更为通用的办法呢?不需要顾及结构体本身的类型,就可以简简单单地把它们串起来。有点类似 Java 中的 LinkedList,如果我需要把一堆 Student 类的对象管理起来,那就很简单:

LinkedList<Student> lstStudents = new LinkedList<Student>();

完事儿!接着直接把对象往 lstStudents 里面放就可以了。

list.h 简介

Linux 内核的源代码中有一个工具头文件 list.h,里面定义了一系列的宏(macro),帮助我们实现对任意类型结构体的串联。然而原始版本的 list.h 是供内核使用的,并不能直接被使用在用户空间(user space)的程序内。好在有网友对其进行了改写,使得其可以被使用在一般应用程序内。因为博客系统的限制,我无法将源代码一并贴上,大家可以自行下载:list.h 。较之 Github 上最新版的 list.h,该修改版提供的宏不是很全面,你可以根据自己的需要,从 Github 摘取、添加新宏。

list.h 的使用

为了利用 list.h 实现链表功能,首先我们需要对我们的结构体做一点小小的改动:

  1. #include "list.h"
  2. typedef struct student {
  3. char first_name[MAX_STRING_LENGTH];
  4. char last_name[MAX_STRING_LENGTH];
  5. unsigned int age;
  6. struct list_head node_student;
  7. } student_t;

首先毫无悬念的,我们需要将 list.h 包含到我们的程序,接着在结构体内,我们添加一个类型为 struct list_head 的字段
node_student。这个字段就像是链条上的环扣,一环一环地将所有实例串联起来。接下去我们需要一个函数,来创建该结构体的实例:

  1. student_t *make_student(const char *fn, const char *ln, unsigned int a) {
  2. student_t *stu = NULL;
  3. if ((stu = calloc(1, sizeof(struct student))) == NULL) {
  4. return NULL; /* Failed to allocate memory. */
  5. }
  6. if (strlen(fn) > (MAX_STRING_LENGTH - 1)) {
  7. return NULL; /* First name too long. */
  8. }
  9. if (strlen(ln) > (MAX_STRING_LENGTH - 1)) {
  10. return NULL; /* Last name too long. */
  11. }
  12. strcpy(stu->first_name, fn);
  13. strcpy(stu->last_name, ln);
  14. stu->age = a;
  15. return stu;
  16. }

函数代码比较简单,就不费口舌解释了。

添加元素

现在在我们的 main 函数内,我们将创建一系列 student_t 结构体的实例,并把它们串联起来:

  1. struct list_head class;
  2. INIT_LIST_HEAD(&class);
  3. student_t *stu = NULL;
  4. /* Create students. */
  5. if ((stu = make_student("Pierre", "Dupont", 16)) == NULL) {
  6. fprintf(stderr, "Failed to create Pierre.\n");
  7. return -1;
  8. }
  9. list_add_tail(&stu->node_student, &class);
  10. if ((stu = make_student("Hugot", "Badeaux", 18)) == NULL) {
  11. fprintf(stderr, "Failed to create Hugot.\n");
  12. return -1;
  13. }
  14. list_add_tail(&stu->node_student, &class);
  15. if ((stu = make_student("Celine", "Brousseau", 17)) == NULL) {
  16. fprintf(stderr, "Failed to create Celine.\n");
  17. return -1;
  18. }
  19. list_add_tail(&stu->node_student, &class);

这里我们首先创建一个链表 class,并用宏 INIT_LIST_HEAD 对其进行初始化。紧接着我们创建三名学生,分别叫:Pierre.Dupont,Hugot.Badeaux 和 Celine.Brousseau。每创建一名学生,我们就用宏 list_add_tail,将其添加到链表 class 内。list_add_tail 取两个参数,首先是结构体内用于串联实例的“环扣”node_student 的指针,其次是链表本身的指针,即 class。

链表的遍历

完成对链表的初始化之后,我们试着打印出链表内所有的学生信息:

  1. /* Print all students in class. */
  2. printf("All the students in class.\n");
  3. list_for_each_entry(stu, &class, node_student) {
  4. printf("First name: %s\n", stu->first_name);
  5. printf("Last name: %s\n", stu->last_name);
  6. printf("Age: %u\n\n", stu->age);
  7. }

对链表的遍历是通过宏 list_for_each_entry 来实现的,它取三个参数,分别是:一个结构体类型的指针,链表的指针,以及结构内“环扣”的名称,即 node_student。程序编译时,该宏会被替换成一个 for 循环,遍历链表内所有的元素,并且打印在终端上。

导出链表

现在学校组织一次春游,为此我们利用宏 LIST_HEAD 添加了另一个新的链表 bus。使用 LIST_HEAD 来创建空链表相对简单,不需要先声明,再用 INIT_LIST_HEAD 进行初始化。现在,我们需要把班级上所有的学生都移到公车 bus 内:

  1. LIST_HEAD(bus);
  2. /* Moving all students into bus. */
  3. printf("Moving all the students into the bus.\n");
  4. list_splice_init(&class, &bus);
  5. if (list_empty(&class)) {
  6. printf("No more student in class.\n");
  7. }
  8. printf("\n");
  9. /* Print all student in bus. */
  10. list_for_each_entry(stu, &bus, node_student) {
  11. printf("%s %s (%u) is in the bus.\n", stu->first_name, stu->last_name, stu->age);
  12. }
  13. printf("\n");

list_splice_init 取两个参数,分别为原链表指针和新链表指针。使用该宏之后,class 链表内的所有元素就会被导出到 bus 链表内。接着我们再用宏 list_empty 测试链表 class 是否为空。顺利完成对学生的移动之后,我们再一次使用 list_for_each_entry,逐一打印出新链表 bus 内的所有学生。不出意外的话,我们会发现 class 链表已为空,且所有学生都被成功转移到了新链表 bus 内。

删除元素

新的麻烦来了,在校车即将出发之际,妹子 Celine 突然决定不去了,要回家。那我们只能将 Celine 从校车中移出,然后再重新清点学生人数。

  1. student_t *tmp = NULL;
  2. /* Celine wanna go home. */
  3. printf("Celine wants to go home, remove her.\n");
  4. list_for_each_entry_safe(stu, tmp, &bus, node_student) {
  5. if (strcmp(stu->first_name, "Celine") == 0) {
  6. list_del(&stu->node_student);
  7. free(stu);
  8. }
  9. }
  10. printf("\n");
  11. /* Print remaining students in bus. */
  12. printf("Remaining students in bus.\n");
  13. list_for_each_entry(stu, &bus, node_student) {
  14. printf("%s %s (%u) is in the bus.\n", stu->first_name, stu->last_name, stu->age);
  15. }
  16. printf("\n");

我们首先用宏 list_for_each_entry_safe 遍历链表 bus 内的所有学生,当我们找到 Celine 的时候,则调用宏 list_del 将其从链表内删除。list_del 只取一个参数,即目标元素内“环扣”的指针。此外 list_for_each_entrylist_for_each_entry_safe 的唯一区别在于,list_for_each_entry_safe 可以在遍历的过程当中删除链表内的元素,且不会造成错误。较之 list_for_each_entrylist_for_each_entry_safe 需多取一个参数 tmp,其同样为结构体类型的指针,用于在遍历过程,临时保存链表元素。在删除 Celine 之后,我们发现 Pierre 和 Hugot 还老老实实地坐在校车内。

程序的最后,校车成功抵达目的地,我们将所有剩余的学生(Pierre 和 Hugot)从校车内移出,并释放系统资源:

  1. /* End of demo. */
  2. printf("End of demo, free all resources.\n");
  3. list_for_each_entry_safe(stu, tmp, &bus, node_student) {
  4. printf("Removing student: %s %s\n", stu->first_name, stu->last_name);
  5. list_del(&stu->node_student);
  6. free(stu);
  7. }
  8. return 0;

编译完成之后,试着运行程序,终端输出为:

  1. All the students in class.
  2. First name: Pierre
  3. Last name: Dupont
  4. Age: 16
  5. First name: Hugot
  6. Last name: Badeaux
  7. Age: 18
  8. First name: Celine
  9. Last name: Brousseau
  10. Age: 17
  11. Moving all the students into the bus.
  12. No more student in class.
  13. Pierre Dupont (16) is in the bus.
  14. Hugot Badeaux (18) is in the bus.
  15. Celine Brousseau (17) is in the bus.
  16. Celine wants to go home, remove her.
  17. Remaining students in bus.
  18. Pierre Dupont (16) is in the bus.
  19. Hugot Badeaux (18) is in the bus.
  20. End of demo, free all resources.
  21. Removing student: Pierre Dupont
  22. Removing student: Hugot Badeaux

一切正如我们预期的那样,我们实现了对链表的添加、遍历、导出和删除。

注意事项

最后,使用 list.h 时需要注意代码的可读性,先看看下面这个例子:

  1. typedef struct school {
  2. struct list_head list_students;
  3. struct list_head list_teachers;
  4. struct list_head list_guards;
  5. struct list_head list_classrooms;
  6. struct list_head list_bus;
  7. } school_t;

这个结构体的本意很明显,就是想包含一所学校内所有的人员和器材等等。但是单凭这样一个结构体,我们无法知道每一个链表内元素的具体类型。尤其是当你把一个项目丢给新接手的开发人员时,他看到这样一个结构体,会比较头疼。而且很多项目内,结构体的名字并非都那么浅显易懂。

当他想使用宏 list_for_each_entry 或者 list_for_each_entry_safe 遍历链表时,如果没有具体注解,他甚至不知道该用什么结构体类型。所以,一定要有详细的注解:

  1. typedef struct school {
  2. struct list_head list_students; /* struct student */
  3. struct list_head list_teachers; /* struct teacher */
  4. struct list_head list_guards; /* struct guard */
  5. struct list_head list_classrooms; /* struct classroom */
  6. struct list_head list_bus; /* struct bus */
  7. } s

综上所述,我个人的意见:list.h 很好用,但是要慎用。

简单总结

  1. typedef struct student{
  2. char first_name[MAX_STRING_LENTH];
  3. char last_name[MAX_STRING_LENTGH];
  4. unsigned int age;
  5. struct list_head student_node;
  6. } student_t;
  7. //定义链表方法1: class
  8. student_t *class = NULL;
  9. struct list_head class;
  10. INIT_LIST_HEAD(&class);
  11. //定义链表方法2: bus
  12. student_t *bus = NULL;
  13. LIST_HEAD(bus);

原因如下:

  1. #define LIST_HEAD_INIT(name) { &(name), &(name) }
  2. #define LIST_HEAD(name) struct list_head name = LIST_HEAD_INIT(name)

MISC

Q1

当然,如果你想在用户态使用list.h 可能不行, 用户态只能使用/usr/include/ 下的lib

所以,如果你想在用户态使用list.h ,需要保证有 /usr/include/linux/list.h

  1. #ll /usr/include/linux/list.h
  2. ls: cannot access /usr/include/linux/list.h: No such file or directory

如果你find到了, 你可以这样:

  1. cp -r /usr/include/linux{,.bak}
  2. #ln -sf /usr/src/kernels/3.10.0-327.xxxxxx.x86_64/include/linux /usr/include/linux

但是,这不是一种科学的方法, 因为你还会遇到很多依赖:

  1. #gcc -o stu stu.c -D__KERNEL__ -DMODULE -O -Wall
  2. In file included from /usr/include/linux/list.h:4:0,
  3. from stu.c:1:
  4. /usr/include/linux/types.h:5:30: fatal error: uapi/linux/types.h: No such file or directory
  5. #include <uapi/linux/types.h>
  6. ^
  7. compilation terminated.

最终办法,在自己的project里放一个list.h : http://www.cnblogs.com/muahao/p/8109733.html

Q2

  1. #cat simple_student.c
  2. #include "list.h"
  3. #include <stdio.h>
  4. #include <stdlib.h>
  5. #include <string.h>
  6. #define MAX_LENGTH 100
  7. typedef struct student {
  8. char first_name[MAX_LENGTH];
  9. char last_name[MAX_LENGTH];
  10. unsigned int age;
  11. struct list_head student_node;
  12. } student_t;
  13. struct list_head class;
  14. INIT_LIST_HEAD(&class);
  15. //LIST_HEAD(class);
  16. student_t *stu = NULL;
  17. student_t *make_student (const char *fn, const char *ln, unsigned int a) {
  18. student_t *stu = NULL;
  19. if ((stu = calloc(1, sizeof(struct student))) == NULL) {
  20. return NULL;
  21. }
  22. if (strlen(fn) > (MAX_LENGTH - 1)) {
  23. return NULL;
  24. }
  25. if (strlen(ln) > (MAX_LENGTH - 1)) {
  26. return NULL;
  27. }
  28. strcpy(stu->first_name, fn);
  29. strcpy(stu->last_name, ln);
  30. stu->age = a;
  31. return stu;
  32. }
  33. int main(){
  34. if ((stu = make_student("ahao","mu",22)) == NULL) {
  35. fprintf(stderr,"Failed to create muahao\n");
  36. return -1;
  37. }
  38. }
  1. 方法1
  2. struct list_head class;
  3. INIT_LIST_HEAD(&class);
  4. 方法2
  5. LIST_HEAD(class);

在这里,我总是,使用方式1 的时候会提示如下错误:

  1. #gcc -o simple_student simple_student.c
  2. simple_student.c:16:16: error: expected declaration specifiers or ‘...’ before&’ token
  3. INIT_LIST_HEAD(&class);
  4. ^

附录

  1. #cat student.c
  2. #include "list.h"
  3. #include <stdlib.h>
  4. #include <string.h>
  5. #include <stdio.h>
  6. #define MAX_LENGTH 100
  7. typedef struct student {
  8. char first_name[MAX_LENGTH];
  9. char last_name[MAX_LENGTH];
  10. unsigned int age;
  11. struct list_head node_student;
  12. } student_t;
  13. student_t *make_student (const char *fn, const char *ln, unsigned int a) {
  14. student_t *stu = NULL;
  15. if ((stu = calloc(1, sizeof(struct student))) == NULL) {
  16. return NULL;
  17. }
  18. if (strlen(fn) > (MAX_LENGTH - 1)) {
  19. return NULL;
  20. }
  21. if (strlen(ln) > (MAX_LENGTH - 1)) {
  22. return NULL;
  23. }
  24. strcpy(stu->first_name, fn);
  25. strcpy(stu->last_name, ln);
  26. stu->age = a;
  27. return stu;
  28. }
  29. int main() {
  30. // Method 1
  31. //struct list_head class;
  32. //INIT_LIST_HEAD(&class);
  33. //Method 2
  34. LIST_HEAD(class);
  35. student_t *stu = NULL;
  36. //create student
  37. if ((stu = make_student("ahao","mu",22)) == NULL) {
  38. fprintf(stderr,"Failed to create muahao\n");
  39. return -1;
  40. }
  41. list_add_tail(&stu->node_student, &class);
  42. if ((stu = make_student("lianjie", "li", 23)) == NULL) {
  43. fprintf(stderr,"Failed to create li tom\n");
  44. return -1;
  45. }
  46. list_add_tail(&stu->node_student, &class);
  47. if ((stu = make_student("xiaolong", "li", 12)) == NULL) {
  48. fprintf(stderr, "Failed to create lixuehua\n");
  49. return -1;
  50. }
  51. list_add_tail(&stu->node_student, &class);
  52. / Print all students
  53. printf("------print all students-----\n");
  54. list_for_each_entry(stu, &class, node_student) {
  55. printf("First name:%s\n", stu->first_name);
  56. printf("Last name:%s\n", stu->last_name);
  57. printf("Age:%d\n", stu->age);
  58. }
  59. list bus
  60. LIST_HEAD(bus);
  61. printf("Moving all students to bus;\n");
  62. list_splice_init(&class, &bus);
  63. if (list_empty(&class)) {
  64. printf("No students in class\n");
  65. }
  66. printf("Print all bus students\n");
  67. list_for_each_entry(stu, &bus, node_student) {
  68. printf("%s %s %d", stu->first_name, stu->last_name, stu->age);
  69. }
  70. student_t *tmp = NULL;
  71. printf("muahao do not want go\n");
  72. list_for_each_entry_safe(stu, tmp, &bus, node_student) {
  73. if (strcmp(stu->first_name, "mu") == 0) {
  74. list_del(&stu->node_student);
  75. free(stu);
  76. }
  77. }
  78. printf("After muahao leave,students are: \n");
  79. list_for_each_entry(stu, &bus, node_student) {
  80. printf("%s %s %d\n",stu->first_name, stu->last_name, stu->age);
  81. }
  82. // end begin clean all students;
  83. list_for_each_entry_safe(stu, tmp, &bus, node_student) {
  84. printf("Removing students: %s %s \n", stu->first_name, stu->last_name);
  85. list_del(&stu->node_student);
  86. free(stu);
  87. }
  88. return 0;
  89. }

 

  1. #cat list.h
  2. /*
  3. * Copyright (C) 2012 Fusion-io. All rights reserved.
  4. *
  5. * This header was taken from the Linux kernel
  6. *
  7. * This program is free software; you can redistribute it and/or
  8. * modify it under the terms of the GNU General Public
  9. * License v2 as published by the Free Software Foundation.
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  14. * General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public
  17. * License along with this program; if not, write to the
  18. * Free Software Foundation, Inc.,
  19. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  20. */
  21. #ifndef _LINUX_LIST_H
  22. #define _LINUX_LIST_H
  23. #define LIST_POISON1 ((void *) 0x00100100)
  24. #define LIST_POISON2 ((void *) 0x00200200)
  25. #undef offsetof
  26. #ifdef __compiler_offsetof
  27. #define offsetof(TYPE,MEMBER) __compiler_offsetof(TYPE,MEMBER)
  28. #else
  29. #define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
  30. #endif
  31. #define container_of(ptr, type, member) ({ \
  32. const typeof( ((type *)0)->member ) *__mptr = (ptr); \
  33. (type *)( (char *)__mptr - offsetof(type,member) );})
  34. /*
  35. * Simple doubly linked list implementation.
  36. *
  37. * Some of the internal functions ("__xxx") are useful when
  38. * manipulating whole lists rather than single entries, as
  39. * sometimes we already know the next/prev entries and we can
  40. * generate better code by using them directly rather than
  41. * using the generic single-entry routines.
  42. */
  43. struct list_head {
  44. struct list_head *next, *prev;
  45. };
  46. #define LIST_HEAD_INIT(name) { &(name), &(name) }
  47. #define LIST_HEAD(name) \
  48. struct list_head name = LIST_HEAD_INIT(name)
  49. static inline void INIT_LIST_HEAD(struct list_head *list)
  50. {
  51. list->next = list;
  52. list->prev = list;
  53. }
  54. /*
  55. * Insert a new entry between two known consecutive entries.
  56. *
  57. * This is only for internal list manipulation where we know
  58. * the prev/next entries already!
  59. */
  60. #ifndef CONFIG_DEBUG_LIST
  61. static inline void __list_add(struct list_head *new,
  62. struct list_head *prev,
  63. struct list_head *next)
  64. {
  65. next->prev = new;
  66. new->next = next;
  67. new->prev = prev;
  68. prev->next = new;
  69. }
  70. #else
  71. extern void __list_add(struct list_head *new,
  72. struct list_head *prev,
  73. struct list_head *next);
  74. #endif
  75. /**
  76. * list_add - add a new entry
  77. * @new: new entry to be added
  78. * @head: list head to add it after
  79. *
  80. * Insert a new entry after the specified head.
  81. * This is good for implementing stacks.
  82. */
  83. #ifndef CONFIG_DEBUG_LIST
  84. static inline void list_add(struct list_head *new, struct list_head *head)
  85. {
  86. __list_add(new, head, head->next);
  87. }
  88. #else
  89. extern void list_add(struct list_head *new, struct list_head *head);
  90. #endif
  91. /**
  92. * list_add_tail - add a new entry
  93. * @new: new entry to be added
  94. * @head: list head to add it before
  95. *
  96. * Insert a new entry before the specified head.
  97. * This is useful for implementing queues.
  98. */
  99. static inline void list_add_tail(struct list_head *new, struct list_head *head)
  100. {
  101. __list_add(new, head->prev, head);
  102. }
  103. /*
  104. * Delete a list entry by making the prev/next entries
  105. * point to each other.
  106. *
  107. * This is only for internal list manipulation where we know
  108. * the prev/next entries already!
  109. */
  110. static inline void __list_del(struct list_head * prev, struct list_head * next)
  111. {
  112. next->prev = prev;
  113. prev->next = next;
  114. }
  115. /**
  116. * list_del - deletes entry from list.
  117. * @entry: the element to delete from the list.
  118. * Note: list_empty on entry does not return true after this, the entry is
  119. * in an undefined state.
  120. */
  121. #ifndef CONFIG_DEBUG_LIST
  122. static inline void list_del(struct list_head *entry)
  123. {
  124. __list_del(entry->prev, entry->next);
  125. entry->next = LIST_POISON1;
  126. entry->prev = LIST_POISON2;
  127. }
  128. #else
  129. extern void list_del(struct list_head *entry);
  130. #endif
  131. /**
  132. * list_replace - replace old entry by new one
  133. * @old : the element to be replaced
  134. * @new : the new element to insert
  135. * Note: if 'old' was empty, it will be overwritten.
  136. */
  137. static inline void list_replace(struct list_head *old,
  138. struct list_head *new)
  139. {
  140. new->next = old->next;
  141. new->next->prev = new;
  142. new->prev = old->prev;
  143. new->prev->next = new;
  144. }
  145. static inline void list_replace_init(struct list_head *old,
  146. struct list_head *new)
  147. {
  148. list_replace(old, new);
  149. INIT_LIST_HEAD(old);
  150. }
  151. /**
  152. * list_del_init - deletes entry from list and reinitialize it.
  153. * @entry: the element to delete from the list.
  154. */
  155. static inline void list_del_init(struct list_head *entry)
  156. {
  157. __list_del(entry->prev, entry->next);
  158. INIT_LIST_HEAD(entry);
  159. }
  160. /**
  161. * list_move - delete from one list and add as another's head
  162. * @list: the entry to move
  163. * @head: the head that will precede our entry
  164. */
  165. static inline void list_move(struct list_head *list, struct list_head *head)
  166. {
  167. __list_del(list->prev, list->next);
  168. list_add(list, head);
  169. }
  170. /**
  171. * list_move_tail - delete from one list and add as another's tail
  172. * @list: the entry to move
  173. * @head: the head that will follow our entry
  174. */
  175. static inline void list_move_tail(struct list_head *list,
  176. struct list_head *head)
  177. {
  178. __list_del(list->prev, list->next);
  179. list_add_tail(list, head);
  180. }
  181. /**
  182. * list_is_last - tests whether @list is the last entry in list @head
  183. * @list: the entry to test
  184. * @head: the head of the list
  185. */
  186. static inline int list_is_last(const struct list_head *list,
  187. const struct list_head *head)
  188. {
  189. return list->next == head;
  190. }
  191. /**
  192. * list_empty - tests whether a list is empty
  193. * @head: the list to test.
  194. */
  195. static inline int list_empty(const struct list_head *head)
  196. {
  197. return head->next == head;
  198. }
  199. /**
  200. * list_empty_careful - tests whether a list is empty and not being modified
  201. * @head: the list to test
  202. *
  203. * Description:
  204. * tests whether a list is empty _and_ checks that no other CPU might be
  205. * in the process of modifying either member (next or prev)
  206. *
  207. * NOTE: using list_empty_careful() without synchronization
  208. * can only be safe if the only activity that can happen
  209. * to the list entry is list_del_init(). Eg. it cannot be used
  210. * if another CPU could re-list_add() it.
  211. */
  212. static inline int list_empty_careful(const struct list_head *head)
  213. {
  214. struct list_head *next = head->next;
  215. return (next == head) && (next == head->prev);
  216. }
  217. static inline void __list_splice(struct list_head *list,
  218. struct list_head *head)
  219. {
  220. struct list_head *first = list->next;
  221. struct list_head *last = list->prev;
  222. struct list_head *at = head->next;
  223. first->prev = head;
  224. head->next = first;
  225. last->next = at;
  226. at->prev = last;
  227. }
  228. /**
  229. * list_splice - join two lists
  230. * @list: the new list to add.
  231. * @head: the place to add it in the first list.
  232. */
  233. static inline void list_splice(struct list_head *list, struct list_head *head)
  234. {
  235. if (!list_empty(list))
  236. __list_splice(list, head);
  237. }
  238. /**
  239. * list_splice_init - join two lists and reinitialise the emptied list.
  240. * @list: the new list to add.
  241. * @head: the place to add it in the first list.
  242. *
  243. * The list at @list is reinitialised
  244. */
  245. static inline void list_splice_init(struct list_head *list,
  246. struct list_head *head)
  247. {
  248. if (!list_empty(list)) {
  249. __list_splice(list, head);
  250. INIT_LIST_HEAD(list);
  251. }
  252. }
  253. /**
  254. * list_entry - get the struct for this entry
  255. * @ptr: the &struct list_head pointer.
  256. * @type: the type of the struct this is embedded in.
  257. * @member: the name of the list_struct within the struct.
  258. */
  259. #define list_entry(ptr, type, member) \
  260. container_of(ptr, type, member)
  261. /**
  262. * list_for_each - iterate over a list
  263. * @pos: the &struct list_head to use as a loop cursor.
  264. * @head: the head for your list.
  265. */
  266. #define list_for_each(pos, head) \
  267. for (pos = (head)->next; pos != (head); \
  268. pos = pos->next)
  269. /**
  270. * __list_for_each - iterate over a list
  271. * @pos: the &struct list_head to use as a loop cursor.
  272. * @head: the head for your list.
  273. *
  274. * This variant differs from list_for_each() in that it's the
  275. * simplest possible list iteration code, no prefetching is done.
  276. * Use this for code that knows the list to be very short (empty
  277. * or 1 entry) most of the time.
  278. */
  279. #define __list_for_each(pos, head) \
  280. for (pos = (head)->next; pos != (head); pos = pos->next)
  281. /**
  282. * list_for_each_prev - iterate over a list backwards
  283. * @pos: the &struct list_head to use as a loop cursor.
  284. * @head: the head for your list.
  285. */
  286. #define list_for_each_prev(pos, head) \
  287. for (pos = (head)->prev; pos != (head); \
  288. pos = pos->prev)
  289. /**
  290. * list_for_each_safe - iterate over a list safe against removal of list entry
  291. * @pos: the &struct list_head to use as a loop cursor.
  292. * @n: another &struct list_head to use as temporary storage
  293. * @head: the head for your list.
  294. */
  295. #define list_for_each_safe(pos, n, head) \
  296. for (pos = (head)->next, n = pos->next; pos != (head); \
  297. pos = n, n = pos->next)
  298. /**
  299. * list_for_each_entry - iterate over list of given type
  300. * @pos: the type * to use as a loop cursor.
  301. * @head: the head for your list.
  302. * @member: the name of the list_struct within the struct.
  303. */
  304. #define list_for_each_entry(pos, head, member) \
  305. for (pos = list_entry((head)->next, typeof(*pos), member); \
  306. &pos->member != (head); \
  307. pos = list_entry(pos->member.next, typeof(*pos), member))
  308. /**
  309. * list_for_each_entry_reverse - iterate backwards over list of given type.
  310. * @pos: the type * to use as a loop cursor.
  311. * @head: the head for your list.
  312. * @member: the name of the list_struct within the struct.
  313. */
  314. #define list_for_each_entry_reverse(pos, head, member) \
  315. for (pos = list_entry((head)->prev, typeof(*pos), member); \
  316. &pos->member != (head); \
  317. pos = list_entry(pos->member.prev, typeof(*pos), member))
  318. /**
  319. * list_prepare_entry - prepare a pos entry for use in list_for_each_entry_continue
  320. * @pos: the type * to use as a start point
  321. * @head: the head of the list
  322. * @member: the name of the list_struct within the struct.
  323. *
  324. * Prepares a pos entry for use as a start point in list_for_each_entry_continue.
  325. */
  326. #define list_prepare_entry(pos, head, member) \
  327. ((pos) ? : list_entry(head, typeof(*pos), member))
  328. /**
  329. * list_for_each_entry_continue - continue iteration over list of given type
  330. * @pos: the type * to use as a loop cursor.
  331. * @head: the head for your list.
  332. * @member: the name of the list_struct within the struct.
  333. *
  334. * Continue to iterate over list of given type, continuing after
  335. * the current position.
  336. */
  337. #define list_for_each_entry_continue(pos, head, member) \
  338. for (pos = list_entry(pos->member.next, typeof(*pos), member); \
  339. &pos->member != (head); \
  340. pos = list_entry(pos->member.next, typeof(*pos), member))
  341. /**
  342. * list_for_each_entry_from - iterate over list of given type from the current point
  343. * @pos: the type * to use as a loop cursor.
  344. * @head: the head for your list.
  345. * @member: the name of the list_struct within the struct.
  346. *
  347. * Iterate over list of given type, continuing from current position.
  348. */
  349. #define list_for_each_entry_from(pos, head, member) \
  350. for (; &pos->member != (head); \
  351. pos = list_entry(pos->member.next, typeof(*pos), member))
  352. /**
  353. * list_for_each_entry_safe - iterate over list of given type safe against removal of list entry
  354. * @pos: the type * to use as a loop cursor.
  355. * @n: another type * to use as temporary storage
  356. * @head: the head for your list.
  357. * @member: the name of the list_struct within the struct.
  358. */
  359. #define list_for_each_entry_safe(pos, n, head, member) \
  360. for (pos = list_entry((head)->next, typeof(*pos), member), \
  361. n = list_entry(pos->member.next, typeof(*pos), member); \
  362. &pos->member != (head); \
  363. pos = n, n = list_entry(n->member.next, typeof(*n), member))
  364. /**
  365. * list_for_each_entry_safe_continue
  366. * @pos: the type * to use as a loop cursor.
  367. * @n: another type * to use as temporary storage
  368. * @head: the head for your list.
  369. * @member: the name of the list_struct within the struct.
  370. *
  371. * Iterate over list of given type, continuing after current point,
  372. * safe against removal of list entry.
  373. */
  374. #define list_for_each_entry_safe_continue(pos, n, head, member) \
  375. for (pos = list_entry(pos->member.next, typeof(*pos), member), \
  376. n = list_entry(pos->member.next, typeof(*pos), member); \
  377. &pos->member != (head); \
  378. pos = n, n = list_entry(n->member.next, typeof(*n), member))
  379. /**
  380. * list_for_each_entry_safe_from
  381. * @pos: the type * to use as a loop cursor.
  382. * @n: another type * to use as temporary storage
  383. * @head: the head for your list.
  384. * @member: the name of the list_struct within the struct.
  385. *
  386. * Iterate over list of given type from current point, safe against
  387. * removal of list entry.
  388. */
  389. #define list_for_each_entry_safe_from(pos, n, head, member) \
  390. for (n = list_entry(pos->member.next, typeof(*pos), member); \
  391. &pos->member != (head); \
  392. pos = n, n = list_entry(n->member.next, typeof(*n), member))
  393. /**
  394. * list_for_each_entry_safe_reverse
  395. * @pos: the type * to use as a loop cursor.
  396. * @n: another type * to use as temporary storage
  397. * @head: the head for your list.
  398. * @member: the name of the list_struct within the struct.
  399. *
  400. * Iterate backwards over list of given type, safe against removal
  401. * of list entry.
  402. */
  403. #define list_for_each_entry_safe_reverse(pos, n, head, member) \
  404. for (pos = list_entry((head)->prev, typeof(*pos), member), \
  405. n = list_entry(pos->member.prev, typeof(*pos), member); \
  406. &pos->member != (head); \
  407. pos = n, n = list_entry(n->member.prev, typeof(*n), member))
  408. #endif

 

 

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/不正经/article/detail/128104
推荐阅读
相关标签
  

闽ICP备14008679号