乡下人产国偷v产偷v自拍,国产午夜片在线观看,婷婷成人亚洲综合国产麻豆,久久综合给合久久狠狠狠9

  • <output id="e9wm2"></output>
    <s id="e9wm2"><nobr id="e9wm2"><ins id="e9wm2"></ins></nobr></s>

    • 分享

      Kobject模型

       My_ARM 2015-05-26
      轉(zhuǎn)自:http://blog./uid-11319766-id-3253414.html

      分類: LINUX

      一。Kobject
      每個在內(nèi)核中注冊的kobject都對應(yīng)于sysfs文件系統(tǒng)中的一個目錄。
      kobject在文件include/linux/kobject中定義

      點擊(此處)折疊或打開

      1. struct kobject {
      2.     const char        *name;                    //kobject的名稱
      3.     struct list_head    entry;            //kobject結(jié)構(gòu)鏈表
      4.     struct kobject        *parent;        //父kobject結(jié)構(gòu)體
      5.     struct kset        *kset;                    //kset集合
      6.     struct kobj_type    *ktype;            //kobject的類型描述符
      7.     struct sysfs_dirent    *sd;            //sysfs文件目錄
      8.     struct kref        kref;                        //kobject引用計數(shù)
      9.     unsigned int state_initialized:1;    //kobject是否初始化
      10.     unsigned int state_in_sysfs:1;    //是否已經(jīng)加入sysfs
      11.     unsigned int state_add_uevent_sent:1;
      12.     unsigned int state_remove_uevent_sent:1;
      13.     unsigned int uevent_suppress:1;
      14. };
      sysfs 組織結(jié)構(gòu),進入sysfs目錄中。有block bus class dev devices firmware fs kernel module power這些目錄。具體代表看名字差不多就可以看出。在層次結(jié)構(gòu)上,假如有一個設(shè)備A。將有一個名稱為A的目錄。A設(shè)備是在B總線上。那A設(shè)備應(yīng)該在 bus目錄下的B總線下。A設(shè)備肯定會有設(shè)備的屬性(ktype),例如是音頻設(shè)備則應(yīng)該有音量屬性,則音量屬性將在A設(shè)備目錄下有個音量屬性文件。在使 用設(shè)備時,如果要改變音量大小,則可以寫屬性文件入音量指。得到音量大小時,可以讀取屬性文件中的音量值。

       二。Kobject初始化
      初始化一個kobject結(jié)構(gòu)體變量,kobject_init函數(shù)(lib/kobject.c),調(diào)用此函數(shù)前應(yīng)先將kobject變量成員全部置0

      點擊(此處)折疊或打開

      1. /**
      2.  * kobject_init - initialize a kobject structure
      3.  * @kobj: pointer to the kobject to initialize
      4.  * @ktype: pointer to the ktype for this kobject.
      5.  *
      6.  * This function will properly initialize a kobject such that it can then
      7.  * be passed to the kobject_add() call.
      8.  *
      9.  * After this function is called, the kobject MUST be cleaned up by a call
      10.  * to kobject_put(), not by a call to kfree directly to ensure that all of
      11.  * the memory is cleaned up properly.
      12.  */
      13. void kobject_init(struct kobject *kobj, struct kobj_type *ktype)
      14. {
      15.     char *err_str;

      16.     if (!kobj) {    //檢查kobj變量是否為空
      17.         err_str = "invalid kobject pointer!";
      18.         goto error;
      19.     }
      20.     if (!ktype) {    //檢查ktype類型變量是否為空
      21.         err_str = "must have a ktype to be initialized properly!\n";
      22.         goto error;
      23.     }
      24.     if (kobj->state_initialized) {    //是否已經(jīng)初始化過
      25.         /* do not error out as sometimes we can recover */
      26.         printk(KERN_ERR "kobject (%p): tried to init an initialized "
      27.          "object, something is seriously wrong.\n", kobj);
      28.         dump_stack();
      29.     }

      30.     kobject_init_internal(kobj);    //進一步初始化kobj內(nèi)部成員
      31.     kobj->ktype = ktype;    //將參數(shù)中傳來的ktype變量賦值給kobj的ktype變量。
      32.     return;

      33. error:
      34.     printk(KERN_ERR "kobject (%p): %s\n", kobj, err_str);
      35.     dump_stack();
      36. }
      分析kobject_init_internal函數(shù)(lib/kobject.c),此函數(shù)主要設(shè)置一些kobj中的一些變量

      點擊(此處)折疊或打開

      1. static void kobject_init_internal(struct kobject *kobj)
      2. {
      3.     if (!kobj)    //kobj是否為空
      4.         return;
      5.     kref_init(&kobj->kref);    //增加kobject的引用計數(shù),kref_set(kref, 1);
      6.     INIT_LIST_HEAD(&kobj->entry);    //初始化kobj的鏈表
      7.     kobj->state_in_sysfs = 0;    //kobject還沒有注冊到sysfs中
      8.     kobj->state_add_uevent_sent = 0;    //
      9.     kobj->state_remove_uevent_sent = 0;
      10.     kobj->state_initialized = 1;
      11. }
      三。kobj_type
      對象的屬性結(jié)構(gòu)體kobj_type(include/linux/kobject.h)

      點擊(此處)折疊或打開

      1. struct kobj_type {
      2.     void (*release)(struct kobject *kobj);    //釋放函數(shù)(驅(qū)動編寫時提供),此函數(shù)會被kobject_put函數(shù)調(diào)用
      3.     struct sysfs_ops *sysfs_ops;    //屬性文件的操作函數(shù)(只有讀和寫操作)
      4.     struct attribute **default_attrs;    //屬性數(shù)組
      5. };
      1. 討論kobj_type和kobject的關(guān)系,就要先說說kobject的引用。引用一個kobject使用函數(shù)kobject_get()這個函數(shù)會 增加kobject的引用并返回kobject的指針。增加其引用是通過其kobject中斷哦kref變量完成的。對kobject的引用管理主要是為 了知道被引用的情況,如引用不為0就不能銷毀kobject對象,引用為0時則調(diào)用相應(yīng)的釋放函數(shù)等。

      點擊(此處)折疊或打開

      1. struct kobject *kobject_get(struct kobject *kobj)
      2. {
      3.     if (kobj)
      4.         kref_get(&kobj->kref);
      5.     return kobj;
      6. }

      點擊(此處)折疊或打開

      1. void kref_get(struct kref *kref)
      2. {
      3.     WARN_ON(!atomic_read(&kref->refcount));
      4.     atomic_inc(&kref->refcount);    //將kref中的這個原子變量加1
      5.     smp_mb__after_atomic_inc();
      6. }
      減少一個kobject對象的引用使用函數(shù)kobject_put()。當一個kobject對象的引用被減少到0時,程序就應(yīng)該釋放這個kobject相關(guān)的資源。所以在減少引用的函數(shù)中就應(yīng)該有調(diào)用釋放資源的相關(guān)代碼,在下面內(nèi)核代碼中我們可以看到。

      點擊(此處)折疊或打開

      1. void kobject_put(struct kobject *kobj)
      2. {
      3.     if (kobj) {
      4.         if (!kobj->state_initialized)    //若kobj沒有初始化就不能減少其引用
      5.             WARN(1, KERN_WARNING "kobject: '%s' (%p): is not "
      6.              "initialized, yet kobject_put() is being "
      7.              "called.\n", kobject_name(kobj), kobj);
      8.         kref_put(&kobj->kref, kobject_release); //減少kref計數(shù)
      9.     }
      10. }
      11. int kref_put(struct kref *kref, void (*release)(struct kref *kref))
      12. {
      13.     WARN_ON(release == NULL);    //為空警告
      14.     WARN_ON(release == (void (*)(struct kref *))kfree); //如果release函數(shù)就是kfree,則警告(即release函數(shù)不能是簡單的kfree)

      15.     if (atomic_dec_and_test(&kref->refcount)) {    //遞減原子變量并檢查其值
      16.         release(kref);    //回調(diào)release函數(shù)
      17.         return 1;
      18.     }
      19.     return 0;
      20. }
      那 這個release函數(shù)在哪里保存呢,這就和kobj_type結(jié)構(gòu)有關(guān)系了。上面我們可以看到kobj_type中有一個release函數(shù)指針,就是 保存在這里。每一個kobject的ktype都指向一個kobj_type,它保存了這個kobject類型的release函數(shù)指針。

      四。Kset集合
      1.Kset是具有相同類型的kobject集合。一個Kset集合可以表示在/sys/drivers/目錄下,表示一類驅(qū)動程序。kobject則表示一個具體的驅(qū)動目錄。這樣kset則可以將kobject組織成層次化結(jié)構(gòu)。

      點擊(此處)折疊或打開

      1. /**
      2.  * struct kset - a set of kobjects of a specific type, belonging to a specific subsystem.
      3.  *
      4.  * A kset defines a group of kobjects. They can be individually
      5.  * different "types" but overall these kobjects all want to be grouped
      6.  * together and operated on in the same manner. ksets are used to
      7.  * define the attribute callbacks and other common events that happen to
      8.  * a kobject.
      9.  *
      10.  * @list: the list of all kobjects for this kset
      11.  * @list_lock: a lock for iterating over the kobjects
      12.  * @kobj: the embedded kobject for this kset (recursion, isn't it fun...)
      13.  * @uevent_ops: the set of uevent operations for this kset. These are
      14.  * called whenever a kobject has something happen to it so that the kset
      15.  * can add new environment variables, or filter out the uevents if so
      16.  * desired.
      17.  */
      18. struct kset {
      19.     struct list_head list;    //這個鏈表存放這個kset關(guān)聯(lián)的所有kobject
      20.     spinlock_t list_lock;        //維護此鏈表的鎖
      21.     struct kobject kobj;        //內(nèi)嵌的kobject。這樣kset本身也是一個kobject也被表現(xiàn)為一個目錄
      22.     struct kset_uevent_ops *uevent_ops;    //支持熱插拔事件的函數(shù)集
      23. };
      kset 中的kobject對象,所有屬于這個kset集合的kobject對象的parent指針,均指向這個內(nèi)嵌的kobject,也即表示在一個kset集 合中的kobject是相同類型的他們有相同的parent對象。kset的引用計數(shù)也就是內(nèi)嵌的kobject的引用計數(shù)。
      所以kobject和kset的關(guān)系簡單來講,就是
      1.kset是kobject的一個頂層容器,它包含了相同類型的kobject,kset中有鏈表成員保存所有的kobject指向。
      2.kobject中的kset指針指向了一個kset
      3.kset中有kobject對象,表明了kset也可以有kobject相關(guān)的操作。
      4.kset鏈表中的kobject對象的parent指針一般都指向kset內(nèi)嵌的kobject對象。
      kset和kobject關(guān)系基本如下圖,

      kset_uevent_ops熱插拔事件
      熱 插拔事件是用內(nèi)核空間發(fā)送到用戶空間的通知。表明內(nèi)核中的某些配置已經(jīng)發(fā)生變化。用戶空間則會根據(jù)這些信息做相應(yīng)的處理。例如,U盤插入USB系統(tǒng)時,會 產(chǎn)生一個熱插拔事件,內(nèi)核會捕捉到這個熱插拔事件,然后調(diào)用/sbin/hotplug程序,該程序通知加載驅(qū)動程序來相應(yīng)U盤的插入動作。
      熱插拔函數(shù)集的定義在include/linux/koject.h中

      點擊(此處)折疊或打開

      1. struct kset_uevent_ops {
      2.     int (*filter)(struct kset *kset, struct kobject *kobj);        //事件過濾函數(shù)
      3.     const char *(*name)(struct kset *kset, struct kobject *kobj);    //事件名稱函數(shù)
      4.     int (*uevent)(struct kset *kset, struct kobject *kobj,struct kobj_uevent_env *env);
      5.         //uevent函數(shù)可在熱插拔程序執(zhí)行前,向環(huán)境變量寫值
      6. };
      詳細的熱插拔事件先不在這里分析。

      2.注冊一個kset

      點擊(此處)折疊或打開

      1. /**
      2.  * kset_register - initialize and add a kset.
      3.  * @k: kset.
      4.  */
      5. int kset_register(struct kset *k)
      6. {
      7.     int err;

      8.     if (!k)
      9.         return -EINVAL;

      10.     kset_init(k);
      11.     err = kobject_add_internal(&k->kobj);    //將kset中的kobject添加進sysfs,函數(shù)將在后面講解
      12.     if (err)
      13.         return err;
      14.     kobject_uevent(&k->kobj, KOBJ_ADD);
      15.     return 0;
      16. }
      17. /**
      18.  * kset_init - initialize a kset for use
      19.  * @k: kset
      20.  */
      21. void kset_init(struct kset *k)
      22. {
      23.     kobject_init_internal(&k->kobj);
      24.     INIT_LIST_HEAD(&k->list);
      25.     spin_lock_init(&k->list_lock);
      26. }
      我們使用函數(shù)kset_create_and_add()還可以一次性將kset創(chuàng)建并注冊進sysyfs

      點擊(此處)折疊或打開

      1. /**
      2.  * kset_create_and_add - create a struct kset dynamically and add it to sysfs
      3.  *
      4.  * @name: the name for the kset
      5.  * @uevent_ops: a struct kset_uevent_ops for the kset
      6.  * @parent_kobj: the parent kobject of this kset, if any.
      7.  *
      8.  * This function creates a kset structure dynamically and registers it
      9.  * with sysfs. When you are finished with this structure, call
      10.  * kset_unregister() and the structure will be dynamically freed when it
      11.  * is no longer being used.
      12.  *
      13.  * If the kset was not able to be created, NULL will be returned.
      14.  */
      15. struct kset *kset_create_and_add(const char *name,
      16.                  struct kset_uevent_ops *uevent_ops,
      17.                  struct kobject *parent_kobj)
      18. {
      19.     struct kset *kset;
      20.     int error;

      21.     kset = kset_create(name, uevent_ops, parent_kobj);    //根據(jù)參數(shù)創(chuàng)建一個kset
      22.     if (!kset)
      23.         return NULL;
      24.     error = kset_register(kset);                //將kset注冊進sysfs,函數(shù)在上面已經(jīng)分析過
      25.     if (error) {
      26.         kfree(kset);
      27.         return NULL;
      28.     }
      29.     return kset;
      30. }

      點擊(此處)折疊或打開

      1. /**
      2.  * kset_create - create a struct kset dynamically
      3.  *
      4.  * @name: the name for the kset
      5.  * @uevent_ops: a struct kset_uevent_ops for the kset
      6.  * @parent_kobj: the parent kobject of this kset, if any.
      7.  *
      8.  * This function creates a kset structure dynamically. This structure can
      9.  * then be registered with the system and show up in sysfs with a call to
      10.  * kset_register(). When you are finished with this structure, if
      11.  * kset_register() has been called, call kset_unregister() and the
      12.  * structure will be dynamically freed when it is no longer being used.
      13.  *
      14.  * If the kset was not able to be created, NULL will be returned.
      15.  */
      16. static struct kset *kset_create(const char *name,
      17.                 struct kset_uevent_ops *uevent_ops,
      18.                 struct kobject *parent_kobj)
      19. {
      20.     struct kset *kset;
      21.     int retval;

      22.     kset = kzalloc(sizeof(*kset), GFP_KERNEL);
      23.     if (!kset)
      24.         return NULL;
      25.     retval = kobject_set_name(&kset->kobj, name);    //設(shè)置kobject名稱
      26.     if (retval) {
      27.         kfree(kset);
      28.         return NULL;
      29.     }
      30.     kset->uevent_ops = uevent_ops;
      31.     kset->kobj.parent = parent_kobj;            //設(shè)置kset的kobject的父對象

      32.     /*
      33.      * The kobject of this kset will have a type of kset_ktype and belong to
      34.      * no kset itself. That way we can properly free it when it is
      35.      * finished being used.
      36.      */
      37.     kset->kobj.ktype = &kset_ktype;    //設(shè)置kset的kobject的默認屬性
      38.     kset->kobj.kset = NULL;

      39.     return kset;
      40. }
      上面這些函數(shù)主要包含即調(diào)用關(guān)系如下,
      kset_create_and_add
      kset_create
      kzalloc
      kset_register
      kset_init
      kobject_add_internal

      kset中嵌入了一個kobject,所以還有一些和kobject相似的函數(shù)如,
      增加kset的引用,實際是調(diào)用kobject_get增加kset中的kobject的引用

      點擊(此處)折疊或打開

      1. static inline struct kset *kset_get(struct kset *k)
      2. {
      3.     return k ? to_kset(kobject_get(&k->kobj)) : NULL;    
      4. }
      減少kset的引用,實際是調(diào)用kobject_put減少kset中的kobject的引用

      點擊(此處)折疊或打開

      1. static inline void kset_put(struct kset *k)
      2. {
      3.     kobject_put(&k->kobj);
      4. }
      順 便提一下,子系統(tǒng)subsystem,在新的內(nèi)核中已經(jīng)沒有這個結(jié)構(gòu)了。在原來的內(nèi)核中它用來表示比kset更高一層的容器,kset應(yīng)該屬于一個子系 統(tǒng),子系統(tǒng)幫助內(nèi)核在分層結(jié)構(gòu)中定位kset。內(nèi)核子系統(tǒng)包括 block_subsys(/sys/block 塊設(shè)備)、 devices_subsys(/sys/devices 核心設(shè)備層)?,F(xiàn)在subsystem已經(jīng)被kset代替了。

      五,將kobject注冊進sysfs系統(tǒng)
      我們在看一下如何將kobject注冊進sysfs系統(tǒng)中。使用函數(shù)kobject_init_and_add()(lib/kobject.c)函數(shù)將一個kobject注冊進sysfs系統(tǒng),在/sys中表現(xiàn)為生成一個相應(yīng)的目錄。

      點擊(此處)折疊或打開

      1. /**
      2.  * kobject_init_and_add - initialize a kobject structure and add it to the kobject hierarchy
      3.  * @kobj: pointer to the kobject to initialize
      4.  * @ktype: pointer to the ktype for this kobject.
      5.  * @parent: pointer to the parent of this kobject.
      6.  * @fmt: the name of the kobject.
      7.  *
      8.  * This function combines the call to kobject_init() and
      9.  * kobject_add(). The same type of error handling after a call to
      10.  * kobject_add() and kobject lifetime rules are the same here.
      11.  */
      12. int kobject_init_and_add(struct kobject *kobj, struct kobj_type *ktype,
      13.              struct kobject *parent, const char *fmt, ...)
      14. {
      15.     va_list args;
      16.     int retval;

      17.     kobject_init(kobj, ktype);            //調(diào)用初始化函數(shù)先初始化kobject變量

      18.     va_start(args, fmt);            //解析可變參數(shù)列表
      19.     retval = kobject_add_varg(kobj, parent, fmt, args); //給kobject添加參數(shù),并且將其添加到sysfs系統(tǒng)。
      20.     va_end(args);                            //結(jié)束解析參數(shù)列表

      21.     return retval;
      22. }

      點擊(此處)折疊或打開

      1. static int kobject_add_varg(struct kobject *kobj, struct kobject *parent, const char *fmt, va_list vargs)
      2. {
      3.     int retval;

      4.     retval = kobject_set_name_vargs(kobj, fmt, vargs);        //設(shè)置kobject的名稱
      5.     if (retval) {
      6.         printk(KERN_ERR "kobject: can not set name properly!\n");
      7.         return retval;
      8.     }
      9.     kobj->parent = parent;            //設(shè)置kobject的父kobject
      10.     return kobject_add_internal(kobj);    //添加kobject
      11. }

      點擊(此處)折疊或打開

      1. static int kobject_add_internal(struct kobject *kobj)
      2. {
      3.     int error = 0;
      4.     struct kobject *parent;

      5.     if (!kobj)        //檢查是否為空
      6.         return -ENOENT;

      7.     if (!kobj->name || !kobj->name[0]) {    //kobj是否有名稱,如果沒有則不能注冊,生成目錄。
      8.         WARN(1, "kobject: (%p): attempted to be registered with empty "
      9.              "name!\n", kobj);
      10.         return -EINVAL;
      11.     }

      12.     parent = kobject_get(kobj->parent);    //獲得父kobject,并增加父kobject的引用計數(shù)

      13.     /* join kset if set, use it as parent if we do not already have one */
      14.     if (kobj->kset) {                                        //是否有kset集合
      15.         if (!parent)                                            //如果沒有父kobject則用kset中的kobject對象
      16.             parent = kobject_get(&kobj->kset->kobj);
      17.         kobj_kset_join(kobj);            //將kobject添加進它關(guān)聯(lián)的kset的list鏈表中。
      18.         kobj->parent = parent;        //設(shè)置父koject
      19.     }

      20.     pr_debug("kobject: '%s' (%p): %s: parent: '%s', set: '%s'\n",
      21.          kobject_name(kobj), kobj, __func__,
      22.          parent ? kobject_name(parent) : "<NULL>",
      23.          kobj->kset ? kobject_name(&kobj->kset->kobj) : "<NULL>");

      24.     error = create_dir(kobj);                //創(chuàng)建kobject的相應(yīng)目錄
      25.     
      26.     if (error) {        //創(chuàng)建時出錯處理
      27.         kobj_kset_leave(kobj);
      28.         kobject_put(parent);
      29.         kobj->parent = NULL;

      30.         /* be noisy on error issues */
      31.         if (error == -EEXIST)
      32.             printk(KERN_ERR "%s failed for %s with "
      33.              "-EEXIST, don't try to register things with "
      34.              "the same name in the same directory.\n",
      35.              __func__, kobject_name(kobj));
      36.         else
      37.             printk(KERN_ERR "%s failed for %s (%d)\n",
      38.              __func__, kobject_name(kobj), error);
      39.         dump_stack();
      40.     } else
      41.         kobj->state_in_sysfs = 1;        //標記為已經(jīng)注冊進sysfs

      42.     return error;
      43. }
      sysfs創(chuàng)建目錄函數(shù)create_dir,在lib/kobject.c

      點擊(此處)折疊或打開

      1. static int create_dir(struct kobject *kobj)
      2. {
      3.     int error = 0;
      4.     if (kobject_name(kobj)) {
      5.         error = sysfs_create_dir(kobj);            //在sysfs中創(chuàng)建目錄,將來有時間了可以分析下sysfs子系統(tǒng)。
      6.         if (!error) {
      7.             error = populate_dir(kobj);
      8.             if (error)
      9.                 sysfs_remove_dir(kobj);
      10.         }
      11.     }
      12.     return error;
      13. }
      以上函數(shù)的主要調(diào)用關(guān)系,如下
      kobject_init_and_add
      kobject_init
      kobject_add_varg
      kobject_add_internal
      create_dir
      還有一個函數(shù)kobject_add,也可以添加一個kobject,它只是沒有kobject_init這一步。

      點擊(此處)折疊或打開

      1. int kobject_add(struct kobject *kobj, struct kobject *parent,
      2.         const char *fmt, ...)
      3. {
      4.     va_list args;
      5.     int retval;

      6.     if (!kobj)
      7.         return -EINVAL;

      8.     if (!kobj->state_initialized) {
      9.         printk(KERN_ERR "kobject '%s' (%p): tried to add an "
      10.          "uninitialized object, something is seriously wrong.\n",
      11.          kobject_name(kobj), kobj);
      12.         dump_stack();
      13.         return -EINVAL;
      14.     }
      15.     va_start(args, fmt);
      16.     retval = kobject_add_varg(kobj, parent, fmt, args);
      17.     va_end(args);

      18.     return retval;
      19. }

        本站是提供個人知識管理的網(wǎng)絡(luò)存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點。請注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊一鍵舉報。
        轉(zhuǎn)藏 分享 獻花(0

        0條評論

        發(fā)表

        請遵守用戶 評論公約

        類似文章 更多