瑞芯微RK3568芯片是一款定位中高端的通用型SOC,采用22nm制程工艺,搭载一颗四核Cortex-A55处理器和Mali G52 2EE 图形处理器。RK3568 支持4K 解码和 1080P 编码,支持SATA/PCIE/USB3.0 外围接口。RK3568内置独立NPU,可用于轻量级人工智能应用。RK3568 支持安卓 11 和 linux 系统,主要面向物联网网关、NVR 存储、工控平板、工业检测、工控盒、卡拉 OK、云终端、车载中控等行业。
?
【公众号】迅为电子
【粉丝群】824412014(加群获取驱动文档+例程)
【视频观看】嵌入式学习之Linux驱动(第九期_设备模型_全新升级)_基于RK3568
【购买链接】迅为RK3568开发板瑞芯微Linux安卓鸿蒙ARM核心板人工智能AI主板
通过上个章节的实验,我们已经知道引用计数器是如何工作的。当引用计数器的值变为0后,会自动调用自定义的释放函数去执行释放的操作。那么kboj是如何释放的呢,本章节我们来从代码层面进行下分析。
要学习kobject是如何释放的,那么我们要先明白kobj是如何创建的。对于 kobject的创建,我们可以进一步分析这两种方法的实现细节。
1. 使用 kobject_create_and_add()函数创建 kobject:
?kobject_create_and_add()函数首先调用 kobject_create()函数,该函数使用 kzalloc()为 kobject分配内存空间。在 kobject_create()函数中,调用 kobject_init()函数对分配的内存进行初始化,并指定了默认的 ktype。接下来,kobject_create_and_add()函数调用 kobject_add()函数将 kobject添加到系统中,使其可见。
kobject_add()函数内部调用了kobject_add_internal()函数,该函数负责将 kobject添加到父对象的子对象列表中,并创建相应的 sysfs 文件系统条目。
2. 使用 kobject_init_and_add()函数创建 kobject:
??kobject_init_and_add()函数需要手动分配内存,并通过 kobject_init()函数对分配的内存进行初始化。此时需要自己实现 ktype结构体。初始化完成后,调用 kobject_add()函数将 kobject 添加到系统中。
无论是哪种方法,最终都会调用 kobject_add()函数将 kobject添加到系统中,以使其可见。了解了 kobject的创建过程后,我们可以深入学习 kobject的释放过程。
我们来追踪下kobject的释放函数——kobject_put()函数的实现。
在Linux内核中,kobject_put()函数用于减少kobject的引用计数,并在引用计数达到0时释放kobject相关的资源。如下图所示,在函数里面,当引用计数器的值变为0以后,会调用release函数执行释放的操作。
图93-1
Linux系统帮我们实现好了释放函数,如下图所示:
图93-2
在上图的release函数中,该函数最终会去调用kobject_cleanup函数,kobject_cleanup函数实现如下图所示:
图93-3
如上图所示,函数定义了一个名叫kobject_cleanup的静态函数,参数为一个指向 struct kobject 结构体的指针 kobj。函数内部定义了一个指向 struct kobj_type 结构体的指针 t,用于获取 kobj 的类型信息。还定义了一个指向常量字符的指针 name,用于保存 kobj 的名称。接下来,使用 pr_debug 打印调试信息,显示 kobject 的名称、地址、函数名称和父对象的地址。
然后,检查 kobj 的类型信息 t 是否存在,并且检查 t->release 是否为 NULL。如下图所示:
图93-4
如果 t 存在但 t->release 为 NULL,表示 kobj 的类型没有定义释放函数,会打印调试信息指示该情况。
接下来,检查 kobj 的状态变量 state_add_uevent_sent 和 state_remove_uevent_sent。如果 state_add_uevent_sent 为真而 state_remove_uevent_sent 为假,表示调用者没有发送 "remove" 事件,会自动发送 "remove" 事件。
然后,检查 kobj 的状态变量 state_in_sysfs。如果为真,表示调用者没有从 sysfs 中删除 kobj,会自动调用 kobject_del() 函数将其从 sysfs 中删除。
接下来,再次检查 t 是否存在,并且检查 t->release 是否存在。如果存在,表示 kobj 的类型定义了释放函数,会调用该释放函数进行资源清理。如下图所示:
图93-4
最后,检查 name 是否存在。如果存在,表示 kobj 的名称是动态分配的,会释放该名称的内存。这就是 kobject_cleanup() 函数的实现。它负责执行 kobject 的资源清理和释放操作,包括处理类型信息、发送事件、删除 sysfs 中的对象以及调用释放函数。
kobject_cleanup() 函数的实现表明,最终调用的释放函数是在 kobj_type 结构体中定义的。这解释了为什么在使用 kobject_init_and_add() 函数时,kobj_type 结构体不能为空的原因。因为释放函数是在 kobj_type 结构体中定义的,如果不实现释放函数,就无法进行正确的资源释放。
接下来,我们来看一下在Linux内核中,dynamic_kobj_ktype 是一个 kobj_type 结构体对象,用于定义动态创建的 kobject 的类型。它指定了释放函数和 sysfs 操作。如下图所示:
图93-5
如下图所示:dynamic_kobj_release函数如下图所示:
图93-6
在上图中,使用kfree函数对创建的kobj进行了释放。总结起来,kobj_type 结构体中的释放函数是为了确保在释放 kobject 时执行必要的资源清理和释放操作,以确保系统的正确运行和资源管理。