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文件系统树的根目录下。
0 0
原创粉丝点击