免费咨询热线
13621929115转自 http://www.wowotech.net1. 前言Kobject是Linux设备模型的基础,也是设备模型中最难理解的一部分(可参考Documentation/kobject.txt的表述)因此有必要先把它分析清楚。
2. 基本概念Linux设备模型的核心是使用Bus、Class、Devic概念模型e、Driver四个核心数据结构,将大量的、不同功能的硬件设备(以及驱动该硬件设备的方法),以树状结构的形式,进行归纳、抽象,从而方便Kernel的统一管理。
而硬件设备的数量、种类是非常多的,这就决定了Kernel中将会有大量的有关设备模型的数据结构这些数据结构一定有一些共同的功能,需要抽象出来统一概念模型实现,否则就会不可避免的产生冗余代码这就是Kobject诞生的背景。
目前为止,Kobject主要提供如下功能:1.通过parent指针,可以将所有Kobject以层次结构的形式组合起来2.使用一个引用计数(reference count),来记录Kobject被引用的次数,并在引用次数变为0时把它释概念模型放(这是Kobject诞生时的唯一功能)。
3.和sysfs虚拟文件系统配合,将每一个Kobject及其特性,以文件的形式,开放到用户空间(有关sysfs,会在其它文章中专门描述,本文不会涉及太多内容)注1:在Linux中,Kobject几乎不会单独存在。
它的主要功能,就是内嵌在一个大型的数据结构中,概念模型为这个数据结构提供一些底层的功能实现 注2:Linux driver开发者,很少会直接使用Kobject以及它提供的接口,而是使用构建在Kobject之上的设备模型接口。
3. 代码解析3.1 在Linux Kernel source code中的位置在Kernel源代码中,Kobject由如下两个文概念模型件实现: include/linux/kobject.h lib/kobject.c
其中kobject.h为Kobject的头文件,包含所有的数据结构定义和接口声明kobject.c为核心功能的实现3.2 主要的数据结构在描述数据结构之前,有必要说明一下Kobject, Kset和Ktype这三个概概念模型念。
Kobject是基本数据类型,每个Kobject都会在"/sys/“文件系统中以目录的形式出现 Ktype代表Kobject(严格地讲,是包含了Kobject的数据结构)的属性操作集合(由于通用性,多个Kobject可能共用同一个属性操作集,因此把Ktype独立出来了)。
注3:在设备模型中,kt概念模型ype的命名和解释,都非常抽象,理解起来非常困难,后面会详细说明Kset是一个特殊的Kobject(因此它也会在"/sys/“文件系统中以目录的形式出现),它用来集合相似的Kobject(这些Kobject可以是相同属性的,也可以不同属性的)。
首先看一下Kobject的原型struct kobjec概念模型t {
name,该Kobject的名称,同时也是sysfs中的目录名称由于Kobj概念模型ect添加到Kernel时,需要根据名字注册到sysfs中,之后就不能再直接修改该字段如果需要修改Kobject的名字,需要调用kobject_rename接口,该接口会主动处理sysfs的相关事宜。
entry,用于将Kobject加入到Kset中的list_headparent,指向parent 概念模型kobject,以此形成层次结构(在sysfs就表现为目录结构)kset,该kobject属于的Kset。
可以为NULL如果存在,且没有指定parent,则会把Kset作为parent(别忘了Kset是一个特殊的Kobject)ktype,该Kobject属于的kobj_type每个Kobject必概念模型须有一个ktype,或者Kernel会提示错误。
sd,该Kobject在sysfs中的表示kref,"struct kref”类型(在include/linux/kref.h中定义)的变量,为一个可用于原子操作的引用计数state_initialized,指示该Kobject是否已经初始化,以在Ko概念模型bject的Init,Put,Add等操作时进行异常校验。
state_in_sysfs,指示该Kobject是否已在sysfs中呈现,以便在自动注销时从sysfs中移除state_add_uevent_sent/state_remove_uevent_sent,记录是否已经向用户空间发送ADD ue概念模型vent,如果有,且没有发送remove uevent,则在自动注销时,补发REMOVE uevent,以便让用户空间正确处理。
uevent_suppress,如果该字段为1,则表示忽略所有上报的uevent事件注4:Uevent提供了“用户空间通知”的功能实现,通过该功能,当内核中有Kobject概念模型的增加、删除、修改等动作时,会通知用户空间。
有关该功能的具体内容,会在其它文章详细描述Kset的原型为/**
list/list_lock,用于保存该kset下所有的kobject的链表kobj,该kset自己的k概念模型object(kset是一个特殊的kobject,也会在sysfs中以目录的形式体现)uevent_ops,该kset的uevent操作函数集。
当任何Kobject需要上报uevent时,都要调用它所从属的kset的uevent_ops,添加环境变量,或者过滤event(kset可以决定哪些even概念模型t可以上报)因此,如果一个kobject不属于任何kset时,是不允许发送uevent的。
release,通过该回调函数,可以将包含该种类型kobject的数据结构的内存空间释放掉sysfs_ops,该种类型的Kobject的sysfs文件系统接口default概念模型_attrs,该种类型的Kobject的atrribute列表(所谓attribute,就是sysfs文件系统中的一个文件)。
将会在Kobject添加到内核时,一并注册到sysfs中child_ns_type/namespace,和文件系统(sysfs)的命名空间有关,这里不再详细说明总结,Ktyp概念模型e以及整个Kobject机制的理解。
Kobject的核心功能是:保持一个引用计数,当该计数减为0时,自动释放(由本文所讲的kobject模块负责) Kobject所占用的meomry空间这就决定了Kobject必须是动态分配的(只有这样才能动态释放)。
而Kobject大多数的使用场景,是内嵌在大型的概念模型数据结构中(如Kset、device_driver等),因此这些大型的数据结构,也必须是动态分配、动态释放的那么释放的时机是什么呢?是内嵌的Kobject释放时。
但是Kobject的释放是由Kobject模块自动完成的(在引用计数为0时),那么怎么一并释放包含自己的大型数据结构呢?这时Ktype就派概念模型上用场了我们知道,Ktype中的release回调函数负责释放Kobject(甚至是包含Kobject的数据结构)的内存空间,那么Ktype及其内部函数,是由谁实现呢?是由上层数据结构所在的模块!因为只有它,才清楚Kobject嵌在哪个数据结构中,并通过Kobject指针以及自身的数据结构类型,找到概念模型需要释放的上层数据结构的指针,然后释放它。
讲到这里,就清晰多了所以,每一个内嵌Kobject的数据结构,例如kset、device、device_driver等等,都要实现一个Ktype,并定义其中的回调函数同理,sysfs相关的操作也一样,必须经过ktype的中转,因为sysfs看到的是Kobje概念模型ct,而真正的文件操作的主体,是内嵌Kobject的上层数据结构!。
顺便提一下,Kobject是面向对象的思想在Linux kernel中的极致体现,但C语言的优势却不在这里,所以Linux kernel需要用比较巧妙(也很啰嗦)的手段去实现,3.3 功能分析3.3.1 Kobject使用流程
Kob概念模型ject大多数情况下(有一种例外,下面会讲)会嵌在其它数据结构中使用,其使用流程如下:定义一个struct kset类型的指针,并在初始化时为它分配空间,添加到内核中根据实际情况,定义自己所需的数据结构原型,该数据结构中包含有Kobject 定义一个适合自己的ktype,并实现其中回调函数
在需要使用概念模型到包含Kobject的数据结构时,动态分配该数据结构,并分配Kobject空间,添加到内核中每一次引用数据结构时,调用kobject_get接口增加引用计数;引用结束时,调用kobject_put接口,减少引用计数
当引用计数减少为0时,Kobject模块调用ktype所提供的release接口,释放概念模型上层数据结构以及Kobject的内存空间上面有提过,有一种例外,Kobject不再嵌在其它数据结构中,可以单独使用,这个例外就是:开发者只需要在sysfs中创建一个目录,而不需要其它的kset、ktype的操作。
这时可以直接调用kobject_create_and_add接口,分配一个kobject概念模型结构并把它添加到kernel中3.3.2 Kobject的分配和释放前面讲过,Kobject必须动态分配,而不能静态定义或者位于堆栈之上,它的分配方法有两种。
通过kmalloc自行分配(一般是跟随上层数据结构分配),并在初始化后添加到kernel这种方法涉及如下接口:extern void kobj概念模型ect_init(struct kobject *kobj, struct kobj_type *ktype);
kobject_init,初始化通过kmalloc等内存分配函数获得的struct kobject指针主要执行逻辑为:确认ko概念模型bj和ktype不为空 如果该指针已经初始化过(判断kobj->state_initialized),打印错误提示及堆栈信息(但不是致命错误,所以还可以继续) 初始化kobj内部的参数,包括引用计数、list、各种标志等 根据输入参数,将ktype指针赋予kobj->ktype kobject_ad概念模型d,将初始化完成的kobject添加到kernel中,参数包括需要添加的kobject、该kobject的parent(用于形成层次结构,可以为空)、用于提供kobject name的格式化字符串。
主要执行逻辑为:确认kobj不为空,确认kobj已经初始化,否则错误退出 调用内部接口kobject_概念模型add_varg,完成添加操作 kobject_init_and_add,是上面两个接口的组合,不再说明。
Copyright © 2002-2020 上海润之模型设计有限公司 版权所有 展示模型,展品模型,展厅模型,展示道具,展厅展品,展品道具,模型定制,模型公司,上海模型公司 备案号:沪ICP备20018260号