Linux内核链表访问链表头指针,linux内核——链表结构分析

http://blog.csdn.net/tigerjibo/article/details/8299584

简单整理(使用linux3.0内核)

这里首先学习的是内核中一种抽象定义的双向链表,为了提高其扩展性。

内核中链表的描述数据结构

位置:Types.h (linux-3.0.12\include\linux)     5444     2011/11/29

222:

struct list_head {

struct list_head *next, *prev;

};

这是一个不含数据域的结构

使用内核链表结构构造自定义结构

我们可以这样定义我们的链表节点

struct my_list_node {

数据域

......

struct list_head index;

......

};

如果需要构造某类对象的特定列表,则在其结构中定义一个类型为

struct list_head的成员,通过这个成员将这类对象连接起来,形成所需列表,并通过通用链表函数对其进行操作。其优点是只需编写通用链表函数,即可构造和操作不同对象的列表,而无需为每类对象的每种列表编写专用函数,实现了代码的重用。

使用方法:以struct list_head 为基本对象,对链表进行插入、删除、合并以及遍历等各种操作。

内核链表头的初始化定义

位置:List.h (linux-3.0.12\include\linux)     21209     2011/11/29

19:

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

}

其中name是一个struct list_head类型变量,list是struct list_head类型指针,上面是两种初始化的方法,使用宏定义和内联函数

自定义链表头初始化

struct list_head my_list_head;

LIST_HEAD(my_list_head);或者

INIT_LIST_HEAD(&my_list_head);

调用后头结点my_list_head的next, prev都指向自己,构成一个空链表。所以,可以借助next是否指向自己 (头结点)来判断链表是否为空。

内核链表操作的定义

判断链表是否为空

/**

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

}

返回值:

为空返回1,不为空返回0

插入节点

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;

}

/**

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

}

/**

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

}

遍历链表

首先看下需要用到额外的宏定义

offsetof:计算某结构体成员在结构体中的偏移地址

位置:Stddef.h (linux-3.0.12\include\linux)     435     2011/11/29

24:

#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)

对这个宏的讲解我们大致可以分为以下4步进行讲解:

1>( (TYPE *)0 )  0地址强制 "转换" 为 TYPE结构类型的指针;

2>((TYPE *)0)->MEMBER   访问TYPE结构中的MEMBER数据成员;

3>&( ( (TYPE *)0 )->MEMBER)取出TYPE结构中的数据成员MEMBER的地址;

4>(size_t)(&(((TYPE*)0)->MEMBER))结果转换为size_t类型。

宏offsetof的巧妙之处在于将0地址强制转换为 TYPE结构类型的指针,TYPE结构以内存空间首地址0作为起始地址,则成员地址自然为偏移地址。可能有的读者会想是不是非要用0呢?当然不是,我们仅仅是为了计算的简便。也可以使用其他的值,只是算出来的结果还要再减去该数值才是偏移地址。

container_of:通过结构体中某个成员的地址,算出结构体的地址

位置:Kernel.h (linux-3.0.12\tools\perf\util\include\linux)     2691     2011/11/29

19:

/**

* container_of - cast a member of a structure out to the containing structure

* @ptr:     the pointer to the member.

* @type:     the type of the container struct this is embedded in.

* @member:     the name of the member within the struct.

*

*/

#define container_of(ptr, type, member) ({               \

const typeof(((type *)0)->member) * __mptr = (ptr);     \

(type *)((char *)__mptr - offsetof(type, member)); })

说明

第一步,首先定义一个临时的数据类型(通过typeof( ((type *)0)->member )获得)与ptr相同的指针变量__mptr,然后用它来保存ptr的值。

说明:typeof是GNU C对标准C的扩展,它的作用是根据变量获取变量的类型《typeof关键字在linux 内核中很常见》

第二步,用(char *)__mptr减去member在结构体中的偏移量,得到的值就是整个结构体变量的首地址(整个宏的返回值就是这个首地址)。

遍历链表的相关宏定义

/**

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

通过成员指针获得整个结构体的指针,Linux链表中仅保存了节点中struct list_head成员变量的地址,通过list_entry宏经struct list_head成员访问到作为它的所有者的节点起始地址。

/**

* list_first_entry - get the first element from a list

* @ptr:     the list head to take the element from.

* @type:     the type of the struct this is embedded in.

* @member:     the name of the list_struct within the struct.

*

* Note, that list is expected to be not empty.

*/

#define list_first_entry(ptr, type, member) \

list_entry((ptr)->next, type, member)

得到ptr指向的节点的next成员指向的结构体变量地址,此处的ptr一般是一个链表的头结点

/**

* 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 doesn't differ from list_for_each() any more.

* We don't do prefetching in either case.

*/

#define __list_for_each(pos, head) \

for (pos = (head)->next; pos != (head); pos = pos->next)

两个宏都是用来遍历链表

pos是一个辅助指针(即链表类型),用于链表遍历

head:链表的头指针(即结构体中成员struct list_head)

/**

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

前面介绍了用于链表遍历的几个宏,它们都是通过移动pos指针来达到遍历的目的。但如果遍历的操作中包含删除pos指针所指向的节点,pos指针的移动就会被中断,因为list_del(pos)将把pos的next、prev置成LIST_POSITION2和LIST_POSITION1的特殊值。当然,调用者完全可以自己缓存next指针使遍历操作能够连贯起来,但为了编程的一致性,Linxu内核链表要求调用者另外提供一个与pos同类型的指针n,在for循环中暂存pos下一个节点的地址,避免因pos节点被释放而造成的断链。

/**

* list_for_each_prev_safe - iterate over a list backwards 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_prev_safe(pos, n, head) \

for (pos = (head)->prev, n = pos->prev; \

pos != (head); \

pos = n, n = pos->prev)

功能与list_for_each_prev相同,用于逆向遍历链表。不同的是使用list_head结构体变量n作为临时存储变量。主要用于链表删除时操作。

下边遍历链表宏定义,所不同的是它是根据链表的结构体地址来进行遍历。大多数情况下,遍历链表的时候都需要获得链表节点数据项,也就是说list_for_each()和list_entry()总是同时使用。与list_for_each()不同,这里的pos是数据项结构指针类型,而不是(struct list_head 类型。

首先是从head开始遍历整个链

/**

* 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_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 - continue list iteration safe against removal

* @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))

pos:用于遍历的指针,只是它的数据类型是结构体类型而不是strut list_head 类型

head:链表头指针

member:该结构体类型定义中struct list_head成员的变量名。

n和pos类型相同

从pos后位置开始顺序遍历到head,需要list_prepare_entry宏先对pos处理

/**

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

从pos前一位置开始逆序遍历到head,需要list_prepare_entry宏先对pos处理

/**

* list_for_each_entry_continue_reverse - iterate backwards from the given 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.

*

* Start to iterate over list of given type backwards, continuing after

* the current position.

*/

#define list_for_each_entry_continue_reverse(pos, head, member)          \

for (pos = list_entry(pos->member.prev, typeof(*pos), member);     \

&pos->member != (head);     \

pos = list_entry(pos->member.prev, typeof(*pos), member))

#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))

从已知的某个结点pos后一个结点开始进行遍历,与list_for_each_entry_continue不同的是,它主要用于链表进行删除时进行的遍历。

从当前pos位置开始遍历到head

#define list_for_each_entry_from(pos, head, member)                \

for (; &pos->member != (head);     \

pos = list_entry(pos->member.next, typeof(*pos), member))

#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))

根据pos得到其下一个节点的起始地址

/**

* list_safe_reset_next - reset a stale list_for_each_entry_safe loop

* @pos:     the loop cursor used in the list_for_each_entry_safe loop

* @n:          temporary storage used in list_for_each_entry_safe

* @member:     the name of the list_struct within the struct.

*

* list_safe_reset_next is not safe to use in general if the list may be

* modified concurrently (eg. the lock is dropped in the loop body). An

* exception to this is if the cursor element (pos) is pinned in the list,

* and list_safe_reset_next is called after re-taking the lock and before

* completing the current iteration of the loop body.

*/

#define list_safe_reset_next(pos, n, member)                    \

n = list_entry(pos->member.next, typeof(*pos), member)

链表节点的删除

/*

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

}

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;

}

list_del()函数将删除后的prev、next指针分别被设为LIST_POSITION2和LIST_POSITION1两个特殊值,这样设置是为了保证不在链表中的节点项不可访问。对LIST_POSITION1和LIST_POSITION2的访问都将引起页故障。

static inline void INIT_LIST_HEAD(struct list_head *list)

{

list->next = list;

list->prev = list;

}

static inline void list_del_init(struct list_head *entry)

{

__list_del_entry(entry);

INIT_LIST_HEAD(entry);

}

list_del_init这个函数首先将entry从双向链表中删除之后,并且将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_entry(list);

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_entry(list);

list_add_tail(list, head);

}

剩下的函数暂时不看了!!

你可能感兴趣的:(Linux内核链表访问链表头指针,linux内核——链表结构分析)