注册 登录
电子工程世界-论坛 返回首页 EEWORLD首页 频道 EE大学堂 下载中心 Datasheet 专题
ID.LODA的个人空间 https://home.eeworld.com.cn/space-uid-499959.html [收藏] [复制] [分享] [RSS]
日志

RT-Thread系统内核简介

已有 752 次阅读2020-4-23 11:37 |个人分类:RT-Thread系统学习

内核基础

RT-Thread 内核架构图

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原创,如需转载或用于商业用途需征得作者同意并注明出处

本文来自论坛,点击查看完整帖子内容。

评论 (0 个评论)

facelist doodle 涂鸦板

您需要登录后才可以评论 登录 | 注册

热门文章