ucos 互斥信号量 源码分析

互斥信号量创建

OS_EVENT  *OSMutexCreate (INT8U   prio,
                          INT8U  *perr)
{
    OS_EVENT  *pevent;
#if OS_CRITICAL_METHOD == 3u    /* Allocate storage for CPU status register */
    OS_CPU_SR  cpu_sr = 0u;
#endif


#ifdef OS_SAFETY_CRITICAL
    if (perr == (INT8U *)0) {
        OS_SAFETY_CRITICAL_EXCEPTION();
        return ((OS_EVENT *)0);
    }
#endif

#ifdef OS_SAFETY_CRITICAL_IEC61508
    if (OSSafetyCriticalStartFlag == OS_TRUE) {
        OS_SAFETY_CRITICAL_EXCEPTION();
        return ((OS_EVENT *)0);
    }
#endif

#if OS_ARG_CHK_EN > 0u
    if (prio != OS_PRIO_MUTEX_CEIL_DIS) {
        if (prio >= OS_LOWEST_PRIO) {     /*优先级超过范围 优先级最大数值为 空优先级*/
           *perr = OS_ERR_PRIO_INVALID;
            return ((OS_EVENT *)0);
        }
    }
#endif
    if (OSIntNesting > 0u) {     /* See if called from ISR ...   */
        *perr = OS_ERR_CREATE_ISR;    /* ... can't CREATE mutex from an ISR   */
        return ((OS_EVENT *)0);
    }
    OS_ENTER_CRITICAL();
    if (prio != OS_PRIO_MUTEX_CEIL_DIS) {
        if (OSTCBPrioTbl[prio] != (OS_TCB *)0) {   /* 互斥优先级没有存在  */
            OS_EXIT_CRITICAL();           /* Task already exist at priority ...   */
           *perr = OS_ERR_PRIO_EXIST;    /* ... ceiling priority      */
            return ((OS_EVENT *)0);
        }
        OSTCBPrioTbl[prio] = OS_TCB_RESERVED;   /* 设为存在     */
    }

    pevent = OSEventFreeList;        /* Get next free event control block        */
    if (pevent == (OS_EVENT *)0) {      /* 没有可用的事件块       */
        if (prio != OS_PRIO_MUTEX_CEIL_DIS) {
            OSTCBPrioTbl[prio] = (OS_TCB *)0;   /* 由于上面设置任务存在,但是没有可用的事件块,所以创建失                                                    败,要清除上面的任务优先级    */
        }
        OS_EXIT_CRITICAL();
       *perr = OS_ERR_PEVENT_NULL;       /* No more event control blocks */
        return (pevent);
    }
    OSEventFreeList     = (OS_EVENT *)OSEventFreeList->OSEventPtr; /* 指向下一个事件块   */
    OS_EXIT_CRITICAL();
    pevent->OSEventType = OS_EVENT_TYPE_MUTEX;
    pevent->OSEventCnt  = (INT16U)((INT16U)prio << 8u) | OS_MUTEX_AVAILABLE; /* Resource is avail. */
    pevent->OSEventPtr  = (void *)0;             /* No task owning the mutex    */
#if OS_EVENT_NAME_EN > 0u
    pevent->OSEventName = (INT8U *)(void *)"?";
#endif
    OS_EventWaitListInit(pevent);
   *perr = OS_ERR_NONE;
    return (pevent);
}

互斥信号量获取 OSMutexPend

void  OSMutexPend (OS_EVENT  *pevent,
                   INT32U     timeout,
                   INT8U     *perr)
{
    INT8U      pcp;           /* Priority Ceiling Priority (PCP)          */
    INT8U      mprio;      /* Mutex owner priority                     */
    BOOLEAN    rdy;        /* Flag indicating task was ready           */
    OS_TCB    *ptcb;
    OS_EVENT  *pevent2;
    INT8U      y;
#if OS_CRITICAL_METHOD == 3u           /* Allocate storage for CPU status register */
    OS_CPU_SR  cpu_sr = 0u;
#endif


#ifdef OS_SAFETY_CRITICAL
    if (perr == (INT8U *)0) {
        OS_SAFETY_CRITICAL_EXCEPTION();
        return;
    }
#endif

#if OS_ARG_CHK_EN > 0u
    if (pevent == (OS_EVENT *)0) {       /* Validate 'pevent'         */
        *perr = OS_ERR_PEVENT_NULL;
        return;
    }
#endif
    if (pevent->OSEventType != OS_EVENT_TYPE_MUTEX) {      /* Validate event block type    */
        *perr = OS_ERR_EVENT_TYPE;
        return;
    }
    if (OSIntNesting > 0u) {                               /* See if called from ISR ...  */
        *perr = OS_ERR_PEND_ISR;                           /* ... can't PEND from an ISR  */
        return;
    }
    if (OSLockNesting > 0u) {                   /* See if called with scheduler locked ...  */
        *perr = OS_ERR_PEND_LOCKED;               /* ... can't PEND when locked     */
        return;
    }
/*$PAGE*/
    OS_ENTER_CRITICAL();
    pcp = (INT8U)(pevent->OSEventCnt >> 8u);         /*得到优先级 */
   
    /* Is Mutex available?  */
    
    if ((INT8U)(pevent->OSEventCnt & OS_MUTEX_KEEP_LOWER_8) == OS_MUTEX_AVAILABLE) {
        pevent->OSEventCnt &= OS_MUTEX_KEEP_UPPER_8;       /* 清除低位 OSEventCnt全部清零 */
        pevent->OSEventCnt |= OSTCBCur->OSTCBPrio;         /*保存当前任务优先级 */
        pevent->OSEventPtr  = (void *)OSTCBCur;            /* Point to owning task's OS_TCB */
        if ((pcp != OS_PRIO_MUTEX_CEIL_DIS) &&
            (OSTCBCur->OSTCBPrio <= pcp)) {                /* 当前任务优先级 高于 互斥事件优先级  */
             OS_EXIT_CRITICAL();                           /* ... than current task!     */
            *perr = OS_ERR_PCP_LOWER;
        } else {
             OS_EXIT_CRITICAL();
            *perr = OS_ERR_NONE;
        }
        return;
    }
    if (pcp != OS_PRIO_MUTEX_CEIL_DIS) {
        mprio = (INT8U)(pevent->OSEventCnt & OS_MUTEX_KEEP_LOWER_8); /* Get priority of mutex owner */
        ptcb  = (OS_TCB *)(pevent->OSEventPtr);             /*  当前任务优先级   */
        if (ptcb->OSTCBPrio > pcp) {                   /*  当前任务优先级 低于 互斥事件优先级 */
            if (mprio > OSTCBCur->OSTCBPrio) {  //互斥事件优先级 低于 当前任务优先级 
                y = ptcb->OSTCBY;
                if ((OSRdyTbl[y] & ptcb->OSTCBBitX) != 0u) {  /*看互斥事件 准备好运行   */
                    OSRdyTbl[y] &= (OS_PRIO)~ptcb->OSTCBBitX;     /*  Yes, Remove owner from Rdy ...*/
                    if (OSRdyTbl[y] == 0u) {                /*   ... list at current prio */
                        OSRdyGrp &= (OS_PRIO)~ptcb->OSTCBBitY;
                    }
                    rdy = OS_TRUE;
                } else {
                    pevent2 = ptcb->OSTCBEventPtr;   //当前任务 由于优先级高 就要移到 就绪列表中
                    if (pevent2 != (OS_EVENT *)0) {      /* Remove from event wait list       */
                        y = ptcb->OSTCBY;
                        pevent2->OSEventTbl[y] &= (OS_PRIO)~ptcb->OSTCBBitX;
                        if (pevent2->OSEventTbl[y] == 0u) {
                            pevent2->OSEventGrp &= (OS_PRIO)~ptcb->OSTCBBitY;
                        }
                    }
                    rdy = OS_FALSE;      /* No                  */
                }
                ptcb->OSTCBPrio = pcp;      /* 当前任务优先级设为 互斥事件任务优先级    */
#if OS_LOWEST_PRIO <= 63u
                ptcb->OSTCBY    = (INT8U)( ptcb->OSTCBPrio >> 3u);
                ptcb->OSTCBX    = (INT8U)( ptcb->OSTCBPrio & 0x07u);
#else
                ptcb->OSTCBY    = (INT8U)((INT8U)(ptcb->OSTCBPrio >> 4u) & 0xFFu);
                ptcb->OSTCBX    = (INT8U)( ptcb->OSTCBPrio & 0x0Fu);
#endif
                ptcb->OSTCBBitY = (OS_PRIO)(1uL << ptcb->OSTCBY);
                ptcb->OSTCBBitX = (OS_PRIO)(1uL << ptcb->OSTCBX);

                if (rdy == OS_TRUE) {        /* 互斥任务准备好运行 添加到 就绪表中 */
                    OSRdyGrp               |= ptcb->OSTCBBitY; /* ... make it ready at new priority */
                    OSRdyTbl[ptcb->OSTCBY] |= ptcb->OSTCBBitX;
                } else {  //当前任务准备好 运行
                    pevent2 = ptcb->OSTCBEventPtr;
                    if (pevent2 != (OS_EVENT *)0) {        /* Add to event wait list  */
                        pevent2->OSEventGrp               |= ptcb->OSTCBBitY;
                        pevent2->OSEventTbl[ptcb->OSTCBY] |= ptcb->OSTCBBitX;
                    }
                }
                OSTCBPrioTbl[pcp] = ptcb;  //事件任务 变为当前任务 
            }
        }
    }
    OSTCBCur->OSTCBStat     |= OS_STAT_MUTEX;     /* Mutex not available, pend current task  */
    OSTCBCur->OSTCBStatPend  = OS_STAT_PEND_OK;
    OSTCBCur->OSTCBDly       = timeout;           /* Store timeout in current task's TCB   */
    OS_EventTaskWait(pevent);            /* Suspend task until event or timeout occurs  */
    OS_EXIT_CRITICAL();
    OS_Sched();                          /* Find next highest priority task ready  */
    OS_ENTER_CRITICAL();
    switch (OSTCBCur->OSTCBStatPend) {         /* See if we timed-out or aborted    */
        case OS_STAT_PEND_OK:
             *perr = OS_ERR_NONE;
             break;

        case OS_STAT_PEND_ABORT:
             *perr = OS_ERR_PEND_ABORT;    /* Indicate that we aborted getting mutex   */
             break;

        case OS_STAT_PEND_TO:
        default:
             OS_EventTaskRemove(OSTCBCur, pevent);
             *perr = OS_ERR_TIMEOUT;      /* Indicate that we didn't get mutex within TO   */
             break;
    }
    OSTCBCur->OSTCBStat          =  OS_STAT_RDY;   /* Set   task  status to ready      */
    OSTCBCur->OSTCBStatPend      =  OS_STAT_PEND_OK;  /* Clear pend  status       */
    OSTCBCur->OSTCBEventPtr      = (OS_EVENT  *)0;    /* Clear event pointers        */
#if (OS_EVENT_MULTI_EN > 0u)
    OSTCBCur->OSTCBEventMultiPtr = (OS_EVENT **)0;
#endif
    OS_EXIT_CRITICAL();
}

 互斥信号 接收 OSMutextPost

INT8U  OSMutexPost (OS_EVENT *pevent)
{
    INT8U      pcp;             /* Priority ceiling priority      */
    INT8U      prio;
#if OS_CRITICAL_METHOD == 3u     /* Allocate storage for CPU status register      */
    OS_CPU_SR  cpu_sr = 0u;
#endif


    if (OSIntNesting > 0u) {          /* See if called from ISR ...     */
        return (OS_ERR_POST_ISR);        /* ... can't POST mutex from an ISR    */
    }
#if OS_ARG_CHK_EN > 0u
    if (pevent == (OS_EVENT *)0) {       /* Validate 'pevent'     */
        return (OS_ERR_PEVENT_NULL);
    }
#endif
    if (pevent->OSEventType != OS_EVENT_TYPE_MUTEX) { /* Validate event block type     */
        return (OS_ERR_EVENT_TYPE);
    }
    OS_ENTER_CRITICAL();
    pcp  = (INT8U)(pevent->OSEventCnt >> 8u);    /* 得到互斥优先级    */
    prio = (INT8U)(pevent->OSEventCnt & OS_MUTEX_KEEP_LOWER_8);  /*  */
    if (OSTCBCur != (OS_TCB *)pevent->OSEventPtr) {   /* 想要释放mutex的任务是不是占用mutex的任务*/
        OS_EXIT_CRITICAL();
        return (OS_ERR_NOT_MUTEX_OWNER);
    }
    if (pcp != OS_PRIO_MUTEX_CEIL_DIS) {
        if (OSTCBCur->OSTCBPrio == pcp) {       /* 当前任务优先级 等于 互斥事件优先级 */
            OSMutex_RdyAtPrio(OSTCBCur, prio);  /* 把该任务的优先级恢复到原来的值  */
        }
        OSTCBPrioTbl[pcp] = OS_TCB_RESERVED;   /* Reserve table entry  */
    }
    if (pevent->OSEventGrp != 0u) {    //等待该mutex的任务列表不为空,则释放mutex
                                             
        prio                = OS_EventTaskRdy(pevent, (void *)0, OS_STAT_MUTEX, OS_STAT_PEND_OK);
        pevent->OSEventCnt &= OS_MUTEX_KEEP_UPPER_8;  //将任务列表中最高优先级的任务进入就绪态,并且把该优先                                                        级保存在mutex的ECB中
        pevent->OSEventCnt |= prio;
        pevent->OSEventPtr  = OSTCBPrioTbl[prio];     /* Link to new mutex owner's OS_TCB  */
        if ((pcp  != OS_PRIO_MUTEX_CEIL_DIS) &&
            (prio <= pcp)) {                          /* PCP 'must' have a SMALLER prio ... */
            OS_EXIT_CRITICAL();                       /* ... than current task!    */
            OS_Sched();                          /*  Find highest priority task ready to run  */
            return (OS_ERR_PCP_LOWER);
        } else {
            OS_EXIT_CRITICAL();
            OS_Sched();                      /*   Find highest priority task ready to run  */
            return (OS_ERR_NONE);
        }
    }
    pevent->OSEventCnt |= OS_MUTEX_AVAILABLE;    /* No,  Mutex is now available      */
    pevent->OSEventPtr  = (void *)0;
    OS_EXIT_CRITICAL();
    return (OS_ERR_NONE);
}

恢复一个任务到他原来的优先级 

//将 任务 优先级 变为 prio
static  void  OSMutex_RdyAtPrio (OS_TCB  *ptcb,
                                 INT8U    prio)
{
    INT8U  y;


    y            =  ptcb->OSTCBY;           /* Remove owner from ready list at 'pcp'    */
    OSRdyTbl[y] &= (OS_PRIO)~ptcb->OSTCBBitX;
    if (OSRdyTbl[y] == 0u) {
        OSRdyGrp &= (OS_PRIO)~ptcb->OSTCBBitY;
    }
    ptcb->OSTCBPrio         = prio;
    OSPrioCur               = prio;        /* The current task is now at this priority */
#if OS_LOWEST_PRIO <= 63u
    ptcb->OSTCBY            = (INT8U)((INT8U)(prio >> 3u) & 0x07u);
    ptcb->OSTCBX            = (INT8U)(prio & 0x07u);
#else
    ptcb->OSTCBY            = (INT8U)((INT8U)(prio >> 4u) & 0x0Fu);
    ptcb->OSTCBX            = (INT8U) (prio & 0x0Fu);
#endif
    ptcb->OSTCBBitY         = (OS_PRIO)(1uL << ptcb->OSTCBY);
    ptcb->OSTCBBitX         = (OS_PRIO)(1uL << ptcb->OSTCBX);
    OSRdyGrp               |= ptcb->OSTCBBitY;   /* Make task ready at original priority     */
    OSRdyTbl[ptcb->OSTCBY] |= ptcb->OSTCBBitX;
    OSTCBPrioTbl[prio]      = ptcb;
}


你可能感兴趣的:(源码分析,ucos,互斥信号量)