Chinaunix首页 | 论坛 | 博客
  • 博客访问: 471418
  • 博文数量: 65
  • 博客积分: 573
  • 博客等级: 中士
  • 技术积分: 693
  • 用 户 组: 普通用户
  • 注册时间: 2011-06-09 17:16
文章分类

全部博文(65)

文章存档

2015年(12)

2014年(9)

2013年(22)

2012年(7)

2011年(15)

分类: LINUX

2014-09-16 16:58:19

kobject与kset的介绍,在ldd3中已经介绍的很详细了,没有了解过的,可以去看看第十四章设备模型这一章,这里只简单介绍一下kobject和kset,并提供一个可运行的示例程序,用做备忘!
示例程序运行kernel版本为3.0.36,示例程序是国嵌的,修改使之在3.0.36内核版本可运行,并消除编译时的警告信息

kobject实现了基本的面相对象管理机制,是构成Linux内核设备模型的核心结构,它与sys紧密相连,在内核中注册的每个kobject对应sys文件系统中一个目录。kobject结构定义如下:
struct kobject {
 const char *name; //名字
 struct list_head entry;
 struct kobject *parent; //父kobject
 struct kset *kset;
 struct kobj_type *ktype; //kobject类型
 struct sysfs_dirent *sd;
 struct kref kref; //引用计数
 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;
};

 struct kobj_type结构定义如下:
struct kobj_type {
 void (*release)(struct kobject *kobj);   //引用计数为0时,调用该函数释放kobject所占用的资源
 const struct sysfs_ops *sysfs_ops; //属性文件的操作函数
 struct attribute **default_attrs; //属性文件,对应sys文件系统中的一个文件
 const struct kobj_ns_type_operations *(*child_ns_type)(struct kobject *kobj);
 const void *(*namespace)(struct kobject *kobj);
};

struct sysfs_ops {
 ssize_t (*show)(struct kobject *, struct attribute *,char *); //读如上属性文件时调用该函数
 ssize_t (*store)(struct kobject *,struct attribute *,const char *, size_t); //写如上属性文件时调用该函数
};

直接贴上示例程序,该模块只是简单注册一个kobject,kobject中包含一个名为kobj_config的属性文件


kobject.c

  1. #include <linux/device.h>
  2. #include <linux/module.h>
  3. #include <linux/kernel.h>
  4. #include <linux/init.h>
  5. #include <linux/string.h>
  6. #include <linux/sysfs.h>
  7. #include <linux/stat.h>
  8.  
  9. MODULE_LICENSE("Dual BSD/GPL");
  10.  
  11. void obj_test_release(struct kobject *kobject);
  12. ssize_t kobj_test_show(struct kobject *kobject, struct attribute *attr,char *buf);
  13. ssize_t kobj_test_store(struct kobject *kobject,struct attribute *attr,const char *buf, size_t count);


  14. //定义的一个属性文件,名字为kobj_config,权限为可读可写
  15. struct attribute test_attr = {
  16.         .name = "kobj_config",
  17.         .mode = S_IRWXUGO,
  18. };
  19.  
  20. static struct attribute *def_attrs[] = {
  21.         &test_attr,
  22.         NULL,
  23. };
  24.  
  25.  
  26. struct sysfs_ops obj_test_sysops =
  27. {
  28.         .show = kobj_test_show, //当对属性文件kobj_config进行读时,执行此函数
  29.         .store = kobj_test_store,//当对属性文件kobj_config进行写时,执行此函数
  30. };
  31. //定义一个kobj_type,描述要注册的kobject的类型信息,如属性和释放操作
  32. struct kobj_type ktype =
  33. {
  34.         .release = obj_test_release, //kobject释放函数
  35.         .sysfs_ops=&obj_test_sysops, //属性文件操作函数
  36.         .default_attrs=def_attrs, //定义的默认属性文件数组
  37. };
  38. //当kobj的应用计数为0时,用于释放kobj的资源,这里只是执行了一条打印信息
  39. void obj_test_release(struct kobject *kobject)
  40. {
  41.         printk("eric_test: release .\n");
  42. }

  43. //当对属性文件kobj_config进行读时,执行此函数
  44. ssize_t kobj_test_show(struct kobject *kobject, struct attribute *attr,char *buf)
  45. {
  46.         printk("have show.\n");
  47.         printk("attrname:%s.\n", attr->name);
  48.         sprintf(buf,"%s\n",attr->name);
  49.         return strlen(attr->name)+2;
  50. }
  51. //当对属性文件kobj_config进行写时,执行此函数
  52. ssize_t kobj_test_store(struct kobject *kobject,struct attribute *attr,const char *buf, size_t count)
  53. {
  54.         printk("havestore\n");
  55.         printk("write: %s\n",buf);
  56.         return count;
  57. }
  58. //定义一个kobj,在模块加载函数中注册
  59. struct kobject kobj;
  60. //模块加载函数
  61. static int kobj_test_init(void)
  62. {
  63.         int ret;
  64.         printk("kboject test init111.\n");
  65.         //初始化并添加一个kobject
  66.         //&kobj==添加的kobject;&ktype==kobject的ktype结构;NULL==该注册的kobject的父kobject,如果为NULL,这表示注册到sys最顶层目录;"kobject_test"==kobject的名字;
  67.         ret=kobject_init_and_add(&kobj,&ktype,NULL,"kobject_test");
  68.         if(ret)
  69.             return -1;
  70.         return 0;
  71. }

  72. //模块注销时执行此函数,删除注册的kobject
  73. static void kobj_test_exit(void)
  74. {
  75.         printk("kobject test exit.\n");
  76.         kobject_del(&kobj);
  77. }
  78.  
  79. module_init(kobj_test_init);
  80. module_exit(kobj_test_exit);
编译完成之后,看看加载之后的效果,执行insmod kobject.ko
操作结果我直接截图了

如我们预期的一样,加载kobject.ko成功之后,在sys/目录下多了一个kobject_test目录,该目录下有一个kobj_config的属性文件。
读kobj_config文件时,程序中的kobj_test_show会得到执行,对kobj_config文件进行写操作时,kobj_test_store函数会得到执行
--------------------------------------------------------------------------------------------------------------------------
kset是嵌入相同类型结构的kobject的集合,kset结构包含一个kobject结构,在sys文件系统上表现出的也是一个目录。和kobject不同的是,kset的目录还可以包含目录,而kobject的目录只能包含属性文件。kset中还包含其子kobject的热插拔处理函数。
kset 结构定义如下:
struct kset {
 struct list_head list; //链接该kset中所有的kobject的链表头
 spinlock_t list_lock;
 struct kobject kobj; //内嵌的kobject
 const struct kset_uevent_ops *uevent_ops; //处理热插拔事件的操作集合
};

struct kset_uevent_ops {
 int (* const filter)(struct kset *kset, struct kobject *kobj); //决定是否将产生事件传递到用户空间,如果返回0,将不传递事件
 const char *(* const name)(struct kset *kset, struct kobject *kobj);// 用于将字符串传递给用户空间的热插拔处理程序
 int (* const uevent)(struct kset *kset, struct kobject *kobj, struct kobj_uevent_env *env); //通过环境变量传递热插拔脚本需要的信息,环境变量存在kobj_uevent_env中
};

下面还是提供一个简单的示例程序,注册两个kset,一个kset_p,一个kset_c,kset_c位于kset_p里面,所以当kset_c加入kset_p时会产生相关热插拔信息

kset.c

  1. #include <linux/device.h>
  2. #include <linux/module.h>
  3. #include <linux/kernel.h>
  4. #include <linux/init.h>
  5. #include <linux/string.h>
  6. #include <linux/sysfs.h>
  7. #include <linux/stat.h>
  8. #include <linux/kobject.h>
  9.  
  10. MODULE_LICENSE("Dual BSD/GPL");
  11.  
  12. struct kset kset_p;
  13. struct kset kset_c;
  14. void kset_p_release(struct kobject *kobject);
  15. void kset_c_release(struct kobject *kobject);
  16. ssize_t kobj_test_show(struct kobject *kobject, struct attribute *attr,char *buf);
  17. ssize_t kobj_test_store(struct kobject *kobject,struct attribute *attr,const char *buf, size_t count);


  18. struct sysfs_ops kset_p_sysops =
  19. {
  20.         .show = kobj_test_show,
  21.         .store = kobj_test_store,
  22. };
  23. struct sysfs_ops kset_c_sysops =
  24. {
  25.         .show = kobj_test_show,
  26.         .store = kobj_test_store,
  27. };
  28. //kset_p内嵌kobject的类型信息,这里没有做添加具体属性
  29. struct kobj_type ktype_p =
  30. {
  31.         .release = kset_p_release,
  32.         .sysfs_ops=&kset_p_sysops,
  33. };
  34. //kset_c内嵌kobject的类型信息,这里没有做添加具体属性
  35. struct kobj_type ktype_c =
  36. {
  37.         .release = kset_c_release,
  38.         .sysfs_ops=&kset_c_sysops,
  39. };

  40. void kset_p_release(struct kobject *kobject)
  41. {
  42.         printk("eric_test: kset_p_release .\n");
  43. }
  44. void kset_c_release(struct kobject *kobject)
  45. {
  46.         printk("eric_test: kset_c_release .\n");
  47. }

  48. ssize_t kobj_test_show(struct kobject *kobject, struct attribute *attr,char *buf)
  49. {
  50.         return 0;
  51. }
  52.  
  53. ssize_t kobj_test_store(struct kobject *kobject,struct attribute *attr,const char *buf, size_t count)
  54. {
  55.         return 0;
  56. }
  57. //决定是否将产生事件传递到用户空间,如果返回0,将不传递事件
  58. //此处永远返回1,表示将产生事件传递到用户空间
  59. int kset_filter(struct kset *kset, struct kobject *kobj)
  60. {
  61.         printk("Filter: kobj %s.\n",kobj->name);
  62.         return 1;
  63. }

  64. // 用于将字符串传递给用户空间的热插拔处理程序,传递的字符串存入buf中
  65. const char *kset_name(struct kset *kset, struct kobject *kobj)
  66. {
  67.         static char buf[20];
  68.         printk("Name: kobj %s.\n",kobj->name);
  69.         sprintf(buf,"%s","kset_name");
  70.         return buf;
  71. }
  72.  //通过环境变量传递热插拔脚本需要的信息,环境变量存在kobj_uevent_env中
  73.  //此处只是将环境变量信息打印出来,并没有添加新的信息
  74. int kset_uevent(struct kset *kset, struct kobject *kobj,struct kobj_uevent_env *env)
  75. {
  76.         int i = 0;
  77.         printk("uevent: kobj %s.\n",kobj->name);

  78.         while( i < env->envp_idx){
  79.                 printk("%s.\n",env->envp[i]);
  80.                 i++;
  81.         }

  82.         return 0;
  83. }

  84. //kset_p热插拔处理程序,这里当注册kset_c时,即将kset_c加入kset_p时,相关函数会执行
  85. struct kset_uevent_ops uevent_ops =
  86. {
  87.         .filter = kset_filter,
  88.         .name = kset_name,
  89.         .uevent = kset_uevent,
  90. };

  91. //模块加载函数
  92. int kset_test_init(void)
  93. {
  94.         int ret;
  95.         
  96.         printk("kset test init1.\n");
  97.         //设置kset_p的名字
  98.         kobject_set_name(&kset_p.kobj,"kset_p");
  99.         //设置kset_p内嵌Kobject的ktype类型,我在3.0.36的代码里运行,必现要加这个,不然会出现内核异常
  100.         kset_p.kobj.ktype=&ktype_p;
  101.         //设置热插拔处理程序
  102.         kset_p.uevent_ops = &uevent_ops;
  103.         //注册kset_p到系统
  104.         ret=kset_register(&kset_p);
  105.         if(ret){
  106.             printk("register kset_p fail\n");
  107.             return -1;
  108.         }
  109.         //设置kset_次的名字
  110.         kobject_set_name(&kset_c.kobj,"kset_c");
  111.         //设置kset_c内嵌Kobject的ktype类型,我在3.0.36的代码里运行,必现要加这个,不然会出现内核异常
  112.         kset_c.kobj.ktype=&ktype_c;
  113.         //设置kset_c内嵌的kobject结构的kset指针执行kset_p,就相当于设置kset_c的父目录为kset_p
  114.         kset_c.kobj.kset = &kset_p;
  115.         //注册kset_c到系统
  116.         ret=kset_register(&kset_c);
  117.         if(ret){
  118.             printk("register kset_c fail\n");
  119.             return -1;
  120.         }
  121.         return 0;
  122. }
  123.  
  124. void kset_test_exit(void)
  125. {
  126.         printk("kset test exit.\n");
  127.         kset_unregister(&kset_p);
  128.         kset_unregister(&kset_c);
  129. }
  130.  
  131. module_init(kset_test_init);
  132. module_exit(kset_test_exit);
编译完成之后,看加载的执行效果
加载程序时相应的热插拔程序得到了执行,同时sys目录下也增加了相应的文件夹
删除kset模块

删除之后的热插拔信息,并没有打印出来,当我再次加载kset时,上传删除kset的热插拔打印信息才打印出来,不解中


最后再贴上编译kobject.c和kset.c的Makefile文件,如要使用该Makefile,请自行修改编译工具链,编译内核代码地址,和编译文件

Makefile

  1. ifneq ($(KERNELRELEASE),)

  2. obj-m := kset.o //要编译的文件

  3. else
  4.     
  5. KDIR := /home/jason/h18/pizza/kernel //运行系统的kernl代码目录
  6. all:
  7.     make -C $(KDIR) M=$(PWD) modules ARCH=arm CROSS_COMPILE=arm-eabi- //编译链
  8. clean:
  9.     rm -f *.ko *.o *.mod.o *.mod.c *.symvers

  10. endif





阅读(1618) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~