天天看點

ucosii信号量和消息隊列源碼 1、信号量Pend和Post2、消息隊列Pend和Post

1、信号量Pend和Post

void  OSSemPend (OS_EVENT  *pevent,
                 INT32U     timeout,
                 INT8U     *perr)
{                       
    OS_CPU_SR  cpu_sr = 0u;

    if (pevent->OSEventType != OS_EVENT_TYPE_SEM) {   
        *perr = OS_ERR_EVENT_TYPE;
        return;
    }
    if (OSIntNesting > 0u) {                          
        *perr = OS_ERR_PEND_ISR;                      
        return;
    }
    if (OSLockNesting > 0u) {                         
        *perr = OS_ERR_PEND_LOCKED;                   
        return;
    }
	
    OS_ENTER_CRITICAL();
    if (pevent->OSEventCnt > 0u) {                   
        pevent->OSEventCnt--;		/*	如果計數器>0,則-1傳回	*/                        
        OS_EXIT_CRITICAL();
        *perr = OS_ERR_NONE;
        return;
    }                                                   
    OSTCBCur->OSTCBStat     |= OS_STAT_SEM;           
    OSTCBCur->OSTCBStatPend  = OS_STAT_PEND_OK;
    OSTCBCur->OSTCBDly       = timeout;         /* 否則更新程式狀态字和延時節拍	*/
    OS_EventTaskWait(pevent);                   /* 讓目前任務等待				*/
    OS_EXIT_CRITICAL();

    OS_Sched();/* 進行一次排程,由目前任務切換到其他任務,等待事件觸發之後,再切回來  */
			
    OS_ENTER_CRITICAL();
    switch (OSTCBCur->OSTCBStatPend) {               
        case OS_STAT_PEND_OK:
             *perr = OS_ERR_NONE;
             break;
        case OS_STAT_PEND_ABORT:
             *perr = OS_ERR_PEND_ABORT;               
             break;
        case OS_STAT_PEND_TO:
        default:
             OS_EventTaskRemove(OSTCBCur, pevent);	  /* 逾時,将目前任務移除等待清單	*/
             *perr = OS_ERR_TIMEOUT;                  
             break;
    }
    OSTCBCur->OSTCBStat          =  OS_STAT_RDY;      
    OSTCBCur->OSTCBStatPend      =  OS_STAT_PEND_OK;  
    OSTCBCur->OSTCBEventPtr      = (OS_EVENT  *)0;    
	/*	還原狀态資訊	*/
    OS_EXIT_CRITICAL();
}
           
INT8U  OSSemPost (OS_EVENT *pevent)
{                        
    OS_CPU_SR  cpu_sr = 0u;

    if (pevent->OSEventType != OS_EVENT_TYPE_SEM) {   
        return (OS_ERR_EVENT_TYPE);
    }
	
    OS_ENTER_CRITICAL();
    if (pevent->OSEventGrp != 0u) {                   
        /*	是否有任務在等待信号量	*/                                              
        (void)OS_EventTaskRdy(pevent, (void *)0, OS_STAT_SEM, OS_STAT_PEND_OK);
        OS_EXIT_CRITICAL();
        OS_Sched();       		/*	有任務則等待信号量,則是其中最高的就緒且排程一次	*/                            
        return (OS_ERR_NONE);
    }
	
    if (pevent->OSEventCnt < 65535u) {                
        pevent->OSEventCnt++; 	/*	沒有任務等待信号量,計數器+1	*/                        
        OS_EXIT_CRITICAL();
        return (OS_ERR_NONE);
    }
	
    OS_EXIT_CRITICAL();                               
    return (OS_ERR_SEM_OVF);
}
           

2、消息隊列Pend和Post

void  *OSQPend (OS_EVENT  *pevent,
                INT32U     timeout,
                INT8U     *perr)
{
    void      *pmsg;
    OS_Q      *pq;
#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'                                  */
        *perr = OS_ERR_PEVENT_NULL;
        return ((void *)0);
    }
#endif
    if (pevent->OSEventType != OS_EVENT_TYPE_Q) {/* Validate event block type                          */
        *perr = OS_ERR_EVENT_TYPE;
        return ((void *)0);
    }
    if (OSIntNesting > 0u) {                     /* See if called from ISR ...                         */
        *perr = OS_ERR_PEND_ISR;                 /* ... can't PEND from an ISR                         */
        return ((void *)0);
    }
    if (OSLockNesting > 0u) {                    /* See if called with scheduler locked ...            */
        *perr = OS_ERR_PEND_LOCKED;              /* ... can't PEND when locked                         */
        return ((void *)0);
    }
    OS_ENTER_CRITICAL();
    pq = (OS_Q *)pevent->OSEventPtr;             /* Point at queue control block                       */
    if (pq->OSQEntries > 0u) {                   /* See if any messages in the queue                   */
        pmsg = *pq->OSQOut++;                    /* Yes, extract oldest message from the queue         */
        pq->OSQEntries--;                        /* Update the number of entries in the queue          */
        if (pq->OSQOut == pq->OSQEnd) {          /* Wrap OUT pointer if we are at the end of the queue */
            pq->OSQOut = pq->OSQStart;
        }
        OS_EXIT_CRITICAL();
        *perr = OS_ERR_NONE;
        return (pmsg);                           /* Return message received                            */
    }
    OSTCBCur->OSTCBStat     |= OS_STAT_Q;        /* Task will have to pend for a message to be posted  */
    OSTCBCur->OSTCBStatPend  = OS_STAT_PEND_OK;
    OSTCBCur->OSTCBDly       = timeout;          /* Load timeout into TCB                              */
    OS_EventTaskWait(pevent);                    /* Suspend task until event or timeout occurs         */
    OS_EXIT_CRITICAL();
    OS_Sched();                                  /* Find next highest priority task ready to run       */
    OS_ENTER_CRITICAL();
    switch (OSTCBCur->OSTCBStatPend) {                /* See if we timed-out or aborted                */
        case OS_STAT_PEND_OK:                         /* Extract message from TCB (Put there by QPost) */
             pmsg =  OSTCBCur->OSTCBMsg;
            *perr =  OS_ERR_NONE;
             break;

        case OS_STAT_PEND_ABORT:
             pmsg = (void *)0;
            *perr =  OS_ERR_PEND_ABORT;               /* Indicate that we aborted                      */
             break;

        case OS_STAT_PEND_TO:
        default:
             OS_EventTaskRemove(OSTCBCur, pevent);
             pmsg = (void *)0;
            *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
    OSTCBCur->OSTCBMsg           = (void      *)0;    /* Clear  received message                       */
    OS_EXIT_CRITICAL();
    return (pmsg);                                    /* Return received message                       */
}
           
INT8U  OSQPost (OS_EVENT  *pevent,
                void      *pmsg)
{
    OS_Q      *pq;
#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_Q) {      /* Validate event block type                    */
        return (OS_ERR_EVENT_TYPE);
    }
    OS_ENTER_CRITICAL();
    if (pevent->OSEventGrp != 0u) {                    /* See if any task pending on queue             */
                                                       /* Ready highest priority task waiting on event */
        (void)OS_EventTaskRdy(pevent, pmsg, OS_STAT_Q, OS_STAT_PEND_OK);
        OS_EXIT_CRITICAL();
        OS_Sched();                                    /* Find highest priority task ready to run      */
        return (OS_ERR_NONE);
    }
    pq = (OS_Q *)pevent->OSEventPtr;                   /* Point to queue control block                 */
    if (pq->OSQEntries >= pq->OSQSize) {               /* Make sure queue is not full                  */
        OS_EXIT_CRITICAL();
        return (OS_ERR_Q_FULL);
    }
    *pq->OSQIn++ = pmsg;                               /* Insert message into queue                    */
    pq->OSQEntries++;                                  /* Update the nbr of entries in the queue       */
    if (pq->OSQIn == pq->OSQEnd) {                     /* Wrap IN ptr if we are at end of queue        */
        pq->OSQIn = pq->OSQStart;
    }
    OS_EXIT_CRITICAL();
    return (OS_ERR_NONE);
}
           

繼續閱讀