0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

rt-thread 优化系列(六)启动流程重构

出出 来源:出出 作者:出出 2022-07-04 15:30 次阅读

前言

去年此时,笔者刚接触 rt-thread 的时候,被它的初始化过程深深折服了。第一次打开一个 rt-thread 的项目,竟然没找到多线程在哪儿初始化的,"main" 函数里没有!
进而发现,"main" 函数不是我们认识的 "main" 函数了。在 rt-thread 里,程序进入 "main" 函数之前还有很长一段路。

目前的初始化流程

见下图吧,一些主要的过程已经被列出来了。

poYBAGLCkJ2AZU2kAADj4Zq8UMY084.png

从图中可以看出来:
1. 任务调度器启动前,有很多的初始化工作。
2. `rt_components_board_init` 里还有很多隐含的外设初始化操作。这个时候没有进入多线程环境。
3. 先创建了三个默认线程(如果启用了软定时器),但并未立马运行,任务调度器启动后从中选择优先级最高的那个运行(可能是 "main" 可能是 "timer")。
4. "main" 线程启动后,还有很多初始化工作,这个时候已经进入多线程环境。

这个流程存在的问题:
1. 堆申请被设计成多线程安全访问,内部有加锁动作,而锁也是限于在线程上下文使用的。串口驱动申请缓存内存却是在任务调度器启动前!
2. 开启 ulog 后,也有可能出现在任务调度器启动之先使用锁的现象。
3. 还有线程安全版 `rt_kprintf` ,这个也是考虑只在线程上下文使用,如果开启了它,任务调度器启动前的 `rt_kprintf` 需求被忽略了。

`rt_components_board_init` `rt_components_init` 两个函数可能有很多隐含操作。但是因为 `rt_components_board_init` 处于非多任务环境中,它比 `rt_components_init` 更容易出问题。

例如,不能使用加锁操作、不能使用 `rt_thread_mdelay` `rt_thread_delay` 等延时操作。

在之前的一篇文章里,[rt-thread 驱动篇(六)serialX弊端及解决方法]( http://www.elecfans.com/d/1850548.html ) 比较全面的梳理了一下串口终端设备怎么用中断发送模式。首先,任务调度器启动前是不会有中断的,用中断发送,可能不会输出数据,如果是阻塞模式,可能会永久卡死到这里;如果是非阻塞模式,可能有很多信息被扔掉。

**所以,任务调度器启动前,串口终端输出要么用轮询输出,要么给个很大的输出缓存**,至于多大合适,这个谁也说不好。

还有一个折中的方法是降低任务调度器启动前的打印输出需求。怎么降低?调整初始化流程,先启动一个无依赖的 idle 线程,把其它操作放到线程中。

新初始化流程设想

poYBAGLCkOyALohXAAC7C3LqP2U345.png

这样一来,初始化注册外设设备的过程也是在线程上下文环境了,这个时候想用加锁操作也可以,申请堆内存也不会出现 `Function[rt_sem_take] shall not be used before scheduler start`

如果不开启 RT_DEBUG,堆、pin、UART、控制台初始化部分也可以放到 idle 线程里。一年前,笔者在 rt-thread 论坛上提出过这个设想——[
rt-thread 系统启动及 SysTick 初始化流程优化可行性分析]( https://club.rt-thread.org/ask/article/ab1c5556dd9f186a.html )。
稍作修改,如下:
1. 配置系统时钟,同时配置 SysTick(同前);
2. 初始化 rtt 系统调度器,定时器链表等全局变量;
3. 创建 idle 线程;
4. 启动 idle 线程并启动 rtt 系统调度;
5. 由 idle 线程启用 SysTick 中断;
6. 由 idle 线程初始化调试串口;
7. 由 idle 线程初始化内存堆;
8. 由 idle 线程调用执行 rt_components_board_init 初始化板级外设配置;
9. 由 idle 线程创建 main 和 soft timer 线程。
10. main 线程进行组件初始化配置,以及创建其它应用线程。

和上面链接里提到的流程,修改了开启 systick 中断节点。
同时如果放弃在初始化配置系统时钟时调试输出信息的想法,放弃创建 idle 线程过程中调试输出错误信息的想法,放弃启动系统任务调度器过程调试输出错误信息的想法后,控制台输出信息也就全处于线程上下文了。

最起码,我们有以下几点收获:
1. 任务调度器启动前,不需要开全局中断。
2. 申请堆内存的操作都可以是在线程上下文。
3. 控制台串口输出数据可以使用中断或者 DMA 任意模式。

缺点:idle 线程栈可能比之前要大一些。而且,这些内存只有一次使用机会,切换到 “main” 线程后多了些“闲置”内存。

实践验证

目前,笔者在自己的项目上,使用 NUC970 系列芯片,验证了上述想法,目前系统启动过程未发现出现异常。

结束语

很多问题是时序的原因,打乱了某件东西本该有的操作 [#5584]( https://github.com/RT-Thread/rt-thread/issues/5584 )。
对系统启动流程做些修改,我们发现很多概念可以理直气壮的讲出来,比如,锁只能在线程上下文使用。当我们通过补丁的方式,使得在任务调度器启动前进行了锁操作而不出异常,那么这样就让人迷惑了。

审核编辑:汤梓红
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 启动流程
    +关注

    关注

    0

    文章

    14

    浏览量

    6463
  • RT-Thread
    +关注

    关注

    31

    文章

    1266

    浏览量

    39864
  • main
    +关注

    关注

    0

    文章

    38

    浏览量

    6130
收藏 人收藏

    评论

    相关推荐

    RT-Thread记录(三、RT-Thread线程操作函数)

    讲完了RT-Thread开发环境,启动流程启动以后当然是开始跑线程了,那么自然我们得学会如何创建线程以及线程的有关操作。
    的头像 发表于 06-20 00:31 6635次阅读
    <b class='flag-5'>RT-Thread</b>记录(三、<b class='flag-5'>RT-Thread</b>线程操作函数)

    RT-Thread记录(二、RT-Thread内核启动流程

    在前面我们RT-Thread Studio工程基础之上讲一讲RT-Thread内核启动流程.
    的头像 发表于 06-20 00:30 4941次阅读
    <b class='flag-5'>RT-Thread</b>记录(二、<b class='flag-5'>RT-Thread</b>内核<b class='flag-5'>启动</b><b class='flag-5'>流程</b>)

    【原创精选】RT-Thread征文精选技术文章合集

    漂移问题分析rt-thread 优化系列(四)信号对 ipc 的影响rt-thread 优化系列
    发表于 07-26 14:56

    RT-Thread快速入门之了解内核启动流程

    1、了解RT-Thread内核的启动流程  内核是操作系统最基础也是最重要的部分。从本文开始进入 RT-Thread 内核相关知识的学习。  首先了解内核的基础知识,对
    发表于 09-05 17:01

    RT-Thread编程指南

    RT-Thread编程指南——RT-Thread开发组(2015-03-31)。RT-Thread做为国内有较大影响力的开源实时操作系统,本文是RT-Thread实时操作系统的编程指南
    发表于 11-26 16:06 0次下载

    RT-Thread用户手册

    RT-Thread用户手册——本书是RT-Thread的编程手册,用于指导在RT-Thread实时操作系统环境下如何进行编 程。
    发表于 11-26 16:16 0次下载

    RT-Thread全球技术大会:Kconfig在RT-Thread中的工作机制

    RT-Thread全球技术大会:Kconfig在RT-Thread中的工作机制               审核编辑:彭静
    的头像 发表于 05-27 14:49 1494次阅读
    <b class='flag-5'>RT-Thread</b>全球技术大会:Kconfig在<b class='flag-5'>RT-Thread</b>中的工作机制

    RT-Thread全球技术大会:RT-Thread测试用例集合案例

    RT-Thread全球技术大会:RT-Thread测试用例集合案例           审核编辑:彭静
    的头像 发表于 05-27 16:34 2052次阅读
    <b class='flag-5'>RT-Thread</b>全球技术大会:<b class='flag-5'>RT-Thread</b>测试用例集合案例

    RT-Thread学习笔记 RT-Thread的架构概述

    RT-Thread 简介 作为一名 RTOS 的初学者,也许你对 RT-Thread 还比较陌生。然而,随着你的深入接触,你会逐渐发现 RT-Thread 的魅力和它相较于其他同类型 RTOS
    的头像 发表于 07-09 11:27 4469次阅读
    <b class='flag-5'>RT-Thread</b>学习笔记 <b class='flag-5'>RT-Thread</b>的架构概述

    RT-Thread文档_RT-Thread 简介

    RT-Thread文档_RT-Thread 简介
    发表于 02-22 18:22 5次下载
    <b class='flag-5'>RT-Thread</b>文档_<b class='flag-5'>RT-Thread</b> 简介

    RT-Thread文档_RT-Thread 潘多拉 STM32L475 上手指南

    RT-Thread文档_RT-Thread 潘多拉 STM32L475 上手指南
    发表于 02-22 18:23 9次下载
    <b class='flag-5'>RT-Thread</b>文档_<b class='flag-5'>RT-Thread</b> 潘多拉 STM32L475 上手指南

    RT-Thread文档_RT-Thread SMP 介绍与移植

    RT-Thread文档_RT-Thread SMP 介绍与移植
    发表于 02-22 18:31 9次下载
    <b class='flag-5'>RT-Thread</b>文档_<b class='flag-5'>RT-Thread</b> SMP 介绍与移植

    基于RT-Thread Studio学习

    前期准备:从官网下载 RT-Thread Studio,弄个账号登陆,开启rt-thread学习之旅。
    的头像 发表于 05-15 11:00 3786次阅读
    基于<b class='flag-5'>RT-Thread</b> Studio学习

    RT-Thread启动流程RT-Thread如何支持不同开发板?

    一个开发板上的RT-Thread启动流程可能是首先从bsp​当中链接脚本指定的startup_xxx.S​中的入口函数(ENTRY)或者复位异常处理函数(ResetHandler)开始运行,这部分我们在讲​bsp​支持时会详细
    的头像 发表于 08-10 15:29 1472次阅读
    <b class='flag-5'>RT-Thread</b><b class='flag-5'>启动</b><b class='flag-5'>流程</b>?<b class='flag-5'>RT-Thread</b>如何支持不同开发板?

    RT-Thread v5.0.2 发布

    RT-Thread 代码仓库地址: ●  https://github.com/RT-Thread/rt-thread RT-Thread 5.0.2 版本发布日志详情: ●  htt
    的头像 发表于 10-10 18:45 1372次阅读
    <b class='flag-5'>RT-Thread</b> v5.0.2 发布