前言
rtthread充分利用了面向对象的编程思想,其中object.c文件中维护了非常重要的rt_object对象的操作接口。前面的文章中拿出了钩子函数体会面向对象的设计思想。本篇将rtthread的object.c文件各个接口进行分析。
内核对象信息表
这里引用一下前述文章中的图。
从图中可以看出,在object.c中管理着一个内核对象信息表,其定义如下:
struct rt_object_information
{
enum rt_object_class_type type; /**< object class type */
rt_list_t object_list; /**< object list */
rt_size_t object_size; /**< object size */
};
钩子函数
这个部分前文已经说明过原理。其实就是当你调用相关函数的时候,可以同时触发用户定义的钩子函数。
增删改查系列
静态创建
void rt_object_init(struct rt_object *object,enum rt_object_class_type type,const char *name){...}
上面是静态对象初始化函数。函数内部主要逻辑如下:
(1)根据传入的类型找到内核对象信息表中的对应结构体指针
(2)将其它入参信息保存在object对象中
(3)将利用object对象内部的链表结构体,采用头插的方法,将该对象插入到对象信息表
静态删除
void rt_object_detach(rt_object_t object){...}
上面是静态对象释放函数。函数内部主要逻辑很简单。因为采用了双链表,所以只要知道节点,就很容易将这个节点删除,但是删除函数(如下)没有对输入参数判空操作,感觉怪怪的。。。
rt_inline void rt_list_remove(rt_list_t *n)
{
n->next->prev = n->prev;
n->prev->next = n->next;
n->next = n->prev = n;
}
动态创建
动态分配的对象创建函数如下:
rt_object_t rt_object_allocate(enum rt_object_class_type type, const char *name){...}
大体执行逻辑和静态对象创建时类似的,主要区别在于类似于malloc函数分配一个内存空间。
动态删除
动态分配对象的删除函数如下:
void rt_object_delete(rt_object_t object)
同样,得益于双链表的结构,删除也比较容易,但是删除后需要释放动态分配的空间。
查找
以下是查找的核心代码:
if (information == RT_NULL) information = &rt_object_container[type];
for (node = information->object_list.next;
node != &(information->object_list);
node = node->next)
{
object = rt_list_entry(node, struct rt_object, list);
if (rt_strncmp(object->name, name, RT_NAME_MAX) == 0)
{
/* leave critical */
rt_exit_critical();
return object;
}
}
下图为上述代码中的宏定义
类似的思路在linux内核中用的相对较多。因为对象链接到对象信息表中是通过对象的list成员实现的,所以遍历节点时,必须先恢复对象的完整信息,所以节点的真实地址必须向后退一个offset,这个offset刚好是member的大小。这样就可以拿到对象的首地址信息,进而拿到它的name属性进行比较。这里也可以看出rtthread认为从前往后查找到第一个name相同的对象,则停止查找(这里先不考虑建立对象时,是否可以name相同的问题)。
补充
除此之外,object.c中还有中断保护相关以及同步相关的代码、配置宏等。但是这些不会影响整体的代码逻辑,有时间的话也可以继续研究一下。