kobject的浅析

/**
    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;

}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值