RT-Thread速览——内核

来源于官方API参考手册

系统初始化

RT-Thread 的启动流程

RT-Thread 的启动流程,大致可以分为四个部分:
(1)初始化与系统相关的硬件;
(2)初始化系统内核对象,例如定时器、调度器、信号;
(3)创建main线程,在main线程中对各类模块依次进行初始化;
(4)初始化定时器线程、空闲线程,并启动调度器。

一般来说,在系统里添加新的功能模块的时候,在使用前都必须先初始化, 通常的做法是在主程序运行前手动添加调用初始化函数。 而 RT-Thread 提供了另一种低耦合高内聚的初始化方式,它不需要我们再 手动添加调用初始化函数,它能在系统运行前自动完成各模块的初始化。
组件初始化方式要求初始化函数主动通过一些宏接口进行申明,链接器会 自动收集所有被申明的初始化函数,放到特定的数据段中,数据段中的 所有函数在系统初始化时会被调用。
组件初始化的所有宏接口及其被初始化的顺序如下表所示:

初始化顺序 接口 描述
1 INIT_BOARD_EXPORT(fn) 硬件的初始化,此时调度器还未启动
2 INIT_PREV_EXPORT(fn) 主要是用于纯软件的初始化、没有太多依赖的函数
3 INIT_DEVICE_EXPORT(fn) 外设驱动初始化相关,比如网卡设备
4 INIT_COMPONENT_EXPORT(fn) 组件初始化,比如文件系统或者LWIP
5 INIT_ENV_EXPORT(fn) 系统环境初始化,比如挂载文件系统
6 INIT_APP_EXPORT(fn) 应用初始化,比如GUI应用

INIT_BOARD_EXPORT(fn)声明的函数会被rt_components_board_init()调用, 其他宏声明的函数会被rt_components_init()调用。

RT-Thread的启动流程如下图所示:

内核对象管理

RT-Thread采用内核对象管理系统来访问/管理所有内核对象,内核对象包含了内核中绝大部分设施, 这些内核对象可以是静态分配的静态对象,也可以是从系统内存堆中分配的动态对象。

RT-Thread内核对象包括:线程,信号量,互斥量,事件,邮箱,消息队列和定时器,内存池,设备驱动等。

下图则显示了RT-Thread中各类内核对象的派生和继承关系。对于每一种具体内核对象和对象控制块,除了基本结构外, 还有自己的扩展属性(私有属性)

线程管理

RT-Thread操作系统是基于线程调度的多任务系统。

调度过程是一种完全抢占式的基于优先级的调度算法。

  • 支持8/32/256优先级,其中0表示最高,7/31/255表示最低。最低优先级7/31/255优先级用于空闲线程。
  • 支持以相同优先级运行的线程。 共享时间片循环调度用于这种情况。
  • 线程包含五种状态,操作系统会自动根据它运行的情况来动态调整它的状态。
状态 描述
初始状态 当线程刚开始创建还没开始运行时就处于初始状态;在初始状态下,线程不参与调度。
就绪状态 在就绪状态下,线程按照优先级排队,等待被执行;一旦当前线程运行完毕让出处理器,操作系统会马上寻找最高优先级的就绪态线程运行。
运行状态 线程当前正在运行。
挂起状态 也称阻塞态。它可能因为资源不可用而挂起等待,或线程主动延时一段时间而挂起。在挂起状态下,线程不参与调度。
关闭状态 当线程运行结束时将处于关闭状态。关闭状态的线程不参与线程的调度。

时钟管理

RT-Thread的时钟管理以时钟节拍为基础,时钟节拍指的是周期性硬件定时器两次中断间的间隔时间长度, 这个周期性硬件定时器称之为系统时钟。时钟节拍(OS Tick)是RT-Thread 操作系统中最小的时钟单位, 系统节拍一般定义为32位无符号整数,提供给应用程序所有和时间有关的服务, 如线程的延时、线程的时间片轮转调度以及定时器超时等,从系统启动开始计数的时钟节拍数称为系统时间。 时钟节拍来源于定时器的周期性中断,一次中断表示一个OS Tick。 OS Tick的长度可以根据RT_TICK_PER_SECOND的定义来调整, 等于1/RT_TICK_PER_SECOND秒,精度越高的时钟将导致系统中定时器频繁检查。

定时器管理

RT-Thread的定时器提供两类定时器机制:第一类是单次触发定时器,这类定时器在启动后只会触发一次定时器事件, 然后定时器自动停止。第二类是周期触发定时器,这类定时器会周期性的触发定时器事件, 直到用户手动的停止,否则将永远持续执行下去。

另外,根据超时函数执行时所处的上下文环境,RT-Thread的定时器可以分为软件定时器硬件定时器。 硬件定时器的超时函数在中断上下文环境中执行,可以在初始化/创建定时器时使用参数RT_TIMER_FLAG_HARD_TIMER来指定。 软件定时器的超时函数在timer线程的上下文环境中执行。可以在初始化/创建定时器时使用参数RT_TIMER_FLAG_SOFT_TIMER来指定。

线程间通信

RT-Thread操作系统支持如下所示的线程间同步与通信的方式:

  • 信号量是一种轻型的用于解决线程间同步问题的内核对象,线程可以获取或释放它,从而达到同步或互斥的目的。
  • 互斥量又叫相互排斥的信号量,是一种特殊的二值信号量,互斥量支持递归访问且能防止线程优先级翻转。
  • 一个事件集可以包含多个事件,利用事件集可以完成一对多,多对多的线程间同步。
  • 邮箱一次可以传递一个4字节大小的邮件,并且邮箱具备一定的存储功能,能够缓存一定数量的邮件数
  • 消息队列能够接收来自线程或中断服务例程中不固定长度的消息,并把消息缓存在自己的内存空间中。
  • 信号用来通知线程发生了异步事件,用做线程之间的异常通知、应急处理。

内存池管理

内存池(Memory Pool)是一种内存分配方式,用于分配大量大小相同的小内存块。 它可以极大地加快内存分配与释放的速度,且能尽量避免内存碎片化。当内存池为空时, 可以阻止分配的线程(或者立即返回,或者等待一段时间返回,这由timeout参数确定)。 当其他线程向此内存池释放内存块时,被阻塞的线程将被唤醒。

动态内存管理

动态内存管理是一个真实的堆内存管理模块,可以在当前资源满足的情况下,根据用户 的需求分配任意大小的内存块。而当用户不需要再使用这些内存块时,又可以释放回堆中 供其他应用分配使用。RT-Thread 系统为了满足不同的需求,提供了两套不同的动态内存 管理算法,分别是小堆内存管理算法和 SLAB 内存管理算法。

小堆内存管理模块主要针对系统资源比较少,一般用于小于2MB内存空间的系统;而SLAB 内存管理模块则主要是在系统资源比较丰富时,提供了一种近似多内存池管理算法的快速 算法。两种内存管理模块在系统运行时只能选择其中之一或者完全不使用动态堆内存管理 器。这两种管理模块提供的API接口完全相同。

除上述之外,RT-Thread还有一种针对多内存堆的管理机制,即memheap内存管理。memheap方法 适用于系统存在多个内存堆的情况,它可以将多个内存“粘贴”在一起,形成一个大的内存堆, 用户使用起来会感到格外便捷。

中断管理

RT-Thread的中断管理功能主要是管理中断设备、中断服务例程、中断嵌套、中断栈的维护、 线程切换时的现场保护和恢复等。

当CPU正在处理内部数据时,外界发生了紧急情况,要求CPU暂停当前的工作转去处理这个异步事件。 处理完毕后,再回到原来被中断的地址,继续原来的工作,这样的过程称为中断。实现这一功能的 系统称为中断系统,申请CPU中断的请求源称为中断源,当多个中断源同时向CPU请求中断时,就存在 一个中断优先权的问题。通常根据中断源的优先级别,优先处理最紧急事件的中断请求源,即最先 响应级别最高的中断请求。

当中断产生时,CPU将按如下的顺序执行:

(1)保存当前处理机状态信息;
(2)载入异常或中断处理函数到PC寄存器;
(3)把控制权转交给处理函数并开始执行;
(4)当处理函数执行完成时,恢复处理器状态信息;
(5)从异常或中断中返回到前一个程序执行点。
中断使得CPU可以在事件发生时才进行处理,而不必让CPU连续不断地查询是否有相应的事件发生。

系统钩子函数

为了在运行时跟踪和记录RT-Thread的活动,引入了一种钩子机制。

钩子函数是在一些特殊检查点调用的一类函数。 钩子函数包括:

  • 对象钩子函数,在创建,删除,获取和放置等对象时调用。
  • 调度器钩子函数,在线程切换和空闲线程循环中调用。
  • 内存钩子函数,在分配或释放内存块时调用。
  • 定时器钩子函数,在定时器超时时调用。
posted @   yinsua  阅读(98)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
点击右上角即可分享
微信分享提示