LV06-04-linux设备模型-04-kobject的释放
kobjet对象怎么释放的?若笔记中有错误或者不合适的地方,欢迎批评指正😃。
点击查看使用工具及版本
PC端开发环境 | Windows | Windows11 |
Ubuntu | Ubuntu20.04.2的64位版本 | |
VMware® Workstation 17 Pro | 17.6.0 build-24238078 | |
终端软件 | MobaXterm(Professional Edition v23.0 Build 5042 (license)) | |
Win32DiskImager | Win32DiskImager v1.0 | |
Linux开发板环境 | Linux开发板 | 正点原子 i.MX6ULL Linux 阿尔法开发板 |
uboot | NXP官方提供的uboot,使用的uboot版本为U-Boot 2019.04 | |
linux内核 | linux-4.19.71(NXP官方提供) |
点击查看本文参考资料
分类 | 网址 | 说明 |
官方网站 | https://www.arm.com/ | ARM官方网站,在这里我们可以找到Cotex-Mx以及ARMVx的一些文档 |
https://www.nxp.com.cn/ | NXP官方网站 | |
https://www.nxpic.org.cn/ | NXP 官方社区 | |
https://u-boot.readthedocs.io/en/latest/ | u-boot官网 | |
https://www.kernel.org/ | linux内核官网 |
点击查看相关文件下载
分类 | 网址 | 说明 |
NXP | https://github.com/nxp-imx | NXP imx开发资源GitHub组织,里边会有u-boot和linux内核的仓库 |
nxp-imx/linux-imx/releases/tag/v4.19.71 | NXP linux内核仓库tags中的v4.19.71 | |
nxp-imx/uboot-imx/releases/tag/rel_imx_4.19.35_1.1.0 | NXP u-boot仓库tags中的rel_imx_4.19.35_1.1.0 | |
I.MX6ULL | i.MX 6ULL Applications Processors for Industrial Products | I.MX6ULL 芯片手册(datasheet,可以在线查看) |
i.MX 6ULL Applications ProcessorReference Manual | I.MX6ULL 参考手册(下载后才能查看,需要登录NXP官网) | |
Source Code | https://elixir.bootlin.com/linux/latest/source | linux kernel源码 |
kernel/git/stable/linux.git - Linux kernel stable tree | linux kernel源码(官网,tag 4.19.71) | |
https://elixir.bootlin.com/u-boot/latest/source | uboot源码 |
在《LV06-04-linux设备模型-02-kobject相关的数据结构.md》中已经了解了引用计数器,知道当引用计数器的值变为 0 后,会自动调用自定义的释放函数去执行释放的操作。那么为什么到 0 的时候就会释放呢?我们来看一下。
一、kobject怎么创建的?
要知道 kobject 是如何释放的,那么我们要先明白 kobject 是如何创建的。对于 kobject 的创 建,我们可以进一步分析这两种方法的实现细节。
1. kobject_create_and_add()
kobject_create_and_add() 函数创建kobject的实现过程大概如下:
2. kobject_init_and_add()
kobject_init_and_add() 创建kobject时需要手动分配内存,并通过 kobject_init() 函数对分配的内存进行初始化。此时需要自己实现 ktype 结构体。初始化完成后,调用 kobject_add_varg() 函数将 kobject 添加到系统中。
二、kobject的释放
我们来看一下 kobject 的释放函数——kobject_put()函数的实现。
1. kobject_put()
在 Linux 内核中,kobject_put()函数用于减少 kobject 的引用计数,并在引用计数达到 0 时 释放 kobject 相关的资源。该函数定义如下:
1 | void kobject_put(struct kobject *kobj) |
可以看到内部最终调用的是 kref_put() 函数来对引用计数进行操作。
1.1 kref_put()
kref_put() 函数定义如下:
1 | static inline int kref_put(struct kref *kref, void (*release)(struct kref *kref)) |
在该函数中,当引用计数器的值变为 0 以后,会调用 release 函数执行释放的操作,这个release是一个函数指针,它指向一个这样的函数:
1 | void (*release)(struct kref *kref) |
这个函数是啥?我们看上一层调用它的函数(kobject_put())给它传的什么,可以看到传入的是:
1 | ref_put(&kobj->kref, kobject_release); |
所以最终其实调用的是 kobject_release() 函数来释放kobject对象。
1.2 kobject_release()
kobject_release() 函数定义如下:
1 | static void kobject_release(struct kref *kref) |
去内核源码搜一下就会发现,正常情况是没有这个CONFIG_DEBUG_KOBJECT_RELEASE宏的,后面会调用 kobject_cleanup() 函数。
1.3 kobject_cleanup()
kobject_cleanup()函数定义在kobject.c - lib/kobject.c - kobject_cleanup。接下来我们详细分析一下:
kobject_cleanup() 函数的参数为一个指向 struct kobject 结构体的指针 kobj。函数内部定义了一个指向 struct kobj_type 结构体的指针 t,用于获取 kobj 的类型信息。还定义了一个指向常量字符的指针 name,用于保存 kobj 的名称。
- 第 638 行
接下来,使用 pr_debug 打印调试信息,显示 kobject 的名称、地址、函数名称和父对象的地址。
- 第 641 行
检查 kobj 的类型信息 t 是否存在,并且检查 t->release 是否为 NULL。如果 t 存在但 t->release 为 NULL,表示 kobj 的类型没有定义释放函数,会打印调试信息指示该情况。
- 第 646 行
检查 kobj 的状态变量 state_add_uevent_sent 和 state_remove_uevent_sent。如果 state_add_uevent_sent 为真而 state_remove_uevent_sent 为假,表示调用者没有发送”remove” 事件,会自动发送 “remove” 事件。
- 第 653 行
检查 kobj 的状态变量 state_in_sysfs。如果为真,表示调用者没有从 sysfs 中删除 kobj,会自动调用 kobject_del() 函数将其从 sysfs 中删除。
- 第 659 行
再次检查 t 是否存在,并且检查 t->release 是否存在。如果存在,表示 kobj 的 类型定义了释放函数,会调用该释放函数进行资源清理。从这里可以知道,最后调用的这个release函数是 kobj_type 结构体中定义的。
- 第 666 行
检查 name 是否存在。如果存在,表示 kobj 的名称是动态分配的,会释放该名称 的内存。
这就是 kobject_cleanup() 函数的实现。它负责执行 kobject 的资源清理和释放操作, 包括处理类型信息、发送事件、删除 sysfs 中的对象以及调用释放函数。
1.4 总结
kobject_cleanup() 函数的实现表明,最终调用的释放函数是在 kobj_type 结构体中定义的。 这解释了为什么在使用 kobject_init_and_add() 函数时,kobj_type 结构体不能为空的原因。因 为释放函数是在 kobj_type 结构体中定义的,如果不实现释放函数,就无法进行正确的资源释放。
2. dynamic_kobj_ktype
dynamic_kobj_ktype 是一个 kobj_type 结构体对 象,用于定义动态创建的 kobject 的类型。它指定了释放函数和 sysfs 操作:
1 | static struct kobj_type dynamic_kobj_ktype = { |
2.1 dynamic_kobj_release()
dynamic_kobj_release()函数定义如下:
1 | static void dynamic_kobj_release(struct kobject *kobj) |
使用 kfree 函数对创建的 kobj 进行了释放。总结起来, kobj_type 结构体中的释放函数是为了确保在释放 kobject 时执行必要的资源清理和释放操作,以确保系统的正确运行。
2.2 kobj_sysfs_ops
kobj_sysfs_ops定义如下:
1 | const struct sysfs_ops kobj_sysfs_ops = { |
2.3 在哪里被调用?
这个dynamic_kobj_ktype 是在 kobject_create() 函数中设置的:
3. 自定义释放函数?
自定义的话,好像要自己采用手动申请内存,创建kobject那种方式,这里有一个demo:05_device_model/05_ktype · 苏木/imx6ull-driver-demo - 码云 - 开源中国
点击查看详情
1 |
|