UCOS---上下文切换(Context Switching)

当 UCOS 决定运行另一个任务时,则需要保存当前任务的上下文,其中主要包括 CPU 相关寄存器,以及当前的任务的栈,并恢复新任务的上下文和重新开始执行任务。这个过程称为上下文切换。

上下文切换增加了内存开销。CPU 的寄存器越多,内存开销越大。执行上下文切换的时间也主要是 CPU 寄存器的保存与恢复。

本文我们主要借助于一个虚构的 CPU 来讨论上下文切换的一般过程。此虚构 CPU 包含 16 个整数寄存器 (R0 - R15),一个独立的 ISR 栈指针、一个独立的状态寄存器。每个寄存器均为 32 位,并且每个寄存器都能存储地址或数据。程序计数器(指令指针寄存器)是 R15,且有两个独立的栈指针 R14 和 R14',其中 R14 表示任务栈指针(task stack pointer TSP),R14' 表示 ISR 栈指针(ISR stack pointer ISP)。当响应一个中断时,CPU 自动切换到 ISP。注意在 ISR 中是可以访问任务栈的(例如:在 ISR 中可以先任务栈中 push 和 pop 元素),中断栈也是可以从任务中访问的。

虚构 CPU

在 UCOS 中,栈的当前帧总是看起像中断刚刚发生的,处理器所有的寄存器都保存于此。任务一旦创建就处于继续状态,显然当前任务的上下文是有软件进行预初始化的。

任务栈指针指向存在任务栈中的最后一个寄存器。PC(program counter) 指针 和 SR(status register)最早保存到栈中的。实际上,在响应中断处理程序时, CPU 自动保存 PC 和 SR 到任务栈中,然后在中断处理程序中保存剩余的寄存器。需要注意的是, SP(stack pointer 或
R14)实际并不是保存在任务栈中,而是保存在任务的 TCB 中。

中断栈指针指向的中断栈的栈顶,是一个不同于任务栈的内存区域。当一个 ISR 执行时,处理器用 R14' 作为 ISR 调用的函数栈。

一个就绪任务的CPU寄存器的入栈顺序

UCOS 中一共存在两种类型的上下文切换:一是从任务中切换,二是从 ISR 中切换。任务级别切换是通过 OSCtxSw() 实现,其实际上是通过调用宏函数 OS_TASK_SW() 完成。ISR上下文切换是 OSIntCtxSw() 实现,此函数是汇编函数,在 os_cpu_a.asm 中。

1 OSCtxSw()

在任务级调度(OSSched())时 OSCtxSw() 将被调用用于切换当前任务到一个高优先级的任务。下图是调用 OSCtxSw() 之前 UCOS 的变量和数据结构状态。

OSCtxSw() 调用之前

(1) OSTCBCurPtr 指针指向当前正在执行的任务,且此任务调用 OSSched()。
(2)OSSched() 找到即将运行的新任务,并将 OSTCBHighRdyPtr 指向其 OS_TCB。
(3)OSTCBHighRdyPtr->StkPtr 指针指向新任务的任务栈
(4)当 UCOS 创建或挂起一个任务时,总是会保留中断发生时的这个栈帧,多有的 CPU 寄存器保存于此,这保留了任务重新开始执行时应有状态。
(5)OSSChed() 调用后,TSP 所指向的位置,依赖于如何调用 OSCtxSw() ,TSP 可以指向 OSCtxSw() 的返回地址。

下图表达了 UCOS 调用 OSCtxSw() 执行任务上下文切换的过程。

OSCtxSw()上下文切换过程

(1)OSCtxSw() 首先保存当前任务的 SR 和 PC 到任务栈中,保存顺序依赖于 CPU 在中断发生时对于栈帧的要求。这里,假设先保存 SR,再保存 PC,然后保存剩余寄存器。
(2)OSCtxSw() 保存寄存器栈指针到 TCB 的 StkPtr 中,开始上下文切换。简言之, OSTCBCurPtr->StkPtr = R14。
(3)OSCtxSw() 然后加载待执行任务的任务栈指针到 R14 中,即 R14 = OSTCBHighRdyPtr->StkPtr。
(4)最后, OSCtxSw() 恢复 CPU 的寄存器为新任务栈中的寄存器帧。SR 和 PC 通常时 CPU 在退出 ISR 时自动完成加载。

2 OSIntCtxSw()

OSIntCtxSw()(参见 os_cpu_a.asm)在 ISR 级别的调度函数 OSIntExit() 中调用,用于切换到一个高优先级的就绪任务。下图是说明了 OSIntCtxSw() 调用前 UCOS 的变量和结构的状态。

调用 OSIntCtxSw() 之前的就内存状态

图中假设 UCOS 在 ISR开始时已经保存好了 CPU 寄存器(中断管理中将会详述)。由于这个原因,注意到 OSTCBCurPtr->StkPtr 的值是一个正在被挂起的任务任务栈指针(图中左边)。OSIntCtxSw() 不用承担保存被挂起任务(当前任务)的 CPU 寄存器的工作,因为这个已经在中断管理部分完成。

下图表示了 OSIntCtxSw() 完成一半的上下文切换,其工作正好是 OSCtxSw() 的一半。

OSIntCtxSw() 执行的工作

(1)OSIntCtxSw() 加载 CPU SP 寄存器为新任务的任务栈顶,即 R14=OSTCBHighRdyPtr->StkPtr。
(2)OSIntCtxSw() 然后恢复 CPU 寄存器的值。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值