.. include:: ../disclaimer-zh_CN.rst :Original: Documentation/core-api/kobject.rst :翻译: å¸å»¶è…¾ Yanteng Si <siyanteng@loongson.cn> .. _cn_core_api_kobject.rst: ======================================================= 关于kobjectsã€ksetså’Œktypesçš„ä¸€åˆ‡ä½ æ²¡æƒ³è¿‡éœ€è¦äº†è§£çš„东西 ======================================================= :作者: Greg Kroah-Hartman <gregkh@linuxfoundation.org> :最åŽä¸€æ¬¡æ›´æ–°: December 19, 2007 æ ¹æ®Jon Corbet于2003å¹´10月1日为lwn.netæ’°å†™çš„åŽŸåˆ›æ–‡ç« æ”¹ç¼–ï¼Œç½‘å€æ˜¯ï¼š https://lwn.net/Articles/51437/ ç†è§£é©±åŠ¨æ¨¡åž‹å’Œå»ºç«‹åœ¨å…¶ä¸Šçš„kobject抽象的部分的困难在于,没有明显的切入点。 处ç†kobjects需è¦ç†è§£ä¸€äº›ä¸åŒçš„类型,所有这些类型都会相互引用。为了使事情 å˜å¾—更简å•ï¼Œæˆ‘们将多路并进,从模糊的术è¯å¼€å§‹ï¼Œå¹¶é€æ¸å¢žåŠ ç»†èŠ‚ã€‚é‚£ä¹ˆï¼Œå…ˆæ¥ äº†è§£ä¸€äº›æˆ‘ä»¬å°†è¦ä½¿ç”¨çš„术è¯çš„简明定义å§ã€‚ - 一个kobject是一个kobject结构体类型的对象。Kobjects有一个åå—和一个 引用计数。一个kobject也有一个父指针(å…许对象被排列æˆå±‚次结构),一个 特定的类型,并且,通常在sysfs虚拟文件系统ä¸è¡¨ç¤ºã€‚ Kobjects本身通常并ä¸å¼•äººå…³æ³¨ï¼›ç›¸å它们常常被嵌入到其他包å«çœŸæ£å¼•äººæ³¨ç›® 的代ç 的结构体ä¸ã€‚ 任何结构体都 **ä¸åº”该** 有一个以上的kobject嵌入其ä¸ã€‚如果有的è¯ï¼Œå¯¹è±¡çš„引用计 数肯定会被打乱,而且ä¸æ£ç¡®ï¼Œä½ 的代ç 就会出现错误。所以ä¸è¦è¿™æ ·åšã€‚ - ktype是嵌入一个kobject的对象的类型。æ¯ä¸ªåµŒå…¥kobject的结构体都需è¦ä¸€ä¸ª 相应的ktype。ktype控制ç€kobject在被创建和销æ¯æ—¶çš„行为。 - 一个kset是一组kobjects。这些kobjectså¯ä»¥æ˜¯ç›¸åŒçš„ktype或者属于ä¸åŒçš„ ktype。kset是kobjects集åˆçš„基本容器类型。Ksets包å«å®ƒä»¬è‡ªå·±çš„kobjects, ä½†ä½ å¯ä»¥å®‰å…¨åœ°å¿½ç•¥è¿™ä¸ªå®žçŽ°ç»†èŠ‚ï¼Œå› ä¸ºksetçš„æ ¸å¿ƒä»£ç 会自动处ç†è¿™ä¸ªkobject。 å½“ä½ çœ‹åˆ°ä¸€ä¸ªä¸‹é¢å…¨æ˜¯å…¶ä»–目录的sysfs目录时,通常这些目录ä¸çš„æ¯ä¸€ä¸ªéƒ½å¯¹åº” 于åŒä¸€ä¸ªksetä¸çš„一个kobject。 æˆ‘ä»¬å°†ç ”ç©¶å¦‚ä½•åˆ›å»ºå’Œæ“作所有这些类型。将采å–一ç§è‡ªä¸‹è€Œä¸Šçš„方法,所以我们 将回到kobjects。 嵌入kobjects ============= å†…æ ¸ä»£ç 很少创建å¤ç«‹çš„kobject,åªæœ‰ä¸€ä¸ªä¸»è¦çš„例外,下é¢ä¼šè§£é‡Šã€‚相å, kobjects被用æ¥æŽ§åˆ¶å¯¹ä¸€ä¸ªæ›´å¤§çš„ã€ç‰¹å®šé¢†åŸŸçš„对象的访问。为æ¤ï¼Œkobjects会被 嵌入到其他结构ä¸ã€‚å¦‚æžœä½ ä¹ æƒ¯äºŽç”¨é¢å‘对象的术è¯æ¥æ€è€ƒé—®é¢˜ï¼Œé‚£ä¹ˆkobjectså¯ ä»¥è¢«çœ‹ä½œæ˜¯ä¸€ä¸ªé¡¶çº§çš„æŠ½è±¡ç±»ï¼Œå…¶ä»–çš„ç±»éƒ½æ˜¯ä»Žå®ƒæ´¾ç”Ÿå‡ºæ¥çš„。一个kobject实现了 一系列的功能,这些功能本身并ä¸ç‰¹åˆ«æœ‰ç”¨ï¼Œä½†åœ¨å…¶ä»–对象ä¸å´å¾ˆå¥½ç”¨ã€‚Cè¯è¨€ä¸å… 许直接表达继承,所以必须使用其他技术——比如结构体嵌入。 ï¼ˆå¯¹äºŽé‚£äº›ç†Ÿæ‚‰å†…æ ¸é“¾è¡¨å®žçŽ°çš„äººæ¥è¯´ï¼Œè¿™ç±»ä¼¼äºŽâ€œlist_headâ€ç»“构本身很少有用, 但总是被嵌入到感兴趣的更大的对象ä¸ï¼‰ã€‚ 例如, ``drivers/uio/uio.c`` ä¸çš„IO代ç 有一个结构体,定义了与uio设备相 关的内å˜åŒºåŸŸ:: struct uio_map { struct kobject kobj; struct uio_mem *mem; }; å¦‚æžœä½ æœ‰ä¸€ä¸ªuio_map结构体,找到其嵌入的kobjectåªæ˜¯ä¸€ä¸ªä½¿ç”¨kobjæˆå‘˜çš„问题。 然而,与kobjects一起工作的代ç 往往会é‡åˆ°ç›¸å的问题:给定一个结构体kobject 的指针,指å‘包å«ç»“æž„ä½“çš„æŒ‡é’ˆæ˜¯ä»€ä¹ˆï¼Ÿä½ å¿…é¡»é¿å…使用一些技巧(比如å‡è®¾ kobject在结构的开头),相åï¼Œä½ å¾—ä½¿ç”¨container_of()å®ï¼Œå…¶å¯ä»¥åœ¨ ``<linux/kernel.h>`` ä¸æ‰¾åˆ°:: container_of(ptr, type, member) å…¶ä¸: * ``ptr`` 是一个指å‘嵌入kobject的指针, * ``type`` 是包å«ç»“构体的类型, * ``member`` 是 ``指针`` 所指å‘的结构体域的å称。 container_of()的返回值是一个指å‘ç›¸åº”å®¹å™¨ç±»åž‹çš„æŒ‡é’ˆã€‚å› æ¤ï¼Œä¾‹å¦‚,一个嵌入到 uio_map结构 **ä¸** çš„kobject结构体的指针kpå¯ä»¥è¢«è½¬æ¢ä¸ºä¸€ä¸ªæŒ‡å‘ **包å«** uio_map 结构体的指针,方法是:: struct uio_map *u_map = container_of(kp, struct uio_map, kobj); 为了方便起è§ï¼Œç¨‹åºå‘˜ç»å¸¸å®šä¹‰ä¸€ä¸ªç®€å•çš„å®ï¼Œç”¨äºŽå°†kobject指针 **å推** åˆ°åŒ…å« ç±»åž‹ã€‚åœ¨æ—©æœŸçš„ ``drivers/uio/uio.c`` ä¸æ£æ˜¯å¦‚æ¤ï¼Œä½ å¯ä»¥åœ¨è¿™é‡Œçœ‹åˆ°:: struct uio_map { struct kobject kobj; struct uio_mem *mem; }; #define to_map(map) container_of(map, struct uio_map, kobj) å…¶ä¸å®çš„å‚数“mapâ€æ˜¯ä¸€ä¸ªæŒ‡å‘有关的kobject结构体的指针。该å®éšåŽè¢«è°ƒç”¨:: struct uio_map *map = to_map(kobj); kobjectsçš„åˆå§‹åŒ– ================ 当然,创建kobject的代ç å¿…é¡»åˆå§‹åŒ–该对象。一些内部å—段是通过(强制)调用kobject_init() æ¥è®¾ç½®çš„:: void kobject_init(struct kobject *kobj, struct kobj_type *ktype); ktype是æ£ç¡®åˆ›å»ºkobjectçš„å¿…è¦æ¡ä»¶ï¼Œå› 为æ¯ä¸ªkobject都必须有一个相关的kobj_type。 在调用kobject_init()åŽï¼Œä¸ºäº†å‘sysfs注册kobject,必须调用函数kobject_add():: int kobject_add(struct kobject *kobj, struct kobject *parent, const char *fmt, ...); 这将æ£ç¡®è®¾ç½®kobject的父级和kobjectçš„å称。如果该kobjectè¦ä¸Žä¸€ä¸ªç‰¹å®šçš„kset相关 è”,在调用kobject_add()之å‰å¿…须分é…kobj->kset。如果kset与kobject相关è”,则 kobject的父级å¯ä»¥åœ¨è°ƒç”¨kobject_add()时被设置为NULL,则kobject的父级将是kset 本身。 由于kobjectçš„åå—æ˜¯åœ¨å®ƒè¢«æ·»åŠ åˆ°å†…æ ¸æ—¶è®¾ç½®çš„ï¼Œæ‰€ä»¥kobjectçš„åå—ä¸åº”该被直接æ“作。 å¦‚æžœä½ å¿…é¡»æ”¹å˜kobjectçš„åå—,请调用kobject_rename():: int kobject_rename(struct kobject *kobj, const char *new_name); kobject_rename()函数ä¸ä¼šæ‰§è¡Œä»»ä½•é”定æ“作,也ä¸ä¼šå¯¹name进行å¯é 性检查,所以调用 者自己检查和串行化æ“作是明智的选择 有一个å«kobject_set_name()的函数,但那是历å²é—产,æ£åœ¨è¢«åˆ é™¤ã€‚å¦‚æžœä½ çš„ä»£ç 需 è¦è°ƒç”¨è¿™ä¸ªå‡½æ•°ï¼Œé‚£ä¹ˆå®ƒæ˜¯ä¸æ£ç¡®çš„,需è¦è¢«ä¿®å¤ã€‚ è¦æ£ç¡®è®¿é—®kobjectçš„å称,请使用函数kobject_name():: const char *kobject_name(const struct kobject * kobj); 有一个辅助函数å¯ä»¥åŒæ—¶åˆå§‹åŒ–å’Œæ·»åŠ kobjectåˆ°å†…æ ¸ä¸ï¼Œä»¤äººæƒŠè®¶çš„是,该函数被称为 kobject_init_and_add():: int kobject_init_and_add(struct kobject *kobj, struct kobj_type *ktype, struct kobject *parent, const char *fmt, ...); å‚数与上é¢æè¿°çš„å•ä¸ªkobject_init()å’Œkobject_add()函数相åŒã€‚ Uevents ======= 当一个kobject被注册到kobjectæ ¸å¿ƒåŽï¼Œä½ 需è¦å‘全世界宣布它已ç»è¢«åˆ›å»ºäº†ã€‚è¿™å¯ä»¥é€š 过调用kobject_uevent()æ¥å®žçŽ°:: int kobject_uevent(struct kobject *kobj, enum kobject_action action); 当kobjectç¬¬ä¸€æ¬¡è¢«æ·»åŠ åˆ°å†…æ ¸æ—¶ï¼Œä½¿ç”¨ *KOBJ_ADD* 动作。这应该在该kobjectçš„ä»» 何属性或å对象被æ£ç¡®åˆå§‹åŒ–åŽè¿›è¡Œï¼Œå› 为当这个调用å‘生时,用户空间会立å³å¼€å§‹å¯» 找它们。 当kobjectä»Žå†…æ ¸ä¸ç§»é™¤æ—¶ï¼ˆå…³äºŽå¦‚何åšçš„细节在下é¢ï¼‰ï¼Œ **KOBJ_REMOVE** çš„uevent 将由kobjectæ ¸å¿ƒè‡ªåŠ¨åˆ›å»ºï¼Œæ‰€ä»¥è°ƒç”¨è€…ä¸å¿…担心手动æ“作。 引用计数 ======== kobject的关键功能之一是作为它所嵌入的对象的一个引用计数器。åªè¦å¯¹è¯¥å¯¹è±¡çš„引用 å˜åœ¨ï¼Œè¯¥å¯¹è±¡ï¼ˆä»¥åŠæ”¯æŒå®ƒçš„代ç )就必须继ç»å˜åœ¨ã€‚用于æ“作kobject的引用计数的低 级函数是:: struct kobject *kobject_get(struct kobject *kobj); void kobject_put(struct kobject *kobj); 对kobject_get()çš„æˆåŠŸè°ƒç”¨å°†å¢žåŠ kobject的引用计数器值并返回kobject的指针。 当引用被释放时,对kobject_put()的调用将递å‡å¼•ç”¨è®¡æ•°å€¼ï¼Œå¹¶å¯èƒ½é‡Šæ”¾è¯¥å¯¹è±¡ã€‚请注 æ„,kobject_init()将引用计数设置为1,所以设置kobject的代ç 最终需è¦kobject_put() æ¥é‡Šæ”¾è¯¥å¼•ç”¨ã€‚ å› ä¸ºkobjects是动æ€çš„,所以它们ä¸èƒ½ä»¥é™æ€æ–¹å¼æˆ–åœ¨å †æ ˆä¸å£°æ˜Žï¼Œè€Œæ€»æ˜¯ä»¥åŠ¨æ€æ–¹å¼åˆ† é…。未æ¥ç‰ˆæœ¬çš„å†…æ ¸å°†åŒ…å«å¯¹é™æ€åˆ›å»ºçš„kobjectsçš„è¿è¡Œæ—¶æ£€æŸ¥ï¼Œå¹¶å°†è¦å‘Šå¼€å‘者这ç§ä¸ 当的使用。 å¦‚æžœä½ ä½¿ç”¨struct kobjectåªæ˜¯ä¸ºäº†ç»™ä½ 的结构体æ供一个引用计数器,请使用struct kref æ¥ä»£æ›¿ï¼›kobject是多余的。关于如何使用kref结构体的更多信æ¯ï¼Œè¯·å‚è§Linuxå†…æ ¸æºä»£ ç æ ‘ä¸çš„文件Documentation/core-api/kref.rst 创建“简å•çš„â€kobjects ==================== 有时,开å‘者想è¦çš„åªæ˜¯åœ¨sysfs层次结构ä¸åˆ›å»ºä¸€ä¸ªç®€å•çš„目录,而ä¸å¿…去æžé‚£äº›å¤æ‚ çš„ksetsã€æ˜¾ç¤ºå’Œå˜å‚¨å‡½æ•°ï¼Œä»¥åŠå…¶ä»–细节。这是一个应该创建å•ä¸ªkobjectçš„ä¾‹å¤–ã€‚è¦ åˆ›å»ºè¿™æ ·ä¸€ä¸ªæ¡ç›®ï¼ˆå³ç®€å•çš„目录),请使用函数:: struct kobject *kobject_create_and_add(const char *name, struct kobject *parent); 这个函数将创建一个kobject,并将其放在sysfsä¸æŒ‡å®šçš„父kobject下é¢çš„ä½ç½®ã€‚è¦åˆ› 建与æ¤kobject相关的简å•å±žæ€§ï¼Œè¯·ä½¿ç”¨:: int sysfs_create_file(struct kobject *kobj, const struct attribute *attr); 或者:: int sysfs_create_group(struct kobject *kobj, const struct attribute_group *grp); 这里使用的两ç§ç±»åž‹çš„属性,与已ç»ç”¨kobject_create_and_add()创建的kobject, 都å¯ä»¥æ˜¯kobj_attribute类型,所以ä¸éœ€è¦åˆ›å»ºç‰¹æ®Šçš„自定义属性。 å‚è§ç¤ºä¾‹æ¨¡å—, ``samples/kobject/kobject-example.c`` ,以了解一个简å•çš„ kobject和属性的实现。 ktypes和释放方法 ================ 以上讨论ä¸è¿˜ç¼ºå°‘一件é‡è¦çš„事情,那就是当一个kobject的引用次数达到零的时候 会å‘生什么。创建kobject的代ç 通常ä¸çŸ¥é“何时会å‘生这ç§æƒ…况;首先,如果它知 é“,那么使用kobject就没有什么æ„义。当sysfs被引入时,å³ä½¿æ˜¯å¯é¢„测的对象生命 周期也会å˜å¾—æ›´åŠ å¤æ‚ï¼Œå› ä¸ºå†…æ ¸çš„å…¶ä»–éƒ¨åˆ†å¯ä»¥èŽ·å¾—在系统ä¸æ³¨å†Œçš„任何kobject 的引用。 最终的结果是,一个由kobjectä¿æŠ¤çš„结构体在其引用计数归零之å‰ä¸èƒ½è¢«é‡Šæ”¾ã€‚引 用计数ä¸å—创建kobject的代ç çš„ç›´æŽ¥æŽ§åˆ¶ã€‚å› æ¤ï¼Œæ¯å½“它的一个kobjects的最åŽä¸€ 个引用消失时,必须异æ¥é€šçŸ¥è¯¥ä»£ç 。 ä¸€æ—¦ä½ é€šè¿‡kobject_add()æ³¨å†Œäº†ä½ çš„kobjectï¼Œä½ ç»å¯¹ä¸èƒ½ä½¿ç”¨kfree()æ¥ç›´æŽ¥é‡Š 放它。唯一安全的方法是使用kobject_put()。在kobject_init()之åŽæ€»æ˜¯ä½¿ç”¨ kobject_put()以é¿å…错误的å‘生是一个很好的åšæ³•ã€‚ 这个通知是通过kobjectçš„release()方法完æˆçš„ã€‚é€šå¸¸è¿™æ ·çš„æ–¹æ³•æœ‰å¦‚ä¸‹å½¢å¼:: 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); } 有一点很é‡è¦ï¼šæ¯ä¸ªkobject都必须有一个release()方法,而且这个kobjectå¿… é¡»æŒç»å˜åœ¨ï¼ˆå¤„于一致的状æ€ï¼‰ï¼Œç›´åˆ°è¿™ä¸ªæ–¹æ³•è¢«è°ƒç”¨ã€‚如果这些约æŸæ¡ä»¶æ²¡æœ‰ 得到满足,那么代ç 就是有缺陷的。注æ„ï¼Œå¦‚æžœä½ å¿˜è®°æä¾›release()方法,内 æ ¸ä¼šè¦å‘Šä½ 。ä¸è¦è¯•å›¾é€šè¿‡æ供一个“空â€çš„释放函数æ¥æ‘†è„±è¿™ä¸ªè¦å‘Šã€‚ å¦‚æžœä½ çš„æ¸…ç†å‡½æ•°åªéœ€è¦è°ƒç”¨kfree()ï¼Œé‚£ä¹ˆä½ å¿…é¡»åˆ›å»ºä¸€ä¸ªåŒ…è£…å‡½æ•°ï¼Œè¯¥å‡½æ•° 使用container_of()æ¥å‘ä¸Šé€ åž‹åˆ°æ£ç¡®çš„类型(如上é¢çš„例å所示),然åŽåœ¨æ•´ä¸ª 结构体上调用kfree()。 注æ„,kobjectçš„åå—在release函数ä¸æ˜¯å¯ç”¨çš„,但它ä¸èƒ½åœ¨è¿™ä¸ªå›žè°ƒä¸è¢«æ”¹ å˜ã€‚å¦åˆ™ï¼Œåœ¨kobjectæ ¸å¿ƒä¸ä¼šå‡ºçŽ°å†…å˜æ³„æ¼ï¼Œè¿™è®©äººå¾ˆä¸çˆ½ã€‚ 有趣的是,release()方法并ä¸å˜å‚¨åœ¨kobject本身;相å,它与ktype相关。 å› æ¤ï¼Œè®©æˆ‘们引入结构体kobj_type:: struct kobj_type { void (*release)(struct kobject *kobj); const struct sysfs_ops *sysfs_ops; struct attribute **default_attrs; const struct attribute_group **default_groups; const struct kobj_ns_type_operations *(*child_ns_type)(struct kobject *kobj); const void *(*namespace)(struct kobject *kobj); void (*get_ownership)(struct kobject *kobj, kuid_t *uid, kgid_t *gid); }; 这个结构æ用æ¥æ述一个特定类型的kobject(或者更æ£ç¡®åœ°è¯´ï¼ŒåŒ…å«å¯¹è±¡çš„ 类型)。æ¯ä¸ªkobject都需è¦æœ‰ä¸€ä¸ªç›¸å…³çš„kobj_typeç»“æž„ï¼›å½“ä½ è°ƒç”¨ kobject_init()或kobject_init_and_add()时必须指定一个指å‘该结构的 指针。 当然,kobj_type结构ä¸çš„releaseå—段是指å‘è¿™ç§ç±»åž‹çš„kobjectçš„release() 方法的一个指针。å¦å¤–两个å—段(sysfs_ops å’Œ default_attrsï¼‰æŽ§åˆ¶è¿™ç§ ç±»åž‹çš„å¯¹è±¡å¦‚ä½•åœ¨ sysfs ä¸è¢«è¡¨ç¤ºï¼›å®ƒä»¬è¶…出了本文的范围。 default_attrs 指针是一个默认属性的列表,它将为任何用这个 ktype 注册 çš„ kobject 自动创建。 ksets ===== 一个kset仅仅是一个希望相互关è”çš„kobjects的集åˆã€‚没有é™åˆ¶å®ƒä»¬å¿…须是相 åŒçš„ktype,但是如果它们ä¸æ˜¯ç›¸åŒçš„,就è¦éžå¸¸å°å¿ƒã€‚ 一个kset有以下功能: - 它åƒæ˜¯ä¸€ä¸ªåŒ…å«ä¸€ç»„对象的袋å。一个ksetå¯ä»¥è¢«å†…æ ¸ç”¨æ¥è¿½è¸ªâ€œæ‰€æœ‰å— 设备â€æˆ–“所有PCI设备驱动â€ã€‚ - kset也是sysfsä¸çš„一个å目录,与kset相关的kobjectså¯ä»¥åœ¨è¿™é‡Œæ˜¾ç¤º 出æ¥ã€‚æ¯ä¸ªkset都包å«ä¸€ä¸ªkobject,它å¯ä»¥è¢«è®¾ç½®ä¸ºå…¶ä»–kobject的父对象; sysfs层次结构的顶级目录就是以这ç§æ–¹å¼æž„建的。 - Ksetså¯ä»¥æ”¯æŒkobjectsçš„ "çƒæ’æ‹”",并影å“uevent事件如何被报告给 用户空间。 在é¢å‘对象的术è¯ä¸ï¼Œâ€œksetâ€æ˜¯é¡¶çº§çš„容器类;ksets包å«å®ƒä»¬è‡ªå·±çš„kobject, 但是这个kobject是由kset代ç 管ç†çš„,ä¸åº”该被任何其他用户所æ“纵。 ksetåœ¨ä¸€ä¸ªæ ‡å‡†çš„å†…æ ¸é“¾è¡¨ä¸ä¿å˜å®ƒçš„å对象。Kobjects通过其ksetå—段指å‘å…¶ 包å«çš„ksetã€‚åœ¨å‡ ä¹Žæ‰€æœ‰çš„æƒ…å†µä¸‹ï¼Œå±žäºŽä¸€ä¸ªksetçš„kobjects在它们的父 对象ä¸éƒ½æœ‰é‚£ä¸ªksetï¼ˆæˆ–è€…ï¼Œä¸¥æ ¼åœ°è¯´ï¼Œå®ƒçš„åµŒå…¥kobject)。 由于ksetä¸åŒ…å«ä¸€ä¸ªkobject,它应该总是被动æ€åœ°åˆ›å»ºï¼Œè€Œä¸æ˜¯é™æ€åœ° æˆ–åœ¨å †æ ˆä¸å£°æ˜Žã€‚è¦åˆ›å»ºä¸€ä¸ªæ–°çš„kset,请使用:: struct kset *kset_create_and_add(const char *name, const struct kset_uevent_ops *uevent_ops, struct kobject *parent_kobj); å½“ä½ å®Œæˆå¯¹kset的处ç†åŽï¼Œè°ƒç”¨:: void kset_unregister(struct kset *k); æ¥é”€æ¯å®ƒã€‚这将从sysfsä¸åˆ 除该kset并递å‡å…¶å¼•ç”¨è®¡æ•°å€¼ã€‚当引用计数 为零时,该ksetå°†è¢«é‡Šæ”¾ã€‚å› ä¸ºå¯¹è¯¥kset的其他引用å¯èƒ½ä»ç„¶å˜åœ¨ï¼Œ 释放å¯èƒ½å‘生在kset_unregister()返回之åŽã€‚ 一个使用kset的例åå¯ä»¥åœ¨å†…æ ¸æ ‘ä¸çš„ ``samples/kobject/kset-example.c`` 文件ä¸çœ‹åˆ°ã€‚ 如果一个kset希望控制与它相关的kobjectsçš„ueventæ“作,它å¯ä»¥ä½¿ç”¨ 结构体kset_uevent_opsæ¥å¤„ç†å®ƒ:: struct kset_uevent_ops { int (* const filter)(struct kset *kset, struct kobject *kobj); const char *(* const name)(struct kset *kset, struct kobject *kobj); int (* const uevent)(struct kset *kset, struct kobject *kobj, struct kobj_uevent_env *env); }; 过滤器函数å…许kset阻æ¢ä¸€ä¸ªç‰¹å®škobjectçš„uevent被å‘é€åˆ°ç”¨æˆ·ç©ºé—´ã€‚ 如果该函数返回0,该ueventå°†ä¸ä¼šè¢«å‘射出去。 name函数将被调用以覆盖ueventå‘é€åˆ°ç”¨æˆ·ç©ºé—´çš„kset的默认å称。默 认情况下,该å称将与kset本身相åŒï¼Œä½†è¿™ä¸ªå‡½æ•°ï¼Œå¦‚æžœå˜åœ¨ï¼Œå¯ä»¥è¦†ç›– 该å称。 当ueventå³å°†è¢«å‘é€è‡³ç”¨æˆ·ç©ºé—´æ—¶ï¼Œuevent函数将被调用,以å…许更多 的环境å˜é‡è¢«æ·»åŠ 到ueventä¸ã€‚ 有人å¯èƒ½ä¼šé—®ï¼Œé‰´äºŽæ²¡æœ‰æ出执行该功能的函数,究竟如何将一个kobject æ·»åŠ åˆ°ä¸€ä¸ªksetä¸ã€‚ç”案是这个任务是由kobject_add()处ç†çš„。当一个 kobjectè¢«ä¼ é€’ç»™kobject_add()时,它的ksetæˆå‘˜åº”该指å‘这个kobject 所属的kset。 kobject_add()将处ç†å‰©ä¸‹çš„部分。 如果属于一个ksetçš„kobject没有父kobjecté›†ï¼Œå®ƒå°†è¢«æ·»åŠ åˆ°ksetçš„ç›® 录ä¸ã€‚并éžæ‰€æœ‰çš„ksetæˆå‘˜éƒ½å¿…é¡»ä½åœ¨kset目录ä¸ã€‚å¦‚æžœåœ¨æ·»åŠ kobject 之å‰åˆ†é…了一个明确的父kobject,那么该kobject将被注册到ksetä¸ï¼Œ ä½†æ˜¯è¢«æ·»åŠ åˆ°çˆ¶kobject下é¢ã€‚ 移除Kobject =========== 当一个kobject在kobjectæ ¸å¿ƒæ³¨å†ŒæˆåŠŸåŽï¼Œåœ¨ä»£ç 使用完它时,必须将其 清ç†æŽ‰ã€‚è¦åšåˆ°è¿™ä¸€ç‚¹ï¼Œè¯·è°ƒç”¨kobject_put()ã€‚é€šè¿‡è¿™æ ·åšï¼Œkobjectæ ¸ 心会自动清ç†è¿™ä¸ªkobject分é…的所有内å˜ã€‚如果为这个对象å‘é€äº† ``KOBJ_ADD`` uevent,那么相应的 ``KOBJ_REMOVE`` uevent也将被å‘é€ï¼Œä»»ä½•å…¶ä»–çš„ sysfs内务将被æ£ç¡®å¤„ç†ã€‚ å¦‚æžœä½ éœ€è¦åˆ†ä¸¤æ¬¡å¯¹kobjectè¿›è¡Œåˆ é™¤ï¼ˆæ¯”å¦‚è¯´åœ¨ä½ è¦é”€æ¯å¯¹è±¡æ—¶æ— æƒç¡çœ ), 那么调用kobject_del()将从sysfsä¸å–消kobject的注册。这使得kobject “ä¸å¯è§â€ï¼Œä½†å®ƒå¹¶æ²¡æœ‰è¢«æ¸…ç†æŽ‰ï¼Œè€Œä¸”该对象的引用计数ä»ç„¶æ˜¯ä¸€æ ·çš„ã€‚åœ¨ç¨ åŽçš„时间调用kobject_put()æ¥å®Œæˆä¸Žè¯¥kobject相关的内å˜çš„清ç†ã€‚ kobject_del()å¯ä»¥ç”¨æ¥æ”¾å¼ƒå¯¹çˆ¶å¯¹è±¡çš„引用,如果循环引用被构建的è¯ã€‚ 在æŸäº›æƒ…况下,一个父对象引用一个å对象是有效的。循环引用必须通过明 确调用kobject_del()æ¥æ‰“æ–ï¼Œè¿™æ ·ä¸€ä¸ªé‡Šæ”¾å‡½æ•°å°±ä¼šè¢«è°ƒç”¨ï¼Œå‰ä¸€ä¸ªå¾ªçŽ¯ ä¸çš„对象会相互释放。 示例代ç 出处 ============ 关于æ£ç¡®ä½¿ç”¨ksetså’Œkobjects的更完整的例å,请å‚è§ç¤ºä¾‹ç¨‹åº ``samples/kobject/{kobject-example.c,kset-example.c}`` ,如果 您选择 ``CONFIG_SAMPLE_KOBJECT`` ,它们将被构建为å¯åŠ 载模å—。