1、RT-Thread 软件架构
2、RT-Thread 内核结构
3、 预备知识
3.1链表
链表是通过节点把离散的数据链接成一个表,通过对节点的插入和删除操作从而实现对数据的存取。而数组是通过开辟一段连续的内存来存储数据,这是数组和链表最大的区别。数组的每个成员对应链表的节点,成员和节点的数据类型可以是标准的C类型或者是用户自定义的结构体。数组有起始地址和结束地址,而链表是一个圈,没有头和尾之分,但是为了方便节点的插入和删除操作会人为的规定一个根节点。 单向链表:
双向链表:
3.2 节点
3.2.2 节点初始化
3.2.3 在双向链表表头后面插入一个节点
3.2.4 在双向链表表头前面插入一个节点
3.2.5 从双向链表删除一个节点
3.2.6 从节点中获取所在结构体的首地址
node 表示一个节点的地址, type 表示该节点所在的结构体的类型,
member 表示该节点在该结构体中的成员名称。
rt_container_of()的实现算法具体见图:
我们知道了一个节点 tlist 的地址 ptr,现在要推算出该节点所在的 type 类型的结构体的起始地址 f_struct_ptr。我们可以将 ptr 的值减去图中灰色部分的偏移的大小就可以得到 f_struct_ptr 的地址,现在的关键是如何计算出灰色部分的偏移大小。这里采取的做法是将 0 地址强制类型类型转换为 type,即(type *)0,然后通过指针访问结构体成员的方式获取到偏移的大小,即(&((type *)0)->member), 最后即可算出 f_struct_ptr = ptr -(&((type *)0)->member)。
3.3 面向对象编程思想 3.3.1 封装 3.3.2 继承 3.3.3 多态
4 内核对象管理架构
RT-Thread 采用内核对象管理系统来访问 / 管理所有内核对象,内核对象包含了内核中线程,信号量,互斥量,事件,邮箱,消息队列和定时器,内存池,设备驱动等。对象容器中包含了每类内核对象的信息,包括对象类型,大小等。对象容器给每类内核对象分配了一个链表,所有的内核对象都被链接到该链表上,如图 RT-Thread 的内核对象容器及链表如下图所示:
下图则显示了 RT-Thread 中各类内核对象的派生和继承关系:
4.1 内核对象数据结构
4.1.1 对象结构
4.1.2 对象容器结构
4.1.3 初始化对象容器
容 器 是 一 个 全 部 变 量 的 数 组 , 数 据 类 型 为 struct rt_object_information, 这是一个结构体类型, 包含对象的三个信息,分别为对象类型、对象列表节点头和对象的大小。
_OBJ_CONTAINER_LIST_INIT()是一个带参宏,用于初始化一个
节点 list,在 object.c 中定义
4.1.4 从容器中获取指定类型的对象信息
4.1.5 初始化对象 每创建一个对象,都需要先将其初始化,主要分成两个部分的工作,首先将对象控制块里面与对象相关的成员初始化,然后将该对象插入到对象容器中。
4.1.6 线程结构
线程状态切换:
RT-Thread 中,实际上线程并不存在运行状态,就绪状态和运行状态是等同的。
4.1.7 初始化线程 在线程初始化之后,线程通过自身的 list 节点将自身挂到容器的对象列表中,对象初始化函数在线程初始化函数里面被调用。
4.1.8 初始化线程栈 在动态创建线程和初始化线程的时候,会使用到内部的线程初始化函数_rt_thread_init(),_rt_thread_init() 函数会调用栈初始化函数 rt_hw_stack_init(),在栈初始化函数里会手动构造一个上下文内容,这个上下文内容将被作为每个线程第一次执行的初始值。上下文在栈里的排布如下图所示:
|