Linux 內核鏈表 list.h 的使用


Linux 內核鏈表 list.h 的使用

C 語言本身並不自帶集合(Collection)工具,當我們需要把結構體(struct)實例串聯起來時,就需要在結構體內聲明指向下一實例的指針,構成所謂的“鏈表”。而為了實現對鏈表的操作,我們需要另外實現一系列的函數,例如添加、刪除、搜索、復制等等。而利用 Kernel 源代碼中自帶的 list.h,則可以方便地實現任意類型結構體的串聯。

編程需求

假設我有一個表示學生資料的結構體:

#define MAX_STRING_LENGTH 50

typedef struct student {
  char first_name[MAX_STRING_LENGTH];
  char last_name[MAX_STRING_LENGTH];
  unsigned int age;
} student_t;

傳統的做法,當我們需要將一系列學生的數據串聯起來,那我們需要在該結構體內部添加一枚指針:

typedef struct student {
  char first_name[MAX_STRING_LENGTH];
  char last_name[MAX_STRING_LENGTH];
  unsigned int age;
  struct student *next; /* Look at dis ;p */
} 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 實現鏈表功能,首先我們需要對我們的結構體做一點小小的改動:

#include "list.h"

typedef struct student {
  char first_name[MAX_STRING_LENGTH];
  char last_name[MAX_STRING_LENGTH];
  unsigned int age;
  struct list_head node_student;
} student_t;

首先毫無懸念的,我們需要將 list.h 包含到我們的程序,接着在結構體內,我們添加一個類型為 struct list_head 的字段
node_student。這個字段就像是鏈條上的環扣,一環一環地將所有實例串聯起來。接下去我們需要一個函數,來創建該結構體的實例:

student_t *make_student(const char *fn, const char *ln, unsigned int a) {
  student_t *stu = NULL;

  if ((stu = calloc(1, sizeof(struct student))) == NULL) {
    return NULL; /* Failed to allocate memory. */
  }
  if (strlen(fn) > (MAX_STRING_LENGTH - 1)) {
    return NULL; /* First name too long. */
  }
  if (strlen(ln) > (MAX_STRING_LENGTH - 1)) {
    return NULL; /* Last name too long. */
  }

  strcpy(stu->first_name, fn);
  strcpy(stu->last_name, ln);
  stu->age = a;
  return stu;
}

函數代碼比較簡單,就不費口舌解釋了。

添加元素

現在在我們的 main 函數內,我們將創建一系列 student_t 結構體的實例,並把它們串聯起來:

struct list_head class;
INIT_LIST_HEAD(&class);

student_t *stu = NULL;

/* Create students. */
if ((stu = make_student("Pierre", "Dupont", 16)) == NULL) {
  fprintf(stderr, "Failed to create Pierre.\n");
  return -1;
}
list_add_tail(&stu->node_student, &class);

if ((stu = make_student("Hugot", "Badeaux", 18)) == NULL) {
  fprintf(stderr, "Failed to create Hugot.\n");
  return -1;
}
list_add_tail(&stu->node_student, &class);

if ((stu = make_student("Celine", "Brousseau", 17)) == NULL) {
  fprintf(stderr, "Failed to create Celine.\n");
  return -1;
}
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。

鏈表的遍歷

完成對鏈表的初始化之后,我們試着打印出鏈表內所有的學生信息:

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

對鏈表的遍歷是通過宏 list_for_each_entry 來實現的,它取三個參數,分別是:一個結構體類型的指針,鏈表的指針,以及結構內“環扣”的名稱,即 node_student。程序編譯時,該宏會被替換成一個 for 循環,遍歷鏈表內所有的元素,並且打印在終端上。

導出鏈表

現在學校組織一次春游,為此我們利用宏 LIST_HEAD 添加了另一個新的鏈表 bus。使用 LIST_HEAD 來創建空鏈表相對簡單,不需要先聲明,再用 INIT_LIST_HEAD 進行初始化。現在,我們需要把班級上所有的學生都移到公車 bus 內:

LIST_HEAD(bus);

/* Moving all students into bus. */
printf("Moving all the students into the bus.\n");
list_splice_init(&class, &bus);
if (list_empty(&class)) {
  printf("No more student in class.\n");
}
printf("\n");
  
/* Print all student in bus. */
list_for_each_entry(stu, &bus, node_student) {
  printf("%s %s (%u) is in the bus.\n", stu->first_name, stu->last_name, stu->age);
}
printf("\n");

list_splice_init 取兩個參數,分別為原鏈表指針和新鏈表指針。使用該宏之后,class 鏈表內的所有元素就會被導出到 bus 鏈表內。接着我們再用宏 list_empty 測試鏈表 class 是否為空。順利完成對學生的移動之后,我們再一次使用 list_for_each_entry,逐一打印出新鏈表 bus 內的所有學生。不出意外的話,我們會發現 class 鏈表已為空,且所有學生都被成功轉移到了新鏈表 bus 內。

刪除元素

新的麻煩來了,在校車即將出發之際,妹子 Celine 突然決定不去了,要回家。那我們只能將 Celine 從校車中移出,然后再重新清點學生人數。

student_t *tmp = NULL;

/* Celine wanna go home. */
printf("Celine wants to go home, remove her.\n");
list_for_each_entry_safe(stu, tmp, &bus, node_student) {
  if (strcmp(stu->first_name, "Celine") == 0) {
    list_del(&stu->node_student);
    free(stu);
  }
}
printf("\n");

/* Print remaining students in bus. */
printf("Remaining students in bus.\n");
list_for_each_entry(stu, &bus, node_student) {
  printf("%s %s (%u) is in the bus.\n", stu->first_name, stu->last_name, stu->age);
}
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)從校車內移出,並釋放系統資源:

/* End of demo. */
printf("End of demo, free all resources.\n");
list_for_each_entry_safe(stu, tmp, &bus, node_student) {
  printf("Removing student: %s %s\n", stu->first_name, stu->last_name);
  list_del(&stu->node_student);
  free(stu);
}

return 0;

編譯完成之后,試着運行程序,終端輸出為:

All the students in class.
First name: Pierre
Last name: Dupont
Age: 16

First name: Hugot
Last name: Badeaux
Age: 18

First name: Celine
Last name: Brousseau
Age: 17

Moving all the students into the bus.
No more student in class.

Pierre Dupont (16) is in the bus.
Hugot Badeaux (18) is in the bus.
Celine Brousseau (17) is in the bus.

Celine wants to go home, remove her.

Remaining students in bus.
Pierre Dupont (16) is in the bus.
Hugot Badeaux (18) is in the bus.

End of demo, free all resources.
Removing student: Pierre Dupont
Removing student: Hugot Badeaux

一切正如我們預期的那樣,我們實現了對鏈表的添加、遍歷、導出和刪除。

注意事項

最后,使用 list.h 時需要注意代碼的可讀性,先看看下面這個例子:

typedef struct school {
  struct list_head list_students;
  struct list_head list_teachers;
  struct list_head list_guards;
  struct list_head list_classrooms;
  struct list_head list_bus;
} school_t;

這個結構體的本意很明顯,就是想包含一所學校內所有的人員和器材等等。但是單憑這樣一個結構體,我們無法知道每一個鏈表內元素的具體類型。尤其是當你把一個項目丟給新接手的開發人員時,他看到這樣一個結構體,會比較頭疼。而且很多項目內,結構體的名字並非都那么淺顯易懂。

當他想使用宏 list_for_each_entry 或者 list_for_each_entry_safe 遍歷鏈表時,如果沒有具體注解,他甚至不知道該用什么結構體類型。所以,一定要有詳細的注解:

typedef struct school {
  struct list_head list_students; /* struct student */
  struct list_head list_teachers; /* struct teacher */
  struct list_head list_guards; /* struct guard */
  struct list_head list_classrooms; /* struct classroom */
  struct list_head list_bus; /* struct bus */
} s

綜上所述,我個人的意見:list.h 很好用,但是要慎用。

簡單總結

typedef struct student{
    char first_name[MAX_STRING_LENTH];
    char last_name[MAX_STRING_LENTGH];
    unsigned int age;
    struct list_head student_node;
} student_t;

//定義鏈表方法1: class
student_t *class = NULL;
struct list_head class;
INIT_LIST_HEAD(&class);

//定義鏈表方法2: bus
student_t *bus = NULL;
LIST_HEAD(bus);

原因如下:

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

REF

必須要看。。。。

list and hlist in kernel

kernel新手區

linux內核hlist分析

MISC

Q1

當然,如果你想在用戶態使用list.h 可能不行, 用戶態只能使用/usr/include/ 下的lib

所以,如果你想在用戶態使用list.h ,需要保證有 /usr/include/linux/list.h

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

如果你find到了, 你可以這樣:

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

但是,這不是一種科學的方法, 因為你還會遇到很多依賴:

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

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

Q2

#cat simple_student.c
#include "list.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define MAX_LENGTH 100

typedef struct student {
    char first_name[MAX_LENGTH];
    char last_name[MAX_LENGTH];
    unsigned int age;
    struct list_head student_node;
} student_t;

struct list_head class;
INIT_LIST_HEAD(&class);
//LIST_HEAD(class);
student_t *stu = NULL;

student_t *make_student (const char *fn, const char *ln, unsigned int a) {
    student_t *stu = NULL;

    if ((stu = calloc(1, sizeof(struct student))) == NULL) {
        return NULL;
    }

    if (strlen(fn) > (MAX_LENGTH - 1)) {
        return NULL;
    }

    if (strlen(ln) > (MAX_LENGTH - 1)) {
        return NULL;
    }

    strcpy(stu->first_name, fn);
    strcpy(stu->last_name, ln);
    stu->age = a;

    return stu;
}


int main(){
	if ((stu = make_student("ahao","mu",22)) == NULL) {
		fprintf(stderr,"Failed to create muahao\n");
			return -1;
	}
}

方法1 : 
struct list_head class;
INIT_LIST_HEAD(&class);

方法2:
LIST_HEAD(class);

在這里,我總是,使用方式1 的時候會提示如下錯誤:

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

附錄

#cat student.c
#include "list.h"
#include <stdlib.h>
#include <string.h>
#include <stdio.h>

#define MAX_LENGTH 100

typedef struct student {
	char first_name[MAX_LENGTH];
	char last_name[MAX_LENGTH];
	unsigned int age;
	struct list_head node_student;
} student_t;

student_t *make_student (const char *fn, const char *ln, unsigned int a) {
	student_t *stu = NULL;

	if ((stu = calloc(1, sizeof(struct student))) == NULL) {
		return NULL;
	}

	if (strlen(fn) > (MAX_LENGTH - 1)) {
		return NULL;
	}

	if (strlen(ln) > (MAX_LENGTH - 1)) {
		return NULL;
	}

	strcpy(stu->first_name, fn);
	strcpy(stu->last_name, ln);
	stu->age = a;

	return stu;
}


int main() {
	// Method 1
	//struct list_head class;
	//INIT_LIST_HEAD(&class);

	//Method 2
	LIST_HEAD(class);

	student_t *stu = NULL;

	//////////////////create student
	if ((stu = make_student("ahao","mu",22)) == NULL) {
		fprintf(stderr,"Failed to create muahao\n");
		return -1;
	}

	list_add_tail(&stu->node_student, &class);

	if ((stu = make_student("lianjie", "li", 23)) == NULL) {
		fprintf(stderr,"Failed to create li tom\n");
		return -1;
	}

	list_add_tail(&stu->node_student, &class);

	if ((stu = make_student("xiaolong", "li", 12)) == NULL) {
		fprintf(stderr, "Failed to create lixuehua\n");
		return -1;
	}

	list_add_tail(&stu->node_student, &class);

	///////////// Print all students

	printf("------print all students-----\n");

	list_for_each_entry(stu, &class, node_student) {
		printf("First name:%s\n", stu->first_name);
		printf("Last name:%s\n", stu->last_name);
		printf("Age:%d\n", stu->age);
	}


	//////////////// list bus

	LIST_HEAD(bus);
	printf("Moving all students to bus;\n");
	list_splice_init(&class, &bus);
	if (list_empty(&class)) {
		printf("No students in class\n");
	}

	printf("Print all bus students\n");
	list_for_each_entry(stu, &bus, node_student) {
		printf("%s %s %d", stu->first_name, stu->last_name, stu->age);
	}

	student_t *tmp = NULL;

	printf("muahao do not want go\n");
	list_for_each_entry_safe(stu, tmp, &bus, node_student) {
		if (strcmp(stu->first_name, "mu") == 0) {
			list_del(&stu->node_student);
			free(stu);
		}
	}

	printf("After muahao leave,students are: \n");
	list_for_each_entry(stu, &bus, node_student) {
		printf("%s %s %d\n",stu->first_name, stu->last_name, stu->age);
	}

	// end begin clean  all students;

	list_for_each_entry_safe(stu, tmp, &bus, node_student) {
		printf("Removing students: %s %s \n", stu->first_name, stu->last_name);
		list_del(&stu->node_student);
		free(stu);
	}

	return 0;
}
#cat list.h
/*
 * Copyright (C) 2012 Fusion-io.  All rights reserved.
 *
 * This header was taken from the Linux kernel
 *
 *  This program is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU General Public
 *  License v2 as published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public
 * License along with this program; if not, write to the
 * Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 */

#ifndef _LINUX_LIST_H
#define _LINUX_LIST_H

#define LIST_POISON1  ((void *) 0x00100100)
#define LIST_POISON2  ((void *) 0x00200200)

#undef offsetof
#ifdef __compiler_offsetof
#define offsetof(TYPE,MEMBER) __compiler_offsetof(TYPE,MEMBER)
#else
#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
#endif

#define container_of(ptr, type, member) ({                      \
	 const typeof( ((type *)0)->member ) *__mptr = (ptr);    \
	(type *)( (char *)__mptr - offsetof(type,member) );})

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

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

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

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

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

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

/**
 * 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.
 */
#ifndef CONFIG_DEBUG_LIST
static inline void list_add(struct list_head *new, struct list_head *head)
{
	__list_add(new, head, head->next);
}
#else
extern void list_add(struct list_head *new, struct list_head *head);
#endif


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

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

/**
 * 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(struct list_head *entry)
{
	__list_del(entry->prev, entry->next);
	entry->next = LIST_POISON1;
	entry->prev = LIST_POISON2;
}
#else
extern void list_del(struct list_head *entry);
#endif

/**
 * list_replace - replace old entry by new one
 * @old : the element to be replaced
 * @new : the new element to insert
 * Note: 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);
}
/**
 * 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->prev, entry->next);
	INIT_LIST_HEAD(entry);
}

/**
 * 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(list->prev, list->next);
        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(list->prev, list->next);
        list_add_tail(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;
}

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

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

static inline void __list_splice(struct list_head *list,
				 struct list_head *head)
{
	struct list_head *first = list->next;
	struct list_head *last = list->prev;
	struct list_head *at = head->next;

	first->prev = head;
	head->next = first;

	last->next = at;
	at->prev = last;
}

/**
 * list_splice - join two lists
 * @list: the new list to add.
 * @head: the place to add it in the first list.
 */
static inline void list_splice(struct list_head *list, struct list_head *head)
{
	if (!list_empty(list))
		__list_splice(list, head);
}

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

/**
 * list_entry - get the struct for this entry
 * @ptr:	the &struct list_head pointer.
 * @type:	the type of the struct this is embedded in.
 * @member:	the name of the list_struct within the struct.
 */
#define list_entry(ptr, type, member) \
	container_of(ptr, type, member)

/**
 * list_for_each	-	iterate over a list
 * @pos:	the &struct list_head to use as a loop cursor.
 * @head:	the head for your list.
 */
#define list_for_each(pos, head) \
	for (pos = (head)->next; pos != (head); \
        	pos = pos->next)

/**
 * __list_for_each	-	iterate over a list
 * @pos:	the &struct list_head to use as a loop cursor.
 * @head:	the head for your list.
 *
 * This variant differs from list_for_each() in that it's the
 * simplest possible list iteration code, no prefetching is done.
 * Use this for code that knows the list to be very short (empty
 * or 1 entry) most of the time.
 */
#define __list_for_each(pos, head) \
	for (pos = (head)->next; pos != (head); pos = pos->next)

/**
 * list_for_each_prev	-	iterate over a list backwards
 * @pos:	the &struct list_head to use as a loop cursor.
 * @head:	the head for your list.
 */
#define list_for_each_prev(pos, head) \
	for (pos = (head)->prev; pos != (head); \
        	pos = pos->prev)

/**
 * list_for_each_safe - iterate over a list safe against removal of list entry
 * @pos:	the &struct list_head to use as a loop cursor.
 * @n:		another &struct list_head to use as temporary storage
 * @head:	the head for your list.
 */
#define list_for_each_safe(pos, n, head) \
	for (pos = (head)->next, n = pos->next; pos != (head); \
		pos = n, n = pos->next)

/**
 * list_for_each_entry	-	iterate over list of given type
 * @pos:	the type * to use as a loop cursor.
 * @head:	the head for your list.
 * @member:	the name of the list_struct within the struct.
 */
#define list_for_each_entry(pos, head, member)				\
	for (pos = list_entry((head)->next, typeof(*pos), member);	\
	     &pos->member != (head); 	\
	     pos = list_entry(pos->member.next, typeof(*pos), member))

/**
 * list_for_each_entry_reverse - iterate backwards over list of given type.
 * @pos:	the type * to use as a loop cursor.
 * @head:	the head for your list.
 * @member:	the name of the list_struct within the struct.
 */
#define list_for_each_entry_reverse(pos, head, member)			\
	for (pos = list_entry((head)->prev, typeof(*pos), member);	\
	     &pos->member != (head); 	\
	     pos = list_entry(pos->member.prev, typeof(*pos), member))

/**
 * list_prepare_entry - prepare a pos entry for use in list_for_each_entry_continue
 * @pos:	the type * to use as a start point
 * @head:	the head of the list
 * @member:	the name of the list_struct within the struct.
 *
 * Prepares a pos entry for use as a start point in list_for_each_entry_continue.
 */
#define list_prepare_entry(pos, head, member) \
	((pos) ? : list_entry(head, typeof(*pos), member))

/**
 * list_for_each_entry_continue - continue iteration over list of given type
 * @pos:	the type * to use as a loop cursor.
 * @head:	the head for your list.
 * @member:	the name of the list_struct within the struct.
 *
 * Continue to iterate over list of given type, continuing after
 * the current position.
 */
#define list_for_each_entry_continue(pos, head, member) 		\
	for (pos = list_entry(pos->member.next, typeof(*pos), member);	\
	     &pos->member != (head);	\
	     pos = list_entry(pos->member.next, typeof(*pos), member))

/**
 * list_for_each_entry_from - iterate over list of given type from the current point
 * @pos:	the type * to use as a loop cursor.
 * @head:	the head for your list.
 * @member:	the name of the list_struct within the struct.
 *
 * Iterate over list of given type, continuing from current position.
 */
#define list_for_each_entry_from(pos, head, member) 			\
	for (; &pos->member != (head);	\
	     pos = list_entry(pos->member.next, typeof(*pos), member))

/**
 * list_for_each_entry_safe - iterate over list of given type safe against removal of list entry
 * @pos:	the type * to use as a loop cursor.
 * @n:		another type * to use as temporary storage
 * @head:	the head for your list.
 * @member:	the name of the list_struct within the struct.
 */
#define list_for_each_entry_safe(pos, n, head, member)			\
	for (pos = list_entry((head)->next, typeof(*pos), member),	\
		n = list_entry(pos->member.next, typeof(*pos), member);	\
	     &pos->member != (head); 					\
	     pos = n, n = list_entry(n->member.next, typeof(*n), member))

/**
 * list_for_each_entry_safe_continue
 * @pos:	the type * to use as a loop cursor.
 * @n:		another type * to use as temporary storage
 * @head:	the head for your list.
 * @member:	the name of the list_struct within the struct.
 *
 * Iterate over list of given type, continuing after current point,
 * safe against removal of list entry.
 */
#define list_for_each_entry_safe_continue(pos, n, head, member) 		\
	for (pos = list_entry(pos->member.next, typeof(*pos), member), 		\
		n = list_entry(pos->member.next, typeof(*pos), member);		\
	     &pos->member != (head);						\
	     pos = n, n = list_entry(n->member.next, typeof(*n), member))

/**
 * list_for_each_entry_safe_from
 * @pos:	the type * to use as a loop cursor.
 * @n:		another type * to use as temporary storage
 * @head:	the head for your list.
 * @member:	the name of the list_struct within the struct.
 *
 * Iterate over list of given type from current point, safe against
 * removal of list entry.
 */
#define list_for_each_entry_safe_from(pos, n, head, member) 			\
	for (n = list_entry(pos->member.next, typeof(*pos), member);		\
	     &pos->member != (head);						\
	     pos = n, n = list_entry(n->member.next, typeof(*n), member))

/**
 * list_for_each_entry_safe_reverse
 * @pos:	the type * to use as a loop cursor.
 * @n:		another type * to use as temporary storage
 * @head:	the head for your list.
 * @member:	the name of the list_struct within the struct.
 *
 * Iterate backwards over list of given type, safe against removal
 * of list entry.
 */
#define list_for_each_entry_safe_reverse(pos, n, head, member)		\
	for (pos = list_entry((head)->prev, typeof(*pos), member),	\
		n = list_entry(pos->member.prev, typeof(*pos), member);	\
	     &pos->member != (head); 					\
	     pos = n, n = list_entry(n->member.prev, typeof(*n), member))

#endif


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM