逐字逐句解析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

  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
\SOFTWARE The main directory from the root where all software-related files are placed. \SOFTWARE\BLOCKS The main directory where all ‘Building Blocks’ are located. With μC/OS-II, I included a ‘building block’ that handles DOS-type compatible functions that are used by the example code. \SOFTWARE\BLOCKS\TO This directory contains the files for the TO utility (see Appendix E, TO). The source file is TO.C and is found in the \SOFTWARE\TO\SOURCE directory. The DOS executable file (TO.EXE) is found in the \SOFTWARE\TO\EXE directory. Note that TO requires a file called TO.TBL which must reside on your root directory. An example of TO.TBL is also found in the \SOFTWARE\TO\EXE directory. You will need to move TO.TBL to the root directory if you are to use TO.EXE. \SOFTWARE\uCOS-II The main directory where all μC/OS-II files are located. \SOFTWARE\uCOS-II\EX1_x86L This directory contains the source code for EXAMPLE #1 (see section 1.07, Example #1) which is intended to run under DOS (or a DOS window under Windows 95). \SOFTWARE\uCOS-II\EX2_x86L This directory contains the source code for EXAMPLE #2 (see section 1.08, Example #2) which is intended to run under DOS (or a DOS window under Windows 95). \SOFTWARE\uCOS-II\EX3_x86L This directory contains the source code for EXAMPLE #3 (see section 1.09, Example #3) which is intended to run under DOS (or a DOS window under Windows 95). \SOFTWARE\uCOS-II\Ix86L This directory contains the source code for the processor dependent code (a.k.a. the port) of μC/OS-II for an 80x86 Real-Mode, Large Model processor. \SOFTWARE\uCOS-II\SOURCE This directory contains the source code for processor independent portion of μC/OS-II. This code is fully portable to other processor architectures.
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值