μC/OS-II 要点分析 ------ PendSV_Handler

2023-05-16

首先贴出今天要与大家分享的内容源码(位于内核源码的 os_cpu_a.asm 中):

PendSV_Handler
  CPSID I
  MRS R0, PSP
  CBZ R0, PendSV_Handler_Nosave

  SUBS R0, R0, #0x20
  STM R0, {R4-R11}

  LDR R1, =OSTCBCur
  LDR R1, [R1]
  STR R0, [R1]

PendSV_Handler_Nosave
  PUSH {R14}
  LDR R0, =OSTaskSwHook
  BLX R0
  POP {R14}

  LDR R0, =OSPrioCur
  LDR R1, =OSPrioHighRdy
  LDRB R2, [R1]
  STRB R2, [R0]

  LDR R0, =OSTCBCur
  LDR R1, =OSTCBHighRdy
  LDR R2, [R1]
  STR R2, [R0]

  LDR R0, [R2]
  LDM R0, {R4-R11}
  ADDS R0, R0, #0x20
  MSR PSP, R0
  ORR LR, LR, #0x04
  CPSIE I
  BX LR

这两段代码尤为重要,内核中任务的切换主要就是由它们实现的。接下来,我将逐行为大家解析其中的奥秘。

这两段代码是中断服务程序(ISR),那么由谁来触发中断呢?我们以OSCtxSw()这个函数为入手点。
它其实就是C程序中的OS_TASK_SW()

#define OS_TASK_SW() OSCtxSw()

开始分析OSCtxSw()

OSCtxSw
  PUSH {R4, R5}
  LDR R4, =NVIC_INT_CTRL
  LDR R5, =NVIC_PENDSVSET
  STR R5, [R4]
  POP {R4, R5}
  BX LR

1.首先进入函数,将R4,R5入栈,保护寄存器。
2.给R4,R5分别赋值,文件中这样定义:
NVIC_INT_CTRL EQU 0xE000ED04
NVIC_PENDSVSET EQU 0x10000000
NVIC_INT_CTRL为中断控制寄存器的地址,NVIC_PENDSVSET为PendSV中断的触发值
3.将触发值写入控制寄存器
4.弹出R4,R5


因为我们一般调用任务切换的时候,都是在临界区调用(禁止中断),所以不会产生中断。之后调用OS_EXIT_CRITICAL()函数退出临界区后,中断才会发生,这样就产生了PendSV异常。

接下来才是我们的重点,开始分析ISR!

CPSID I
#关中断,防止切换任务期间被打扰

MRS R0, PSP
#取出PSP(程序栈指针)赋值给R0

CBZ R0, PendSV_Handler_Nosave
#若R0为0,则跳转到PendSV_Handler_Nosave函数继续执行,这里我们讲述的就是由延时导致的任务切换,PSP都是有值的,所以继续执行

SUBS R0, R0, #0x20
#将R0 - 0x20 则R0与PSP之间空出8个单位(每个单位4个字节)

STM R0, {R4-R11}
#将寄存器的R4-R11存入空出的8个单位

LDR R1, =OSTCBCur
#将当前TCB的地址赋给R1

LDR R1, [R1]
#取出地址处的数据(即OSTCBCur->SP的地址,因为OSTCB结构体的第一个数据就是SP)赋给R1

STR R0, [R1]
#将R0(栈顶数据的地址)赋值给OSTCBCur->SP,则OSTCBCur->SP与R0指向的位置相同

 

!!这段程序的OSTCBCur指的都是old_task的指针

这段程序的图解:

 

 

PUSH {R14}
LDR R0, =OSTaskSwHook
BLX R0
POP {R14}
#这小段代码就是执行OSTaskSwHook这个C的函数

LDR R0, =OSPrioCur
LDR R1, =OSPrioHighRdy
LDRB R2, [R1]
STRB R2, [R0]
#这小段代码就将OSPrioHighRdy赋给OSPrioCur

LDR R0, =OSTCBCur
LDR R1, =OSTCBHighRdy
LDR R2, [R1]
STR R2, [R0]
#这小段代码就将OSTCBHighRdy->SP赋给OSPrioCur->SP

LDR R0, [R2]
#将OSTCBHighRdy->SP的值(指向新任务栈中的地址,也就是新任务的栈顶)赋值给R0

LDM R0, {R4-R11}
#以R0为基址,读出8个单位的数据给CPU的寄存器

ADDS R0, R0, #0x20
#R0地址 + 0x20,指向几个重要的寄存器值(当前栈顶)

MSR PSP, R0
#将当前R0的值赋值给PSP

ORR LR, LR, #0x04
#确保异常返回后,新任务使用PSP指针

CPSIE I
#开启中断

 

!!这段程序的OSTCBCur指的都是new_task的指针

这段程序的图解:

 

这样也就完成了old_task到new_task的切换!

转载于:https://www.cnblogs.com/GyForever1004/p/8318860.html

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

μC/OS-II 要点分析 ------ PendSV_Handler 的相关文章

  • Android 处理程序更改 WeakReference

    我的静态处理程序有一个WeakReference to my Activity 这是为了防止有据可查的内存泄漏问题 我发布了一条长时间延迟的消息 我希望将此消息传递到我的活动 应该位于前台 我担心的是 在方向改变时 我的活动被销毁 并且处理
  • C++ 未处理的异常

    如果发生未处理的异常 C 是否提供了一种 显示 可视化内容的方法 我想做的是做一些像assert unhandled exception msg 如果它确实发生 如下面的示例所示 include
  • 检测 Paypal 订阅取消

    我编写了一个简单的贝宝订阅系统 用户可以在其中输入他们的信息 单击按钮 然后开始订阅 我想知道如何知道用户何时取消订阅 我已经看到 txn type subscr cancel 但我不知道如何使用它 因为 paypal 不会再次调用我的处理
  • 如何使用netty在单独的线程池中执行业务逻辑处理程序

    我有一个需要执行一些业务逻辑的处理程序 我希望它在单独的线程池中执行 以免阻塞 io 事件循环 我已将 DefaultEventExecutorGroup 添加到管道中 如中指定的http netty io 4 0 api io netty
  • postDelayed是否会导致消息跳到队列的前面?

    我在 Android 文档中查找 postDelayed发布延迟的文档 这与另一个问题类似 https stackoverflow com questions 25820528 is postdelayed relative to when
  • Python,日志记录:使用带有字典配置的自定义处理程序?

    这是关于 Python 3 2 GNU Linux x86 64 上的日志记录模块 是否可以使用字典配置设置自定义处理程序 这是我正在尝试的代码 import logging import logging config class Cust
  • MySQL 事务难题

    我需要在单个原子事务中执行多次插入 例如 开始交易 插入 插入 commit 然而 当 MySQL 遇到错误时 它只会中止导致错误的特定语句 例如 如果第二个插入语句中有错误 提交仍然会发生 并且第一个插入语句将被记录 因此 当发生错误时
  • Web API - 405 - 请求的资源不支持 http 方法“PUT”

    我有一个 Web API 项目 但无法对其启用 PUT Patch 请求 我从 fiddler 得到的回应是 HTTP 1 1 405 Method Not Allowed Cache Control no cache Pragma no
  • Android 2.1:单个 Activity 中的多个处理程序

    我有不止一个Handlers在活动中 我在中创建所有处理程序onCreate 的主要活动 我的理解是handleMessage 每个处理程序的方法永远不会同时被调用 因为所有消息都放在同一个队列 Activity 线程 MessageQue
  • 处理程序与线程

    我想知道一次 我读过很多地方 当我想做一些 长时间操作 时 我应该使用Handler 但我不明白为什么 我所有的 长时间操作 都用常规线程包围 并且工作正常 我为什么要使用Handler为了这 我唯一需要使用的时间Handler是 当我必须
  • 如何在 python 中创建非 root 记录器

    我正在尝试使用logging getLogger child 在子python模块中创建一个非根记录器 但我收到错误 找不到记录器 child 的处理程序 我正在尝试将父模块日志记录到父日志文件中 父模块将创建子模块的实例 我希望子模块写入
  • IIS 7.5 无法打开处理程序映射?

    我需要更新 IIS 7 5 上的处理程序映射 以允许将没有扩展名的 URL 路由到应用程序 该应用程序最初是用 ASP NET 2 0 编写的 但后来升级到 ASP NET 3 5 我不知道这是否相关 但我之前更新其他 net 3 5 应用
  • Android - 延迟加载图像

    我正在尝试伪造某种进度条 我有 X 张图片并想要一张ImageView以一定的延迟向他们展示 我尝试过做这样的事情 for i 2 i
  • 如何处理android中的睡眠模式进入?

    我在任何地方都没有找到它 我该如何处理在android中进入睡眠模式 当Android设备进入睡眠模式时我想做什么 这是可能的还是有办法处理它 只需使用 BroadCastReceivers 进行系统调用 唤醒 睡眠 即可实现此目的 And
  • Android 中稳定、准确的计时

    我正在尝试为 Android 设备创建一个音乐音序器应用程序 并且希望获得一些有关如何实现坚如磐石的计时功能的建议 如果我将 Runnable 传递给 Handler postDelayed 并指定 x 毫秒的延迟时间 那么该 Runnab
  • 找不到记录器的处理程序

    我是Python新手 我正在尝试登录 python 我遇到了找不到记录器的处理程序尝试通过记录器实例打印一些警告时出错 下面是我尝试过的代码 import logging logger logging getLogger logger lo
  • 为什么要使用 Handlers 而 runOnUiThread 会做同样的事情?

    我都遇到过Handlers http developer android com reference android os Handler html and 在UiThread上运行 http developer android com r
  • Python 日志记录:为什么 __init__ 被调用两次?

    我正在尝试将 python 日志记录与配置文件和自己的处理程序一起使用 这在某种程度上是有效的 真正让我困惑的是 init 被叫两次并且 del 被调用一次 当我删除整个配置文件内容并直接在代码中创建处理程序时 init 被调用一次并且 d
  • Chrome 84+:网站想要打开此应用程序:处理程序

    我进行了以下修复 每次都在 Chrome 中打开所需的应用程序而无需确认 他们工作得很好 直到更新版本 84 0 4147 89 官方版本 64 位 Fix 1 In C Users
  • Asp.NET 处理程序和通用处理程序

    在 Visual Studio 2010 中 当您说 new Item 时 您可以看到 Asp NET Handler 和 Generic Handler 你能告诉我有什么区别吗 我认为它是随 NET 4 0 一起提供的 因为我在 Goog

随机推荐