1、kobject 結構
在Linux內核里,kobject是組成Linux設備模型的基礎,一個kobject對應sysfs里的一個目錄。從面向對象的角度來說,kobject可以看作是所有設備對象的基類,因為C語言并沒有面向對象的語法,所以一般是把kobject內嵌到其他結構體里來實現類似的作用,這里的其他結構體可以看作是kobject的派生類。Kobject為Linux設備模型提供了很多有用的功能,比如引用計數,接口抽象,父子關系等等。引用計數本質上就是利用kref實現的。
另外,Linux設備模型還有一個重要的數據結構kset。Kset本身也是一個kobject,所以它在sysfs里同樣表現為一個目錄,但它和kobject的不同之處在于kset可以看作是一個容器,如果你把它類比為C++里的容器類如list也無不可。Kset之所以能作為容器來使用,其內部正是內嵌了一個雙向鏈表結構struct list_head。
kobject 在內核中的描述
[cpp]?view plain
?copystruct?kobject?{??????const?char??????*name;??????struct?list_head????entry;??????struct?kobject??????*parent;??????struct?kset?????*kset;??????struct?kobj_type????*ktype;??????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;??};??
內核里的設備之間是以樹狀形式組織的,在這種組織架構里比較靠上層的節點可以看作是下層節點的父節點,反映到sysfs里就是上級目錄和下級目錄之間的關系,
在內核里,正是kobject幫助我們實現這種父子關系
。在kobject的定義里,name表示的是kobject在sysfs中的名字;指針parent用來指向kobject的父對象;Kref大家應該比較熟悉了,kobject通過它來實現引用計數;Kset指針用來指向這個kobject所屬的kset,下文會再詳細描述kset的用法;對于ktype,如果只是望文生義的話,應該是用來描述kobject的類型信息。Ktype的定義如下:
[cpp]?view plain
?copystruct?kobj_type?{??????void?(*release)(struct?kobject?*kobj);??????const?struct?sysfs_ops?*sysfs_ops;??????struct?attribute?**default_attrs;??};??
函數指針release是給kref使用的,
當引用計數為0這個指針指向的函數會被調用來釋放內存
。sysfs_ops和attribute是做什么用的呢?前文里提到,一個kobject對應sysfs里的一個目錄,
而目錄下的文件就是由sysfs_ops和attribute來實現的,其中,attribute定義了kobject的屬性,在sysfs里對應一個文件,sysfs_ops用來定義讀寫這個文件的方法。
Ktype里的attribute是默認的屬性,另外也可以使用更加靈活的手段,本文的重點還是放在default attribute。
[cpp]?view plain
?copy#include?<linux/kernel.h>??#include?<linux/module.h>??#include?<linux/slab.h>??#include?<linux/kobject.h>????struct?my_kobj?{?????????int?val;??????struct?kobject?kobj;??};????struct?my_kobj?*obj1,?*obj2;??struct?kobj_type?my_type;????struct?attribute?name_attr?=?{??????.name?=?"name",???????.mode?=?0444,????};????struct?attribute?val_attr?=?{??????.name?=?"val",???????.mode?=?0666,???};????struct?attribute?*my_attrs[]?=?{??????&name_attr,???????&val_attr,??????NULL,??};?????????ssize_t?my_show(struct?kobject?*kobj,?struct?attribute?*attr,?char?*buffer)??{??????struct?my_kobj?*obj?=?container_of(kobj,?struct?my_kobj,?kobj);??????ssize_t?count?=?0;????????if?(strcmp(attr->name,?"name")?==?0)?{??????????count?=?sprintf(buffer,?"%s\n",?kobject_name(kobj));??????}?else?if?(strcmp(attr->name,?"val")?==?0)?{??????????count?=?sprintf(buffer,?"%d\n",?obj->val);??????}????????return?count;??}????ssize_t?my_store(struct?kobject?*kobj,?struct?attribute?*attr,?const?char?*buffer,?size_t?size)??{??????struct?my_kobj?*obj?=?container_of(kobj,?struct?my_kobj,?kobj);????????if?(strcmp(attr->name,?"val")?==?0)?{??????????sscanf(buffer,?"%d",?&obj->val);??????}????????return?size;??}????struct?sysfs_ops?my_sysfsops?=?{??????.show?=?my_show,??????.store?=?my_store,??};????void?obj_release(struct?kobject?*kobj)??{??????struct?my_kobj?*obj?=?container_of(kobj,?struct?my_kobj,?kobj);??????printk(KERN_INFO?"obj_release?%s\n",?kobject_name(&obj->kobj));??????kfree(obj);??}????static?int?__init?mykobj_init(void)??{??????printk(KERN_INFO?"mykobj_init\n");????????obj1?=?kzalloc(sizeof(struct?my_kobj),?GFP_KERNEL);???????if?(!obj1)?{??????????return?-ENOMEM;??????}??????obj1->val?=?1;????????obj2?=?kzalloc(sizeof(struct?my_kobj),?GFP_KERNEL);??????if?(!obj2)?{??????????kfree(obj1);??????????return?-ENOMEM;??????}??????obj2->val?=?2;????????my_type.release?=?obj_release;??????my_type.default_attrs?=?my_attrs;??????my_type.sysfs_ops?=?&my_sysfsops;????????kobject_init_and_add(&obj1->kobj,?&my_type,?NULL,?"mykobj1");???????kobject_init_and_add(&obj2->kobj,?&my_type,?&obj1->kobj,?"mykobj2");?????????????????return?0;??}????static?void?__exit?mykobj_exit(void)??{??????printk(KERN_INFO?"mykobj_exit\n");????????kobject_del(&obj2->kobj);???????kobject_put(&obj2->kobj);????????????kobject_del(&obj1->kobj);??????kobject_put(&obj1->kobj);????????return;??}??????????module_init(mykobj_init);??module_exit(mykobj_exit);????MODULE_LICENSE("GPL"); ?
總結
以上是生活随笔為你收集整理的Linux 设备模型之 (kobject、kset 和 Subsystem)(二)的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。