您的位置:首页 > 运维架构 > Linux

linux内核list模块的使用

2015-07-16 15:35 567 查看
List模块是linux内核提供的循环链表函数集,头文件是:<linux/list.h>。

主要数据结构:

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

使用之前必须初始化一个链表头,可以使用下面的宏直接定义并且初始化一个链表头:

LIST_HEAD(name)

宏参数name是链表头定义名。

例如:

LIST_HEAD(listHead)

使用list模块中的方法时,你的数据结构中必须包含struct list_head类成员,例如:

Struct myNode{
Int a;
Struct list_head listNode;
};
Struct myNode nodeVar;


插入操作

/*
* 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函数可以将一个数据节点加入到链表中.

List_add(&nodeVar->listNode,&listHead)

将元素加入到链表首位置,即链表头listHead的下一个位置。

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


List_add_tail(&nodeVar->listNode,&listHead);

其实它是把nodeVar中的listNode元素接入链表末尾

删除操作

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


查找操作

#define list_for_each_entry(pos, head, member)                          \
for (pos = list_entry((head)->next, typeof(*pos), member);      \
prefetch(pos->member.next), &pos->member != (head);        \
pos = list_entry(pos->member.next, typeof(*pos), member))
#define list_entry(ptr, type, member) \
container_of(ptr, type, member)
其中pos是暂存的结构体指针,member是结构体内部的struct listhead结构变量,head是链表头。container_of()见最后注。

假如有n个struct myNode变量加入了链表,查找元素a =100的节点的操作如下

Struct myNode* Pos
list_for_each_entry(Pos, &listHead,listNode)
{
If(Pos->a== 100)
{
…….
}
}


如果涉及到Pos的指针内存操作,例如释放等,可以使用函数:

/**
* 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))
这个函数使用n来保存pos的值,以免pos释放后继续操作pos造成内存错误。

例子:

Struct myNode* cPos, nPos;
list_for_each_entry_safe(cPos, nPos, &listHead, listNode)
{
list_del(cPos);
free(cPos);
}


注:

container_of(ptr, type, member)是那就是根据一个结构体变量中的一个域成员变量的指针来获取指向整个结构体变量的指针。

例如:container_of(&nodeVar->listNode, struct myNode, listNode)

得到的将是nodeVar的地址。

关于container_of见kernel.h中:
/**
* 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) );})
container_of在Linux Kernel中的应用非常广泛,它用于获得某结构中某成员的入口地址.

关于offsetof见stddef.h中:

#define offsetof(TYPE, MEMBER) ((size_t)&((TYPE *)0)->MEMBER
TYPE是某struct的类型,0是一个假想TYPE类型struct,MEMBER是该struct中的一个成员。
由于该struct的基地址为0, MEMBER的地址就是该成员相对与struct头地址的偏移量.

关于typeof,这是gcc的C语言扩展保留字,用于声明变量类型。

const typeof( ((type *)0->member ) *__mptr =(ptr);意思是声明一个与member同一个类型的指针常量 *__mptr,并初始化为ptr。

(type *)( (char *)__mptr - offsetof(type,member));意思是__mptr的地址减去member在该struct中的偏移量得到的地址,
再转换成type型指针,该指针就是member的入口地址了。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: