uclinux内核的对象表示:kobjects

来源:互联网 发布:巴洛特利 fifa15数据 编辑:程序博客网 时间:2024/06/05 07:34

快乐虾

http://blog.csdn.net/lights_joy/

lights@hb165.com

  

本文适用于

ADI bf561 DSP

优视科技BV561EVB开发板

uclinux-2008r1.5-rc3 (smp patch)

Visual DSP++ 5.0(update 5)

  

欢迎转载,但请保留作者信息

 

内核中使用了kobject来表示与管理一些内核对象,从documentation/kobject的描述可知,kobject兼有以下几个作用:

- Object reference counting.

- Maintaining lists (sets) of objects.

- Object set locking.

- Userspace representation.

kobjectsysfs文件系统有着密切的关系,所有注册到kobject核心的对象都将在sysfs文件系统中拥有一个目录,从而达到导出内核对象的目的。

1.1    相关数据结构

1.1.1   kref

这个结构体的定义位于include/linux/kref.h,用于表示一个kobject对象的引用计数。

struct kref {

     atomic_t refcount;

};

就是一个atomic_t类型的数据。

通常使用kref_init函数对它进行初始化:

/**

 * kref_init - initialize object.

 * @kref: object in question.

 */

void kref_init(struct kref *kref)

{

     atomic_set(&kref->refcount,1);

     smp_mb();

}

即将refcount的初值设置为1

1.1.2   kobject

这个结构体用于表示一个内核对象,其定义在include/linux/kobject.h

#define KOBJ_NAME_LEN            20

 

struct kobject {

     const char         * k_name;

     char          name[KOBJ_NAME_LEN];

     struct kref        kref;

     struct list_head   entry;

     struct kobject         * parent;

     struct kset        * kset;

     struct kobj_type   * ktype;

     struct dentry      * dentry;

     wait_queue_head_t  poll;

};

l         entry

每个kset下面都可有一长串的kobject列表,此成员即用于此目的。

l         dentry

由于每个kobject都将在sysfs文件系统中创建一个目录,这个值就是指向它的目录节点,因为sysfs是在内存中实现的,因而需要用一个dentry来表示,而不是一个inode

l         k_name

这个成员可以单独指定一个名称,如果没有单独指定,它将指向此结构体的name成员。而且k_name不允许为空字符串。

 

kobject结构体使用kobject_init函数进行初始化:

/**

 *   kobject_init - initialize object.

 *   @kobj:   object in question.

 */

void kobject_init(struct kobject * kobj)

{

     if (!kobj)

         return;

     kref_init(&kobj->kref);

     INIT_LIST_HEAD(&kobj->entry);

     init_waitqueue_head(&kobj->poll);

     kobj->kset = kset_get(kobj->kset);

}

通过此函数,引用计数设置为1

当要引用一个kobject对象时,通常使用kobject_get函数:

/**

 *   kobject_get - increment refcount for object.

 *   @kobj:   object.

 */

 

struct kobject * kobject_get(struct kobject * kobj)

{

     if (kobj)

         kref_get(&kobj->kref);

     return kobj;

}

/**

 * kref_get - increment refcount for object.

 * @kref: object.

 */

void kref_get(struct kref *kref)

{

     WARN_ON(!atomic_read(&kref->refcount));

     atomic_inc(&kref->refcount);

     smp_mb__after_atomic_inc();

}

kobject_get函数将此kobject对象的引用加1后返回此对象。

 

1.1.3   kset

这个结构体用于表示某一类对象(用kobject表示)的集合,其定义为:

/**

 *   kset - a set of kobjects of a specific type, belonging

 *   to a specific subsystem.

 *

 *   All kobjects of a kset should be embedded in an identical

 *   type. This type may have a descriptor, which the kset points

 *   to. This allows there to exist sets of objects of the same

 *   type in different subsystems.

 *

 *   A subsystem does not have to be a list of only one type

 *   of object; multiple ksets can belong to one subsystem. All

 *   ksets of a subsystem share the subsystem's lock.

 *

 *   Each kset can support specific event variables; it can

 *   supress the event generation or add subsystem specific

 *   variables carried with the event.

 */

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);

};

struct kset {

     struct kobj_type   * ktype;

     struct list_head   list;

     spinlock_t         list_lock;

     struct kobject         kobj;

     struct kset_uevent_ops * uevent_ops;

};

list这个成员可以很容易知道每个kset下面都将有许多的kobject。从kobj这个成员也可以猜测出内核是将kset也当成一个对象来看待的,呵呵。

通常使用kset_init函数进行此结构体的初始化:

/**

 *   kset_init - initialize a kset for use

 *   @k:  kset

 */

 

void kset_init(struct kset * k)

{

     kobject_init(&k->kobj);

     INIT_LIST_HEAD(&k->list);

     spin_lock_init(&k->list_lock);

}

注意在此并不改变uevent_ops成员的值,此值通常在定义kset的全局变量时初始化(可以初始化为NULL)。Ktype的值同样在全局变量定义时进行初始化,也可以设置为NULL

 

1.1.4   kobj_type

这个类型用以表示对某一类kobject的操作:

struct kobj_type {

     void (*release)(struct kobject *);

     struct sysfs_ops   * sysfs_ops;

     struct attribute   ** default_attrs;

};

 

1.2    对象集的定义:decl_subsys

内核中使用了decl_subsys这个宏来定义一类对象集:

#define decl_subsys(_name,_type,_uevent_ops) /

struct kset _name##_subsys = { /

     .kobj = { .name = __stringify(_name) }, /

     .ktype = _type, /

     .uevent_ops =_uevent_ops, /

}

比如在fs/namespace.c中就定义了这么一个对象集:

decl_subsys(fs, NULL, NULL);

这个对象集在mnt_init函数中进行注册:

     err = subsystem_register(&fs_subsys);

在内核中搜索,可以发现有不少的decl_subsys

  F:/embed/uClinux/uClinux-dist-2008R1.5-RC3/linux-2.6.x/block/genhd.c(611):decl_subsys(block, &ktype_block, &block_uevent_ops);

  F:/embed/uClinux/uClinux-dist-2008R1.5-RC3/linux-2.6.x/drivers/base/bus.c(147):static decl_subsys(bus, &ktype_bus, NULL);

  F:/embed/uClinux/uClinux-dist-2008R1.5-RC3/linux-2.6.x/drivers/base/class.c(75):static decl_subsys(class, &ktype_class, NULL);

  F:/embed/uClinux/uClinux-dist-2008R1.5-RC3/linux-2.6.x/drivers/base/class.c(481):static decl_subsys(class_obj, &ktype_class_device, &class_uevent_ops);

  F:/embed/uClinux/uClinux-dist-2008R1.5-RC3/linux-2.6.x/drivers/base/core.c(431):decl_subsys(devices, &ktype_device, &device_uevent_ops);

  F:/embed/uClinux/uClinux-dist-2008R1.5-RC3/linux-2.6.x/drivers/base/firmware.c(19):static decl_subsys(firmware, NULL, NULL);

  F:/embed/uClinux/uClinux-dist-2008R1.5-RC3/linux-2.6.x/drivers/base/sys.c(135):static decl_subsys(system, &ktype_sysdev_class, NULL);

  F:/embed/uClinux/uClinux-dist-2008R1.5-RC3/linux-2.6.x/fs/namespace.c(44):decl_subsys(fs, NULL, NULL);

  F:/embed/uClinux/uClinux-dist-2008R1.5-RC3/linux-2.6.x/kernel/ksysfs.c(66):decl_subsys(kernel, NULL, NULL);

  F:/embed/uClinux/uClinux-dist-2008R1.5-RC3/linux-2.6.x/kernel/params.c(697):decl_subsys(module, &module_ktype, &module_uevent_ops);

这些kset的共同特点是它们都没有parent

1.3    注册对象集:subsystem_register

此函数用于注册一个kset,其实现在fs/kobject.c中:

int subsystem_register(struct kset *s)

{

     return kset_register(s);

}

跟踪kset_register

/**

 *   kset_register - initialize and add a kset.

 *   @k:  kset.

 */

 

int kset_register(struct kset * k)

{

     if (!k)

         return -EINVAL;

     kset_init(k);

     return kset_add(k);

}

挺简单的,先初始化kset结构体,再将它加入到内核中kset的链表中。

跟踪kset_add

/**

 *   kset_add - add a kset object to the hierarchy.

 *   @k:  kset.

 */

 

int kset_add(struct kset * k)

{

     return kobject_add(&k->kobj);

}

从这里可以明显看出kset本身的确也是一个kobject

跟踪kobject_add

/**

 *   kobject_add - add an object to the hierarchy.

 *   @kobj:   object.

 */

int kobject_add(struct kobject * kobj)

{

     return kobject_shadow_add(kobj, NULL);

}

跟踪kobject_shadow_add

/**

 *   kobject_shadow_add - add an object to the hierarchy.

 *   @kobj:   object.

 *   @shadow_parent: sysfs directory to add to.

 */

 

int kobject_shadow_add(struct kobject * kobj, struct dentry *shadow_parent)

{

     int error = 0;

     struct kobject * parent;

 

     if (!(kobj = kobject_get(kobj)))

         return -ENOENT;

     if (!kobj->k_name)

         kobj->k_name = kobj->name;

     if (!*kobj->k_name) {

         pr_debug("kobject attempted to be registered with no name!/n");

         WARN_ON(1);

         kobject_put(kobj);

         return -EINVAL;

     }

     parent = kobject_get(kobj->parent);

 

     pr_debug("kobject %s: registering. parent: %s, set: %s/n",

          kobject_name(kobj), parent ? kobject_name(parent) : "<NULL>",

          kobj->kset ? kobj->kset->kobj.name : "<NULL>" );

 

     if (kobj->kset) {

         spin_lock(&kobj->kset->list_lock);

 

         if (!parent)

              parent = kobject_get(&kobj->kset->kobj);

 

         list_add_tail(&kobj->entry,&kobj->kset->list);

         spin_unlock(&kobj->kset->list_lock);

         kobj->parent = parent;

     }

 

     error = create_dir(kobj, shadow_parent);

     if (error) {

         /* unlink does the kobject_put() for us */

         unlink(kobj);

         kobject_put(parent);

 

         /* be noisy on error issues */

         if (error == -EEXIST)

              printk(KERN_ERR "kobject_add failed for %s with "

                     "-EEXIST, don't try to register things with "

                     "the same name in the same directory./n",

                     kobject_name(kobj));

         else

              printk(KERN_ERR "kobject_add failed for %s (%d)/n",

                     kobject_name(kobj), error);

         dump_stack();

     }

 

     return error;

}

此时shadow_parent参数为NULL

在此函数中,如果kobject有指定的kset,则将此object添加到kset的对象链表中,如果没有显式指定parent,则取kset做为它的parent

然后调用create_dir函数在sysfs文件系统中创建此kobject的入口。

1.4    kobject创建目录:create_dir

此函数的定义在lib/kobject.c

static int create_dir(struct kobject * kobj, struct dentry *shadow_parent)

{

     int error = 0;

     if (kobject_name(kobj)) {

         error = sysfs_create_dir(kobj, shadow_parent);

         if (!error) {

              if ((error = populate_dir(kobj)))

                   sysfs_remove_dir(kobj);

         }

     }

     return error;

}

两步走,先用sysfs_create_dir创建目录,如果没有发生错误,它将正确设置好kobject::dentry,使其指向正确的目录指针。如果此kobject有指定的parent,那么sysfs_create_dir将把它挂在其parent目录下,如果没有则挂在sysfs_mount->mnt_sb->s_root下面。

接着用populate_dir设置目录的属性。

1.5    设置kobject属性:populate_dir

此函数的定义在lib/kobject.c中:

/**

 *   populate_dir - populate directory with attributes.

 *   @kobj:   object we're working on.

 *

 *   Most subsystems have a set of default attributes that

 *   are associated with an object that registers with them.

 *   This is a helper called during object registration that

 *   loops through the default attributes of the subsystem

 *   and creates attributes files for them in sysfs.

 *

 */

 

static int populate_dir(struct kobject * kobj)

{

     struct kobj_type * t = get_ktype(kobj);

     struct attribute * attr;

     int error = 0;

     int i;

    

     if (t && t->default_attrs) {

         for (i = 0; (attr = t->default_attrs[i]) != NULL; i++) {

              if ((error = sysfs_create_file(kobj,attr)))

                   break;

         }

     }

     return error;

}

此函数将为此kobject的每一个属性在sysfs中创建一个attribute file

 

1       参考资料

细读内核双链表(2008/6/29)

loops_per_jiffy的计算(2008/6/24)

uclinux-2008r1(bf561)内核中的EXPORT_SYMBOL (2008/5/19)

uClinux2.6中的双链表2008/3/11

 

 

 

 

 

原创粉丝点击