kobject --- kernel对象的意思,是内核中类似面向对象的概念.
kobject可以被认为是最顶层的基类,其他类都是他的派生物。
C语言中不允许直接描述继承关系,所以使用了诸如在一个结构中嵌入另外一个结构的技术。
定义如下:
struct kobject{
const char *name;
struct list_head entry;
struct kobject *parent; //上一层kobject结构的指针
struct kset *kset;
struct kobj_type *ktype;
struct sysfs_dirent *sd;
struct kref kref;
unsigned int state_initialized:1;
unsigned int state_in_sysfs:1;
unsigned int state_add_uevent_sent:1;
unsigned int state_remove_uevent_sent:1;
unsigned int uevent_suppress:1;
};
1. kobject初始化:对kobject的初始化比较复杂。
a. 将整个kobject置0,这里通常使用memset()函数. 如果忘记对kobject的清零初始化,则在以后使用kobject时,可能会发生一些奇怪的错误。
b. 调用kobject_init()函数,用来设置kobject结构内部的一些成员,如设置kobject的引用计数为1。
/**
* kobject_init - initialize a kobject structure
* @kobj: pointer to the kobject to initialize
* @ktype: pointer to the ktype for this kobject.
*
* This function will properly initialize a kobject such that it can then
* be passed to the kobject_add() call.
*
* After this function is called, the kobject MUST be cleaned up by a call
* to kobject_put(), not by a call to kfree directly to ensure that all of
* the memory is cleaned up properly.
*/
void kobject_init(struct kobject*kobj, struct kobj_type *ktype)
{
char *err_str;
if (!kobj){
err_str = "invalid kobject pointer!";
goto error;
}
if (!ktype){
err_str = "must have a ktype to be initialized properly!\n";
goto error;
}
if (kobj->state_initialized){
/* do not error out as sometimes we can recover */
printk(KERN_ERR "kobject (%p): tried to init an initialized "
"object, something is seriously wrong.\n", kobj);
dump_stack();
}
kobject_init_internal(kobj);
kobj->ktype= ktype;
return;
error:
printk(KERN_ERR "kobject (%p): %s\n", kobj, err_str);
dump_stack();
}
EXPORT_SYMBOL(kobject_init);
c. 使用者必须至少设置kobject的名字,这是sysfs入口中使用的名字.可以用:
int kobject_set_name(struct kobject *kobj, const char *fmt, ...)
/**
* kobject_set_name - Set the name of a kobject
* @kobj: struct kobject to set the name of
* @fmt: format string used to build the name
*
* This sets the name of the kobject. If you have already added the
* kobject to the system, you must call kobject_rename() in order to
* change the name of the kobject.
*/
int kobject_set_name(struct kobject*kobj, const char *fmt, ...)
{
va_list vargs;
int retval;
va_start(vargs, fmt);
retval = kobject_set_name_vargs(kobj, fmt, vargs);
va_end(vargs);
return retval;
}
EXPORT_SYMBOL(kobject_set_name);
d. 为包含它的结构设置引用计数。只要对象的引用计数存在,对象就必须存在。底层控制kobject引用计数的函数:
*kobject_get():引用计数+1
kobject_put(): 引用计数-1
/**
* kobject_get - increment refcount for object.
* @kobj: object.
*/
struct kobject *kobject_get(struct kobject*kobj)
{
if (kobj)
kref_get(&kobj->kref);
return kobj;
}
/**
* kobject_put - decrement refcount for object.
* @kobj: object.
*
* Decrement the refcount, and if 0, call kobject_cleanup().
*/
void kobject_put(struct kobject*kobj)
{
if (kobj){
if (!kobj->state_initialized)
WARN(1, KERN_WARNING"kobject: '%s' (%p): is not "
"initialized, yet kobject_put() is being "
"called.\n", kobject_name(kobj), kobj);
kref_put(&kobj->kref, kobject_release);
}
}
kobject的引用计数不足以防止竞态的产生。当kobject继续被使用时,不能卸载该模块。
e. 每个kobject必须有一个release方法,有趣的事,release函数并没有包含在kobject自身内。而是用kobj_type结构:
struct kobj_type{
void (*release)(struct kobject*kobj); //这个就是用来保存kobject release函数指针。
const struct sysfs_ops*sysfs_ops;
struct attribute**default_attrs;
const struct kobj_ns_type_operations*(*child_ns_type)(struct kobject*kobj);
const void*(*namespace)(struct kobject *kobj);
};
每个kobject都需要一个相应的kobj_type结构,可以在两个不同的地方找到这个指针:
1) kobject结构中包含了一个成员(ktype)保存了该指针。
2) 如果kobject是kset的一个成员的话,kset会提供kobj_type指针。
static inline struct kobj_type *get_ktype(struct kobject*kobj)
{
return kobj->ktype; //用来查找指定kobject的kobj_type指针。
}
2. kobject的层次结构:
内核用kobject结构将各个对象连接起来,组成一个分层的结构体系。
有2中独立的机制用于连接:parent指针和kset。
1. parent: kobject结构的parent成员 用来保存另一个kobject结构的指针,这个结构表示了分层结构中的上一层节点。parent指针最重要的用途是在sysfs分层结构中定位对象。
2. kset:是嵌入相同类型的kobject的集合。
kobj_type结构关心的是对象的类型,而kset结构关心的是对象的集合。这两个概念是分立的,同种类型的对象可以出现在不同的集合中。
实际上,kset是kobject的顶层容器类,在每个kset内部,都包含了自己的kobject,并且可以用多种处理kobject的方法处理kset.