ucos sem信號量 源碼分析

信號量的建立操做

OS_EVENT  *OSSemCreate (INT16U cnt)
{
    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_IEC61508
    if (OSSafetyCriticalStartFlag == OS_TRUE) {
        OS_SAFETY_CRITICAL_EXCEPTION();
        return ((OS_EVENT *)0);
    }
#endif

    if (OSIntNesting > 0u) {               /* See if called from ISR ...               */
        return ((OS_EVENT *)0);            /* ... can't CREATE from an ISR             */
    }
    OS_ENTER_CRITICAL();
    pevent = OSEventFreeList;                /* Get next free event control block        */
    if (OSEventFreeList != (OS_EVENT *)0) {      /* 判斷是否爲還有 事件塊 若是還有鏈表就日後移動,指向下一個                                                    事件塊   */
        OSEventFreeList = (OS_EVENT *)OSEventFreeList->OSEventPtr;
    }
    OS_EXIT_CRITICAL();
    if (pevent != (OS_EVENT *)0) {                     /* 當前事件塊不爲空就進行賦值       */
        pevent->OSEventType    = OS_EVENT_TYPE_SEM;
        pevent->OSEventCnt     = cnt;               /* Set semaphore value                      */
        pevent->OSEventPtr     = (void *)0;          /* Unlink from ECB free list                */
#if OS_EVENT_NAME_EN > 0u
        pevent->OSEventName    = (INT8U *)(void *)"?";
#endif
        OS_EventWaitListInit(pevent);             /* Initialize to 'nobody waiting' on sem.   */
    }
    return (pevent);
}

OS_EventWaitListInit() 清空事件表

void  OS_EventWaitListInit (OS_EVENT *pevent)
{
    INT8U  i;

    pevent->OSEventGrp = 0u;          /* No task waiting on event        */
    for (i = 0u; i < OS_EVENT_TBL_SIZE; i++) {
        pevent->OSEventTbl[i] = 0u;
    }
}

OSSemPend() 任務 添加到 事件任務

void  OSSemPend (OS_EVENT  *pevent,
                 INT32U     timeout,       //多少時間沒有接收到 也添加到就緒隊列
                 INT8U     *perr)
{
#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_SEM) {   /* 非法的事件塊類型        */
        *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;
    }
    OS_ENTER_CRITICAL();
    if (pevent->OSEventCnt > 0u) {       /* 信號量大於0 有效..   */
        pevent->OSEventCnt--;            /* ... decrement semaphore only if positive.     */
        OS_EXIT_CRITICAL();
        *perr = OS_ERR_NONE;
        return;
    }
    
     /* Otherwise, must wait until event occurs       */
     
    OSTCBCur->OSTCBStat     |= OS_STAT_SEM;     /* Resource not available, pend on semaphore     */
    OSTCBCur->OSTCBStatPend  = OS_STAT_PEND_OK;
    OSTCBCur->OSTCBDly       = timeout;         /* Store pend timeout in TCB                     */
    OS_EventTaskWait(pevent);                  /*將任務 變爲阻塞狀態    */
    OS_EXIT_CRITICAL();
    OS_Sched();                              /* 找到最高優先級運行         */
    /************************************************************************
    ** 爲何會到這裏,勉強猜想 OSTimeTick() 當時間到了時,任務恢復
    ** 接着上次到這裏運行,感受不對
    ************************************************************************/
    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            */
             break;

        case OS_STAT_PEND_TO:  //time out TO 時間溢出
        default:
             OS_EventTaskRemove(OSTCBCur, pevent); //時間到了,從事件中移除
             *perr = OS_ERR_TIMEOUT;       /* Indicate that we didn't get event 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();
}

OSPost()發送消息 將事件中的任務 添加到就緒隊列中

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



#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_SEM) {   /* Validate event block type   */
        return (OS_ERR_EVENT_TYPE);
    }
    OS_ENTER_CRITICAL();
    if (pevent->OSEventGrp != 0u) {     /* See if any task waiting for semaphore   */
           /* Ready HPT waiting on event     */
           
        (void)OS_EventTaskRdy(pevent, (void *)0, OS_STAT_SEM, OS_STAT_PEND_OK);
        OS_EXIT_CRITICAL();
        OS_Sched();             /* Find HPT ready to run                         */
        return (OS_ERR_NONE);
    }
    if (pevent->OSEventCnt < 65535u) { /* Make sure semaphore will not overflow         */
        pevent->OSEventCnt++;           /* Increment semaphore count to register event   */
        OS_EXIT_CRITICAL();
        return (OS_ERR_NONE);
    }
    OS_EXIT_CRITICAL();            /* 通常不太可能到這裏   */
    return (OS_ERR_SEM_OVF);
}

等待事件的任務 轉到 就緒任務  OS_EventTaskRdy( );

INT8U  OS_EventTaskRdy (OS_EVENT  *pevent,          //事件
                        void      *pmsg,            //消息 只在MAILBOXEs and QUEUEs時應用
                        INT8U      msk,           //清除OS_STAT_SEM OS_STAT_MBOX標誌
                        INT8U      pend_stat)   //任務狀態
{
    OS_TCB   *ptcb;
    INT8U     y;
    INT8U     x;
    INT8U     prio;
#if OS_LOWEST_PRIO > 63u
    OS_PRIO  *ptbl;
#endif

//這裏 得到事件隊列中的任務的優先級 而後賦給到 TCB 就緒任務中 這樣就能夠被系統調度

#if OS_LOWEST_PRIO <= 63u
    y    = OSUnMapTbl[pevent->OSEventGrp];    /* Find HPT waiting for message      */
    x    = OSUnMapTbl[pevent->OSEventTbl[y]];
    prio = (INT8U)((y << 3u) + x);            /* Find priority of task getting the msg   */
#else
    if ((pevent->OSEventGrp & 0xFFu) != 0u) {     /* Find HPT waiting for message       */
        y = OSUnMapTbl[ pevent->OSEventGrp & 0xFFu];
    } else {
        y = OSUnMapTbl[(OS_PRIO)(pevent->OSEventGrp >> 8u) & 0xFFu] + 8u;
    }
    ptbl = &pevent->OSEventTbl[y];
    if ((*ptbl & 0xFFu) != 0u) {
        x = OSUnMapTbl[*ptbl & 0xFFu];
    } else {
        x = OSUnMapTbl[(OS_PRIO)(*ptbl >> 8u) & 0xFFu] + 8u;
    }
    prio = (INT8U)((y << 4u) + x);         /* Find priority of task getting the msg   */
#endif

    ptcb                  =  OSTCBPrioTbl[prio];   /* Point to this task's OS_TCB    */
    ptcb->OSTCBDly        =  0u;                /* Prevent OSTimeTick() from readying task */
#if ((OS_Q_EN > 0u) && (OS_MAX_QS > 0u)) || (OS_MBOX_EN > 0u)
    ptcb->OSTCBMsg        =  pmsg;            /* Send message directly to waiting task       */
#else
    pmsg                  =  pmsg;             /* Prevent compiler warning if not used    */
#endif
    ptcb->OSTCBStat      &= (INT8U)~msk;       /* Clear bit associated with event type   */
    ptcb->OSTCBStatPend   =  pend_stat;       /* Set pend status of post or abort    */
     /* See if task is ready (could be susp'd)      */
          
    if ((ptcb->OSTCBStat &   OS_STAT_SUSPEND) == OS_STAT_RDY) {
       
        //這裏就是 傳值到 就緒任務表中 系統就能夠調度了
        
        OSRdyGrp         |=  ptcb->OSTCBBitY;     /* Put task in the ready to run list   */
        OSRdyTbl[y]      |=  ptcb->OSTCBBitX;
    }
    
    //這裏  把事件任務刪除 他的做用(恢復源任務優先級)已經完成,全部刪除
    OS_EventTaskRemove(ptcb, pevent);         /* Remove this task from event  wait list     */
    
#if (OS_EVENT_MULTI_EN > 0u)
    if (ptcb->OSTCBEventMultiPtr != (OS_EVENT **)0) {   /* Remove this task from events' wait lists    */
        OS_EventTaskRemoveMulti(ptcb, ptcb->OSTCBEventMultiPtr);
        ptcb->OSTCBEventPtr       = (OS_EVENT  *)pevent;/* Return event as first multi-pend event ready*/
    }
#endif

    return (prio);
}

事件任務 刪除 OS_EventTaskRemove

void  OS_EventTaskRemove (OS_TCB   *ptcb,
                          OS_EVENT *pevent)
{
    INT8U  y;
    
    y                       =  ptcb->OSTCBY;
    pevent->OSEventTbl[y]  &= (OS_PRIO)~ptcb->OSTCBBitX; /* Remove task from wait list      */
    
    if (pevent->OSEventTbl[y] == 0u) {
        pevent->OSEventGrp &= (OS_PRIO)~ptcb->OSTCBBitY;
    }
}

任務 添加到 事件任務 OS_EventTaskWait

void  OS_EventTaskWait (OS_EVENT *pevent)
{
    INT8U  y;


    OSTCBCur->OSTCBEventPtr               = pevent;      /* Store ptr to ECB in TCB         */
    
    //將事件表中任務優先級 置1 即將 任務 添加到  事件任務表(這裏優先級同樣是爲了在得到信號量是,還原到就緒任務    隊列中
    
    pevent->OSEventTbl[OSTCBCur->OSTCBY] |= OSTCBCur->OSTCBBitX; /* Put task in waiting list */
    pevent->OSEventGrp                   |= OSTCBCur->OSTCBBitY;

    y             =  OSTCBCur->OSTCBY;            /* Task no longer ready                */
    OSRdyTbl[y]  &= (OS_PRIO)~OSTCBCur->OSTCBBitX;
    
    // 這裏將 OSRdyGrp 清零 即從就緒任務表中 將任務 刪除(這樣就不會被調度了)
    if (OSRdyTbl[y] == 0u) {          /* Clear event grp bit if this was only task pending */
        OSRdyGrp &= (OS_PRIO)~OSTCBCur->OSTCBBitY;
    }
}
相關文章
相關標籤/搜索