uCOS中任务调度时的上下文切换

这里以STM32处理器为例,也就是Cortex-M3内核。

所谓的上下文切换呢,就是当 uC/OS转向执行另一个任务的时候,它保存了当前任务的CPU 寄存器到堆栈。并从新任务的的堆栈中 CPU 寄存器载入 CPU。

在这里上下文切换分为两种:一个是任务级的,一个是中断级的。

(1) 开始执行切换,保存状态寄存器和程序指针寄存器到当前的任务堆栈。保存的顺序与中断发生时 CPU 保存寄存器的顺序相同。假定 SR 先入栈,然后其它寄存器入栈。

(2) 当任务被停止时,保存 CPU 的 TSP 到该任务的OS_TCB 中,换句话说,OSTCBCurPtr->StkPtr=R14。

(3) 然后将新任务 OS_TCB 的顶部地址存入 CPU 的TSP 中。换句话说,R14=OSTCBCurPtr->StkPtr。

(4) 最后, 将新任务堆栈中 R13~~R0 关内容载入 CPU寄存器。再然后(此时的会 TSP 指向 PC,如图),通过一个中断返回指令{比如汇编中的 IRET},程序指针寄存器和状态寄存器被恢复到 CPU 的寄存器中。

以上是一个大概的流程分析,下面来看看其具体的代码实现过程,当然,这里是用汇编来实现。

PendSV_Handler

CPSID   I                                                   ; Prevent interruption during context switch关所以中断

MRS     R0, PSP                                             ; PSP is process stack pointer  PSP是当前进程堆栈的指针,将PSP赋值给R0

CBZ     R0, PendSV_Handler_Nosave                     ; Skip register save the first time如果R0为0时跳转到PendSV_Handler_Nosave

SUBS    R0, R0, #0x20                                       ; Save remaining regs r4-11 on process stack偏移0x20的位置用来保存R4至R11

STM     R0, {R4-R11} ;将剩下的R4至R11寄存器保存在此进程的堆栈中

LDR     R1, =p_OSTCBCur                                     ; OSTCBCur->OSTCBStkPtr = SP; 即OSTCBCur->OSTCBStkPtr这个保存当前的栈尾,以便下次弹出

LDR     R1, [R1]

STR     R0, [R1]                                            ; R0 is SP of process being switched out

; At this point, entire context of process has been saved此时,整个上下文的过程已经被保存

PendSV_Handler_Nosave

PUSH    {R14}                                               ; Save LR exc_return value

LDR     R0, =OSTaskSwHook                                   ; OSTaskSwHook();  这里的话可以删除的,用于用户扩展呵呵

BLX     R0

POP     {R14}

LDR     R0, =OSPrioCur                                      ; OSPrioCur = OSPrioHighRdy;

LDR     R1, =OSPrioHighRdy ;将当前优先级变量指向最高优先级

LDRB    R2, [R1]

STRB    R2, [R0]

LDR     R0, =p_OSTCBCur                                     ; OSTCBCur  = OSTCBHighRdy;

LDR     R1, =p_OSTCBHighRdy ;TCB表也一样

LDR     R2, [R1]

STR     R2, [R0]

;到这里,[R2]保存的是新的进程的堆栈指针SP

LDR     R0, [R2]                                            ; R0 is new process SP; SP = OSTCBHighRdy->OSTCBStkPtr;  将堆栈指针赋值给SP

LDM     R0, {R4-R11}                                        ; Restore r4-11 from new process stack 弹出其它寄存器,和前面的是一个逆过程

ADDS    R0, R0, #0x20 ;和前面的逆过程对比可知

MSR     PSP, R0                                             ; Load PSP with new process SP将R0中的SP赋值给PSP寄存器

ORR     LR, LR, #0x04                                       ; Ensure exception return uses process stack确保异常返回时使用进程堆栈

CPSIE   I ;开中断

BX      LR                                                  ; Exception return will restore remaining context异常返回将恢复那些自动出栈的剩余寄存器

晕,排版有点乱,勉强凑合着看吧。。。

可以看出这其实是一个PendSV中断来的,也就是M3的可编程挂起中断,为什么用这个中断来进行上下文切换呢?后面将会进行说明下。

CBZ     R0, PendSV_Handler_Nosave

这句是用来判断是否第一次进入切换,也就是系统刚启动的时候,则直接跳到PendSV_Handler_Nosave这个标号来执行了,因为系统刚启动还没有当前任务嘛。

当不是刚启动的,进行上下文切换,首先是要将当前任务的寄存器保存下来,保存到当前任务的堆栈里,R4-R11手动保存到堆栈,其余会自动保存。

然后

LDR     R0, =OSPrioCur                                      ; OSPrioCur = OSPrioHighRdy;

LDR     R1, =OSPrioHighRdy ;将当前优先级变量指向最高优先级

LDRB    R2, [R1]

STRB    R2, [R0]

LDR     R0, =p_OSTCBCur                                     ; OSTCBCur  = OSTCBHighRdy;

LDR     R1, =p_OSTCBHighRdy ;TCB表也一样

LDR     R2, [R1]

STR     R2, [R0]

这里是将优先级最高的,也就是需要切换到的那个任务替换为当前任务。

然后让PSP指向任务堆栈,再然后是一个逆过程,弹出堆栈里的数据到对应的寄存器。

上下文切换就差不多这样。。。

关于在M3内核,为什么使用PendSV这个中断来进行上下文切换呢?其原因是这个中断拥有最低优先级的软件中断。

又问,为什么要在拥有最低优先级的软件中断中进行切换呢?这个答案在《Cortex-M3权威指南》第7章 异常   里有详细的答案。

uCOS中任务调度时的上下文切换相关推荐

  1. 参考任哲的《嵌入式实时操作系统μC_OS-II原理及应用》,对UCOS的任务调度做了下整理。

    参考任哲的< 嵌入式 实时操作系统μC_OS-II原理及应用>,对 UCOS 的任务调度做了下整理. UCOS有两种调度器,一种是任务级的调度器,一种是中断级的调度器.任务级的调度器由OS ...

  2. ucos中的三种临界区管理机制

    熟悉ucos,或者读过Jean.J.Labrosse写过的ucos书籍的人,一定会知道ucos中著名的临界去管理宏:OS_ENTER_CRITICAL()和OS_EXIT_CRITICAL(). 同样 ...

  3. 操作系统中任务调度的实现

    操作系统中任务调度的实现   作者:谢煜波 Email : xieyubo@126.com QQ : 13916830 2004-5-31 简 介 说起任务调度,我想我们大家都非常熟悉,任何一本操作系 ...

  4. ucos 中的 OS_PRIO_SELF

    今天在看ucosii 中关于删除任务的函数 OSTaskDel 时看到 if (prio == OS_PRIO_SELF) {                                 /* S ...

  5. 关于ucos中os_tmr.c中的代码分析

    我本身也是个初学者,喜欢嵌入式而自学ucos系统,ucos是个开源的代码,短小而又简单,这是我学习的笔记,希望能对喜欢ucos的人有一点帮助,因本人也是初学者,如有错误迎指点.一般的书多是2.5版本, ...

  6. 我在React Native中构建时获得的经验教训

    by Amanda Bullington 通过阿曼达·布林顿(Amanda Bullington) 我在React Native中构建时获得的经验教训 (Lessons I learned while ...

  7. 从前台页面取参数到sql的like中比较时参数的预处理

    //从前台页面取参数到sql的like中比较时参数的预处理 this.keytxt.Text.Trim().Replace("'", "''").Replace ...

  8. MySQL中查询时对字母大小写的区分

    我相信很多人在mysql中查询时都遇到过mysql不区分字母大小写的情况:如以下例子: 1.SELECT * FROM `user` WHERE userpass = 'Z20'; 结果为: 2.SE ...

  9. universal image loader在listview/gridview中滚动时重复加载图片的问题及解决方法

    universal image loader在listview/gridview中滚动时重复加载图片的问题及解决方法 参考文章: (1)universal image loader在listview/ ...

最新文章

  1. 智源青年科学家梁云:异构系统中张量计算的自动调度和优化框架
  2. Oracle 11G R2 RAC中的scan ip 的用途和基本原理【转】
  3. Docker容器私有仓库——Harbor私有仓库的搭建
  4. Python教程:import 、from import 及from import *
  5. 十五天精通WCF——第十一天 如何对wcf进行全程监控
  6. Foursquare引爆了什么
  7. oracle分组后伪列,Oracle伪列和伪表和分组函数(row_number,Rank)
  8. SQL Server 高可用方案
  9. ERROR in static/js/vendor.js from UglifyJs UUnexpected token: name (Dom7)
  10. 修改看板视图默认显示个数
  11. qt checkbox 选中事件_Qt学习笔记3(布局管理)
  12. d语言 c++ 混合编程,C++,D语言,Python语言一次模拟合作开发
  13. 源头防堵信息泄露 监管拟全面推行支付标记化
  14. 《嵌入式系统Linux内核开发实战指南(ARM平台)》书评
  15. 如何在Mac电脑上自定义Spotlight的搜索结果?
  16. vector容器v1、v2之间相互赋值的三种方法及易错点详解
  17. python 汉诺塔问题_Python汉诺塔问题
  18. android自定义dialog大小,android – 自定义对话框大小匹配Theme.Holo.Light.Dialog
  19. ftm国际化解决方案
  20. 微信小程序之CSS实现图片遮罩

热门文章

  1. 【Round #36 (Div. 2 only) B】Safe Spots
  2. flex 结合sandy引擎创作
  3. Tomcat容器、JSP和Servlet
  4. 那些年我在CSDN追过的安全白帽师傅,respect
  5. Java+MyEclipse+Tomcat (一)配置过程及jsp网站开发入门
  6. Git 仓库设置记住密码
  7. 763. Partition Labels 划分字母区间
  8. 337. House Robber III 打家劫舍 III
  9. 中国大学MOOC 人工智能导论第五章测试
  10. 数据库开发——MySQL——基本操作