/**
kobject 实现了面向对象的管理机制,一般嵌入一个更大的结构体中
在内核中注册的一个kobject 对应 sysfs系统中的一个目录
向设备驱动模型中添加kobject,并在sysfs文件系统中添加一个目录
static int kobject_add_internal ( )
{
......
error = create_dir(kobj) //在sysfs中创建一个目录,该目录的名字 kobj->name
----> sysfs_create_dir( )
if ( error )
{
....
}
else{
kobj->state_in_sysfs = 1; //创建成功,表示kobject在sysfs中了
}
}
*/
struct kobject {
//kobject的名字,这个名字将显示在sysfs文件系统中,作为一个目录的名字。
const char *name;
//用于将该kobject链接到它所属的kset下的kobject链表中
//kset维护了一个链表。包含在该kset下的所有kobject被组织成一个双向的循环链表
struct list_head entry;
/*
父kobject,用来构建父子层次结构。
属于kset下的所有kobject对象的parent指针,都指向kset中内嵌的kobject ,
static int kobject_add_internal(struct kobject *kobj)
{
if (kobj->kset) { //是否属于一个kset集合
//如果该kobject没有父kobject,使用kset的kobject作为该kobject的父kobject
if (!parent)
parent = kobject_get(&kobj->kset->kobj); //增加引用计数
kobj_kset_join(kobj); //添加该kobject到kset维护的链表
kobj->parent = parent;//设置父kobject
}
}
*/
struct kobject *parent;
/**
相同类型的kobject集合
这样就很方便的通过kobject就能找到kset集合
如: 当内核调用kobject_add()、kobject_del()时,
根据kobject的kset指针找到它所属的kset,然后执行kset中的uevent_ops中的热插拔函数
struct kset{
....
struce kset_uevent_ops *uevent_ops;
};
*/
struct kset *kset;
/**
kobject的属性,表示sysfs中的文件,放在kobject对应的目录下
对sysfs中的文件进行读写 :
kobject->ktype->sysfs_ops
struct kobj_type {
释放函数.
当kobject的引用计数为0的时候(kobject_get、kobject_put),自动调用
void (*release)(struct kobject *kobj);
包含了操作属性的函数
struct sysfs_ops *sysfs_ops;
属性数组。一个kobjet可以有一个、多个属性
struct attribute **default_attrs;
};
*/
struct kobj_type *ktype;
/**
对应的sysfs目录项,下面代码有解释
*/
struct sysfs_dirent *sd;
/**
引用计数器,嵌套在kobject中记录该kobejct的引用计数,当计数值为0的时候自动调用release函数
下面是它的结构:
struct kref {
atomic_t refcount;//当它的值为0的时候,kobject的生命周期就结束了,release会被调用
};
包含一个atomic_t类型的计数值,省去了获取锁--访问临界区---释放锁的过程。
release函数被调用 源码:
void kobject_put(struct kobject *kobj)
{
...
kref_put(&kobj->kref, kobject_release)
{
...
从原子变量refcount中减去 1 ,如果refcount为0,返回true,就调用release函数
if (atomic_dec_and_test(&kref->refcount)) {
release(kref); //release函数被调用
return 1;
}
}
}
*/
struct kref kref;
/**
kobject是否已经进行过了初始化。
大致流程 :
void kobject_init(struct kobject *kobj, struct kobj_type *ktype)
{
kobject_init_internal(kobj)
{
kobj->state_in_sysfs = 0;
kobj->state_add_uevent_sent = 0;
kobj->state_remove_uevent_sent = 0;
kobj->state_initialized = 1; // 1 表示已经初始化了
}
}
*/
unsigned int state_initialized:1;
/**
state_in_sysfs 流程 :
1: 初始值 为 1,
2: kobject_init
kobject_init_internal 中设置成了 0.表示还没有在sysfs中
3: -->kobject_init_and_add
--> kobject_add_varg
---> kobject_add_internal 向设备驱动模型中添加kobject,并在sysfs文件系统中添加一个目录
当该函数调用成功后,state_in_sysfs被设置成了 1,表示该kobject在sysfs中了
4 : --->kobject_del , 将state_in_sysfs设置为0,表示该kobejct没有在sysfs中。
源码 :
void kobject_del(struct kobject *kobj)
{
if (!kobj)
return;
sysfs_remove_dir(kobj); //从sysfs中删除该kobject对应的目录
kobj->state_in_sysfs = 0;//不存在sysfs中了
kobj_kset_leave(kobj); //如果属于一个kset,那么将该kobject从kset维护的链表中删除
kobject_put(kobj->parent);//减少引用计数
kobj->parent = NULL; //父kobject设置为null
}
*/
unsigned int state_in_sysfs:1;
/**
kobject加入内核时,是否发送uevent事件
删除kobject时,是否发送uevent事件
该kobject状态发生变化的时候(如:移动kobject)是否发送uevent事件
*/
unsigned int state_add_uevent_sent:1;
unsigned int state_remove_uevent_sent:1;
unsigned int uevent_suppress:1;
};
1 :
static int kobject_add_internal(struct kobject *kobj)
{
....
error = create_dir(kobj); //在sysfs下创建目录
{
if (kobject_name(kobj)) {
sysfs_create_dir(kobj)
{
error = create_dir(kobj, parent_sd, type, ns, kobject_name(kobj), &sd)
{
struct sysfs_dirent *sd;
...
/**
sysfs中每个节点由一个syfs_dirent表示。
对应的名称为: kobject_name(kobj)
初始化sysfs_dirent结构体
*/
sd = sysfs_new_dirent(name, mode, SYSFS_DIR);
...
sd->s_dir.kobj = kobj; //sysfs_dirent与kobject关联,记录了对应的kobject
..
}
}
}
}
if (error)
{
.....
}else
{
kobj->state_in_sysfs = 1;//创建成功,表示该kobject已经在sysfs中了
}
}
2:
kobject的函数
/**
初始化kobject、添加该kobject到kobject结构层次中,成功后 将在/sys目录下生成一目录,生成目录的位置取决于第三个参数(该kobject的父kobject)的设置,如果设置为NULL,生成目录的位置位于sysfs的顶层
调用到了俩个函数
kobject_init(kobj, ktype);
kobject_add_varg(kobj, parent, fmt, args);
*/``
int kobject_init_and_add(struct kobject *kobj,struct kobj_type *ktype,struct kobject * parent,const char * fmt,...)
{
va_list args; //参数列表
int retval;
/**
初始化kobject
*/
kobject_init(kobj, ktype);
va_start(args,fmt); //解析可变参数列表
//为kobject添加参数。
retval = kobject_add_varg(kobj, parent, fmt, args);
va_end; //结束解析
return retval;
}
void kobject_init(struct kobject *kobj, struct kobj_type *ktype)
{
char *err_str;
//如果kobject为空,则出错
if (!kobj) { //等价与 if(NULL == kobj)
err_str = "invalid kobject pointer!";
goto error;
}
//如果ktype为空,则出错。可见必需传递一个ktype进来,即使该ktype是空的。
if (!ktype) {
err_str = "must have a ktype to be initialized properly!\n";
goto error;
}
/**
如果该kobject已经被初始化了,则出错。
*/
if (kobj->state_initialized) {
printk(KERN_ERR "kobject (%p): tried to init an initialized "
"object, something is seriously wrong.\n", kobj);
dump_stack();
}
/**
初始化kobject的内部成员
*/
kobject_init_internal(kobj);
/**
将传递过来的ktyp赋值给kobj->ktype
为什么要将ktype与kobject绑定呢?这是因为通过sysfs对属性文件的操作,就是对设备的操作
*/
kobj->ktype = ktype;
return;
}
static void kobject_init_internal(struct kobject *kobj)
{
if(!kobj) //如果传入的kobject指针为空,则退出
{
return;
}
/**
底层是调用atomic_t()函数,将kobject内嵌的struct kfre(引用计数器)中的refcount置 1,因为设置成了1,创建kobject的时候就不需要kobject_get()来增加引用计数了。
atomic_set(&kref->refcount, 1);
*/
kref_init(&kobj->kref);
//初始化kobject的链表
INIT_LIST_HEAD(&kobj->entry);
//表示kobject还没有被注册到sysfs中
kobj->state_in_sysfs = 0;
//添加kobject到内核发送uevent事件
////从内核中删除kobject的时候发送uevent事件
kobj->state_remove_uevent_sent = 0;
//表示该kobject已经被初始化过了
kobj->state_initialized = 1;
}