Linux kernel -- 内核对象kobject
来源:互联网 发布:医院药房软件系统 编辑:程序博客网 时间:2024/06/02 02:03
内核对象和集合
Linux驱动模型的基础是内核对象。它将总线类型、设备、驱动等看作是内核对象。内核对象的结构为kobject,相当于其它对象的基类。结构kobject的定义如下:
struct kobject { const char *name; /*kobject的名字*/ struct list_head entry; /*将kobject链接到kset的连接件*/ struct kobject *parent; /*指向kobject的父对象的指针*/ struct kset *kset; /*如果kobject已链接到kset,则指向它*/ struct kobj_type *ktype; /*kobject的类型*/ struct sysfs_dirent *sd; /*指向kobject在sysfs内部树中的节点*/ struct kref kref; /*kobject的引用计数*/ unsigned int state_initialized:1; /*如果为1,表示kobject已被经过初始化*/ unsigned int state_in_sysfs:1; /*如果为1,表示kobject已被添加到内核关系树中*/ unsigned int state_add_uevent_sent:1; /*如果为1,表示kobject已发送过添加事件到用户空间*/ unsigned int state_remove_uevent_sent:1; /*如果为1,表示kobject已发送过删除事件到用户空间*/ unsigned int uevent_suppress:1; /*如果为1,表示抑制发送事件到用户空间*/};
说明:本文所有的源代码均取自内核2.6.32。
对于内核对象kobject,有些成员和方法是内核对象类型特定的。即对该类型的所有内核对象,这些成员和方法是相同的。
struct kobj_type { void (*release)(struct kobject *kobj); /*该类型的内核对象的释放方法*/ struct sysfs_ops *sysfs_ops; /*指向操作表结构的指针,其中实现该类型内核对象的属性读/写方法*/ struct attribute **default_attrs; /*该类型的内核对象的默认属性*/};
kset表示内核对象的集合。结构kset的定义如下:
struct kset { struct list_head list; /*该kset中的所有kobjetc的链表*/ spinlock_t list_lock; /*用于遍历该kset的所有kobject的自旋锁*/ struct kobject kobj; /*该kset的内嵌kobject(递归)*/ struct kset_uevent_ops *uevent_ops; /*该kset的uevent操作集。相应的函数在kobject发生某种事件时调用,kset可以添加新的环境变量,或者过滤一些uevent*/};
创建或初始化内核对象
在使用内核对象之前,必须创建或初始化kobject结构体。对应的函数分别是kobject_create或kobject_init。如果用户已为kobject分配了空间,则只需要调用kobject_init。否则,需要调用kobject_create,该函数先为kobject分配空间,接着调用kobject_init。
函数kobject_create定义如下:
struct kobject *kobject_create(void){ struct kobject *kobj; kobj = kzalloc(sizeof(*kobj), GFP_KERNEL); if (!kobj) return NULL; kobject_init(kobj, &dynamic_kobj_ktype); return kobj;}
函数kobject_init定义如下:
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();}
函数首先进行了一些必要的检查。内核对象原则上不应该被重复初始化,但是如果出现这种情况,程序也不退出,而是打印错误信息后继续执行。然后调用函数kobject_init_internal初始化内核对象中的部分变量。
函数kobject_init_internal定义如下:
static void kobject_init_internal(struct kobject *kobj){ if (!kobj) return; kref_init(&kobj->kref); INIT_LIST_HEAD(&kobj->entry); kobj->state_in_sysfs = 0; kobj->state_add_uevent_sent = 0; kobj->state_remove_uevent_sent = 0; kobj->state_initialized = 1;}
kobject_init_internal初始化了内核对象中的部分变量,主要包括:
- 初始化内核对象的内嵌引用计数;
- 初始化内核对象用于链接到kset的连接件;
- 当前内核对象还没被添加到sysfs文件系统,此外,也没有向用户空间发送任何uevent事件,因此对象的变量都设为0;
- 该函数执行结束时,意味着内核对象已初始化完成,设置state_initialized为1。
将内核对像添加到sysfs文件系统
在调用kobject_init后,要向sysfs注册该kobject,所以必须调用kobject_add函数。如果kobject结构体不准备在sysfs层次使用,就不用调用kobject_add函数。
函数kobject_add定义如下:
int kobject_add(struct kobject *kobj, struct kobject *parent, const char *fmt, ...){ va_list args; int retval; if (!kobj) return -EINVAL; if (!kobj->state_initialized) { printk(KERN_ERR "kobject '%s' (%p): tried to add an " "uninitialized object, something is seriously wrong.\n", kobject_name(kobj), kobj); dump_stack(); return -EINVAL; } va_start(args, fmt); retval = kobject_add_varg(kobj, parent, fmt, args); va_end(args); return retval;}
函数kobject_add_varg定义:
static int kobject_add_varg(struct kobject *kobj, struct kobject *parent, const char *fmt, va_list vargs){ int retval; retval = kobject_set_name_vargs(kobj, fmt, vargs); if (retval) { printk(KERN_ERR "kobject: can not set name properly!\n"); return retval; } kobj->parent = parent; return kobject_add_internal(kobj);}
调用kobject_set_name_vargs函数设置内核对象kobject的名字,并设置了父对象。
函数kobject_add_internal定义:
static int kobject_add_internal(struct kobject *kobj){ int error = 0; struct kobject *parent; if (!kobj) return -ENOENT; if (!kobj->name || !kobj->name[0]) { WARN(1, "kobject: (%p): attempted to be registered with empty " "name!\n", kobj); return -EINVAL; } parent = kobject_get(kobj->parent); /* join kset if set, use it as parent if we do not already have one */ if (kobj->kset) { if (!parent) parent = kobject_get(&kobj->kset->kobj); kobj_kset_join(kobj); kobj->parent = parent; } pr_debug("kobject: '%s' (%p): %s: parent: '%s', set: '%s'\n", kobject_name(kobj), kobj, __func__, parent ? kobject_name(parent) : "<NULL>", kobj->kset ? kobject_name(&kobj->kset->kobj) : "<NULL>"); error = create_dir(kobj); if (error) { kobj_kset_leave(kobj); kobject_put(parent); kobj->parent = NULL; /* be noisy on error issues */ if (error == -EEXIST) printk(KERN_ERR "%s failed for %s with " "-EEXIST, don't try to register things with " "the same name in the same directory.\n", __func__, kobject_name(kobj)); else printk(KERN_ERR "%s failed for %s (%d)\n", __func__, kobject_name(kobj), error); dump_stack(); } else kobj->state_in_sysfs = 1; return error;}
如果设置了内核对象的kset变量,并且内核对象的parent变量为空,则将它重新设置为kset变量的内嵌内核对象。内核对象的parent变量将决定内核对象在sysfs树中的位置。因此,在该函数调用之前,存在以下三种可能:
- 如果内核对象的parent和kset变量都已设置,则内核对象在sysfs树中的位置由其parent决定,它将被放置在内核对象的父对象所对应的目录;
- 如果内核对象的parent为NULL,而kset已设置,在此会把kset变量的内嵌内核对象值赋值给内核对象的parent变量,因此kset决定了内核对象在sysfs树中的位置,它将放置在kset的内嵌内核对象所对应的目录下;
- 如果内核对象的parent和kset均为NULL,则内核对象将被放置在sysfs文件系统树的根目录下。
- Linux kernel -- 内核对象kobject
- Linux内核kobject模型(添加kobject对象,模拟kobject状态变化)
- Kobject模型之linux内核源码
- linux内核kobject事件处理详解
- Linux内核中的kobject和kset介绍
- 什么是内核(kernel)对象?
- Kernel Objects 内核对象
- 嵌入式 linux中kernel代码/lib/kobject.c文件分析
- linux对象系统---kobject, ktype, kset, subsys
- Linux内核 monolithic Kernel
- 编译Linux内核(kernel)
- linux kernel 内核定时器
- Linux kernel(内核)
- linux内核常用头文件之-----linux/kobject.h
- linux内核设计与实现之kobject和sysfs
- Linux内核修炼之kobject,ktype,kset,subsys关系
- Linux内核部件分析--设备驱动模型的基石kobject
- linux内核部件之---设备驱动模型的基石kobject
- URI与URL、URN区别
- android的程序锁
- hadoop学习之HDFS(2):CentOS7安装完全分布式hadoop-2.7.2
- z-index属性的总结
- 删除CentOS更新后,启动项上多余的内核
- Linux kernel -- 内核对象kobject
- BZOJ3714 [PA2014]Kuglarz
- 二维背包问题 + 代码模板
- 安卓全屏设置
- MyEclipse集成Gradle
- PKU1003 Hangover(水题)
- 蓝桥杯——生物芯片
- 大整数加减法
- java中的SPI机制