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                                                               
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

DingUXiu

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值