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;
    }
}


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