kobject

在Linux设备模型中,kobject是它的基础结构。其数据结构定义在kernel-4.9/include/linux/kobject.h。

struct kobject {
	const char		*name;
	struct list_head	entry;
	struct kobject		*parent;
	struct kset		*kset;
	struct kobj_type	*ktype;
	struct kernfs_node	*sd; /* sysfs directory entry */
	struct kref		kref;
#ifdef CONFIG_DEBUG_KOBJECT_RELEASE
	struct delayed_work	release;
#endif
	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;
};

name, kobject的名称,它将以一个目录的形式出现在sysfs文件系统中

kref对象,用于引用计数管理。kref_init()接口用于初始化kref接口,kref_get()用于增加相关的引用计数,而kref_put则用于减少引用计数,当没有剩下的引用后,对象会被释放。kref的相关定义在kernel-4.9/include/linux/kref.h中。

kset的指针,表征kobject归属的对象集。

kobj_type,用于描述kobject的对象类型。

kobject与sysfs紧密关联。内核中的每个对象实例都有一个sysfs的代表。


kobject的使用

内核代码几乎不会去创建一个单独的kobject对象。它在使用时,会被嵌入到其他的结构中。这个和之前提到的双向链表 list_head的用法一样。要找到对应包含kobject的结构,需要用到之前提到宏container_of。

初始化:

首先要将整个kobject设置为0,这通常使用memset函数。之后调用kobject_init()函数,再通过kobject_set_name设个名字,这个名字会在sysfs入口中使用。kobject的创建者需要直接或者间接设置的成员有:ktype、kset和parent。

以下是kobject和引用计数相关一些函数:

/* 调用成功将增加kobject的引用计数,并返回指向kobject的指针。
 * 如果kobject已经处于被销毁的过程中,则调用失败,kobject_get返回NULL。
 * 必须检查返回值,否则可能会产生麻烦的竟态。
 */
extern struct kobject *kobject_get(struct kobject *kobj);
/* 调用后减少引用计数,并在可能的情况下释放该对象。
 * 请记住kobject_init设置引用计数为1,所以当创建kobject时,
 * 如果不再需要初始的引用,就要调用响应的kobject_put函数。
 */
extern void kobject_put(struct kobject *kobj);

在许多情况下,kobject中的引用计数不足以防止竞态的产生。举个例子,kobject的存在需要创建它的模块继续存在。当kobject继续被使用时,不能卸载该模块。以下是cdev结构中的引用计数的实现:

struct kobject *cdev_get(struct cdev *p) {
    struct module *owner = p->owner;
    struct kobject *kobj;
    if (owner && !try_module_get(owner)) {
        return NULL;
    }
    kobj = kobject_get(&p->kobj);
    if (!kobj) {
        module_put(owner);
    }

    return kobj;
}

创建cdev结构的引用时,也需要创建包含它的模块的引用。因此,cdev_get使用try_module_get去增加模块的使用计数。如果操作成功,使用kobject_get增加kobject的引用计数。当然这个操作也可能会失败,因此代码需要检测kobject_get的返回值。如果失败,则释放对模块的引用计数。

当kojbect的引用计数为0时,会异步的调用对应的release方法释放资源。每一个kobject都必须有一个release方法,并且kobject在该方法被调用前必须保持不变(处于稳定状态)。release被包含在kobj_type中,如下:

struct kobj_type {
	void (*release)(struct kobject *kobj);
	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);
};

kobj_type是kobject的一个成员。在初始化时作为参数传入:

extern void kobject_init(struct kobject *kobj, struct kobj_type *ktype);

猜你喜欢

转载自blog.csdn.net/weixin_39821531/article/details/88390537
今日推荐