kobject和kset

kobject和kset实现了基本的面向对象管理机制,是构成linux2.6设备模型的核心结构。它与sysfs文件系统紧密相联,在内核中注册的每个kobject对象对应sysfs文件系统中的一个目录。

kset是kobject的集合,kobject只能包含属性(在sysfs中即为文件),kset可以包含目录(亦即kobject)。

linux2.6 引入了sysfs文件系统,与proc文件系统同类,属于ramfs。

sysfs把连接在系统上的设备和总线组织称分级的文件,使其从用户空间可以访问,修改。


kobject最初只是被理解为一个简单的引用计数,但现在也有了很多成员,它所能处理的任务以及它所支持的代码包括:对象的引用计数、sysfs表述、结构关联、热插拔事件处理等。
        struct kobject {
            const char      *k_name;

            char        name[KOBJ_NAME_LEN];
 /*k_name指针指向kobject名称的起始位置,如果名称长度小于KOBJ_NAME_LEN,那么该kobject的名称便存放到name数组中,k_name指向数组头;如果名称大于20,则动态分配以讹足够大的缓冲区来存放kobject的名称,这时k_name指向缓冲区。*/
            struct kref     kref;   //该kobject的引用计数。
            struct list_head    entry;   //链表的节点,用于挂接到该kobject对象到kset;所有同一子系统下的所有相同类型的kobject被链接成一个链表组织在一起,成员kset就是嵌入相同类型结构的kobject集合
            struct kobject      *parent;  //指向该kobject所属分层结构中的上一层节点,所有内核模块的parent是module
            struct kset         *kset;   //所属的kest的指针,即父kset
            struct kobj_type    *ktype;  //指向对象类型描述符的指针
            struct dentry       *dentry;   //文件系统相关中雨该对象对应的文件节点入口
        };

 

调用函数:
1:void kobject_init(struct kobject *):
初始化kobject,设置引用计数为1,entry域指向自身,所属的kset引用计数加1


2:int kobject_set_name(struct kobject *, const char *, ...)
用于设置置顶的kobject名称


3:void kobject_cleanup(struct kobject *)
用于清除kobject,当引用计数为0的时候,释放对象占用的资源


4:struct kobject *kobject_get(struct kobject *)
增加一个引用计数,返回该对象指针


5:void kobject_put(struct kobject *)
减少引用计数


6:int kobject_add(struct kobject *)
将对象加入linux设备层次,挂接该对象到kset的list中,增加父目录各级kobject的引用计数;并在其父对象指向的目录下创建文件节点,并启用该类型内核对象的hotplug函数


7:int kobject_add(struct kobject *)
kobject_add()函数的反函数,操作相反


8:int kobject_register(struct kobject *)
用于注册kobject,先调用kobject_init()函数进行初始化,后调用kobject_add()完成对象增加


9:int kobject_unregister(struct kobject *)
先调用kobject_del从设备层次删除该对象,在调用kobject_put减少该对象的引用计数,如果引用计数降为0,则释放该对象

 

注:新创建的kobject被加入到kset时(调用kobject_init),引用计数被加1,然后kobject跟它的parent建立关联时,引用计数被加1,所以一个新创建的kobject,其引用计数总是为2。另外kobject通常是嵌入到其他结构中的,其单独意义其实并不大。相反,那些更为重要的结构体才真正需要用到kobject结构。比如struct cdev。

 

其他相关结构:

1:struct kset {
    struct subsystem    *subsys;  //所在的subsystem的指针
    struct kobj_type    *ktype;  //指向该kest的kobject对象类型描述符的指针,被该kset的所有kobject共享
    struct list_head    list;  //用于连接该kset所拥有的kobject的链表头
    spinlock_t          list_lock;  //用于同步的自旋锁
    struct kobject      kobj;  //嵌入的kobject对象,用于引用计数,这也是该kset的引用计数
    struct kset_uevent_ops  * uevent_ops;  //事件操作集,具体可看linux设备驱动开发详解P102
    };
注:调用函数与kobject基本类似

 

2:struct kobj_type {
   void  (*release)(struct kobject *);  //kobject引用计数减至0时要调用的析构函数
   struct  sysfs_ops  * sysfs_ops;   //属性操作
   struct  attribute  ** default_attrs;   //默认属性
};
注:其属性操作函数由sysfs_ops定义:
struct sysfs_ops
   {
       ssize_t (*show)(struct kobject *kobj, struct attribute *attr, char *buffer);
       ssize_t (*store)(struct kobject *kobj, struct attribute *attr, const char *buffer, size_t size);
   };

show:读属性文件时调用

store:写属性文件时调用

 3:struct kset_uevent_ops {
   int (*filter)(struct kset *kset, struct kobject *kobj);
   const char *(*name)(struct kset *kset, struct kobject *kobj);
   int (*uevent)(struct kset *kset, struct kobject *kobj, char **envp, int num_envp, char *buffer, int buffer_size);

};

filter:决定是否将时间传递到用户空间。如果filter返回0,将不传递事件。

name:用于将字符串传递给用户空间的热插拔处理程序。

uevent:将用户空间需要的参数添加到环境变量中。


实例:

kobject.c

建立目录:/sys/kobject_test

建立文件:/sys/kobject_test/kobj_config

#include <linux/device.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/string.h>
#include <linux/sysfs.h>
#include <linux/stat.h>
 
MODULE_AUTHOR("gzliu");
MODULE_LICENSE("Dual BSD/GPL");
 
void obj_test_release(struct kobject *kobject);
ssize_t kobj_test_show(struct kobject *kobject, struct attribute *attr,char *buf);
ssize_t kobj_test_store(struct kobject *kobject,struct attribute *attr,const char *buf, size_t count);
 
struct attribute test_attr = {
        .name = "kobj_config",
        .mode = S_IRWXUGO,
};
 
static struct attribute *def_attrs[] = {
        &test_attr,
        NULL,
};
 
 
struct sysfs_ops obj_test_sysops =
{
        .show = kobj_test_show,
        .store = kobj_test_store,
};
 
struct kobj_type ktype = 
{
        .release = obj_test_release,
        .sysfs_ops=&obj_test_sysops,
        .default_attrs=def_attrs,
};
 
void obj_test_release(struct kobject *kobject)
{
        printk("eric_test: release .\n");
}
 
ssize_t kobj_test_show(struct kobject *kobject, struct attribute *attr,char *buf)
{
        printk("have show.\n");
        printk("attrname:%s.\n", attr->name);
        sprintf(buf,"%s\n",attr->name);
        return strlen(attr->name)+2;
}
 
ssize_t kobj_test_store(struct kobject *kobject,struct attribute *attr,const char *buf, size_t count)
{
        printk("havestore\n");
        printk("write: %s\n",buf);
        return count;
}
 
struct kobject kobj;
static int kobj_test_init()
{
        printk("kboject test init.\n");
        kobject_init_and_add(&kobj,&ktype,NULL,"kobject_test");
        return 0;
}
 
static int kobj_test_exit()
{
        printk("kobject test exit.\n");
        kobject_del(&kobj);
        return 0;
}
 
module_init(kobj_test_init);
module_exit(kobj_test_exit);

kset.c

建立目录:/sys/kset_p

                   /sys/kset_p/kset_c

#include <linux/device.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/string.h>
#include <linux/sysfs.h>
#include <linux/stat.h>
#include <linux/kobject.h>
 
MODULE_AUTHOR("gzliu");
MODULE_LICENSE("Dual BSD/GPL");
 
struct kset kset_p;
struct kset kset_c;

int kset_filter(struct kset *kset, struct kobject *kobj)
{
        printk("Filter: kobj %s.\n",kobj->name);
        return 1;
}
 
const char *kset_name(struct kset *kset, struct kobject *kobj)
{
        static char buf[20];
        printk("Name: kobj %s.\n",kobj->name);
        sprintf(buf,"%s","kset_name");
        return buf;
}
 
int kset_uevent(struct kset *kset, struct kobject *kobj,struct kobj_uevent_env *env)
{
        int i = 0;
        printk("uevent: kobj %s.\n",kobj->name);

        while( i < env->envp_idx){
                printk("%s.\n",env->envp[i]);
                i++;
        }

        return 0;
}

struct kset_uevent_ops uevent_ops = 
{
        .filter = kset_filter,
        .name   = kset_name,
        .uevent = kset_uevent,
};
 
int kset_test_init()
{
        printk("kset test init.\n");
        kobject_set_name(&kset_p.kobj,"kset_p");
        kset_p.uevent_ops = &uevent_ops;
        kset_register(&kset_p);
 
        kobject_set_name(&kset_c.kobj,"kset_c");
        kset_c.kobj.kset = &kset_p;
        kset_register(&kset_c);
        return 0;
}
 
int kset_test_exit()
{
        printk("kset test exit.\n");
        kset_unregister(&kset_p);
        kset_unregister(&kset_c);
        return 0;
}
 
module_init(kset_test_init);
module_exit(kset_test_exit);


你可能感兴趣的:(kobject和kset)