嵌入式LINUX驱动学习之13内核数据结构(链表)
一、头文件、函数及说明
/*
1、linux内核初始化链表函数 :INIT_LIST_HEAD()
*/
static inline void INIT_LIST_HEAD(struct list_head *list)
{
list->next = list;
list->prev = list;
}
/*
2、向链表添加节点函数:list_add()
参数说明:
new : 需要添加到链表的结构体的struct list_head 成员
head :链表头
功能:向链表head中添加一个节点;
*/
static inline void list_add(struct list_head *new, struct list_head *head)
{
__list_add(new, head, head->next);
}
/*
3、从链表中删除一个节点:list_del()
参数说明:
entry : 要删除的节点成员struct list_head变量名
*/
void list_del(struct list_head *entry);
/*
4、将两个链表合并: list_move()
参数说明:
list : 被合并的链表的头
head : 目的链表的头
*/
void list_move(struct list_head *list, struct list_head *head)
/*
5、判断一个节点是否为链表最后一个节点:list_is_last()
参数说明:
list : 用于判断的节点
head : 链表的头
*/
int list_is_last(const struct list_head *list,const struct list_head *head)
/*
6、判断链表是否为空:list_empty()
*/
int list_empty(const struct list_head *head)
/*
7、遍历列表方式一 :list_for_each()
参数说明:
pos : 用于保存遍历过程中的节点结构体的struct list_head成员变量的地址
head : 要遍历的链表头的地址
*/
#define list_for_each(pos, head) \
for (pos = (head)->next; pos != (head); pos = pos->next)
/*
8、根据结构体的struct list_head成员变量的地址得到结构体地址:list_entry()
参数说明:
ptr : struct list_head成员变量的地址
type : 结构体名称,如:struct inode
member : 结构体中成员变量结构struct list_head 变量名称
主要是配合上面的list_for_each()使用;
*/
#define list_entry(ptr, type, member) \
container_of(ptr, type, member)
/*
例 A.1 后续举例均有可能参考当前实例的内容
list_for_each()和list_entry()配合使用举例:
struct person {
char name[30];
char sex[4];
int age;
//........省略更多........
struct list_head person_list;//用这个成员构成链表
}
void xxx_func(void){
struct person *zhangsan,*lisi,*wangwu,*zhaoliu;
struct person *tmp_person;
struct list_head *person_list_head;
struct list_head *list_head_addr;
INIT_LIST_HEAD(person_list_head);
zhangsan = kmalloc(sizeof(*zhangsan),GFP_KERNEL);
strcpy(zhangsan -> name , "张三");
strcpy(zhangsan ->sex , "男");
zhangsan ->age = 20;
//.........省略更多..............
//.........省略:lisi,wangwu,zhaoliu.........
list_add(zhangsan,person_list_head); //将zhangsan结构体加入到链表person_list_head中
list_add(lisi,person_list_head);
list_add(wangwu,person_list_head);
list_add(zhaoliu,person_list_head);
//遍历列表,将每次的struct list_head对象地址保存到list_head_addr中
list_for_each(list_head_addr,person_list_head)
//根据结构体struct person、成员变量链表person_list、链表中节点的地址list_head_addr得到结构体struct person的地址;
tmp_person = list_entry(list_head_addr,struct person,person_list)
printk("姓名:%s , 性别 :%s , 年龄:%d .....\n",tmp_person ->name,tmp_person -> sex , tmp_person -> age);
*/
9、遍历列表方式二 :list_for_each_entry()
参数说明:
pos : 用于保存遍历过程中的节点结构体地址
head : 要遍历的链表头的地址
member :pos中的struct list_head成员变量的名称
*/
#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))
/*
10、可用于安全删除节点的遍历函数一:list_for_each_entry_safe()
参数说明(引用上述的例A.1结构体):
pos : struct person 结构体类型指针
n : struct person 结构体类型指针
head : 要遍历的链表头的地址,结构体:struct list_head
member: struct person 结构体中成员变量struct list_head类型结构体名
*/
#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))
/*
使用举例(引用例A.1的结构体、对象、方法):
//安全的删除所有节点,***实际开发中要记得加锁***
per *pos , *pos_next;
list_for_each_entry_safe(pos,pos_next,&per_list_head,per_list){
list_del(&(pos -> per_list));
kfree(pos);
}
*/
11、可用于安全删除节点的遍历函数二:
参数说明:
pos : struct list_head 结构体类型指针
n : struct list_head 结构体类型指针
head : 要遍历的链表头的地址,结构体:struct list_head
#define list_for_each_safe(pos, n, head) \
for (pos = (head)->next, n = pos->next; pos != (head); \
pos = n, n = pos->next)
/*
使用举例(引用例A.1的结构体、对象、方法):
//安全的删除所有节点,***实际开发中要记得加锁***
struct list_head *list_pos , *list_pos_next;
per *tmp_per_list;
list_for_each_safe(list_pos,list_pos_next,&per_list_head){
tmp_per_list = list_entry(list_pos,per,per_list);
list_del(list_pos);
kfree(tmp_per_list);
}
//实例删除遍历中的某个节点,***实际开发中要记得加锁***
list_for_each_safe(list_pos,list_pos_next,&per_list_head){
if(list_pos == &(per_3 ->per_list)){
tmp_per_list = list_entry(list_pos,per,per_list);
list_del(list_pos);
kfree(tmp_per_list);
}
}
*/