您的位置:首页 > 移动开发 > Objective-C

翻译 /documentation/kobject.txt

2016-06-30 19:54 501 查看
Everything you never wanted to know about kobjects, ksets, and ktypes

Greg Kroah-Hartman <gregkh@linuxfoundation.org>

Based on an original article by Jon Corbet for lwn.net written October 1,

2003 and located at http://lwn.net/Articles/51437/
Last updated December 19, 2007

Part of the difficulty in understanding the driver model - and the kobject

abstraction upon which it is built - is that there is no obvious starting

place. Dealing with kobjects requires understanding a few different types,

all of which make reference to each other. In an attempt to make things

easier, we'll take a multi-pass approach, starting with vague terms and

adding detail as we go. To that end, here are some quick definitions of

some terms we will be working with.

一部分难以理解驱动模型和kobject抽象的原因在于没有好的入口。要理解kobj需要理解一些相互

关联的不同的类型。为了简化理解,我们用了一些方法,先用模糊的表达,然后慢慢往上添加实质内容。

为了达到目的,这里有些定义我们会要用到。

 - A kobject is an object of type struct kobject.  Kobjects have a name

   and a reference count.  A kobject also has a parent pointer (allowing

   objects to be arranged into hierarchies), a specific type, and,

   usually, a representation in the sysfs virtual filesystem.

一个kobj是一个结构体。他有一个名字和引用计数。它也有一个指向父对象的指针(这样允许对象实现层级),

有特定的类别,通常还有一个在虚拟文件系统的一个表达。

   

   Kobjects are generally not interesting on their own; instead, they are

   usually embedded within some other structure which contains the stuff

   the code is really interested in.

kobj不自身独立存在;相反,他们通常被别的有实际意义的结构体包含。

   

   No structure should EVER have more than one kobject embedded within it.

   If it does, the reference counting for the object is sure to be messed

   up and incorrect, and your code will be buggy.  So do not do this.

所有的结构体都不应该包含多于一个以上的kobj。如果多于一个了,你的程序必定会各种出错。

 - A ktype is the type of object that embeds a kobject.  Every structure

   that embeds a kobject needs a corresponding ktype.  The ktype controls

   what happens to the kobject when it is created and destroyed.

ktype是被kobj包含的对象,所有用kobj的对象都要设定好看type。ktype在创建和销毁kobj时会起到决定作用。

   

 - A kset is a group of kobjects.  These kobjects can be of the same ktype

   or belong to different ktypes.  The kset is the basic container type for

   collections of kobjects. Ksets contain their own kobjects, but you can

   safely ignore that implementation detail as the kset core code handles

   this kobject automatically.

kset是一组kobj的基础容器。一个kset中的kobj可以是有相同或不同的kypte。你可以不用管kset的实现细节,

kset核会自动帮你处理。

   When you see a sysfs directory full of other directories, generally each

   of those directories corresponds to a kobject in the same kset.

如果你看到一个sysfs文件夹都是文件夹,通常每个文件夹都是同一个kset的kobj相对应的

We'll look at how to create and manipulate all of these types. A bottom-up

approach will be taken, so we'll go back to kobjects.

接下来让我们学习如何创造和操作这些东西。我们用自底向上的方式学,最后在回到kobj。

Embedding kobjects

It is rare for kernel code to create a standalone kobject, with one major

exception explained below.  Instead, kobjects are used to control access to

a larger, domain-specific object.  To this end, kobjects will be found

embedded in other structures.  If you are used to thinking of things in

object-oriented terms, kobjects can be seen as a top-level, abstract class

from which other classes are derived.  A kobject implements a set of

capabilities which are not particularly useful by themselves, but which are

nice to have in other objects.  The C language does not allow for the

direct expression of inheritance, so other techniques - such as structure

embedding - must be used.

通常,内核不会创建孤立的kobj,当然也有例外。kobj使用控制大型的特定域的权限。因此,kobj会嵌入到别的

结构体中去。如果以用面向对象的方法看它,可以把它看做顶层的类,别的类都继承于它。它用于实现继承机制,

尽管c语言不支持继承。

(As an aside, for those familiar with the kernel linked list implementation,

this is analogous as to how "list_head" structs are rarely useful on

their own, but are invariably found embedded in the larger objects of

interest.)

(顺便一提,他其实就像list_head的功能一样,提供对象之间的特定联系,用于构建容器)

So, for example, the UIO code in drivers/uio/uio.c has a structure that

defines the memory region associated with a uio device:

例如,uio驱动有一个定义内存空间的结构体如下:

    struct uio_map {
struct kobject kobj;
struct uio_mem *mem;

    };

If you have a struct uio_map structure, finding its embedded kobject is

just a matter of using the kobj member.  Code that works with kobjects will

often have the opposite problem, however: given a struct kobject pointer,

what is the pointer to the containing structure?  You must avoid tricks

(such as assuming that the kobject is at the beginning of the structure)

and, instead, use the container_of() macro, found in <linux/kernel.h>:

如果你用了kobj你会发现,你找不到你的包含结构体,你不应该认为kobj对象在结构体的开头,

你应该用下面的宏来获取包含结构体。

    container_of(pointer, type, member)

where:

  * "pointer" is the pointer to the embedded kobject,

  * "type" is the type of the containing structure, and

  * "member" is the name of the structure field to which "pointer" points.

The return value from container_of() is a pointer to the corresponding

container type. So, for example, a pointer "kp" to a struct kobject

embedded *within* a struct uio_map could be converted to a pointer to the

*containing* uio_map structure with:

返回值是包含结构体的指针。

    struct uio_map *u_map = container_of(kp, struct uio_map, kobj);

For convenience, programmers often define a simple macro for "back-casting"

kobject pointers to the containing type.  Exactly this happens in the

earlier drivers/uio/uio.c, as you can see here:

为了方便,程序员往往把这个宏进行了再次封装,如下:

    struct uio_map {

        struct kobject kobj;

        struct uio_mem *mem;

    };

    #define to_map(map) container_of(map, struct uio_map, kobj)

where the macro argument "map" is a pointer to the struct kobject in

question.  That macro is subsequently invoked with:

    struct uio_map *map = to_map(kobj);

Initialization of kobjects

Code which creates a kobject must, of course, initialize that object. Some

of the internal fields are setup with a (mandatory) call to kobject_init():

如果用到了kobj,就要对其进行初始化,用到如下函数

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

The ktype is required for a kobject to be created properly, as every kobject

must have an associated kobj_type.  After calling kobject_init(), to

register the kobject with sysfs, the function kobject_add() must be called:

ktype在初始化的时候是至关重要的。初始化后还要注册它,必须要调用如下函数:

    int kobject_add(struct kobject *kobj, struct kobject *parent, const char *fmt, ...);

This sets up the parent of the kobject and the name for the kobject

properly.  If the kobject is to be associated with a specific kset,

kobj->kset must be assigned before calling kobject_add().  If a kset is

associated with a kobject, then the parent for the kobject can be set to

NULL in the call to kobject_add() and then the kobject's parent will be the

kset itself.

这函数会设置kobj的父对象和名字。如果需要把kobj加入一个kset中,在kobject_add()之前要设置好kobj->kset。

如果okbj会被加入一个kset,那么kobj的父对象可以为null,且kobject_add()后kobj的父对象被设置为kset。

As the name of the kobject is set when it is added to the kernel, the name

of the kobject should never be manipulated directly.  If you must change

the name of the kobject, call kobject_rename():

当kobj被加入内核后,不应该直接修改其名字,而是用下面的函数。

    int kobject_rename(struct kobject *kobj, const char *new_name);

kobject_rename does not perform any locking or have a solid notion of

what names are valid so the caller must provide their own sanity checking

and serialization.

这个函数没有加锁和名字规则判断,所以程序员要自己保证其正确性。

There is a function called kobject_set_name() but that is legacy cruft and

is being removed.  If your code needs to call this function, it is

incorrect and needs to be fixed.

不要用这个函数kobject_set_name()

To properly access the name of the kobject, use the function<
f5a4
br />
kobject_name():

获取kobj的名字用下面函数:

    const char *kobject_name(const struct kobject * kobj);

There is a helper function to both initialize and add the kobject to the

kernel at the same time, called surprisingly enough kobject_init_and_add():

下面这个函数即初始化kobj而且会同时注册到内核:

    int kobject_init_and_add(struct kobject *kobj, struct kobj_type *ktype,

                             struct kobject *parent, const char *fmt, ...);

The arguments are the same as the individual kobject_init() and

kobject_add() functions described above.

Uevents

After a kobject has been registered with the kobject core, you need to

announce to the world that it has been created.  This can be done with a

call to kobject_uevent():

一个kobj被加载到内核后,你需要告诉所有对象它被注册了,调用下面函数可以实现:

    int kobject_uevent(struct kobject *kobj, enum kobject_action action);

Use the KOBJ_ADD action for when the kobject is first added to the kernel.

This should be done only after any attributes or children of the kobject

have been initialized properly, as userspace will instantly start to look

for them when this call happens.

第一次加载时用KOBJ_ADD参数。这只能在属性或者子kobj被完整的初始化之后被调用,用户空间

会马上找到他们。

When the kobject is removed from the kernel (details on how to do that is

below), the uevent for KOBJ_REMOVE will be automatically created by the

kobject core, so the caller does not have to worry about doing that by

hand.

当一个kobj被移除,内核会自动调用KOBJ_REMOVE参数uevent,我们不用关心它。

Reference counts

One of the key functions of a kobject is to serve as a reference counter

for the object in which it is embedded. As long as references to the object

exist, the object (and the code which supports it) must continue to exist.

The low-level functions for manipulating a kobject's reference counts are:

kobj的最重要用处在于保存一个引用计数。只要还有引用,这个对象就必须一直存在,

底层的操作引用计数的函数如下:

    struct kobject *kobject_get(struct kobject *kobj);

    void kobject_put(struct kobject *kobj);

A successful call to kobject_get() will increment the kobject's reference

counter and return the pointer to the kobject.

kobject_get()会增加引用计数,并返回kobj的指针。

When a reference is released, the call to kobject_put() will decrement the

reference count and, possibly, free the object. Note that kobject_init()

sets the reference count to one, so the code which sets up the kobject will

need to do a kobject_put() eventually to release that reference.

当应用释放,调用kobject_put()会减少引用计数而且会释放对象。注意kobject_init()会把

引用计数置一,所以要释放对象,至少要调用一次kobject_put()。

Because kobjects are dynamic, they must not be declared statically or on

the stack, but instead, always allocated dynamically.  Future versions of

the kernel will contain a run-time check for kobjects that are created

statically and will warn the developer of this improper usage.

因为kobj是动态的,不要静态的声明或者放在栈上面。未来的版本会自检然后提醒编程者。

If all that you want to use a kobject for is to provide a reference counter

for your structure, please use the struct kref instead; a kobject would be

overkill.  For more information on how to use struct kref, please see the

file Documentation/kref.txt in the Linux kernel source tree.

如果你只是单单用到引用计数功能,推荐使用kref。Documentation/kref.txt是说明书。

Creating "simple" kobjects

Sometimes all that a developer wants is a way to create a simple directory

in the sysfs hierarchy, and not have to mess with the whole complication of

ksets, show and store functions, and other details.  This is the one

exception where a single kobject should be created.  To create such an

entry, use the function:

有时,编程人员只是想创建一个单一kobj,不想处理复杂的sysfs,可以调用如下函数:

    struct kobject *kobject_create_and_add(char *name, struct kobject *parent);

This function will create a kobject and place it in sysfs in the location

underneath the specified parent kobject.  To create simple attributes

associated with this kobject, use:

这个函数会创造一个kobj并值它于一个特定父kobj对象下,创建简答attr用如下函数:

    int sysfs_create_file(struct kobject *kobj, struct attribute *attr);

or

    int sysfs_create_group(struct kobject *kobj, struct attribute_group *grp);

Both types of attributes used here, with a kobject that has been created

with the kobject_create_and_add(), can be of type kobj_attribute, so no

special custom attribute is needed to be created.

两种方法都会用到kobj_attribute,所以不需要再添加别的sttr了。

See the example module, samples/kobject/kobject-example.c for an

implementation of a simple kobject and attributes.

可以看例程samples/kobject/kobject-example.c,它实现了一个简单的kobj和attr。

ktypes and release methods

One important thing still missing from the discussion is what happens to a

kobject when its reference count reaches zero. The code which created the

kobject generally does not know when that will happen; if it did, there

would be little point in using a kobject in the first place. Even

predictable object lifecycles become more complicated when sysfs is brought

in as other portions of the kernel can get a reference on any kobject that

is registered in the system.

没有谈的是当引用为零,会发生什么。突出一个不需要知道细节。

The end result is that a structure protected by a kobject cannot be freed

before its reference count goes to zero. The reference count is not under

the direct control of the code which created the kobject. So that code must

be notified asynchronously whenever the last reference to one of its

kobjects goes away.

引用不为零,对象不会死,引用一般不由创建者控制,所以必须有通知机制来告诉创建者什么时候

计数被清零了。

Once you registered your kobject via kobject_add(), you must never use

kfree() to free it directly. The only safe way is to use kobject_put(). It

is good practice to always use kobject_put() after kobject_init() to avoid

errors creeping in.

你不能用kfree()来释放你注册的kobj。只能用 kobject_put()。

This notification is done through a kobject's release() method. Usually

such a method has a form like:

利用如下的范式来释放:

    void my_object_release(struct kobject *kobj)

    {

       struct my_object *mine = container_of(kobj, struct my_object, kobj);

   /* Perform any additional cleanup on this object, then... */
   kfree(mine);

    }

One important point cannot be overstated: every kobject must have a

release() method, and the kobject must persist (in a consistent state)

until that method is called. If these constraints are not met, the code is

flawed.  Note that the kernel will warn you if you forget to provide a

release() method.  Do not try to get rid of this warning by providing an

"empty" release function; you will be mocked mercilessly by the kobject

maintainer if you attempt this.

必须必须:每个kobj要有一个releas函数,kboj在这函数被调用前都必须保持存在。

内核会告诉你没有release。你必须要警惕。

Note, the name of the kobject is available in the release function, but it

must NOT be changed within this callback.  Otherwise there will be a memory

leak in the kobject core, which makes people unhappy.

注意:在release函数中不要改kobj名字,会内存泄露。

Interestingly, the release() method is not stored in the kobject itself;

instead, it is associated with the ktype. So let us introduce struct

kobj_type:

release函数不在kobj中,而在ktype中,如下;

    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);

    };

This structure is used to describe a particular type of kobject (or, more

correctly, of containing object). Every kobject needs to have an associated

kobj_type structure; a pointer to that structure must be specified when you

call kobject_init() or kobject_init_and_add().

这东西用来描述对象类别。在调用kobject_init() or kobject_init_and_add(),kobj必有ktype。

The release field in struct kobj_type is, of course, a pointer to the

release() method for this type of kobject. The other two fields (sysfs_ops

and default_attrs) control how objects of this type are represented in

sysfs; they are beyond the scope of this document.

release是函数指针,其余的成员本文档不管。

The default_attrs pointer is a list of default attributes that will be

automatically created for any kobject that is registered with this ktype.

default_attrs指针指向一个默认attr表。

ksets

A kset is merely a collection of kobjects that want to be associated with

each other.  There is no restriction that they be of the same ktype, but be

very careful if they are not.

kset是kobj的容器。不需要相同的ktype,当然这需要注意。

A kset serves these functions:

有如下功能:

 - It serves as a bag containing a group of objects. A kset can be used by

   the kernel to track "all block devices" or "all PCI device drivers."

方便内核遍历

   

 - A kset is also a subdirectory in sysfs, where the associated kobjects

   with the kset can show up.  Every kset contains a kobject which can be

   set up to be the parent of other kobjects; the top-level directories of

   the sysfs hierarchy are constructed in this way.

kset也是sysfs的一个子目录,kset必有一个kobj用来作为其成员的父对象,顶层目录就是如此构建的。

   

 - Ksets can support the "hotplugging" of kobjects and influence how

   uevent events are reported to user space.

它支持热插拔,使能用户控件的uevent。

   

In object-oriented terms, "kset" is the top-level container class; ksets

contain their own kobject, but that kobject is managed by the kset code and

should not be manipulated by any other user.

面对对象来说,kset是基类,其包含的kobj不应该被别的东西操作,只能自己操作。

A kset keeps its children in a standard kernel linked list.  Kobjects point

back to their containing kset via their kset field. In almost all cases,

the kobjects belonging to a kset have that kset (or, strictly, its embedded

kobject) in their parent.

kset用标准链表连住子对象,子对象也有指向kset的指针。

As a kset contains a kobject within it, it should always be dynamically

created and never declared statically or on the stack.  To create a new

kset use:

kset也要动态生成,不能静态或者在栈里面,用下面函数:

  struct kset *kset_create_and_add(const char *name,
  struct kset_uevent_ops *u,
  struct kobject *parent);

When you are finished with the kset, call:

  void kset_unregister(struct kset *kset);

to destroy it.

释放函数如上:

An example of using a kset can be seen in the

samples/kobject/kset-example.c file in the kernel tree.

例子在samples/kobject/kset-example.c

If a kset wishes to control the uevent operations of the kobjects

associated with it, it can use the struct kset_uevent_ops to handle it:

可以用kset_uevent_ops控制uevent

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,

                      struct kobj_uevent_env *env);

};

The filter function allows a kset to prevent a uevent from being emitted to

userspace for a specific kobject.  If the function returns 0, the uevent

will not be emitted.

filt函数使能kset过滤掉一些kobj的uevent,如果filt返回0,就会阻止。

The name function will be called to override the default name of the kset

that the uevent sends to userspace.  By default, the name will be the same

as the kset itself, but this function, if present, can override that name.

name函数可以修改被发送到用户空间的kset的名字,一般名字是一样的,但是这个函数可以改名字。

The uevent function will be called when the uevent is about to be sent to

userspace to allow more environment variables to be added to the uevent.

uevent函数用来在发送前添加更多的uevent全局变量。

One might ask how, exactly, a kobject is added to a kset, given that no

functions which perform that function have been presented.  The answer is

that this task is handled by kobject_add().  When a kobject is passed to

kobject_add(), its kset member should point to the kset to which the

kobject will belong.  kobject_add() will handle the rest.

kobj的kset在调用kobject_add()前被设置好,其余的都不用你管了。

If the kobject belonging to a kset has no parent kobject set, it will be

added to the kset's directory.  Not all members of a kset do necessarily

live in the kset directory.  If an explicit parent kobject is assigned

before the kobject is added, the kobject is registered with the kset, but

added below the parent kobject.

如果一个kobj没有父对象,默认会被设置成kset的目录。不是所有kset成员都要在kset目录下。如果kobj有显式父对象

则会被添加到父对象下。

Kobject removal

After a kobject has been registered with the kobject core successfully, it

must be cleaned up when the code is finished with it.  To do that, call

kobject_put().  By doing this, the kobject core will automatically clean up

all of the memory allocated by this kobject.  If a KOBJ_ADD uevent has been

sent for the object, a corresponding KOBJ_REMOVE uevent will be sent, and

any other sysfs housekeeping will be handled for the caller properly.

调用kobject_put()会释放对象。kobj内核会自动处理。如果一个KOBJ_ADD事件发到那个被删对象,

相应的KOBJ_REMOVE会被内核自动发送到发送者那里。

If you need to do a two-stage delete of the kobject (say you are not

allowed to sleep when you need to destroy the object), then call

kobject_del() which will unregister the kobject from sysfs.  This makes the

kobject "invisible", but it is not cleaned up, and the reference count of

the object is still the same.  At a later time call kobject_put() to finish

the cleanup of the memory associated with the kobject.

调用kobject_del()会隐藏一个对象,但他还是存在,只是不能被调用,之后可以用kobject_put()来释放。

kobject_del() can be used to drop the reference to the parent object, if

circular references are constructed.  It is valid in some cases, that a

parent objects references a child.  Circular references _must_ be broken

with an explicit call to kobject_del(), so that a release functions will be

called, and the objects in the former circle release each other.

kobject_del()可以用来消除对父对象的应用,如果形成了环路。环路必须显式的调用kobject_del(),

不然释放不了。

Example code to copy from

看例子samples/kobject/{kobject-example.c,kset-example.c}

For a more complete example of using ksets and kobjects properly, see the

example programs samples/kobject/{kobject-example.c,kset-example.c},

which will be built as loadable modules if you select CONFIG_SAMPLE_KOBJECT.
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: