ucos 任务调度与中断的关系

转载自:http://blog.csdn.net/alliswall1/article/details/49701905

在ucos的中断函数中是每次写中断函数都需要OSIntEnter()和OSIntExit() 用来判断中断嵌套层数和进行任务调度,有些情况是这样的,例如有的书上的程序中有RTC中断服务函数,但是并没有调用操作系统的进入中断服务函数OSIntEnter()和退出中断服务函数OSIntExit(),

  解释是因为在RTC中断服务函数中没有调用任何操作系统的服务函数(如发送信号量之类的函数),故不需要操作系统干预  

 下面就上述解释,以源码为依据进行阐述个人理解
void OSIntEnter (void)
{
if (OSRunning == OS_TRUE) 
{

if (OSIntNesting < 255u)

{

OSIntNesting++;//对OSIntNesting变量进行了加1操作

}

}
}

注释部分代码对全局变量OSIntNesting进行了加1操作

    INT8U OSSemPost (OS_EVENT *pevent)
    {
    #if OS_CRITICAL_METHOD == 3 
        OS_CPU_SR cpu_sr = 0;
    #endif



    #if OS_ARG_CHK_EN > 0
        if (pevent == (OS_EVENT *)0) { 
            return (OS_ERR_PEVENT_NULL);
        }
    #endif
        if (pevent->OSEventType != OS_EVENT_TYPE_SEM) { 
            return (OS_ERR_EVENT_TYPE);
        }
        OS_ENTER_CRITICAL();
        if (pevent->OSEventGrp != 0) { 
            (void)OS_EventTaskRdy(pevent, (void *)0, OS_STAT_SEM); 
            OS_EXIT_CRITICAL();
            OS_Sched(); //进行了调度
            return (OS_NO_ERR);
        }
        if (pevent->OSEventCnt < 65535u) { 
            pevent->OSEventCnt++; 
            OS_EXIT_CRITICAL();
            return (OS_NO_ERR);
        }
        OS_EXIT_CRITICAL(); 
        return (OS_SEM_OVF);
    }

而OSSempost函数而言,对照其源码发现,当有任务对OSSempost()的event进行等待,则会使高优先级的任务处于就绪状态,并调用OSSched()对任务进行调度,如上边代码的注释部分

    void  OS_Sched (void)  
    {  
    #if OS_CRITICAL_METHOD == 3                           
        OS_CPU_SR  cpu_sr;  
    #endif      
        INT8U      y;                                     


        OS_ENTER_CRITICAL();                               

        if ((OSIntNesting == 0) && (OSLockNesting == 0)) {   
            //如果没有任何中断嵌套,且调度允许的,则任务调度函数将找出进入就绪态的  
            //最高优先级任务,进入就绪态的任务在就绪表中OSRdyTbl[]中相应位置位。  
            y             = OSUnMapTbl[OSRdyGrp];                    */  
            OSPrioHighRdy = (INT8U)((y << 3) + OSUnMapTbl[OSRdyTbl[y]]);  

            if (OSPrioHighRdy != OSPrioCur) {             
                       OSTCBHighRdy = OSTCBPrioTbl[OSPrioHighRdy];  
                OSCtxSwCtr++;                                
                OS_TASK_SW();                               
            }  
        }  
        OS_EXIT_CRITICAL();                              
    }  

对照源码注释部分可见,如果OS_Sched()函数不是中断服务程序中调用并且调度是允许的,才会使高优先级的任务就绪, 用OS_TASK_SW();完成恢复高优先级任务的运行,假设调用OSSempos()的函数是在中断中的话,由于OSIntEnter (void)函数对OSIntNesting进行加1操作,这里就不会进行任务切换

那问题就来了,必须有个函数能够实现在中断结束后任务切换的功能呀!!!!!!!

下面分析OSIntExit()函数

void OSIntExit (void)

{

#if OS_CRITICAL_METHOD == 3;

OS_CPU_SR  cpu_sr;

#endif

if (OSRunning == TRUE) {

OS_ENTER_CRITICAL();

if (OSIntNesting > 0){

OSIntNesting--;

}

if ((OSIntNesting == 0) &&(OSLockNesting == 0)) {

OSIntExitY    = OSUnMapTbl[OSRdyGrp];

OSPrioHighRdy = (INT8U)((OSIntExitY<< 3) +  UnMapTbl[OSRdyTbl[OSIntExitY]]);

if (OSPrioHighRdy != OSPrioCur){

OSTCBHighRdy  = OSTCBPrioTbl[OSPrioHighRdy];

              OSCtxSwCtr++;

                     OSIntCtxSw(); //调用任务切换函数                            

              }

}

        OS_EXIT_CRITICAL();

}

}

注释部分函数代码调用OSIntCtxSw()实现中断任务切换的问题,也解决了上面提出的疑问

对于文章首部分提出的问题,如果中断中没有调用操作系统服务函数(如发送信号量之类的函数),中断应该直接返回被中断的任务代码,而不应该是就绪的最高优先级的任务。


void  OSIntEnter (void)
{
    if (OSRunning == OS_TRUE) {
        if (OSIntNesting < 255u) {
            OSIntNesting++;                      /* Increment ISR nesting level                        */
        }
    }
}

这个函数执行使变量OSIntNesting自增1,是有作用的。
比如你错误的在中断中调用了OSFlagPend函数,如果这个变量不为0,那么说明此时是在中断里面,
直接返回OS_ERR_PEND_ISR,否则有可能引起程序卡在中断里出不来,因为PEND会导致挂起,一直等待!

void  OSIntExit (void)
{
#if OS_CRITICAL_METHOD == 3                                /* Allocate storage for CPU status register */
    OS_CPU_SR  cpu_sr = 0;
#endif



    if (OSRunning == OS_TRUE) {
        OS_ENTER_CRITICAL();
        if (OSIntNesting > 0) {                            /* Prevent OSIntNesting from wrapping       */
            OSIntNesting--;
        }
        if (OSIntNesting == 0) {                           /* Reschedule only if all ISRs complete ... */
            if (OSLockNesting == 0) {                      /* ... and not locked.                      */
                OS_SchedNew();
                if (OSPrioHighRdy != OSPrioCur) {          /* No Ctx Sw if current task is highest rdy */
                    OSTCBHighRdy  = OSTCBPrioTbl[OSPrioHighRdy];
#if OS_TASK_PROFILE_EN > 0
                    OSTCBHighRdy->OSTCBCtxSwCtr++;         /* Inc. # of context switches to this task  */
#endif
                    OSCtxSwCtr++;                          /* Keep track of the number of ctx switches */
                    OSIntCtxSw();                          /* Perform interrupt level ctx switch       */
                }
            }
        }
        OS_EXIT_CRITICAL();
    }

这个函数会判断此OSIntNesting是否已经为0,如果为0,会发生任务调度,如果不为0,那么退出一层中断,
主要是用于在多个中断嵌套的时候防止中断还没结束,就执行任务调度!!

猜你喜欢

转载自blog.csdn.net/jrc_january/article/details/78726032