搜索
bottom↓
回复: 12

关于ucos2.86运行在cortex-M3上出现bug的原因分析

[复制链接]

出0入0汤圆

发表于 2015-10-31 17:30:22 | 显示全部楼层 |阅读模式
本帖最后由 Eric_Xue 于 2015-10-31 17:48 编辑

ucos2.86在cortex-M3出现的bug,具体现象,可参考下面的链接。
ucos中的这个问题(BUG),
[url]http://blog.csdn.net/sunlei_telchina/article/details/6205515


2.88修正了bug,下面列出2.88和2.86的不同点。
2.86中的代码是这样的:
     if (OSLockNesting == 0) {                      /* ... scheduler is not locked                  */
            OS_SchedNew();
            if (OSPrioHighRdy != OSPrioCur) {          /* No Ctx Sw if current task is highest rdy     */
                OSTCBHighRdy = OSTCBPrioTbl[OSPrioHighRdy];
                OSCtxSwCtr++;                          /* Increment context switch counter             */
                OS_TASK_SW();                          /* Perform a context switch                     */
            }
2.88中的代码是这样的:   
    if (OSLockNesting == 0u) {                     /* ... scheduler is not locked                  */
            OS_SchedNew();
            OSTCBHighRdy = OSTCBPrioTbl[OSPrioHighRdy];
            if (OSPrioHighRdy != OSPrioCur) {          /* No Ctx Sw if current task is highest rdy     */
                OSCtxSwCtr++;                          /* Increment context switch counter             */
                OS_TASK_SW();                          /* Perform a context switch                     */
            }
        }
---------------------------------------------------------
原文是这样的

OS_CORE.C:

OSIntExit() and OS_Sched() have changed slightly because of a boundary condition found with the Cortex-M3 port. Specifically, we needed to move the statement:

OSTCBHighRdy = OSTCBPrioTbl[OSPrioHighRdy];

Before testing for the priority.

-----------------------------------------------
下面开始分析原因          xcj 2015/10/31 15:52

假设有两个任务程序 A 和 B,任务A的优先级比任务B的优先级要高。

正在运行的任务A执行了一个OSTimeDly(1)来延时,OSTimeDly(1)调用OS_Sched()
            
       OS_ENTER_CRITICAL();
        if (OSIntNesting == 0u) {                       
             if (OSLockNesting == 0u) {   
              OS_SchedNew();                   // <----执行完该语句后,OSPrioHighRdy = B,
            if (OSPrioHighRdy != OSPrioCur)   //<------由于OSPrioCur =A,与OSPrioHighRdy不相等
             {
                    OSTCBHighRdy = OSTCBPrioTbl[OSPrioHighRdy]; //<----所以,OSTcbHighRdy = B
                    OSCtxSwCtr++;
                    OS_TASK_SW();  //<-- 在Cortex-M3上会触发一个PendSV,在PendSV中执行任务切换。
            }                                   //<----由于中断关闭,所以必须等中断打开才能
        }                                      //<---假设刚好运行到此处发生SysTick中断,但是由于前面已经关闭中断了,所以不会响应SysTick中断。
      }                                       // <------此时,有两个中断在排队了,SysTick中断和PendSV,假设SysTick中断的优先级比PendSV的高。
      OS_ENTER_CRITICAL();  // <------一旦执行了该行,意味着立马进入SysTick中断。
   
     记住此时:OSPrioCur          = A ,   OSTCBCur         = A
                        OSPrioHighRdy = B,   OSTCBHighRdy = B


在SysTick中会发现任务A的延时到期了。任务A又会进入就绪表,所以在OSIntExit()调用OS_Sched()时
     
  OS_ENTER_CRITICAL();
        if (OSIntNesting == 0u) {                       
             if (OSLockNesting == 0u) {   
             OS_SchedNew();                    <---由于任务A延时到了,所以OSPrioHighRdy = A,
            if (OSPrioHighRdy != OSPrioCur)   <-----而此时OSPrioCur =A,与OSPrioHighRdy相等所以不会执行下面括号里的语句。
             {
                    OSTCBHighRdy = OSTCBPrioTbl[OSPrioHighRdy];
                    OSCtxSwCtr++;
                    OSIntCtxSw();  <-- 该句子不执行,不触发PendSV。
            }      <----此时,OSTCBHighRdy =B                        
        }                                    
      }                                      
      OS_ENTER_CRITICAL();   <-----从SysTick退出后,会立马进入PendSV中断(由A.OSTimeDly(1)触发的)
注意此时:
                     OSPrioCur          = A,   OSTCBCur         = A
                       OSPrioHighRdy = A,   OSTCBHighRdy = B


在PendSV的程序中,只执行任务切换

    OSPrioCur  <= OSPrioHighRdy;
    OSTCBCur <= OSTCBHighRdy;
   任务寄存器出栈。
跑到任务程序里面发现:
          OSPrioCur = A,  OSTCBCur =B;

也就是说虽然当前运行的实际任务是B,但是当前的优先级却是A。这也就是是为什么最后程序运行到一个低级的程序出不来。高级的程序无法运行的原因。

同样的情况也可能发生在下面这种情况:
(1)正在运行的A调用系统函数SemPend(),semPend()执行完后会OSPrioHighRdy = B, OSTCBHighRdy = B。
(2) 在SemPend()中执行OSched()中过程中发生了外部中断。OSChed()运行完立即进去外部中断程序(而不是PendSV程序)。
(3)而在外部中断中调用了SemPost(),又让A就绪了。执行外部中断的SemPost的OSChed()中会让OSPrioRdy = A,OSTCBHighRdy = B(因为OSPrioHighRdy≠OSPrioCur不成立)
(4)从外部中断后退出,直接进入PendSV中断,PendSV中断直接将 OSPrioCur  <= OSPrioHighRdy;    OSTCBCur <= OSTCBHighRdy;
(5) PendSV返回后,实际运行的任务堆栈OSTCBCur =B,而其优先级OSPrioCur =A(任务B占着A的优先级)。

这样任务A永远无法运行(即使任务B延迟自己)。只能让更低优先级任务B运行。

  把程序修改一下,使OSTCBHighRdy与OSPrioHighRdy同步更新。就不会出现上述的bug。这里就留给坛友去分析了。

  if (OSLockNesting == 0u) {                     /* ... scheduler is not locked                  */
            OS_SchedNew();
            OSTCBHighRdy = OSTCBPrioTbl[OSPrioHighRdy];
            if (OSPrioHighRdy != OSPrioCur) {          /* No Ctx Sw if current task is highest rdy     */
                OSCtxSwCtr++;                          /* Increment context switch counter             */
                OS_TASK_SW();                          /* Perform a context switch                     */
            }
        }

如果我有分析错误的地方,还请坛友指正。


阿莫论坛20周年了!感谢大家的支持与爱护!!

如果想吃一顿饺子,就得从冰箱里取出肉,剁馅儿,倒面粉、揉面、醒面,擀成皮儿,下锅……
一整个繁琐流程,就是为了出锅时那一嘴滚烫流油的热饺子。

如果这个过程,禁不住饿,零食下肚了,饺子出锅时也就不香了……《非诚勿扰3》

出0入0汤圆

发表于 2015-10-31 19:51:48 | 显示全部楼层
学习一下。。。UCOS!

出0入13汤圆

发表于 2015-11-1 07:12:44 来自手机 | 显示全部楼层
分析的很详细,不错

出0入0汤圆

 楼主| 发表于 2015-11-2 09:01:57 | 显示全部楼层
原文中链接出错,再次发下链接。
ucoii 低版本错误
http://blog.csdn.net/sunlei_telchina/article/details/6205515

出0入211汤圆

发表于 2015-11-2 11:31:37 | 显示全部楼层
楼主分析得非常到位,去年年中,我也是被这个问题折腾得不轻!

出0入0汤圆

发表于 2016-1-25 12:15:44 | 显示全部楼层
学习咯~~~~

出0入0汤圆

发表于 2016-1-25 17:16:57 | 显示全部楼层
顶一下!!!!!!!!!!!!

出100入101汤圆

发表于 2016-6-2 16:42:05 | 显示全部楼层
LZ分析很到位

出0入0汤圆

发表于 2016-6-2 17:12:30 | 显示全部楼层

顶一下!!!!!!!!!!!!

出870入263汤圆

发表于 2016-6-2 23:14:15 | 显示全部楼层
虽然是个老帖子了,但是回味起来依然精彩!顶一下!

出0入4汤圆

发表于 2017-4-24 22:49:58 | 显示全部楼层
分析透彻

出0入0汤圆

发表于 2019-7-5 17:28:10 | 显示全部楼层
真不错  感谢 感谢~~~~~~~~~~~

出0入0汤圆

发表于 2019-7-12 21:29:45 | 显示全部楼层
This is great.
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-3-28 23:03

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

快速回复 返回顶部 返回列表