//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
逐字逐句解析ucos ii 源代码-》OS_Q.C
猜你喜欢
转载自blog.csdn.net/m19930517/article/details/79258524
今日推荐
周排行