uC/OS-II源碼解析(os_mutex.c)

/*
** ver   : 2.52
** file  : os_mutex.c
** brief : 互斥型信號量相關函數 C 文件
**
** mutex : 互斥型信號量
** PIP   : 優先級繼承優先級
*/

#ifndef  OS_MASTER_FILE
#include "includes.h"                   /* 包含頭文件    */
#endif

/*
******************************************************************************
*                                            邏輯常量
******************************************************************************
*/

#define  OS_MUTEX_KEEP_LOWER_8   0x00FF /* 低八位 : 標註mutex是否有效    */
#define  OS_MUTEX_KEEP_UPPER_8   0xFF00 /* 高八位 : 記錄優先級繼承優先級 */

#define  OS_MUTEX_AVAILABLE      0x00FF /* mutex有效                     */


#if OS_MUTEX_EN > 0
/*
*******************************************************************************
*                                  無等待的獲取mutex
*
* brief  : 該函數用於無等待的請求mutex.
*
* pevent : 指向事件控制塊的指針
*
* err    : 指向錯誤代碼的指針,可能取值:
*            OS_NO_ERR          成功
*            OS_ERR_EVENT_TYPE  錯誤的事件類型
*            OS_ERR_PEVENT_NULL 無效的事件控制塊指針
*            OS_ERR_PEND_ISR    不能在中斷內請求
*
* Returns    : == 1       mutex有效
*              == 0       a) mutex無效
*                         b) 錯誤的事件控制塊指針
*                         c) 中斷內調用
*
**************************************************************************************
*/

#if OS_MUTEX_ACCEPT_EN > 0
INT8U  OSMutexAccept (OS_EVENT *pevent, INT8U *err)
{
#if OS_CRITICAL_METHOD == 3                            
    OS_CPU_SR  cpu_sr;
#endif    


    if (OSIntNesting > 0) {                            /* 不允許在中斷內調用      */
        *err = OS_ERR_PEND_ISR;
        return (0);
    }
#if OS_ARG_CHK_EN > 0
    if (pevent == (OS_EVENT *)0) {                     /* 無效的事件控制塊指針    */
        *err = OS_ERR_PEVENT_NULL;
        return (0);
    }
    if (pevent->OSEventType != OS_EVENT_TYPE_MUTEX) {  /* 錯誤的事件類型          */
        *err = OS_ERR_EVENT_TYPE;
        return (0);
    }
#endif                                                     
    OS_ENTER_CRITICAL();                               
    if ((pevent->OSEventCnt & OS_MUTEX_KEEP_LOWER_8) == OS_MUTEX_AVAILABLE) {     
        pevent->OSEventCnt &= OS_MUTEX_KEEP_UPPER_8;   /* 記錄優先級  */
        pevent->OSEventCnt |= OSTCBCur->OSTCBPrio;   
        pevent->OSEventPtr  = (void *)OSTCBCur;        /*  鏈接TCB    */
        OS_EXIT_CRITICAL();
        *err = OS_NO_ERR;
        return (1);
    }
    OS_EXIT_CRITICAL();
    *err = OS_NO_ERR;
    return (0);
}
#endif                                                     

/*$PAGE*/
/*
**************************************************************************************
*                                  創建 Mutex 
*
* breif : 該函數用於創建mutex.
*
* prio  : PIP
*
* err   : 指向錯誤代碼的指針,可能取值:
*           OS_NO_ERR           成功.
*           OS_ERR_CREATE_ISR   不允許在中斷中創建mutex
*           OS_PRIO_EXIST       PIP的任務已經存在
*           OS_ERR_PEVENT_NULL  無空餘事件控制塊
*           OS_PRIO_INVALID     無效優先級
*
* Note(s)    : 1) '.OSEventCnt' 低八位爲0xFF表示mutex有效,否則爲佔用資源的任務優先級
*              2) '.OSEventCnt' 高八位記錄PIP
***************************************************************************************
*/

OS_EVENT  *OSMutexCreate (INT8U prio, INT8U *err)
{
#if OS_CRITICAL_METHOD == 3                              
    OS_CPU_SR  cpu_sr;
#endif    
    OS_EVENT  *pevent;


    if (OSIntNesting > 0) {                   /* 不允許中斷創建mutex      */
        *err = OS_ERR_CREATE_ISR;            
        return ((OS_EVENT *)0);
    }
#if OS_ARG_CHK_EN > 0
    if (prio >= OS_LOWEST_PRIO) {             /* 無效的優先級             */
        *err = OS_PRIO_INVALID;
        return ((OS_EVENT *)0);
    }
#endif
    OS_ENTER_CRITICAL();
    if (OSTCBPrioTbl[prio] != (OS_TCB *)0) {  /* PIP任務已經存在          */
        OS_EXIT_CRITICAL();                   
        *err = OS_PRIO_EXIST;                              
        return ((OS_EVENT *)0);                            
    }
    OSTCBPrioTbl[prio] = (OS_TCB *)1;         /* 佔用 OSTCBPrioTbl[prio]   */
    pevent             = OSEventFreeList;     /* 獲取事件控制塊            */
    if (pevent == (OS_EVENT *)0) {            /* 無剩餘事件控制塊可用      */
        OSTCBPrioTbl[prio] = (OS_TCB *)0;     /* 釋放 OSTCBPrioTbl[prio]   */
        OS_EXIT_CRITICAL();
        *err               = OS_ERR_PEVENT_NULL;                   
        return (pevent);
    }
    OSEventFreeList     = (OS_EVENT *)OSEventFreeList->OSEventPtr;/* 調整ECB鏈表 */
    OS_EXIT_CRITICAL();
    pevent->OSEventType = OS_EVENT_TYPE_MUTEX;
    pevent->OSEventCnt  = (prio << 8) | OS_MUTEX_AVAILABLE;/* PIP|資源有效       */
    pevent->OSEventPtr  = (void *)0;                       /* 無任務等待         */
    OS_EventWaitListInit(pevent);
    *err                = OS_NO_ERR;
    return (pevent);
}

/*$PAGE*/
/*
**********************************************************************************
*                                          刪除 Mutex
*
* brief  : 該函數用刪除 mutex
*
* pevent : 指向事件控制塊的指針
*
* opt    : 刪除選項
*            opt == OS_DEL_NO_PEND   無任務等待時刪除
*            opt == OS_DEL_ALWAYS    刪除,如有任務等待則置爲就緒
*                                                   
*
* err    : 指向錯誤代碼的指針,可能取值:
*            OS_NO_ERR               成功
*            OS_ERR_DEL_ISR          不允許中斷中刪除
*            OS_ERR_INVALID_OPT      無效的刪除選項
*            OS_ERR_TASK_WAITING     有任務等待
*            OS_ERR_EVENT_TYPE       錯誤的事件類型
*            OS_ERR_PEVENT_NULL      無效的事件控制塊指針
*
**********************************************************************************
*/

#if OS_MUTEX_DEL_EN
OS_EVENT  *OSMutexDel (OS_EVENT *pevent, INT8U opt, INT8U *err)
{
#if OS_CRITICAL_METHOD == 3                      
    OS_CPU_SR  cpu_sr;
#endif    
    BOOLEAN    tasks_waiting;
    INT8U      pip;


    if (OSIntNesting > 0) {                  /* 中斷中不能刪除mutex    */
        *err = OS_ERR_DEL_ISR;           
        return (pevent);
    }
#if OS_ARG_CHK_EN > 0
    if (pevent == (OS_EVENT *)0) {           /* 無效的事件控制塊指針   */
        *err = OS_ERR_PEVENT_NULL;
        return ((OS_EVENT *)0);
    }
    if (pevent->OSEventType != OS_EVENT_TYPE_MUTEX) {      /* 無效的事件類型      */
        *err = OS_ERR_EVENT_TYPE;
        return (pevent);
    }
#endif
    OS_ENTER_CRITICAL();
    if (pevent->OSEventGrp != 0x00) {                      /* 是否有任務在等待mutex*/
        tasks_waiting = TRUE;                               
    } else {
        tasks_waiting = FALSE;                            
    }
    switch (opt) {
        case OS_DEL_NO_PEND:                               /* 無任務等待刪除mutex*/
             if (tasks_waiting == FALSE) {
                 pip                 = (INT8U)(pevent->OSEventCnt >> 8);
                 OSTCBPrioTbl[pip]   = (OS_TCB *)0;/* 釋放PIP,創建信號量時佔用   */
                 pevent->OSEventType = OS_EVENT_TYPE_UNUSED;
                 pevent->OSEventPtr  = OSEventFreeList;    /* 返還事件控制塊     */
                 OSEventFreeList     = pevent;
                 OS_EXIT_CRITICAL();
                 *err = OS_NO_ERR;
                 return ((OS_EVENT *)0);                             
             } else {                                      /* 有任務等待         */
                 OS_EXIT_CRITICAL();
                 *err = OS_ERR_TASK_WAITING;
                 return (pevent);
             }

        case OS_DEL_ALWAYS:                                /* 無條件刪除         */
             while (pevent->OSEventGrp != 0x00) {          /* 就緒所有等待任務   */
                 OS_EventTaskRdy(pevent, (void *)0, OS_STAT_MUTEX);
             }
             pip                 = (INT8U)(pevent->OSEventCnt >> 8);
             OSTCBPrioTbl[pip]   = (OS_TCB *)0;            /* 釋放PIP            */
             pevent->OSEventType = OS_EVENT_TYPE_UNUSED;
             pevent->OSEventPtr  = OSEventFreeList;        /* 返還事件控制塊     */
             OSEventFreeList     = pevent;              
             OS_EXIT_CRITICAL();
             if (tasks_waiting == TRUE) {                  
                 OS_Sched();                               /* 任務調度           */
             }
             *err = OS_NO_ERR;
             return ((OS_EVENT *)0);                    

        default:
             OS_EXIT_CRITICAL();
             *err = OS_ERR_INVALID_OPT;
             return (pevent);
    }
}
#endif

/*$PAGE*/
/*
*******************************************************************************
*                                  請求mutex
*
* brief   : 該函數用來請求mutex
*
* pevent  : 指向事件控制塊的指針
*
* timeout : 等待超時
*
* err     : 指向錯誤代碼的指針,可能取值:
*             OS_NO_ERR          成功
*             OS_TIMEOUT         超時
*             OS_ERR_EVENT_TYPE  錯誤的事件類型
*             OS_ERR_PEVENT_NULL 無效的事件控制塊指針
*             OS_ERR_PEND_ISR    不允許在中斷中請求 
*
* Note(s)    : 1) 擁有mutex的任務,不能在請求任何其他mutex 
*              2) 不一定非要改變任務的優先級
********************************************************************************
*/
void  OSMutexPend (OS_EVENT *pevent, INT16U timeout, INT8U *err)
{
#if OS_CRITICAL_METHOD == 3                              
    OS_CPU_SR  cpu_sr;
#endif    
    INT8U      pip;                  /* 優先級繼承優先級(PIP)      */
    INT8U      mprio;                /* 當前佔用mutex的任務優先級  */
    BOOLEAN    rdy;                  /* 任務就緒標誌               */
    OS_TCB    *ptcb;


    if (OSIntNesting > 0) {          /* 中斷內不能請求mutex        */
        *err = OS_ERR_PEND_ISR;     
        return;
    }
#if OS_ARG_CHK_EN > 0
    if (pevent == (OS_EVENT *)0) {   /* 無效的事件控制塊指針       */
        *err = OS_ERR_PEVENT_NULL;
        return;
    }
    if (pevent->OSEventType != OS_EVENT_TYPE_MUTEX) {/* 無效的事件類型 */
        *err = OS_ERR_EVENT_TYPE;
        return;
    }
#endif
    OS_ENTER_CRITICAL();                                   
    if ((INT8U)(pevent->OSEventCnt & OS_MUTEX_KEEP_LOWER_8) == OS_MUTEX_AVAILABLE) {
        pevent->OSEventCnt &= OS_MUTEX_KEEP_UPPER_8;       /* mutex有效        */
        pevent->OSEventCnt |= OSTCBCur->OSTCBPrio;         /* 記錄優先級       */
        pevent->OSEventPtr  = (void *)OSTCBCur;            /* 指向任務控制塊   */
        OS_EXIT_CRITICAL();
        *err  = OS_NO_ERR;
        return;        
    }
    /* 獲取優先級繼承優先級 */
    pip   = (INT8U)(pevent->OSEventCnt >> 8);     
    /* 獲取佔用mutex任務的優先級 */
    mprio = (INT8U)(pevent->OSEventCnt & OS_MUTEX_KEEP_LOWER_8); 
    /* 獲取佔用mutex任務的控制塊 */
    ptcb  = (OS_TCB *)(pevent->OSEventPtr);   
     /* 是否需要提升佔用任務優先級*/
    if (ptcb->OSTCBPrio != pip && mprio > OSTCBCur->OSTCBPrio) { 
        if ((OSRdyTbl[ptcb->OSTCBY] & ptcb->OSTCBBitX) != 0x00) { /* 查看是否就緒   */
                                                                  /*  取消就緒      */                                  
            if ((OSRdyTbl[ptcb->OSTCBY] &= ~ptcb->OSTCBBitX) == 0x00) {
                OSRdyGrp &= ~ptcb->OSTCBBitY;
            }
            rdy = TRUE;
        } else {
            rdy = FALSE;                                        
        }
        ptcb->OSTCBPrio         = pip;                     /* 修改優先級 */
        ptcb->OSTCBY            = ptcb->OSTCBPrio >> 3;    /* 預計算     */
        ptcb->OSTCBBitY         = OSMapTbl[ptcb->OSTCBY];
        ptcb->OSTCBX            = ptcb->OSTCBPrio & 0x07;
        ptcb->OSTCBBitX         = OSMapTbl[ptcb->OSTCBX];
        if (rdy == TRUE) {                                 /* 新優先級就緒 */
            OSRdyGrp               |= ptcb->OSTCBBitY;     
            OSRdyTbl[ptcb->OSTCBY] |= ptcb->OSTCBBitX;
        }
        OSTCBPrioTbl[pip]       = (OS_TCB *)ptcb;
    }
    OSTCBCur->OSTCBStat |= OS_STAT_MUTEX;             /* 等待mutex狀態  */
    OSTCBCur->OSTCBDly   = timeout;                   /* 記錄等到超時   */
    OS_EventTaskWait(pevent);                         /* 任務進入等待   */
    OS_EXIT_CRITICAL();
    OS_Sched();                                       /* 任務調度       */
    OS_ENTER_CRITICAL();
    if (OSTCBCur->OSTCBStat & OS_STAT_MUTEX) {        /* 查看是否超時繼續運行 */
        OS_EventTO(pevent);
        OS_EXIT_CRITICAL();
        *err = OS_TIMEOUT;                            /* 超時進入就緒   */
        return;
    }
    OSTCBCur->OSTCBEventPtr = (OS_EVENT *)0;
    OS_EXIT_CRITICAL();
    *err = OS_NO_ERR;
}
/*$PAGE*/
/*
******************************************************************************
*                                  釋放mutex
*
* brief  : 該函數用於釋放 mutex
*
* pevent : 指向事件控制塊的指針
*
* Returns    : OS_NO_ERR               成功
*              OS_ERR_EVENT_TYPE       錯誤的事件類型
*              OS_ERR_PEVENT_NULL      無效的事件控制塊指針
*              OS_ERR_POST_ISR         不能自中斷中釋放mutex
*              OS_ERR_NOT_MUTEX_OWNER  釋放mutex的任務並沒有佔用mutex
********************************************************************************
*/

INT8U  OSMutexPost (OS_EVENT *pevent)
{
#if OS_CRITICAL_METHOD == 3                          
    OS_CPU_SR  cpu_sr;
#endif    
    INT8U      pip;                             /* 優先級繼承優先級       */
    INT8U      prio;


    if (OSIntNesting > 0) {                     /* 中斷內不允許釋放mutex  */
        return (OS_ERR_POST_ISR);                              
    }
#if OS_ARG_CHK_EN > 0
    if (pevent == (OS_EVENT *)0) {              /* 無效的事件控制塊指針   */
        return (OS_ERR_PEVENT_NULL);
    }
    if (pevent->OSEventType != OS_EVENT_TYPE_MUTEX) { /* 無效的事件類型   */
        return (OS_ERR_EVENT_TYPE);
    }                                                 
#endif
    OS_ENTER_CRITICAL();
    pip  = (INT8U)(pevent->OSEventCnt >> 8);          /* 獲取PIP    */
    /* 獲取佔用mutex的任務優先級  */
    prio = (INT8U)(pevent->OSEventCnt & OS_MUTEX_KEEP_LOWER_8);  
    if (OSTCBCur->OSTCBPrio != pip && 
        OSTCBCur->OSTCBPrio != prio) {/* 當前任務未佔有mutex  */
        OS_EXIT_CRITICAL();
        return (OS_ERR_NOT_MUTEX_OWNER);
    }
    if (OSTCBCur->OSTCBPrio == pip) { /* 優先級被提升 */

        /* 移除PIP的就緒 */                                      
        if ((OSRdyTbl[OSTCBCur->OSTCBY] &= ~OSTCBCur->OSTCBBitX) == 0) {
            OSRdyGrp &= ~OSTCBCur->OSTCBBitY;
        }
        OSTCBCur->OSTCBPrio         = prio;      /* 修改爲原來優先級 */
        OSTCBCur->OSTCBY            = prio >> 3; /* 預運算           */
        OSTCBCur->OSTCBBitY         = OSMapTbl[OSTCBCur->OSTCBY];
        OSTCBCur->OSTCBX            = prio & 0x07;
        OSTCBCur->OSTCBBitX         = OSMapTbl[OSTCBCur->OSTCBX];
        OSRdyGrp                   |= OSTCBCur->OSTCBBitY;/* 置就緒  */
        OSRdyTbl[OSTCBCur->OSTCBY] |= OSTCBCur->OSTCBBitX;
        OSTCBPrioTbl[prio]          = (OS_TCB *)OSTCBCur; 
    }
    OSTCBPrioTbl[pip] = (OS_TCB *)1;     /* 佔用OSTCBPrioTbl[pip] 請求mutex時用 */
    if (pevent->OSEventGrp != 0x00) {                 /* 是否有任務在等待mutex  */
                                                      /* 等待任務進入就緒       */
        prio                = OS_EventTaskRdy(pevent, (void *)0, OS_STAT_MUTEX);
        pevent->OSEventCnt &= OS_MUTEX_KEEP_UPPER_8;  /* 記錄優先級             */
        pevent->OSEventCnt |= prio;
        pevent->OSEventPtr  = OSTCBPrioTbl[prio];     /* 鏈接任務控制塊         */
        OS_EXIT_CRITICAL();
        OS_Sched();                                   /* 任務調度               */
        return (OS_NO_ERR);
    }
    pevent->OSEventCnt |= OS_MUTEX_AVAILABLE;         /* 使mutex有效            */
    pevent->OSEventPtr  = (void *)0;
    OS_EXIT_CRITICAL();
    return (OS_NO_ERR);
}
/*$PAGE*/
/*
*******************************************************************************
*                                     查詢mutex
*
* brief  : 該函數用於查詢mutex
*
* pevent : 指向事件控制塊的指針
*
* pdata  : 保存mutex信息的數據結構指針
*
* Returns    : OS_NO_ERR            成功
*              OS_ERR_QUERY_ISR     不能再中斷中請求
*              OS_ERR_PEVENT_NULL   無效的事件控制塊指針
*              OS_ERR_EVENT_TYPE    錯誤的事件類型
********************************************************************************
*/

#if OS_MUTEX_QUERY_EN > 0
INT8U  OSMutexQuery (OS_EVENT *pevent, OS_MUTEX_DATA *pdata)
{
#if OS_CRITICAL_METHOD == 3                      
    OS_CPU_SR  cpu_sr;
#endif    
    INT8U     *psrc;
    INT8U     *pdest;


    if (OSIntNesting > 0) {                          /* 不允許在中斷內調用    */
        return (OS_ERR_QUERY_ISR);                   
    }
#if OS_ARG_CHK_EN > 0
    if (pevent == (OS_EVENT *)0) {                   /* 無效的事件控制塊指針  */
        return (OS_ERR_PEVENT_NULL);
    }
    if (pevent->OSEventType != OS_EVENT_TYPE_MUTEX) {/* 錯誤的事件類型        */
        return (OS_ERR_EVENT_TYPE);
    }
#endif
    OS_ENTER_CRITICAL();
    pdata->OSMutexPIP  = (INT8U)(pevent->OSEventCnt >> 8);/* 優先級繼承優先級 */
    /* 佔有mutex的任務優先級,若爲0xFF則爲被佔用mutex有效 */
    pdata->OSOwnerPrio = (INT8U)(pevent->OSEventCnt & OS_MUTEX_KEEP_LOWER_8);
    if (pdata->OSOwnerPrio == 0xFF) {
        pdata->OSValue = 1; /* mutex有效 */
    } else {
        pdata->OSValue = 0; /* mutex無效 */
    }
    pdata->OSEventGrp  = pevent->OSEventGrp;     /* 複製等待任務鏈表            */
    psrc               = &pevent->OSEventTbl[0];
    pdest              = &pdata->OSEventTbl[0];
#if OS_EVENT_TBL_SIZE > 0
    *pdest++           = *psrc++;
#endif

#if OS_EVENT_TBL_SIZE > 1
    *pdest++           = *psrc++;
#endif

#if OS_EVENT_TBL_SIZE > 2
    *pdest++           = *psrc++;
#endif

#if OS_EVENT_TBL_SIZE > 3
    *pdest++           = *psrc++;
#endif

#if OS_EVENT_TBL_SIZE > 4
    *pdest++           = *psrc++;
#endif

#if OS_EVENT_TBL_SIZE > 5
    *pdest++           = *psrc++;
#endif

#if OS_EVENT_TBL_SIZE > 6
    *pdest++           = *psrc++;
#endif

#if OS_EVENT_TBL_SIZE > 7
    *pdest             = *psrc;
#endif
    OS_EXIT_CRITICAL();
    return (OS_NO_ERR);
}
#endif                                                     
#endif                                                               
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章