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

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

3天内不再提示

RT-Thread启动进入就绪态最高优先级线程的全过程与栈帧分析(上)

冬至子 来源:lchnu 作者:lchnu 2023-11-08 12:47 次阅读

本文简单讨论RT-Thread在启动后,逐步进入到处于就绪态最高优先级main线程的全过程。部分内容涉及到汇编指令,但通俗易懂。通过简化工程,配合Debug过程,逐步观察寄存器的变化、绘制栈帧结构、绘制线程控制块和rt_interrupt_from_thread、rt_interrupt_to_thread等典型变量取值(指向,虽然是rt_uint32_t类型,但实际在汇编中是作为指针使用),能有效帮助理解RTOS的线程栈的恢复与启动过程。

通过本文对线程启动过程的了解,对于两个线程/多个线程之间的互相切换能奠定坚实的基础,化繁为简,结合论坛关于上下文切换的代码注释,能帮助快速抓住主线。

使用的软硬件环境如下:

IDE工具 - RT-Thread Studio 2.2.6
硬件 - STM32L431RCT6,Cortex M4内核
软件 - RT-Thread 4.0.5版本
配置 - 仅使能main线程和tidle0线程

一、工程设置

Step 1. 新建名称为EVBMX_RTThread405_Switch的4.0.5版本工程

1.jpg

Step 2. 不使能软件定时器,使能线程状态更改的调试

关闭软件定时器线程,避免干扰。

1.jpg

Step 3. 关闭msh shell,禁用Finsh

关闭tshell线程,避免干扰。仅仅保留main线程和tidle0线程。

1.jpg

Step 4. 修改main函数

修改main函数后,线程进入一次,休眠且切换1次,再次切回且return,然后彻底退出,只留下tidle0线程。

#include
#define DBG_TAG "main"
#define DBG_LVL DBG_LOG
#include
int main(void)
{
rt_thread_mdelay(1000);
return RT_EOK;
}

Step 5. 下载程序,观察输出结果

读完全文后,对下方输出结果的每一行语句所代表的含义和发生时刻,能有更深刻体会。

1.jpg

二、调试运行

Step 6. 在component.c中257行按F9设置断点;F5全速运行到此处后,再按F9关闭此处断点。

1.jpg

Step 7. 依次进入rt_thread_create, _thread_init, 停留在thread.c的164行。

将变量thread添加到表达式窗口,可以查看各个成员的值,其中,thread->stack_addr = 0x20001138, thread->stack_size = 0x800,分别表示栈底位置和栈空间大小。

164行的函数rt_hw_stack_init对于理解线程切换是一个相当重要的函数,其形参分别为:

线程入口函数:main_thread_entry

线程参数RT_NULL:

线程栈栈顶地址:thread->stack_addr + thread->stack_size - 4 = 0x20001138 + 0x800 - 4 = 0x20001934

1.jpg

Step 8. 单步进入到rt_hw_stack_init函数内部,开展分析

149行,由于传递进来的stack_addr = 0x20001934,执行完毕后,stk为0x20001938。从0x20001138(含)到0x20001934(含),合计是0x800 = 2048字节。STM32使用的满递减栈,所以此处的stk是0x20001938。

150行,此处设置8字节对齐。由于0x20001938 = (536877368)Decimal,该数据除8等于67109671,能被8整除,该语句执行栈对齐操作后,stk依然为0x20001938。

1.jpg

Step 9. 继续了解rt_hw_stack_init函数。

151行,更新stk的值,减去struct stack_frame结构体的大小。执行完毕后,stk = 0x200018F4。
153行,stack_frame指针指向0x200018F4。
156至159行,通过for循环将0x200018F4至0x20001938的所有内存变成0xdeadbeaf魔法字。
161行至168行,将stack_frame成员的exception_stack_frame中的r0~psr共8个寄存器分别设置为:线程参数,4个0,线程返回地址,线程入口地址,0x01000000。
175行,返回stk的值,此时变成0x200018F4。这个值在初始化线程时,将返回给thread->sp,即线程栈的临时栈顶指针。
依次将线程的形参、r1-r3, r12, 线程返回地址、线程入口地址,线程的xPSR写入异常栈帧结构中。
在初入门时,这里是难点。C语言中使用结构体定义的栈结构,如何和实际寄存器的顺序进行一一对应?,后文会通过逐步Debug揭示这个问题答案。

1.jpg

至此,main线程创建完毕后,线程结构体和线程栈空间如下所示。

1.jpg

Step 10. 继续单步到rt_system_scheduler_start函数处,并单独跟踪进入到该函数内部。

期间,RT-Thread会调用rt_thread_idle_init函数,在该函数中使用静态创建方式初始化tidle0线程。可以按照上述过程记录tidle0线程的栈空间。

1.jpg

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

    关注

    31

    文章

    5282

    浏览量

    119762
  • STM32
    +关注

    关注

    2264

    文章

    10852

    浏览量

    354164
  • C语言
    +关注

    关注

    180

    文章

    7589

    浏览量

    135767
  • Shell
    +关注

    关注

    1

    文章

    362

    浏览量

    23252
  • RT-Thread
    +关注

    关注

    31

    文章

    1257

    浏览量

    39811
收藏 人收藏

    评论

    相关推荐

    RT-Thread启动进入就绪最高优先级线程全过程分析(下)

    Step 11. 继续单步到rt_hw_context_switch_to函数处。
    的头像 发表于 11-08 12:53 1223次阅读
    <b class='flag-5'>RT-Thread</b><b class='flag-5'>启动</b><b class='flag-5'>进入</b><b class='flag-5'>就绪</b><b class='flag-5'>态</b><b class='flag-5'>最高</b><b class='flag-5'>优先级</b><b class='flag-5'>线程</b>的<b class='flag-5'>全过程</b>与<b class='flag-5'>栈</b><b class='flag-5'>帧</b><b class='flag-5'>分析</b>(下)

    灵动微课堂 (第135讲) | 基于MM32 MCU的OS移植与应用——RT-Thread 线程管理

    的属性,如线程控制块、线程、入口函数等。图 1 对象容器与线程对象线程的调度RT-Thread
    发表于 09-03 17:40

    什么是RT-Thread线程管理看完你就懂了

    ,每个线程都有重要的属性,如线程控制块、线程、入口函数等。RT-Thread线程调度器是抢
    发表于 03-29 06:16

    【每日一练】RT-Thread Nano-线程创建1(第五节学习视频)

    )A、256.0 B、32.32 C、512.0D、256.2562、rt_thread_create()函数有哪几个参数?请说明(问答)3、启动线程后,线程
    发表于 05-21 10:04

    RT-Thread基于优先级的全抢占式调度算法的实现

    thread2,当它们都进入就绪状态等待调度时,效果如下:此时问题来了,当任务们都进入就绪状态,挂载在这个
    发表于 04-20 14:17

    基于STM32L475VET5的RT-Thread线程管理学习

    调度。此状态在 RT-Thread 中的宏定义为 RT_THREAD_INIT。(2)就绪状态:在就绪状态下,线程按照
    发表于 04-22 15:00

    RT-Thread代码启动线程切换过程的实现

    就绪列表里面, 表示线程已经就绪,系统随时可以调度。2.1.1. 实现就绪列表就绪列表实际就是
    发表于 04-25 11:38

    RT-Thread嵌入式操作系统线程优先级该怎样去实现呢

    就绪列表RT-Thread 要支持多优先级,需要靠就绪列表的支持,从代码看,就绪列表由两个在
    发表于 05-09 14:32

    rt-thread优先级线程可以调度执行吗?

    请教下,在rt-thread中,如果低优先级线程中用while(1){}直接死循环,是不是高优先级线程也无法调度执行了?如果高
    发表于 05-13 10:51

    RT-Thread线程优先级链表与位图算法的介绍

    队列为当前系统最高优先级,则调用rt_list_insert_before(&(rt_thread_priority_table[thread
    发表于 05-13 15:38

    RT-Thread系统线程调度器的设计实现

    就将演变为在优先级数组中寻找具有最高优先级线程的非空链表。RT-Thread内核中采用了基于位图的优先级
    发表于 08-23 15:24

    RT-Thread实时操作系统中的五种状态之间是如何变换的

    线程由于申请一个资源(例如使用rt_sem_take),而可能进入挂起。又例如因为一个外部中断发生了,系统转入中断服务例程,在中断服务例程中释放了相应的资源,导致把等待在这个资源
    发表于 08-24 16:15

    RT-Thread线程管理手册指南

    _resume (rt_thread_t thread)使线程恢复运行详细描述线程管理接口RT-Thread操作系统是基于
    发表于 08-26 16:22

    RT-Thread实时系统的线程设计应该注意什么要点

    key线程来处理按键。线程的状态跃迁这里说的状态跃迁指的是线程运行中状态的变化,从就绪过渡到挂起
    发表于 09-14 15:45

    如何去处理RT-Thread线程优先级的问题呢

    RT-Thread优先级问题,官方文档互斥量一节,线程2的优先级线程1高,但在线程2runni
    发表于 12-05 11:51