|
RT-Thread 内核架构图
从上图可以看到,RT-Thread实时内核的实现包括:对象管理、线程管理及调度器、线程间通信管理、时钟管理及内存管理等等,内核最小的资源占用情况是 3KB ROM,1.2KB RAM
一般执行顺序是:系统先从启动文件开始运行,然后进入 RT-Thread 的启动 rtthread_startup() ,最后进入用户入口 main(),如下图所示:
rtthread_startup() 函数的代码如下所示:
// components.c
int rtthread_startup(void)
{
rt_hw_interrupt_disable();
/* 板级初始化:需在该函数内部进行系统堆的初始化 */
rt_hw_board_init();
/* 打印 RT-Thread 版本信息 */
rt_show_version();
/* 定时器初始化 */
rt_system_timer_init();
/* 调度器初始化 */
rt_system_scheduler_init();
#ifdef RT_USING_SIGNALS
/* 信号初始化 */
rt_system_signal_init();
#endif
/* 由此创建一个用户 main 线程 */
rt_application_init();
/* 定时器线程初始化 */
rt_system_timer_thread_init();
/* 空闲线程初始化 */
rt_thread_idle_init();
/* 启动调度器 */
rt_system_scheduler_start();
/* 不会执行至此 */
return 0;
}
这部分启动代码,大致可以分为四个部分:
(1)初始化与系统相关的硬件;
(2)初始化系统内核对象,例如定时器、调度器、信号;
(3)创建 main 线程,在 main 线程中对各类模块依次进行初始化;
(4)初始化定时器线程、空闲线程,并启动调度器。
自动初始化机制是指初始化函数不需要被显式调用,只需要在函数定义处通过宏定义的方式进行申明,就会在系统启动过程中被执行。
用来实现自动初始化功能的宏接口定义详细描述如下表所示:
初始化顺序 | 宏接口 | 描述 |
---|---|---|
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 应用 |
系统中总共存在两类线程,分别是系统线程和用户线程。
线程管理是通过结构体struct rt_thread ,包含了优先级、线程名称、线程状态等信息
线程具有独立的线程栈,当进行线程切换时,会将当前线程的上下文存在栈中,当线程要恢复运行时,再从栈中读取上下文信息,进行恢复。
线程状态分:初始,就绪,运行,挂起,关闭
系统线程:空闲线程和主线程
涉及到的主要函数如下
// thread.c
rt_thread_t rt_thread_create(const char *name,
void (*entry)(void *parameter),
void *parameter,
rt_uint32_t stack_size,
rt_uint8_t priority,
rt_uint32_t tick);
rt_err_t rt_thread_init(struct rt_thread *thread,
const char *name,
void (*entry)(void *parameter),
void *parameter,
void *stack_start,
rt_uint32_t stack_size,
rt_uint8_t priority,
rt_uint32_t tick);
rt_err_t rt_thread_delete(rt_thread_t thread);
rt_err_t rt_thread_startup(rt_thread_t thread);
rt_err_t rt_thread_detach(rt_thread_t thread);
rt_thread_t rt_thread_self(void);
/**
* This function will let current thread yield processor, and scheduler will
* choose a highest thread to run. After yield processor, the current thread
* is still in READY state.
*
* @return RT_EOK
*/
rt_err_t rt_thread_yield(void);
rt_err_t rt_thread_sleep(rt_tick_t tick);
rt_err_t rt_thread_delay(rt_tick_t tick);
rt_err_t rt_thread_mdelay(rt_int32_t ms);
rt_err_t rt_thread_control(rt_thread_t thread, int cmd, void *arg);
rt_err_t rt_thread_suspend(rt_thread_t thread);
rt_err_t rt_thread_resume(rt_thread_t thread);
时钟节拍和定时器
线程的延时、线程的时间片轮转调度以及定时器超时等离不开时钟节拍,是系统运行的心跳
定时器分HARD_TIMER 模式与 SOFT_TIMER 模式,机制分单次触发和周期触发两种
定时器链表 rt_timer_list。系统新创建并激活的定时器都会按照以超时时间排序(Skip List算法)的方式插入到 rt_timer_list 链表中。
设计到主要函数
void rt_timer_init(rt_timer_t timer,
const char *name,
void (*timeout)(void *parameter),
void *parameter,
rt_tick_t time,
rt_uint8_t flag);
rt_err_t rt_timer_detach(rt_timer_t timer);
rt_timer_t rt_timer_create(const char *name,
void (*timeout)(void *parameter),
void *parameter,
rt_tick_t time,
rt_uint8_t flag);
rt_err_t rt_timer_delete(rt_timer_t timer);
rt_err_t rt_timer_start(rt_timer_t timer);
rt_err_t rt_timer_stop(rt_timer_t timer);
rt_err_t rt_timer_control(rt_timer_t timer, int cmd, void *arg);
信号量,互斥量和事件集三种方式
信号量:二值,多值,优先级反转,生产者和消费者问题
互斥量:优先级继承算法解决优先级反转的问题,其他和二值信号量类似
事件集:一对多,多对多的同步
涉及到函数实现
邮箱,消息队列,信号
邮箱:开销比较低,效率较高。每封邮件容纳固定四字节内容,一般用于传递数据指针
消息队列:邮箱的扩展,用于线程间的消息交换、使用串口接收不定长数据等。先进先出。
信号:软中断,用来通知线程发生了异步事件,用做线程之间的异常通知、应急处理
涉及到的函数实现
总体上可分为两类:内存堆管理与内存池管理,而内存堆管理又根据具体内存设备划分为三种情况:
第一种是针对小内存块的分配管理(小内存管理算法,一般小于2MB);
第二种是针对大内存块的分配管理(slab 管理算法);
第三种是针对多内存堆的分配情况(memheap 管理算法)
涉及到的函数实现
rt_err_t rt_memheap_init(struct rt_memheap *memheap,
const char *name,
void *start_addr,
rt_size_t size);
rt_err_t rt_memheap_detach(struct rt_memheap *heap);
内存池,采用链表串联的结构,提高效率和减少碎片。
涉及到的函数实现
RT-Thread内核相关的一些机制和Free RTOS,uCos都有相似之处,也加入了一些特有的机制,比如内核的一些算法,启动流程+自动初始化机制,内存优化算法等,为用户提供了更便捷的服务,让用户更放心的专注应用的开发,简化了流程。
此内容由EEWORLD论坛网友ID.LODA原创,如需转载或用于商业用途需征得作者同意并注明出处