六 上下文切换

来源:互联网 发布:mysql 名字的格式 编辑:程序博客网 时间:2024/06/18 05:08

一   定义

当UCOS-III转向执行另一项新任务的时候,他保存了当前任务的CPU寄存器到堆栈,并从新任务的堆栈CPU寄存器载入CPU,这个过程叫做上下文切换

上下文切换需要一些开支,CPU的寄存器越多,开支越大。上下文切换的时间基本取决于有多少个CPU寄存器需要被存储和载入。

上下文切换的代码是移植UCOS -II 时编写的,该部分代码要适用于处理器,这些代码被放在C和汇编文件中:OS_CPU.H,OS_CPU_C.C,OS_CPU_A.ASM。移植部分在下面会详细介绍,根据不同的CPU架构,移植的时候需要注意很多不部分细节。

我们先来看一下常见CPU的结构:包含16个整数寄存器(R0~R15)和一个中断堆栈寄存器和状态寄存器。每个寄存器都是32位的,16个整数寄存器都是可以存储数据或者地址,指令指针寄存器是R15,两个堆栈指针是R14和R14‘,其实R14是指向任务的堆栈的指针TSP,R14’是指向ISR的堆栈的指针ISP。当CPU接收到一个中断的时候自动切换到ISR堆栈(也就是说CPU有独立用于处理中断的堆栈)

在uC/OS-III 中,任务切换时的堆栈设置类似于中断发生时的那样,所有的CPU 寄存器都被保存。我们假定任务堆栈中的信息将要被载入到CPU 中,TSP 指向任务堆栈中最后一个被保存的寄存器。程序指针寄存器和状态寄存器是最先被保存在任务堆栈中。事实上,当中断发生时这些是被CPU 自动执行的。其它的寄存器通过软件被压入任务堆栈
TSP 不会被保存到堆栈,但会被保存到任务的TCB。ISP 指向当前中断堆栈的顶部。当中断服务程序被执行时,处理器把R14"作为堆栈指针用于指向函数和局部参数。

有两种上下文切换的方式:一个是任务级的,一个是中断级的,任务级切换时通过OSCtxSW()实现的,实际上它是被OS_TASK_SW宏调用的中断级切换是通过调用OSIntCtxSw()实现。它是用汇编语言写的,保存于OS_CPU_A.ASM。

二  OSCtxSw()

OSCtxSw()实现上下文切换的相关步骤:


1)OSCtxSw()开始执行,保存状态寄存器和程序指针寄存器到当前的任务堆栈。保存的顺序与中断发生时CPU 保存寄存器的顺序相同。假定SR 先入栈,然后其它寄存器入栈。
2)当任务被停止时,OSCtxSw()保存CPU 的TSP 到该任务的OS_TCB 中,换句话说,OSTCBCurPtr->StkPtr=R14。
3)然后OSCtxSw()将新任务OS_TCB 的顶部地址存入CPU 的TSP 中。换句话说,R14=OSTCBCurPtr->StkPtr。
4)最后,OSCtxSw()将新任务堆栈中R13~~R0 关内容载入CPU寄存器。再然后(此时的会TSP 指向PC,如图),通过一个中断返回指令{比如汇编中的IRET},程序指针寄存器和状态寄存器被恢复到CPU 的寄存器中。

终上所述,其实就是对前一个任务在遇到比它优先级还高的任务的时候,CPU先停止其任务,并把它的TSP(就是R14里面的数据)保存到TCB中,然后再把新任务的TCB指针存入TSP。

三  OSIntCtxSw()

在ISR就绪了高优先级的任务B,ISR返回时将不会回到中前的任务A,而是去转向优先级更高的任务B,但是在此时,由于中断产生时,已经将任务A的状态保存到任务A堆栈中,所以ISR无需再保存任务A的状态,而是直接载入任务B的CPU寄存器到硬件CPU寄存器即可,调用OSIntCtxSw()执行该操作。


1)OSIntCtxSw()将新任务OS_TCB 的顶部堆栈地址值载入CPU 中的TSP。即R14=OSTCBHighRdyPtr->StkPtr。
2)然后OSIntCtxSw()将新堆栈的相关内容载入到CPU 寄存器中。通过一个中断返回指令,程序指针寄存器和状态寄存器被载入

中断级上下文切换和任务级上下文切换本质上是一致的,只不过中断级省掉了保存原来堆栈的步骤。

四  总结

上下文切换包括两个内容,保存就任务的内容,载入新任务的内容
任务级切换时,通过调用OSSched()实现的,中断级切换时,通过调用OSIntExit来实现的
OSSched()中调用OSCtxSw()实现上下文切换。OSIntExit()中调用OSIntCtxSw()实现上下文切换。然而,OSIntCtxSw()只需用做上下文切换的第二部分,因为中断时被中断任务的CPU 寄存器已经被保存到被中断任务的堆栈中了。