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.
kobject与sysfs文件系统有着密切的关系,所有注册到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)
- uclinux内核的对象表示:kobjects
- uclinux内核的container_of
- uclinux内核的console
- uclinux内核线程的创建
- uclinux内核的文件系统类型
- uclinux内核的任务切换
- 编译自己的uclinux内核
- uclinux内核的console(1):数据结构
- uclinux内核的console(2):early console
- uclinux内核的任务优先级及其load_weight
- uclinux第一个内核线程的运行
- uclinux内核驱动的初始化顺序
- uclinux内核中根文件系统的建立
- uclinux内核VFS的简单遍历
- uclinux内核的console(1):数据结构
- uclinux内核的console(5):printk相关的内核参数
- uClinux内核和标准linux内核的比较
- uClinux内核添加应用程序
- MyEclipse快捷键与插件大全
- 何为分布式应用开发模式
- 计算机视觉和模式识别牛人的主页
- How to talk to anyone
- ajax初步学习
- uclinux内核的对象表示:kobjects
- vs.php for visual studio 2005错误解决
- 杨澜说女孩应该这样:
- SQL注入内容更新.
- js报表效果
- 在 struts中的ajax
- 2009-04-24单词学习
- Linux系统网络配置详细说明
- 企业网站为什么要选择搜索引擎优化