linux设备驱动程序(第三版)阅读笔记(十一)

来源:互联网 发布:如何加盟菜鸟网络 编辑:程序博客网 时间:2024/05/21 22:47

 

说明:版权所有归作者,只供学习交流,若有其它用途请联系作者,转载请遵守IT人职业规范,请注明转载地址

 

 

第十一章:内核的数据类型

1,(内核使用的数据类型)内核使用的数据类型主要被分成三大类:类似int这样的标准C语言类型,类似u32这样的有确定大小的类型,以及像pid_t这样的用于特定内核对象的类型。

 

2,(内核链表)就像很多其他程序一样,操作系统内核经常需要维护数据结构的列表。有时,linux内核中同时存在多个链表的实现代码。为了减小重复代码的数量,内核开发者已经建立了一套标准的循环、双向链表的实现。如果你需要操作链表,那么建议你使用这一内核设施。

当使用这些链表接口时,应该始终牢记这些链表函数不进行任何锁定。如果你的驱动程序有可能试图对同一个链表执行并发操作的话,则有责任实现一个锁方案。否则,崩溃的链表结构体、数据丢失、内核混乱等问题是很难诊断的。

为了能使用这个链表机制,驱动程序必须包含头文件<linux/list.h>。该文件定义了一个简单的list_head类型的结构体。

struct list_head

{

struct list_head *next,*prev;

}

用于实际代码的链表几乎总是由某种结构类型构成,每个结构描述链表中的一项。为了在代码中使用Linux链表设施,只需要在构成链表的结构里面嵌入一个list_head

链表头通常是一个独立的list_head结构。

在使用链表之前,必须用INIT_LIST_HEAD宏来初始化链表头。可如下声明并初始化一个实际的链表头:

struct list_head todo_list;

INIT_LIST_HEAD(&todo_list);

也可在编译时像下面这样初始化链表:

LIST_HEAD(todo_list);

 

链表的操作:

list_add(struct list_head *new, struct list_head *head);

在链表头添加新项----通常在链表的头部。这样,它可以被用来建立栈。但需要注意的是,head并不一定非得是链表名义上的头;如果传递了一个恰巧位于链表中间某处的list_head结构体,新项会紧跟在它后面。因为linux链表是循环式的,链表头通常与其他的项没有本质上的区别。

 

list_add_tail(struct list_head *new, struct list_head *head);

在给定链表的末尾处添加一个新的项。因此,可用list_add_tail来创建先进先出(FIFO)队列。

 

list_del(struct list_head *entry);

list_del_init(struct list_head *entry);

删除链表中的给定项。如果该项还可能被重新插入到另一个链表中的话,应该使用list_del_init,它会重新初始化链表的指针。

 

list_move(struct list_head *entry, struct list_head *head);

list_move_tail(structlist_head *entry, struct list_head *head);

把给定项移动到链表的开始处。如果要把给定项放到新链表的末尾,使用list_move_tail

 

list_empty(struct list_head *head);

清空链表,如果给定的链表为空,返回一个非零值。

 

list_splice(struct list_head *list, struct list_head *head);

通过在head之后插入list来合并两个链表。

 

list_head结构体有利于实现具有类似结构的链表,但调用程序通常对组成链表的大结构感兴趣。因此,可利用list_entry宏将一个list_head结构指针映射回指向包含它的大结构的指针。换句话说list_entry的作用就是以知数据结构中的节点指针ptr,提取大数据结构中的其他信息。可如下调用宏:

list_entry(struct list_head *ptr, type_of_struct, field_name);

其中,ptr是指向正被使用的struct list_head的指针,type_of_struct是包含ptr的结构类型,field_name是结构中链表字段的名字。

 

list_for_each(struct list_head *cursor, struct list_head *list);

该宏创建一个for循环,每当游标指向链表中的下一项时执行一次。在遍历链表时要注意对它的修改。

 

List_for_each_prev(struct list_head *cursor, struct list_head * list);

该版本向后遍历链表。

 

List_for_each_safe(struct list_head *cursor, struct list_head *next, struct list_head *list);

如果循环可能会删除链表中的项,就应该使用该版本。它只是简单地在循环的开始处把链表中的下一项存储在next中,这样如果cursor所指的项被删除也不会造成混乱。

 

List_for_each_entry(type*cursor, struct list_head *list, member);

List_for_each_entry_safe(type*cursor, type *next, struct list_head *list,member);

这些宏使处理一个包含给定类型的结构体的链表时更加容易。这里,cursor是指向包含结构体类型的指针,member是包含结构体内list_head结构体的名字。使用这些宏就不需要在循环内调用list_entry了。

 

原创粉丝点击