0518

OSIntCtxSw()

  1. 在µC/OS-II中,由于中断的产生可能会引起任务切换,在中断服务程序的最后会调用OSIntExit()函数检查任务就绪状态,如果需要进行任务切换,将调用OSIntCtxSw()。所以OSIntCtxSw()又称为中断级的任务切换函数。由于在调用OSIntCtxSw()之前已经发生了中断,OSIntCtxSw()将默认CPU寄存器已经保存在被中断任务的堆栈中了。  


  1. 程序清单L9.5给出的代码大部分与OSCtxSw()的代码相同,不同之处是,第一,由于中断已经发生,此处不需要再保存CPU寄存器(没有PUSHA, PUSH ES, 或PUSH DS);第二,OSIntCtxSw()需要调整堆栈指针,去掉堆栈中一些不需要的内容,以使堆栈中只包含任务的运行环境。图F9.5可以帮助读者理解这一过程。  
  2.   
  3. 程序清单L 9.5   OSIntCtxSw().  
  4. _OSIntCtxSw PROC   FAR  
  5. ;                ; Ignore calls to OSIntExit and OSIntCtxSw  
  6. ;   ADD  SP,8    ; (Uncomment if OS_CRITICAL_METHOD is 1, see OS_CPU.H) (1)  
  7.     ADD  SP,10   ; (Uncomment if OS_CRITICAL_METHOD is 2, see OS_CPU.H)  
  8. ;  
  9.     MOV  AX, SEG _OSTCBCur               ; 载入DS  
  10.     MOV  DS, AX                              
  11. ;  
  12.     LES  BX, DWORD PTR DS:_OSTCBCur      ; OSTCBCur->OSTCBStkPtr = SS:SP (2)  
  13.     MOV  ES:[BX+2], SS                      
  14.     MOV  ES:[BX+0], SP                     
  15. ;  
  16.     CALL FAR PTR _OSTaskSwHook  (3)  
  17. ;  
  18.     MOV  AX, WORD PTR DS:_OSTCBHighRdy+2 ; OSTCBCur = OSTCBHighRdy  (4)  
  19.     MOV  DX, WORD PTR DS:_OSTCBHighRdy     
  20.     MOV  WORD PTR DS:_OSTCBCur+2, AX        
  21.     MOV  WORD PTR DS:_OSTCBCur, DX          
  22. ;  
  23.     MOV  AL, BYTE PTR DS:_OSPrioHighRdy  ; OSPrioCur = OSPrioHighRdy    (5)  
  24.     MOV  BYTE PTR DS:_OSPrioCur, AL  
  25. ;  
  26.     LES  BX, DWORD PTR DS:_OSTCBHighRdy  ; SS:SP = OSTCBHighRdy->OSTCBStkPtr (6)  
  27.     MOV  SS, ES:[BX+2]               
  28.     MOV  SP, ES:[BX]                 
  29. ;  
  30.     POP  DS                              ; 载入新任务的CPU环境  (7)  
  31.     POP  ES                                 (8)  
  32.     POPA                                    (9)  
  33. ;  
  34.     IRET                                 ; 返回新任务    (10)  
  35. ;  
  36. _OSIntCtxSw ENDP  
  37.   
  38. <img src="https://img-blog.csdn.net/20170517091158576?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvRnVua3lGcm9nODIxOTUxMjU5/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" alt=""><pre code_snippet_id="2398550" snippet_file_name="blog_20170517_2_5958581" name="code" class="cpp">当中断发生后,CPU在完成当前指令后,进入中断处理过程。首先是保存现场,将返回地址压入当前任务堆栈,然后保存状态寄存器的内容。接下来CPU从中断向量处找到中断服务程序的入口地址,运行中断服务程序。在µC/OS-II中,要求用户的中断服务程序在开头保存CPU其他寄存器的内容[图F9.5(1)]。此后,用户必须调用OSIntEnter()或着把全局变量OSIntNesting加1。此时,被中断任务的堆栈中保存了任务的全部运行环境。在中断服务程序中,有可能引起任务就绪状态的改变而需要任务切换,例如调用了OSMboxPost(), OSQPostFront(),OSQPost(),或试图唤醒一个优先级更高的任务(调用OSTaskResume()),还可能调用 OSTimeTick(), OSTimeDlyResume()等等。  
  39. µC/OS-II要求用户在中断服务程序的末尾调用OSIntExit(),以检查任务就绪状态。在调用OSIntExit()后,返回地址会压入堆栈中[图F9.5(2)]。  
  40. 进入OSIntExit()后,由于要访问临界代码区,首先关闭中断。由于OS_ENTER_CRITICAL()可能有不同的操作(见9.03.02节),状态寄存器SW的内容有可能被压入堆栈[图F9.5(3)]。如果确实要进行任务切换,指针OSTCBHighRdy将指向新的就绪任务的OS_TCB,OSIntExit()会调用OSIntCtxSw()完成任务切换。注意,调用OSIntCtxSw()会在再一次在堆栈中保存返回地址[图F9.5(4)]。在进行任务切换的时候,我们希望堆栈中只保留一次中断发生的任务环境(如图F9.5(1)),而忽略掉由于函数嵌套调用而压入的一系列返回地址(图F9.5(2),(3),(4))。忽略的方法也很简单,只要把堆栈指针加一个固定的值就可以了[图F9.5(5)/程序清单L9.5(1)]。如果用方法2实现OS_ENTER_CRITICAL(),这个固定值是10;如果用方法1,则是8。实际操作中还与编译器以及编译模式有关。例如,有些编译器会为OSIntExit()在堆栈中分配临时变量,这都会影响具体占用堆栈的大小,这一点需要提醒用户注意。  
  41. 一但堆栈指针重新定位后,就被保存到将要被挂起的任务OS_TCB中[图F9.5(6)/程序清单L9.5(2)]。在µC/OS-II中(包括µC/OS),OSIntCtxSw()是唯一一个与编译器相关的函数,也是用户问的最多的。如果您的系统移植后运行一段时间后就会死机,就应该怀疑是OSIntCtxSw()中堆栈指针重新定位的问题。  
  42. 当当前任务的现场保存完毕后,用户定义的对外接口函数OSTaskSwHook()会被调用[程序清单L9.5(3)]。注意到OSTCBCur指向当前任务的OS_TCB,OSTCBHighRdy指向新任务的OS_TCB。在函数OSTaskSwHook()中用户可以访问这两个任务的OS_TCB。如果不用对外接口函数,请在头文件中关闭相应的开关选项,提高任务切换的速度。  
  43. 从对外接口函数OSTaskSwHook()返回后,由于任务的更替,变量OSTCBHighRdy被拷贝到OSTCBCur中[程序清单L9.5(4)],同样,OSPrioHighRdy被拷贝到OSPrioCur中[程序清单L9.5(5)]。此时,OSIntCtxSw()将载入新任务的CPU环境,首先从新任务OS_TCB中取出SS和SP寄存器的值[图F9.5(7)/程序清单L9.5(6)],然后运行POP DS [图F9.5(8)/程序清单L9.5(7)], POP ES [图F9.5(9)/程序清单L9.5(8)], POPA[图F9.5(10)/程序清单L9.5(9)]取出其他寄存器的值,最后用中断返回指令IRET [图F9.5(11)/程序清单L9.5(10)]完成任务切换。  
  44. 需要注意的是在运行OSIntCtxSw()和用户定义的OSTaskSwHook()函数期间,中断是禁止的。</pre><br>  
  45. 图F 9.5 中断级任务切换时的80x86堆栈结构  
  46. <pre></pre>  
  47. <br>

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值