1. 程式人生 > >ucos 任務排程與中斷的關係

ucos 任務排程與中斷的關係

在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,那麼退出一層中斷,
主要是用於在多箇中斷巢狀的時候防止中斷還沒結束,就執行任務排程!!