Chinaunix首页 | 论坛 | 博客
  • 博客访问: 504459
  • 博文数量: 68
  • 博客积分: 5011
  • 博客等级: 大校
  • 技术积分: 806
  • 用 户 组: 普通用户
  • 注册时间: 2007-11-30 22:06
文章分类
文章存档

2011年(1)

2009年(8)

2008年(59)

我的朋友

分类: LINUX

2008-07-19 19:19:44

   1/*
   2 * kobject.h - generic kernel object infrastructure.
   3 *
   4 * Copyright (c) 2002-2003      Patrick Mochel
   5 * Copyright (c) 2002-2003      Open Source Development Labs
   6 *
   7 * This file is released under the GPLv2.
   8 *
   9 *
  10 * Please read Documentation/kobject.txt before using the kobject
  11 * interface, ESPECIALLY the parts about reference counts and object
  12 * destructors.
  13 */
 
   /**
     *http://blog.chinaunix.net/u1/55599/
     */
请结合:http://blog.chinaunix.net/u1/55599/showart_1091047.html 文章看,
我相信效果会很好。
功能kobject结构功能说明:
Kobject 是组成设备模型的基本结构。它嵌入于更大的对象的对象中--所谓的容器--用来描述设备模型的组件。如bus, devices, drivers 都是典型的容器。对于内核代码它很少创建一个孤立的 kobject; 相反, kobject 被用来控制存取更大的, 特定域的对象. 为此, kobject 被嵌入到其他结构中. 如果你习惯以面向对象的术语考虑事情, kobject 可被看作一个顶级的, 抽象类, 其他的类自它而来. 一个 kobject 实现一系列功能, 这些功能对自己不是特别有用而对其他对象是好的. C 语言不允许直接表达继承。

  容器有了kobject之后,允许内核:

  a) 保存对容器的引用计数

  b) 保存容器之间的层次关系

  c) 为每个容器的属性提供一个用户视图

  14
  15#ifndef _KOBJECT_H_
  16#define _KOBJECT_H_
 
  18#ifdef __KERNEL__
 
  20#include
  21#include
  22#include
  23#include
  24#include
  25#include
  26#include
  27#include
  28#include
  29
  30#define KOBJ_NAME_LEN                   20
  /**
   *在定义kobject数据结构指针*k_name,作为判断,长度小于KOBJ_NAME_LEN ,那么
   *kobject名称存在name数组中,*k_name指向组头;如果长度大于KOBJ_NAME_LEN。
   *就动态分配一个足够大的缓冲区来存放kobject的名称,这时*k_name指向缓冲区
   */
  31#define UEVENT_HELPER_PATH_LEN          256
 
  33/* path to the userspace helper executed on an event */
  34extern char uevent_helper[];
 
  36/* counter to tag the uevent, read only except for the kobject core */
  37extern u64 uevent_seqnum;
 

  39/*
  40 * The actions here must match the index to the string array
  41 * in lib/kobject_uevent.c
  42 *
  43 * Do not add new actions here without checking with the driver-core
  44 * maintainers. Action strings are not meant to express subsystem
  45 * or device specific properties. In most cases you want to send a
  46 * kobject_uevent_env(kobj, KOBJ_CHANGE, env) with additional event
  47 * specific variables added to the event environment.
  48 */
  49enum kobject_action {
  50        KOBJ_ADD,
  51        KOBJ_REMOVE,
  52        KOBJ_CHANGE,
  53        KOBJ_MOVE,
  54        KOBJ_ONLINE,
  55        KOBJ_OFFLINE,
  56        KOBJ_MAX
  57};

  59/* The list of strings defining the valid kobject actions as specified above */
  60extern const char *kobject_actions[];


  63struct kobject {
  64        const char              * k_name;
  65        char                    name[KOBJ_NAME_LEN];
  66        struct kref             kref;
  67        struct list_head        entry;
  68        struct kobject          * parent;
  69        struct kset             * kset;
  70        struct kobj_type        * ktype;
  71        struct dentry        * dentry;
  72};
  /**
   *在定义kobject数据结构指针*k_name,作为判断,长度小于KOBJ_NAME_LEN ,那么
    kobject名称存在name数组中,*k_name指向组头;如果长度大于KOBJ_NAME_LEN。
    就动态分配一个足够大的缓冲区来存放kobject的名称,这时*k_name指向缓冲区
   *kref成员实现对象的计数,且提供两个函数kobject_get(),kobject_put分别用于增加
    和减少引用计数。
   *entry用于挂载kobject到kset链表
   *  * parent指针用于指向kobject的父对象。可以把多个对象间的关系表现出来。
    这也是sysfs的真正面目:一个用户空间的文件系统,用来表现kobject对象的层次关系。
   *  * ktype,* kset指向kobject所需其他结构体,下面详细解释。
   *  * dentry指针指向dentry结构体。
   */
 
  74extern int kobject_set_name(struct kobject *, const char *, ...)
  75        __attribute__((format(printf,2,3)));
  /**
   *该函数的作用设置指定kobject的名称。
   *其中__attribute__()是gcc格式对编译过程的处理,具体参见本博客C编程中详细介绍。
   */
  76
  77static inline const char * kobject_name(const struct kobject * kobj)
  78{
  79        return kobj->k_name;
  80}
  /**
   *可以取得当前kobj对象的名称
   */
 
  82extern void kobject_init(struct kobject *);
  83extern void kobject_cleanup(struct kobject *);
  /**
   *kobject_init()用于初始化kobject,它设置kobject引用计数为1。
   *kobject_cleanup()
    在/linux/lib/kobject.c中定义如下
     492static void kobject_release(struct kref *kref)
     493{
     494        kobject_cleanup(container_of(kref, struct kobject, kref));
     495}
    kobject清除函数。当其引用计数为0时,释放对象占用的资源。
    *其中container_of()是宏,可以获得kobject的首地址。调用kobject_cleanup释放
      资源。
   */

  85extern int __must_check kobject_add(struct kobject *);
  86extern int __must_check kobject_shadow_add(struct kobject *kobj,
                                         struct sysfs_dirent *shadow_parent);
  /**
   *在/linux/lib/kobject.c中定义如下
    222int kobject_add(struct kobject * kobj)
    223{
    224        return kobject_shadow_add(kobj, NULL);
    225}
    将kobj对象加入Linux设备层次。挂接该kobject对象到kset的list链中,增加父目录各级kobject的引用计数,
    在其parent指向的 目录下创建文件节点,并启动该类型内核对象的hotplug函数。

在 sysfs 中创建kobject的目录入口是kobject_shadow_add的工作的一部分,有些知识值得记住:
(1)kobjects 的 sysfs 入口始终为目录, kobject_add 的调用将在sysfs 中创建一个目录,这个目录包含一个或多个属性(文件);
(2) 分配给 kobject 的名字( 用 kobject_set_name ) 是 sysfs 中的目录名,出现在 sysfs 层次的相同部分的 kobjects 必须有唯一的名字. 分配给 kobjects 的名字也应当是合法的文件名字: 它们不能包含非法字符(如:斜线)且不推荐使用空白。
(3)sysfs 入口位置对应 kobject 的 parent 指针。若 parent 是 NULL ,则它被设置为嵌入到新 kobject 的 kset 中的 kobject;若 parent 和 kset 都是 NULL, 则sysfs 入口目录在顶层目录,通常不推荐。

 (4)实际创建目录是, 函数实现的。
  *其中__must_check也是宏,实现__attribute_()作用
   */
  88extern void kobject_del(struct kobject *);
  /**
   *从Linux设备层次(hierarchy)中删除kobj对象。
   
();  删除相应的目录
   */
 
  90extern int __must_check kobject_rename(struct kobject *, const
                                                                                  char *new_name);
  91extern int __must_check kobject_shadow_rename(struct kobject *kobj,
                                                   struct sysfs_dirent *new_parent,
                                                   const char *new_name);
    /**
     * kobject_rename()改变kobject结构对象名称
     * kobject_shadow_rename()改变kobject结构对象的名称,
       还有其parent的名称(目录的名称),相当于创建新目录
     *具体参考linux/fs/sysfs/dir.c  
     */
 
  94extern int __must_check kobject_move(struct kobject *, struct kobject *);
  /**
   *kobject赋给一个新parent对象
   */
 
  96extern int __must_check kobject_register(struct kobject *);
  97extern void kobject_unregister(struct kobject *);
  /**
   *kobject_register注册函数。通过调用kobject_get(),
    再调用kobject_add()完成该内核对象的注册。上面有介绍,还没有
       忘记吧
   *kobject_unregister注销函数。与kobject_register()相反,它首先调用
    kobject_del  从设备层次中删除该对象,再调用
    kobject_put()减少该对象的引用计数,如果引用计数降为0,则释放该kobject对象。
   */
 
  99extern struct kobject * kobject_get(struct kobject *);
 100extern void kobject_put(struct kobject *);
 /**
  *kobject_get 对象的引用计数加1,同时返回该对象的指针。
  *将kobject_put对象的引用计数减1,如果引用计数降为0,
    则调用kobject_release()释放该kobject对象。
  */

 102extern struct kobject *kobject_kset_add_dir(struct kset *kset,
                                                  struct kobject *, const char *);
 104extern struct kobject *kobject_add_dir(struct kobject *, const char *);
 /**
  *在kobject数据parent对象中创建目录,目录名称为const char *指向的名称
  *在/linux/lib/kobject.c中说明如下
    564struct kobject *kobject_add_dir(struct kobject *parent, const char *name)
    565{
    566        return kobject_kset_add_dir(NULL, parent, name);
    567}
  而
kobject_kset_add_dir()会调用(); 呵呵,又回到这个函数了。
  看了这篇文章得把kobject_add()调用关系层次好好的看下了。
  */

 106extern char * kobject_get_path(struct kobject *, gfp_t)
 /**
  *这个函数比较有趣,先调用get_kobj_path_length()函数,获得其
   父结点的个数代码如下

        do {
if (() == )
return 0;
+= (()) + 1;
= ->;
} while ();
return ;

*然后调用fill_kobj_paht()函数,获得路径
  *获得当前kobj对象的路径
  */
 107
 108struct kobj_type {
 109        void (*release)(struct kobject *);
 110        struct sysfs_ops        * sysfs_ops;
 111        struct attribute        ** default_attrs;
 112};
 
 /**
  *当被创建时, 每个 kobject 被给定一套缺省属性. 这些属性通过
   kobj_type 结构来指定. 这个结构
  *default_attr 成员列举了对每个这样类型的 kobject 被创建的属性,
   并且 sysfs_ops 提供方法来实现这些属性.
   我们从    default_attrs 开始, 它指向一个指向属性结构的指针数组:
   struct attribute
   {
      char *name;
      struct module *owner;
      mode_t mode;
   };
   在这个结构中, name 是属性的名字, owner 是一个指向模块的指针,
   模块负责这个属性的实现, 并且 mode 是应用到这个属性的保护位.
   mode 常常是 S_IRUGO 对于只读属性;
   如果这个属性是可写的, 你可以扔出 S_IWUSR 来只给 root
   写权限( modes 的宏定义在 中).
   default_attrs 列表中的最后一个入口必须用 0 填充.
   default_attr 数组说明这些属性是什么, 但是没有告诉 sysfs 如何真正实现这些属性.
   这个任务落到 kobj_type->sysfs_ops 成员,
   它指向一个结构, 定义为:
   struct sysfs_ops
   {
       ssize_t (*show)(struct kobject *kobj, struct attribute *attr, char *buffer);
       ssize_t (*store)(struct kobject *kobj, struct attribute *attr, const char *buffer, size_t size);
   };
  *store()方法在写操作时调用它会从buffer中读取size大小字节。
  并将其存入attr表示属性的结构变量。
  *show()方法在读操作时调用,它会拷贝由attr提供的属性值到buffer指定的缓冲区,
   缓冲区的大小为PAGE_SIZE字节。
  * 注:默认的文件的集合是通过kobject和kset中的ktype字段实现的。
    因此所有具有相同类型的kobject在它们
        对应的sysfs目录下都拥有相同的默认文件集合。所以也具有相同的默认属性也相同。
        内核提供如下函数:
        int sysfs_create_file(struct kobject *kobj,const struct attribute *attr);  //添加属性
        int sysfs_remove_file(struct kobject *kobj,const struct attribute *attr);  //删除属性      
  */
 114struct kset_uevent_ops {
 115        int (*filter)(struct kset *kset, struct kobject *kobj);
 116        const char *(*name)(struct kset *kset, struct kobject *kobj);
 117        int (*uevent)(struct kset *kset, struct kobject *kobj, char **envp,
 118                        int num_envp, char *buffer, int buffer_size);
 119};
 /**
  *filter()用于过滤掉不需要用户空间的事件,
  *uevent()函数用于导出一些环境变量给热插拨程序。
   根据导出不同的环境变量采取相应的行动。
  *
  */
 121/*
 122 *      struct kset - a set of kobjects of a specific type, belonging
 123 *      to a specific subsystem.
 124 *
 125 *      All kobjects of a kset should be embedded in an identical
 126 *      type. This type may have a descriptor, which the kset points
 127 *      to. This allows there to exist sets of objects of the same
 128 *      type in different subsystems.
 129 *
 130 *      A subsystem does not have to be a list of only one type
 131 *      of object; multiple ksets can belong to one subsystem. All
 132 *      ksets of a subsystem share the subsystem's lock.
 133 *
 134 *      Each kset can support specific event variables; it can
 135 *      supress the event generation or add subsystem specific
 136 *      variables carried with the event.
 137 */

注:有上面kobject结构调用的层次关系,下面就会调用关系简略写下。

 138struct kset {
 139        struct kobj_type        * ktype;
 140        struct list_head        list;
 141        spinlock_t              list_lock;
 142        struct kobject          kobj;
 143        struct kset_uevent_ops  * uevent_ops;
 144};
 /**
  *   * ktype指向kset对象类型描述符的指针
  *list用于链接所有kset中所有kobject的链表头
  *list_lock避免竞态的自旋琐
  *kobj嵌入的kobject
  *   * uevent_ops指向kset_uevent_ops
  */


 147extern void kset_init(struct kset * k);
 /**
  *kset_init完成指定的kset的初始化
  */
 148extern int __must_check kset_add(struct kset * k);
 /**
  *实现将指定的kset对象加入设备层次
  */
 149extern int __must_check kset_register(struct kset * k);
 150extern void kset_unregister(struct kset * k);
 /**
  *作用分别实现kset对象的注册和注销
  */

 152static inline struct kset * to_kset(struct kobject * kobj)
 153{
 154        return kobj ? container_of(kobj,struct kset,kobj) : NULL;
 155}

 157static inline struct kset * kset_get(struct kset * k)
 158{
 159        return k ? to_kset(kobject_get(&k->kobj)) : NULL;
 160}
 /**
  *如果参数不为空,就返回kobj所嵌入的kset
  */

 162static inline void kset_put(struct kset * k)
 163{
 164        kobject_put(&k->kobj);
 165}
 /**
  *kset_get()实现增加kset对象引用计数
  *kset_put()实现减少kset对象引用计数
  */
 
 167static inline struct kobj_type * get_ktype(struct kobject * k)
 168{
 169        if (k->kset && k->kset->ktype)
 170                return k->kset->ktype;
 171        else
 172                return k->ktype;
 173}
 /**
  *以查找指定kobject的kobj_type 指针
  */

 175extern struct kobject * kset_find_obj(struct kset *, const char *);
 /**
  *通过kset对象查找kobject对象
  */


 178/*
 179 * Use this when initializing an embedded kset with no other
 180 * fields to initialize.
 181 */
 182#define set_kset_name(str)      .kset = { .kobj = { .name = str } }
 /**
  *用于设置kset对象的名称
  */

 185#define decl_subsys(_name,_type,_uevent_ops) \
 186struct kset _name##_subsys = { \
 187        .kobj = { .name = __stringify(_name) }, \
 188        .ktype = _type, \
 189        .uevent_ops =_uevent_ops, \
 190}
 191#define decl_subsys_name(_varname,_name,_type,_uevent_ops) \
 192struct kset _varname##_subsys = { \
 193        .kobj = { .name = __stringify(_name) }, \
 194        .ktype = _type, \
 195        .uevent_ops =_uevent_ops, \
 196}
 /**
  *通过define decl_subsys(_name,_type,_uevent_ops),decl_subsys_name(_varname,_name,_type,_uevent_ops)
  *ksets可以通过其指针指向subsys指针指向一个subsystem。
  *而其中__stringify(_name)是一个宏,
#ifndef
#define

/* Indirect stringification.  Doing two levels allows the parameter to be a
* macro itself.  For example, compile with -DFOO=bar, __stringify(FOO)
* converts to "bar".
*/

#define ()        #x
#define ()          ()

#endif 
/* !__LINUX_STRINGIFY_H */

 *
该宏的作用把#后的x转换成字符串类型的
  *其中define decl_subsys(_name,_type,_uevent_ops)对kset对象的初始化
  *decl_subsys_name(_varname,_name,_type,_uevent_ops)对kset对象的初始化
  */

 198/* The global /sys/kernel/ subsystem for people to chain off of */
 199extern struct kset kernel_subsys;
 200/* The global /sys/hypervisor/ subsystem  */
 201extern struct kset hypervisor_subsys;
 /**
  *引用kset结构 hypervisor_subsys,kset kernel_subsys全局变量
  */

 203/*
 204 * Helpers for setting the kset of registered objects.
 205 * Often, a registered object belongs to a kset embedded in a
 206 * subsystem. These do no magic, just make the resulting code
 207 * easier to follow.
 208 */

 210/**
 211 *      kobj_set_kset_s(obj,subsys) - set kset for embedded kobject.
 212 *      @obj:           ptr to some object type.
 213 *      @subsys:        a subsystem object (not a ptr).
 214 *
 215 *      Can be used for any object type with an embedded ->kobj.
 216 */

 218#define kobj_set_kset_s(obj,subsys) \
                   (obj)->kobj.kset = &(subsys)
 /**
  *设置kset对象嵌入kobject对象
  */

 221/**
 222 *      kset_set_kset_s(obj,subsys) - set kset for embedded kset.
 223 *      @obj:           ptr to some object type.
 224 *      @subsys:        a subsystem object (not a ptr).
 225 *
 226 *      Can be used for any object type with an embedded ->kset.
 227 *      Sets the kset of @obj's  embedded kobject (via its embedded
 228 *      kset) to @subsys.kset. This makes @obj a member of that
 229 *      kset.
 230 */
 231
 232#define kset_set_kset_s(obj,subsys) \
 233        (obj)->kset.kobj.kset = &(subsys)
  /**
  *设置kset对象嵌入kset对象
  */

 235/**
 236 *      subsys_set_kset(obj,subsys) - set kset for subsystem
 237 *      @obj:           ptr to some object type.
 238 *      @_subsys:       a subsystem object (not a ptr).
 239 *
 240 *      Can be used for any object type with an embedded ->subsys.
 241 *      Sets the kset of @obj's kobject to @subsys.kset. This makes
 242 *      the object a member of that kset.
 243 */

 245#define subsys_set_kset(obj,_subsys) \
 246        (obj)->subsys.kobj.kset = &(_subsys)
 /**
  *设置kset对象插入
subsystem链表中
  */

 248extern void subsystem_init(struct kset *);
 /**
  *subsystem_init,
subsystem的初始化
  */
 249extern int __must_check subsystem_register(struct kset *);
 250extern void subsystem_unregister(struct kset *);
 /**
  *subsystem_register函数,
subsystem的注册
  *subsystem_unregister ,
subsystem的注销
  */

 252static inline struct kset *subsys_get(struct kset *s)
 253{
 254        if (s)
 255                return kset_get(s);
 256        return NULL;
 257}
 258
 259static inline void subsys_put(struct kset *s)
 260{
 261        kset_put(s);
 262}
 /**
  *subsys_get函数为
subsystem增加的引用计数
  *subsys_put函数为
subsystem减少的引用计数
  */

 264struct subsys_attribute {
 265        struct attribute attr;
 266        ssize_t (*show)(struct kset *, char *);
 267        ssize_t (*store)(struct kset *, const char *, size_t);
 268};

 270extern int __must_check subsys_create_file(struct kset *,
                                        struct subsys_attribute *);
 /**
  *前面已经讲过,为默认集合添加新属性
  */
 272
 273#if defined(CONFIG_HOTPLUG)
 274int kobject_uevent(struct kobject *kobj, enum kobject_action action);
 275int kobject_uevent_env(struct kobject *kobj, enum kobject_action action,
 276                        char *envp[]);
 /**
  *在在/linux/lib/kobject.c中定义如下
    232int kobject_uevent(struct kobject *kobj, enum kobject_action action)
    233{
    234        return kobject_uevent_env(kobj, action, NULL);
    235}
   *kobject_uevent_env函数发送message给用户空间,其中message在
     enum   kobject_action{}结构定义
   *action 发送的消息
   *kobj发生消息动作的对象
   *envp指向环境变量
   */
 277
 278int add_uevent_var(char **envp, int num_envp, int *cur_index,
 279                        char *buffer, int buffer_size, int *cur_len,
 280                        const char *format, ...)
 281        __attribute__((format (printf, 7, 8)));
 /**
  *add_uevent_var()添加指定的环境变量到变量中
  *其中这个函数要理解va_start()  va_end()等函数,本博客有详细介绍
  */
 282#else
 283static inline int kobject_uevent(struct kobject *kobj, enum kobject_action action)
 284{ return 0; }
 285static inline int kobject_uevent_env(struct kobject *kobj,
 286                                      enum kobject_action action,
 287                                      char *envp[])
 288{ return 0; }
 289
 290static inline int add_uevent_var(char **envp, int num_envp, int *cur_index,
 291                                      char *buffer, int buffer_size, int *cur_len,
 292                                      const char *format, ...)
 293{ return 0; }
 294#endif
 295
 296#endif /* __KERNEL__ */
 297#endif /* _KOBJECT_H_ */


注:以上是本人自己分析的源代码,欢迎校正。禁止复制。
     为方便阅读,里面源代码的注释保留。由于在文本写的,复制过来的,
     代码不规范,见谅。
参考书:linux设备驱动开发   linux内核设计与实现
阅读(4043) | 评论(3) | 转发(0) |
给主人留下些什么吧!~~

a2755329382011-01-06 17:23:18

楼主分析很好,佩服

niutao.linux2008-07-24 19:43:07

在文章前面若能添加对该文件功能的介绍和其中的核心数据结构kobject的功能介绍会更好,我认为。

chinaunix网友2008-07-21 12:48:09

在对这个文件进行分析后,可以写一个模块,来对Kobject进行操作,以便在/sys目录下增加一个新的目录。 你对代码的分析基本到位,再从整体上和相互关系上能进一步梳理一下就更好了。