linux内核list模块的使用
来源:互联网 发布:加州州立大学知乎 编辑:程序博客网 时间:2024/05/17 10:55
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_LISTstatic 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;}#elseextern 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_LISTstatic inline void list_add(struct list_head *new, struct list_head *head){ __list_add(new, head, head->next);}#elseextern 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_LISTstatic inline void list_del(struct list_head *entry){ __list_del(entry->prev, entry->next); entry->next = LIST_POISON1; entry->prev = LIST_POISON2;}#elseextern 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* Poslist_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)->MEMBERTYPE是某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的入口地址了。
0 0
- linux内核list模块的使用
- Linux 内核list使用
- Linux内核---60.linux内核链表list的使用
- Linux内核模块的管理
- linux内核模块的makefile
- Linux内核模块的加载
- linux内核模块的编译
- linux内核的主要模块
- Linux 内核模块的程序结构
- linux内核模块的安全
- linux的内核模块机制
- linux内核模块的编写
- linux的内核模块介绍
- Linux内核模块:模块的编译
- 使用UML调试Linux内核和模块
- (转载)使用kgdb调试linux内核及内核模块
- (转载)使用kgdb调试linux内核及内核模块
- 使用kgdb调试linux内核及内核模块
- 如何将Eclipse中的项目迁移到Android Studio 中
- paint 画笔的一些属性
- HTTP协议的C/S模式的信息交换过程
- java 重定向和转发的区别
- 设计模式--原型模式
- linux内核list模块的使用
- Tarjan应用:求割点/桥/缩点/强连通分量/双连通分量/LCA(最近公共祖先)
- 【apache-commons】一 io包 它是一个文件和IO流操作的源码通用工具包
- Android APP安装后不在桌面显示图标的应用场景举例和实现方法
- 【LintCode】 Backpack II 背包问题II
- listview重复混乱加载
- 九度 OJ 之 题目1202:排序
- 算法的封装与切换——策略模式(一):电影票打折方案
- Emit学习(1)-Emit概览