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

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

3天内不再提示

揭秘RTOS任务入口函数执行完之后去哪里了

strongerHuang 来源:Mculover666 作者:mculover666 2021-11-05 14:20 次阅读

1. 说明

在工作过程中,我发现在实际使用RTOS完成项目时,理解这些知识仅能达到会用RTOS的水平,要想用好RTOS,还需要了解一些比较细节的机制,否则容易掉坑进去,花大量时间定位问题。

本文结合TencentOS-Tiny实时操作系统给大家讲述一下相关内容。

2. 任务的通常写法

遵循“不使用就让出”的原则,任务通常有两种写法。

「阻塞等待」某个事件处理,等待到之后处理:

voidtask1_entry(void*arg)
{
//init...

while(1){
//1.waitsomekernelobject...
//eg.tos_sem_pend,tos_mutex_pend,tos_event_pend.

//2.waitsuccess,handle!
}
}

这种写法中,在没有事件发生的时候,任务会因为等待某个内核对象而被挂起,让出CPU不参与调度。

② 定时执行

voidtask1_entry(void*arg)
{
//init...

while(1){
//1.dosomething...

//2.sleep!
//eg.tos_task_delay,tos_sleep_ms.
}
}

这种写法中,任务在干完活之后,会主动进入睡眠状态,让出CPU不参与调度。

3. 一次性任务

上面两种写法的共性是都有主循环,不需要考虑任务入口函数退出的情况,但在一些场景中任务只需要执行一次即可:

voidtask1_entry(void*arg)
{
//init...

//dosomething...

//exit?
}

「这个时候就要思考一个问题:任务入口函数执行完毕之后去了哪里?」

4. 寻找答案

首先,「任务入口函数本质上是一个函数」,跳转函数的指令是BL,CPU在执行该指令跳转到某个函数执行时,会将当前PC地址作为函数返回地址、加载到LR寄存器中、保证函数执行完可以返回到这儿继续执行,再将函数地址加载到PC寄存器、程序接着执行就到了函数中。

6cdb8e6e-3dfd-11ec-82a9-dac502259ad0.png

那么,任务入口函数没有被别的函数主动调用,是如何被拉起来执行的呢?

任务切换分为两步:保存上文、切换下文。切换下文就是指将保存在任务栈中的CPU寄存器组的值、加载到CPU中。

「所以,当任务栈中初始保存的CPU寄存器组的值中、PC寄存器值为该任务的任务入口函数地址时,切换下文加载之后,由于PC指向任务入口函数,所以CPU接着运行就到了任务入口函数中,也就是该任务在运行。」

同样的道理,「任务栈中初始保存的CPU寄存器组的值中、LR寄存器的值决定了、任务入口函数退出时候返回到哪里。」

由于不同CPU架构的CPU寄存器组不同,所以初始化任务栈的代码与架构强相关,在arch目录下都有不同架构对应的实现。

这里我们以ARM Cortex-M4为例(Arm-v7m)看看代码如何实现:

6d302d48-3dfd-11ec-82a9-dac502259ad0.png

从代码里可以看到,TencentOS-Tiny默认退出函数为exit参数指定的值,接下来我们看看退出函数~

5. 任务退出函数

在创建任务的API tos_task_create 中,初始化任务栈的过程中会指定退出函数为 task_exit

task->sp=cpu_task_stk_init((void*)entry,arg,(void*)task_exit,stk_base,stk_size);

task_exit 函数主要完成销毁自身的工作,具体实现如下:

__STATIC__voidtask_exit(void)
{
tos_task_destroy(K_NULL);
}

该销毁函数传入的参数为NULL表示销毁自身,如果是静态任务则按以下步骤销毁(动态任务销毁值得用一篇文章去讲述):

  • 将任务从就绪列表移除
  • 将任务从等待列表移除
  • 将任务从统计列表移除
  • 任务状态置为K_TASK_STATE_DELETED

6. 总结

本文讲述了任务的两种常规写法,以及任务函数执行完毕之后去了哪里?

当任务函数执行完毕退出时,会执行到哪里由任务栈初始化时LR寄存器的值决定,RTOS内核都会提供一个默认退出函数,TencentOS-Tiny提供的任务退出函数中,会自动销毁任务自身。

所以在编写一次性任务时,就不需要主动调用销毁API销毁自身啦~

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

    关注

    31

    文章

    5336

    浏览量

    120252
  • API
    API
    +关注

    关注

    2

    文章

    1499

    浏览量

    61971
  • 函数
    +关注

    关注

    3

    文章

    4329

    浏览量

    62576
  • RTOS
    +关注

    关注

    22

    文章

    811

    浏览量

    119599

原文标题:RTOS 任务入口函数执行完之后去哪里了?

文章出处:【微信号:strongerHuang,微信公众号:strongerHuang】欢迎添加关注!文章转载请注明出处。

收藏 人收藏

    评论

    相关推荐

    如何获取入口函数不是__iar_program_start的Program entry的stack使用情况

    问题 IAR中默认的入口函数是__iar_program_start,使能stack usage analysis之后: 生成的map文件中STACK USAGE章节里面会包含Program
    的头像 发表于 11-25 16:23 165次阅读
    如何获取<b class='flag-5'>入口</b><b class='flag-5'>函数</b>不是__iar_program_start的Program entry的stack使用情况

    MaXim96717 VPG功能启用之后去哪里查看图像

    MaXim96717 VPG功能启用之后去哪里查看图像
    发表于 11-01 10:42

    freertos和rtos区别是什么

    (Real-Time Operating System,实时操作系统)是一种特殊的操作系统,它能够为实时任务提供确定性的响应时间。RTOS 通常用于嵌入式系统,如工业自动化、汽车电子、医疗设备等领域
    的头像 发表于 09-02 14:18 1191次阅读

    SPI数据速率影响定时器中断,问题出在哪里

    就会发送到 RTOS 队列。 此时会执行一个任务,在该任务中会执行一个记录到终端的日志函数。 现
    发表于 07-23 07:07

    请问从哪里获得ESP8266 RTOS SDK的SPI驱动程序?

    我计划将ESP8266用作SPI从设备,它可以根据功能从某些SPI主设备进行操作。我已经检查 NON OS SDK 中有 SPI 驱动程序ESP8266但 RTOS SDK ESP8266没有任何源。 那么,有没有人知道我可以从哪里
    发表于 07-12 07:28

    请问CMSIS-RTOS RTX的任务调度锁在哪里

    请问一下,CMSIS-RTOS RTX的任务调度锁在哪里?谢谢!
    发表于 05-13 08:28

    RTOS+LwIP Socket不工作的原因?

    本人用RTOS创建了五个任务, 如下: /* RTOS任务创建调度机制 */ osThreadDef(TCPSOCKETSERVER, TCP_Socket_Server
    发表于 04-30 07:20

    STM8S003中主函数执行while(1)自动跳出循环是怎么回事?

    ();/*LCD显示*/ } } 在上面这段主函数的代码中,如果不加看门狗IWDG_FEED,程序执行while(1)后就会自动跳出,为什么会非要加看门狗才不会跳出while(1)?不应该是不加IWDG_F
    发表于 04-18 07:52

    显示接收消息一定要等所有消息全部发送才显示如何解决?

    ; /****************************任务句柄**********************/ /* *任务句柄是一个指针,用于指向一个任务,当任务创建
    发表于 04-16 06:13

    鸿蒙TypeScript入门学习第8天:【TypeScript 函数

    函数是一组一起执行一个任务的语句。 您可以把代码划分到不同的函数中。如何划分代码到不同的函数中是由您来决定的,但在逻辑上,划分通常是根
    的头像 发表于 04-03 14:54 419次阅读
    鸿蒙TypeScript入门学习第8天:【TypeScript <b class='flag-5'>函数</b>】

    基于RTOS的应用进程中的典型线程

    RTOS中的关键因素是最小的中断延迟和最小的线程切换延迟。RTOS的价值在于它的响应速度或可预测性,而不是它在给定时间段内可以执行的工作量。
    发表于 03-05 09:32 597次阅读
    基于<b class='flag-5'>RTOS</b>的应用进程中的典型线程

    请问RTOS USBSetuPcb回调函数是在中断还是单独线程中处理的?

    UART 通信)和异步 USB Setup 请求回调处理程序函数之间的 Uart 访问之间存在竞争条件。 -> 在执行主循环UART功能的同时,正在执行USB消息处理UART功能。 要
    发表于 02-23 06:10

    verilog中函数任务对比

    在verilog中,函数任务均用来描述共同的代码段,并且在模式内任意位置被调用,提高代码效率,让代码更加的直观,提高代码可读性。但是在实际使用的过程中,函数任务也存在诸多的不同,下
    的头像 发表于 02-12 18:43 883次阅读

    GD32 MCU是如何进入中断函数

    用过GD32 MCU的小伙伴们都知道,程序是顺序执行的,但当有中断来的时候程序会跳转到中断函数执行中断函数后程序又继续回到原来的位置继续
    的头像 发表于 01-30 09:45 1074次阅读
    GD32 MCU是如何进入中断<b class='flag-5'>函数</b>的

    GD32 MCU启动后如何运行到main函数

    GD32 MCU启动后如何运行到main函数入口?你是否也有这样的疑虑。在执行到main函数之前MCU干了哪些事情呢?下面为大家解答。
    的头像 发表于 01-15 10:00 1077次阅读
    GD32 MCU启动后如何运行到main<b class='flag-5'>函数</b>