逐字逐句解析ucos ii 源代码-》OS_Q.C

//BY 简单的元清  

//部分内容引用了其他博主的文章,对这些博主表示感谢,时间关系就不一一指出了。  

//如有转载,请说明,谢谢  

/*
*********************************************************************************************************
*                                                uC/OS-II
*                                          The Real-Time Kernel
*                                        MESSAGE QUEUE MANAGEMENT
*
*                        (c) Copyright 1992-1998, Jean J. Labrosse, Plantation, FL
*                                           All Rights Reserved
*
*                                                  V2.00
*
* File : OS_Q.C
* By   : Jean J. Labrosse
*********************************************************************************************************
*/

#ifndef  OS_MASTER_FILE
#include "software\includes.h"
#endif

#if OS_Q_EN && (OS_MAX_QS >= 2)
/*
*********************************************************************************************************
*                                           LOCAL DATA TYPES  
*********************************************************************************************************
*/

typedef struct os_q {                  /* QUEUE CONTROL BLOCK                                          */
    struct os_q   *OSQPtr;             /* Link to next queue control block in list of free blocks      */
    void         **OSQStart;           /* Pointer to start of queue data                               */
    void         **OSQEnd;             /* Pointer to end   of queue data                               */
    void         **OSQIn;              /* Pointer to where next message will be inserted  in   the Q   */
    void         **OSQOut;             /* Pointer to where next message will be extracted from the Q   */
    INT16U         OSQSize;            /* Size of queue (maximum number of entries)                    */
    INT16U         OSQEntries;         /* Current number of entries in the queue                       */
} OS_Q;

/*
*********************************************************************************************************
*                                         LOCAL GLOBAL VARIABLES
*********************************************************************************************************
*/

static  OS_Q        *OSQFreeList;              /* Pointer to list of free QUEUE control blocks         */
static  OS_Q         OSQTbl[OS_MAX_QS];        /* Table of QUEUE control blocks                        */

/*$PAGE*/
/*
*********************************************************************************************************
*                                      ACCEPT MESSAGE FROM QUEUE
*
* Description: This function checks the queue to see if a message is available.  Unlike OSQPend(),
*              OSQAccept() does not suspend the calling task if a message is not available.
*
* Arguments  : pevent        is a pointer to the event control block
*
* Returns    : != (void *)0  is the message in the queue if one is available.  The message is removed
*                            from the so the next time OSQAccept() is called, the queue will contain
*                            one less entry.
*              == (void *)0  if the queue is empty
*                            if you passed an invalid event type
*********************************************************************************************************
*/
// 无等待地从一个消息队列中取得消息
void *OSQAccept (OS_EVENT *pevent) reentrant
{
    void  *msg;
    OS_Q  *pq;


    OS_ENTER_CRITICAL();
	//进入临界区
    if (pevent->OSEventType != OS_EVENT_TYPE_Q) {     /* Validate event block type                     */
	//检查队列的类型是不是队列
        OS_EXIT_CRITICAL();
        return ((void *)0);
		//如果不是就退出临界区
    }
    pq = pevent->OSEventPtr;                     /* Point at queue control block                       */
	//指针指向队列的块
    if (pq->OSQEntries != 0) {                   /* See if any messages in the queue                   */
	//检查队列里面是否有东西
        msg = *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;
			//如果队列到头了需要把队列的指针从头开始
        }
    } else {
        msg = (void *)0;                         /* Queue is empty       
		//没有消息
		*/
    }
    OS_EXIT_CRITICAL();
	//退出临界区
    return (msg);                                /* Return message received (or NULL)                  */
}
/*$PAGE*/
/*
*********************************************************************************************************
*                                        CREATE A MESSAGE QUEUE
*
* Description: This function creates a message queue if free event control blocks are available.
*
* Arguments  : start         is a pointer to the base address of the message queue storage area.  The
*                            storage area MUST be declared as an array of pointers to 'void' as follows
*
*                            void *MessageStorage[size]
*
*              size          is the number of elements in the storage area
*
* Returns    : != (void *)0  is a pointer to the event control clock (OS_EVENT) associated with the
*                            created queue
*              == (void *)0  if no event control blocks were available
*********************************************************************************************************
*/
//创建一个队列消息
OS_EVENT *OSQCreate (void **start, INT16U size) reentrant
{
    OS_EVENT *pevent;
    OS_Q     *pq;


    OS_ENTER_CRITICAL();
	//进入临界区
    pevent = OSEventFreeList;                    /* Get next free event control block                  */
	//从空列表中摘下一个块
    if (OSEventFreeList != (OS_EVENT *)0) {      /* See if pool of free ECB pool was empty             */
        OSEventFreeList = (OS_EVENT *)OSEventFreeList->OSEventPtr;
		//检查ECB链表的OSEventFreeList是否为零,不为零赋值为零。
    }
    OS_EXIT_CRITICAL();
	//退出临界区
    if (pevent != (OS_EVENT *)0) {               /* See if we have an event control block              */
	//判断事件控制块里面是否为空
        OS_ENTER_CRITICAL();                     /* Get a free queue control block                     */
		//进入临界区
        pq = OSQFreeList;
		//从OSQFreeList指针指向pq
        if (OSQFreeList != (OS_Q *)0) {
            OSQFreeList = OSQFreeList->OSQPtr;
			//检查OSQFreeList是否为零,不为零赋值为零。
        }
        OS_EXIT_CRITICAL();
		//退出临界区
        if (pq != (OS_Q *)0) {                   /* See if we were able to get a queue control block   */
		//判断pq是否有效
            pq->OSQStart        = start;         /* Yes, initialize the queue                          */
            pq->OSQEnd          = &start[size];
            pq->OSQIn           = start;
            pq->OSQOut          = start;
            pq->OSQSize         = size;
            pq->OSQEntries      = 0;
            pevent->OSEventType = OS_EVENT_TYPE_Q;
            pevent->OSEventPtr  = pq;
			//对队列的内容进行填充
            OSEventWaitListInit(pevent);
			//把设置好的队列添加进等待列表
        } else {                                 /* No,  since we couldn't get a queue control block   */
            OS_ENTER_CRITICAL();                 /* Return event control block on error                */
			//进入临界区
            pevent->OSEventPtr = (void *)OSEventFreeList;
			//OSEventPtr指向一个空的块
            OSEventFreeList    = pevent;
			//OSEventFreeList为空
            OS_EXIT_CRITICAL();
			//退出临界区
            pevent = (OS_EVENT *)0;
        }
    }
    return (pevent);
}
/*$PAGE*/
/*
*********************************************************************************************************
*                                           FLUSH QUEUE
*
* Description : This function is used to flush the contents of the message queue.
*
* Arguments   : none
*
* Returns     : OS_NO_ERR          upon success
*               OS_ERR_EVENT_TYPE  If you didn't pass a pointer to a queue
*********************************************************************************************************
*/
//允许用户删除一个消息队列中的所有消息,重新开始使用
INT8U OSQFlush (OS_EVENT *pevent) reentrant
{
    OS_Q  *pq;
    

    OS_ENTER_CRITICAL();
	//进入临界区
    if (pevent->OSEventType != OS_EVENT_TYPE_Q) {     /* Validate event block type                     */
        OS_EXIT_CRITICAL();
        return (OS_ERR_EVENT_TYPE);
		//如果类型不是队列,而退出临界区并返回错误码
    }
    pq             = pevent->OSEventPtr;              /* Point to queue storage structure              */
    pq->OSQIn      = pq->OSQStart;
    pq->OSQOut     = pq->OSQStart;
    pq->OSQEntries = 0;
	//把队列里面的东西进行初始化
    OS_EXIT_CRITICAL();
	//退出临界区
    return (OS_NO_ERR);
}

/*$PAGE*/
/*
*********************************************************************************************************
*                                      QUEUE MODULE INITIALIZATION
*
* Description : This function is called by uC/OS-II to initialize the message queue module.  Your
*               application MUST NOT call this function.
*
* Arguments   :  none
*
* Returns     : none
*********************************************************************************************************
*/
//队列初始化
void OSQInit (void) reentrant
{
    INT16U i;


    for (i = 0; i < (OS_MAX_QS - 1); i++) {      /* Init. list of free QUEUE control blocks            */
        OSQTbl[i].OSQPtr = &OSQTbl[i+1];
    }
	//初始化队列控制块
    OSQTbl[OS_MAX_QS - 1].OSQPtr = (OS_Q *)0;
	//队列的最后一个为零
    OSQFreeList                  = &OSQTbl[0];
	//队列的空块指向OSQTbl
}

/*$PAGE*/
/*
*********************************************************************************************************
*                                     PEND ON A QUEUE FOR A MESSAGE
*
* Description: This function waits for a message to be sent to a queue
*
* Arguments  : pevent        is a pointer to the event control block associated with the desired queue
*
*              timeout       is an optional timeout period (in clock ticks).  If non-zero, your task will
*                            wait for a message to arrive at the queue up to the amount of time 
*                            specified by this argument.  If you specify 0, however, your task will wait 
*                            forever at the specified queue or, until a message arrives.
*
*              err           is a pointer to where an error message will be deposited.  Possible error
*                            messages are:
*
*                            OS_NO_ERR         The call was successful and your task received a message.
*                            OS_TIMEOUT        A message was not received within the specified timeout
*                            OS_ERR_EVENT_TYPE You didn't pass a pointer to a queue
*                            OS_ERR_PEND_ISR    If you called this function from an ISR and the result
*                                               would lead to a suspension.
*
* Returns    : != (void *)0  is a pointer to the message received
*              == (void *)0  if no message was received or you didn't pass a pointer to a queue.
*********************************************************************************************************
*/
//队列等待
void *OSQPend (OS_EVENT *pevent, INT16U timeout, INT8U *err) reentrant
{
    void  *msg;
    OS_Q  *pq;


    OS_ENTER_CRITICAL();
	//进入临界区
    if (pevent->OSEventType != OS_EVENT_TYPE_Q) {/* Validate event block type                          */
        OS_EXIT_CRITICAL();
        *err = OS_ERR_EVENT_TYPE;
        return ((void *)0);
		//对事件的类型进行检查,如果不是队列,退出临界区并返回错误码
    }
    pq = pevent->OSEventPtr;                     /* Point at queue control block                       */
	//指针指向一个队列块
    if (pq->OSQEntries != 0) {                   /* See if any messages in the queue                   */
	//如果队列中有消息
        msg = *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();
        *err = OS_NO_ERR;
		//退出临界区并返回错误码
    } else if (OSIntNesting > 0) {               /* See if called from ISR ...                         */
        OS_EXIT_CRITICAL();                      /* ... can't PEND from an ISR                         */
        *err = OS_ERR_PEND_ISR;
		//如果存在中断发生,退出临界区并返回错误码
    } else {
        OSTCBCur->OSTCBStat    |= OS_STAT_Q;     /* Task will have to pend for a message to be posted  */
		//等到队列消息
        OSTCBCur->OSTCBDly      = timeout;       /* Load timeout into TCB                              */
		//设置超时时间
        OSEventTaskWait(pevent);                 /* Suspend task until event or timeout occurs         */
		//把任务添加等待列表
        OS_EXIT_CRITICAL();
		//退出临界区
        OSSched();                               /* Find next highest priority task ready to run       */
		//进行一次调度
        OS_ENTER_CRITICAL();
		//进入临界区
        if ((msg = OSTCBCur->OSTCBMsg) != (void *)0) {/* Did we get a message?                         */
		//判断是否收到了消息
            OSTCBCur->OSTCBMsg      = (void *)0;      /* Extract message from TCB (Put there by QPost) */
			//把OSTCBCur->OSTCBMsg 赋值为0
            OSTCBCur->OSTCBStat     = OS_STAT_RDY;
			//TCB块的状态改为OS_STAT_RDY
            OSTCBCur->OSTCBEventPtr = (OS_EVENT *)0;  /* No longer waiting for event                   */
			//OSTCBEventPtr清空
            OS_EXIT_CRITICAL();
            *err                    = OS_NO_ERR;
			//退出临界区并返回错误码
		
        } else if (OSTCBCur->OSTCBStat & OS_STAT_Q) { /* Timed out if status indicates pending on Q    */
		//如果TCB的状态是OS_STAT_Q
            OSEventTO(pevent);
			//超时直接进入运行,不再等待
            OS_EXIT_CRITICAL();
            msg                     = (void *)0;      /* No message received                           */
            *err                    = OS_TIMEOUT;     /* Indicate a timeout occured                    */
			//退出临界区并返回错误码
	
        } else {
            msg = *pq->OSQOut++;                      /* Extract message from 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 Q    */
                pq->OSQOut = pq->OSQStart;
				//如果队列头部等于尾部,重新把头尾移到头部
            }
            OSTCBCur->OSTCBEventPtr = (OS_EVENT *)0;
			//事件的指针指0
            OS_EXIT_CRITICAL();
            *err = OS_NO_ERR;
			//退出临界区并返回错误码
        }
    }                                                 
    return (msg);                                     /* Return message received (or NULL)             */
	//返回消息
}
/*$PAGE*/
/*
*********************************************************************************************************
*                                        POST MESSAGE TO A QUEUE
*
* Description: This function sends a message to a queue
*
* Arguments  : pevent        is a pointer to the event control block associated with the desired queue
*
*              msg           is a pointer to the message to send.  You MUST NOT send a NULL pointer.  
*
* Returns    : OS_NO_ERR          The call was successful and the message was sent
*              OS_Q_FULL          If the queue cannot accept any more messages because it is full.
*              OS_ERR_EVENT_TYPE  If you didn't pass a pointer to a queue.
*********************************************************************************************************
*/
//发送一个队列消息
INT8U OSQPost (OS_EVENT *pevent, void *msg) reentrant
{
    OS_Q   *pq;


    OS_ENTER_CRITICAL();
	//进入临界区
    if (pevent->OSEventType != OS_EVENT_TYPE_Q) {     /* Validate event block type                     */
        OS_EXIT_CRITICAL();
        return (OS_ERR_EVENT_TYPE);
		//如果不是队列,退出临界区并返回错误码
    }
    if (pevent->OSEventGrp) {                         /* See if any task pending on queue              */
	//判断是否有等待的任务
        OSEventTaskRdy(pevent, msg, OS_STAT_Q);       /* Ready highest priority task waiting on event  */
		//找出优先级最高的等待任务
        OS_EXIT_CRITICAL();
		//退出临界区
        OSSched();                                    /* Find highest priority task ready to run       */
        return (OS_NO_ERR);
		//退出临界区并返回错误码
    } else {
        pq = pevent->OSEventPtr;                      /* Point to queue control block                  */
		//指针指向队列的块
        if (pq->OSQEntries >= pq->OSQSize) {          /* Make sure queue is not full                   */
		//如果队列是否为空
            OS_EXIT_CRITICAL();
			 return (OS_Q_FULL);
			 //退出临界区并返回错误码
			
        } else {
            *pq->OSQIn++ = msg;                       /* 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_NO_ERR);
    }
}
/*$PAGE*/
/*
*********************************************************************************************************
*                                   POST MESSAGE TO THE FRONT OF A QUEUE
*
* Description: This function sends a message to a queue but unlike OSQPost(), the message is posted at
*              the front instead of the end of the queue.  Using OSQPostFront() allows you to send
*              'priority' messages.  
*
* Arguments  : pevent        is a pointer to the event control block associated with the desired queue
*
*              msg           is a pointer to the message to send.  You MUST NOT send a NULL pointer.  
*
* Returns    : OS_NO_ERR          The call was successful and the message was sent
*              OS_Q_FULL          If the queue cannot accept any more messages because it is full.
*              OS_ERR_EVENT_TYPE  If you didn't pass a pointer to a queue.
*********************************************************************************************************
*/
//将发送的消息插到消息队列的最前端
INT8U OSQPostFront (OS_EVENT *pevent, void *msg) reentrant
{
    OS_Q   *pq;


    OS_ENTER_CRITICAL();
	//进入临界区
    if (pevent->OSEventType != OS_EVENT_TYPE_Q) {     /* Validate event block type                     */
        OS_EXIT_CRITICAL();
        return (OS_ERR_EVENT_TYPE);
		//如果不是队列,退出临界区并返回错误码
    }
    if (pevent->OSEventGrp) {                         /* See if any task pending on queue              */
	//判断是否有任务在等待
        OSEventTaskRdy(pevent, msg, OS_STAT_Q);       /* Ready highest priority task waiting on event  */
		//找出优先级最高的任务
        OS_EXIT_CRITICAL();
		//退出临界区
        OSSched();                                    /* Find highest priority task ready to run       */
		//进行调度
        return (OS_NO_ERR);
		//返回错误码
    } else {
        pq = pevent->OSEventPtr;                      /* Point to queue control block                  */
		//队列指针指向队列控制块
        if (pq->OSQEntries >= pq->OSQSize) {          /* Make sure queue is not full                   */
		//如果队列为0
            OS_EXIT_CRITICAL();
			
            return (OS_Q_FULL);
			//退出临界区并返回错误码
        } else {
            if (pq->OSQOut == pq->OSQStart) {         /* Wrap OUT ptr if we are at the 1st queue entry */
                pq->OSQOut = pq->OSQEnd;
				//如果到队列的尾部了,重新移动到头部
            }
            pq->OSQOut--;
			//?????
            *pq->OSQOut = msg;                        /* Insert message into queue                     */
			//在队列中插入消息
            pq->OSQEntries++;                         /* Update the nbr of entries in the queue        */
			//数目依次加加
            OS_EXIT_CRITICAL();
			//退出临界区
        }
        return (OS_NO_ERR);
    }
}
/*$PAGE*/
/*
*********************************************************************************************************
*                                        QUERY A MESSAGE QUEUE
*
* Description: This function obtains information about a message queue.
*
* Arguments  : pevent        is a pointer to the event control block associated with the desired mailbox
*
*              pdata         is a pointer to a structure that will contain information about the message
*                            queue.
*
* Returns    : OS_NO_ERR          The call was successful and the message was sent
*              OS_ERR_EVENT_TYPE  If you are attempting to obtain data from a non queue.
*********************************************************************************************************
*/

INT8U OSQQuery (OS_EVENT *pevent, OS_Q_DATA *ppdata) reentrant
{
    OS_Q   *pq;
    INT8U   i;
    INT8U  *psrc;
    INT8U  *pdest;
    
    
    OS_ENTER_CRITICAL();
	//进入临界区
    if (pevent->OSEventType != OS_EVENT_TYPE_Q) {          /* Validate event block type                */
        OS_EXIT_CRITICAL();
        return (OS_ERR_EVENT_TYPE);
		//如果不是队列,退出临界区并返回错误码
    }
    ppdata->OSEventGrp = pevent->OSEventGrp;                /* Copy message mailbox wait list           */
    psrc              = &pevent->OSEventTbl[0];
    pdest             = &ppdata->OSEventTbl[0];
    //把消息直接复制到pevent
    for (i = 0; i < OS_EVENT_TBL_SIZE; i++) {
        *pdest++ = *psrc++;   
    }
    pq = (OS_Q *)pevent->OSEventPtr;
	//OSEventPtr指向pq
    if (pq->OSQEntries > 0) {
        ppdata->OSMsg = pq->OSQOut;                         /* Get next message to return if available  */
		//查询下一个消息
    } else {
        ppdata->OSMsg = (void *)0;
		//指针指向空
    }
    ppdata->OSNMsgs = pq->OSQEntries;
    ppdata->OSQSize = pq->OSQSize;
	//ppdata读取数目和尺寸
    OS_EXIT_CRITICAL();
	
    return (OS_NO_ERR);
	//退出临界区并返回错误码
}
#endif

猜你喜欢

转载自blog.csdn.net/m19930517/article/details/79258524