sysfs之kobject分析
来源:互联网 发布:厦门铠甲网络 陈滨 编辑:程序博客网 时间:2024/06/02 13:33
一 ,Kobjects概述
1.一个kboject是类型为structkobject的一个对象
2.一个ktype是 包含kobject的对象的类型
3.一个kset是一组kobjects
4.kobject是一种数据结构,定义在中 。
struct kobject{
constchar
structlist_head
structkobject
structkset
structkobj_type
struct sysfs_dirent*sd;
structkref
unsigned intstate_initialized:1;
unsigned intstate_in_sysfs:1;
unsigned intstate_add_uevent_sent:1;
unsigned intstate_remove_uevent_sent:1;
unsigned int uevent_suppress:1;
};其中,重要的变量已经加了注释,这里再简要介绍一下:
kref:
kref域表示该对象引用的计数,内核通过kref实现对象引用计数管理,内核提供两个函数kobject_get()、kobject_put() 分别用于增加和减少引用计数,当引用计数为0时,所有该对象使用的资源释放。
Ktype:
域是一个指向kobj type结构的指针,表示该对象的类型。
parent
指针指向kobject的父对象。因此,kobject就会在内核中构造一个对象层次结构,并且可以将对各对象间的关系表现出来,就如你看到的,这便是sysfs的真正面目:一个用户空间的文件系统,用来表示内核中kobject对象的层次结构。
kobject 是组成设备模型的基本结构,初始它只被作为一个简单的引用计数, 但随时间的推移,其任务越来越多。现在kobject所处理的任务和支持代码包括:
对象的引用计数 :跟踪对象生命周期的一种方法是使用引用计数。当没有内核代码持有该对象的引用时,该对象将结束自己的有效生命期并可被删除。
sysfs 表述:在 sysfs 中出现的每个对象都对应一个 kobject, 它和内核交互来创建它的可见表述。
数据结构关联:整体来看, 设备模型是一个极端复杂的数据结构,通过其间的大量链接而构成一个多层次的体系结构。kobject实现了该结构并将其聚合在一起。
热插拔事件处理 :kobject 子系统将产生的热插拔事件通知用户空间。
一个kobject对自身并不感兴趣,它存在的意义在于把高级对象连接到设备模型上。因此内核代码很少(甚至不知道)创建一个单独的kobject;而kobject 被用来控制对大型域(domain)相关对象的访问,所以kobject被嵌入到其他结构中。kobject 可被看作一个最顶层的基类,其他类都它的派生产物。 kobject实现了一系列方法,对自身并没有特殊作用,而对其他对象却非常有效。
对于给定的kobject指针,可使用container_of宏得到包含它的结构体的指针。
二、操作kobject
15,初始化和注册kobject
创建kobject的代码当然必须得初始化那个对象。一些内部的域强制使用kobject_init()来初始化:
因为每个kobject必须和一个kobj_type相关联,所以要想正确地创建kobject就需要一个ktype。
调用kobject_init()后,为了在sysfs中注册kobject,函数kobject_add()必须被调用:
还有一个函数用于同时初始化和将kobject加入内核,即kobject_init_and_add():
该函数的参数和单独的函数kobject_init()和kobject_add()所描述的参数一样。
int kobject_add(struct kobject * kobj)将kobj对象加入Linux设备层次。挂接该kobject对象到kset的list链中,增加父目录 各级kobject的引用计数,在其parent指向的目录下创建文件节点,并启动该类型内 核对象的hotplug函数。
void kobject_del(struct kobject * kobj)从Linux设备层次(hierarchy)中删除kobj对象。
int kobject_register(structkobject * kobj) kobject注册函数。通过调用kobjectinit()初始化kobj,再调用kobject_add()完 成该内核对象的注册。
void kobject_unregister(structkobject * kobj) kobject注销函数。与kobject register()相反,它首先调用kobjectdel从设备层次 中删除该对象,再调
该函数可以正确地设置kobject的名称和它的父节点。如果kobject被关联到一个特殊的kset,在调用kobject_add()之前kobj->kset必须被赋值。如果一个kset被关联到一个kobject,那么在kobject_add()调用中该kobject的父节点可被设置为NULL(就是kobject_add()的第二个参数设置为NULL),并且,该kobject的父节点就是那个kset本身。
2,kobject名称
因为kobject的名称在kobject加入内核的时候就被设定了,所以永远不要直接操作一个kobject的名字。如果你必须改变kobject的名字,那么请调用kobject_rename():设置kobject名称
该函数不会进行任何locking,也不会去检查名字的合法性,所以调用者必须提供locking机制和检查名字的合法性。
还有一个叫做kobject_set_name()的函数,该函数将被删除,所以不要调用这个函数。
应该使用函数kobject_name()来获取kobject的名字:
三、热插拔
当一个kobject被注册到kobject核心后,需要对外声明该kobject已经被创建。可以通过调用kobject_uevent()来实现:
当kobject第一次被加入内核时,使用KOBJ_ADD事件。使用该事件时,所有的kobject的属性或孩子都必须已被正确地初始化,因为当KOBJ_ADD发生时用户空间会立刻开始检查它们。
当kobject被从内核移除时,kobject核心会自动创建KOBJ_REMOVE事件,调用者无需手动创建。
四、引用计数
Kobject的一个关键的功能就是作为包含它的对象的引用计数。只要对这个对象的引用还存在,该对象(和支持该对象的代码)就必须存在。底层操作kobject引用计数的函数是:
正确调用kobject_get()将会增加kobject的引用计数并且返回指向kobject的指针。
当释放一个引用时,调用kobject_put()会减少引用计数,并且有可能会释放对象(当引用计数为0时)。注意,kobject_init()设置引用计数为1,所以设置kobject的代码最终需要调用kobject_put()来释放那个引用。
因为kobjects是动态的,所以它们不能被声明为静态的或者存放在堆栈上,而总是要动态地分配。未来版本的内核会包含对kobject的运行时检查,如果发现kobject是静态创建的,将会警告开发者。
如果你仅仅想用kobject作为你的结构体的引用计数器,那么请使用结构kref;使用kobject太浪费了。想了解kref的信息请参考Documentation/kref.txt。
五、创建“简单”的kobjects
有时开发者仅仅希望有一种途径去在sysfs层次中创建一个简单的目录,而不是必须要和复杂的ksets、show和store方法,还有别的细节搞混。这就是一个需要单独创建一个kobject的例外(前面说过一般不单独创建一个kobject的)。为了创建这样一个入口,可以使用函数:
该函数会在sysfs中指定父kobject的下面创建和放置一个kobject。
创建简单的和该kobject相关联的属性时,可以使用:
int sysfs_create_file(struct kobject *kobj, struct attribute*attr);
或者int sysfs_create_group(structkobject *kobj, struct attribute_group *grp);
这里使用在通过kobject_create_and_add()创建的kobject上的两种类型的属性,可以是kobj_attribute类型的,因此不需要创建自定义的属性。
六、ktypes和release方法
一个重要的事情还没有被讨论,那就是当一个kobject的引用计数为0时,将会发生什么?创建kobject的代码一般不知道这种情况什么时候会发生(引用计数变为0);引入sysfs后,即使是可以预期的对象生命周期也会变得复杂,因为内核的其他部分可以引用任何注册于系统内的kobject。
最终的结果就是,一个被kobject保护的结构(结构中包含一个kobject)在其引用计数变为0之前不能被释放。创建kobject的代码并不直接控制引用计数。因此,当对kobjects的最后一个引用消失时,代码必须异步地通知。
一旦你通过kobject_add()注册了你的kobject,永远不要直接使用kfree()去释放它。仅有的安全的方法是使用kobject_put()。
这个通知是通过kobject的release()方法来完成的。通常这样的方法有一种格式:
很重要的一点是:每个kobject都必须有一个release()方法,并且kobject必须持久(在一个稳定的状态),直到这个方法被调用。如果没有遇到这样的限制,那么代码就是有瑕疵的。注意,如果你忘记提供release()方法,内核会给出警告。不要尝试通过提供一个“空的”release方法来规避这个警告;如果你尝试这么做,那么你会被kobject的维护者无情地嘲笑。
注意,在release方法中kobject的名字是可以获取的,但是在回调中必须不能被改变。否则,kobject核心将会出现内存泄漏,令人不快。
有趣的是,release方法并不存在于kobject内部,而是和ktype关联。所以让我们来介绍kobj_type结构:
这个结构体被用来描述一个特殊类型的kobject(或者,更准确点说,描述kobject的“容器”对象)。每个kobject都需要一个相关联的kobj_type结构;当你调用kobject_init()或者kobject_init_and_add()时指向kobj_type结构的指针必须被赋值。
结构体kobj_type的release成员是一个指向对应于该类kobject的release方法。其他两个成员(sysfs_ops和default_attrs)控制如何在sysfs中表示这个类型的对象;这超出了本文档的范围。
default_attrs指针是默认属性的列表,当创建注册于这个ktype的kobject的时候,这些默认属性会被自动的添加。
每个 kobject 必须有一个release函数, 并且这个kobject 必须在release函数被调用前保持不变( 稳定状态 ) 。这样,每一个 kobject 需要有一个关联的kobj_type 结构,指向这个结构的指针能在 2 个不同的地方找到:
(1)kobject 结构自身包含一个成员(ktype)指向kobj_type ;
(2)如果这个 kobject 是一个 kset 的成员, kset 会提供kobj_type 指针。
struct kset {
};
以下宏用以查找指定kobject的kobj_type 指针:
struct kobj_type *get_ktype(struct kobject *kobj);
这个函数其实就是从以上提到的这两个地方返回kobj_type指针,源码如下:
static inline struct kobj_type * get_ktype(struct kobject *k)
{
}
七、ksets
八、Kobject的移除
当一个kobject被成功地注册进kobject核心后,在代码结束对它的使用时,必须清除它。你可以调用kobject_put(),调用该函数后,kobject核心将会自动释放分配给该kobject的所有内存。如果一个KOBJ_ADDuevent被发送到kobject,那么一个对应的KOBJ_REMOVEuevent也将被发送,并且所有其他的sysfs的空间管理也将会被处理。
如果你需要两个阶段来删除kobject(就是说当需要销毁kobject的时候不允许睡眠),调用kobject_del(),该函数会将kobject从sysfs中移除,这将使得kobject不可见,但是并未被清除,并且对象的引用计数也未改变。在稍后的时间里调用kobject_put()来完成与kobject相关联的内存的释放。
如果循环引用构成,kobject_del()可以被用来放弃对父节点的引用。这在有些场合很有效,比如一个父节点引用一个子节点。必须使用kobject_del()来破坏循环引用,之后一个release方法将被调用,并且之前环路中的对象互相release。
- sysfs之kobject分析
- sysfs 之 kobject
- 深入分析kobject与sysfs的关系
- sysfs kobject
- linux内核设计与实现之kobject和sysfs
- LINUX内核设计与实现之kobject与sysfs
- LINUX内核设计与实现之kobject与sysfs
- kobject&sysfs[1]
- kobject与sysfs
- kobject与sysfs
- sysfs与kobject交互
- 读书笔记之linux内核设计与实现(16)kobject和sysfs
- kobject之kobject_uevent.c文件分析
- Linux设备模型分析之kobject
- kobject之kobject_uevent.c文件分析
- Linux设备模型分析之kobject
- Linux设备模型分析之kobject
- sysfs文件系统和kobject的关系
- 字符编码学习笔记
- HZK16的介绍及使用
- IIRF(Ionic's Isapi Rewrite Filt er)入门,在IIS上重写Url
- Linux内核热拔插机制
- CCIR656
- sysfs之kobject分析
- nor current process has android.permission.WRITE_APN_SETTINGS Proxy andriod,代理上网,wap网络请求问题(柯昌合)
- oracle 数据库中dual虚拟表的介绍
- CDT无法解析系统库定义类型问题的解决方法
- Win7下IIS由于扩展配置问题而无法提供请求的页
- android menu实时更新内容
- SQL Prompt5 破解版+使用说明
- 广播地址设为自己的ip地址,子网掩码设为255.255.255.255 是什么意思
- iOS企业应用发布教程