typedefstructQueueDefinition{int8_t*pcHead;/* 指向队列存储区头*/int8_t*pcTail;/* 指向队列存储区尾*/int8_t*pcWriteTo;/* 指向存储区中下一个空闲区域 */union/* Use of a union is an exception to the coding standard to ensure two mutually exclusive structure members don't appear simultaneously (wasting RAM). */{int8_t*pcReadFrom;/*<当结构用作队列时,指向最后一个出队的队列项首地址 */UBaseType_t uxRecursiveCallCount;/* 当用作递归互斥量的时候用来记录递归互斥量被调用的次数 */ List_t xTasksWaitingToSend;/* 等待发送任务列表 */List_t xTasksWaitingToReceive;/* 等待接收任务列表 */volatile UBaseType_t uxMessagesWaiting;/* 队列中当前队列项数量(消息数) */UBaseType_t uxLength;/* 创建队列时指定的队列长度 */UBaseType_t uxItemSize;/* 创建队列时指定的每个队列项(消息)最大长度*/volatile BaseType_t xRxLock;/* 当队列上锁后用来统计从队列中接收到(出队的)的队列项数量,若未上锁为queueUNLOCKED*/volatile BaseType_t xTxLock;/* 当队列上锁后用来统计发送到(入队的)队列中的队列项数量,若未上锁为queueUNLOCKED */#if( configUSE_TRACE_FACILITY ==1)/* 跟踪调试相关宏 */UBaseType_t uxQueueNumber;uint8_t ucQueueType;#endif#if( configUSE_QUEUE_SETS ==1)/* 队列集相关宏 */structQueueDefinition*pxQueueSetContainer;#endif} xQUEUE;/* The old xQUEUE name is maintained above then typedefed to the new Queue_t
name below to enable the use of older kernel aware debuggers. */typedef xQUEUE Queue_t;
2.创建队列 xQueueGenericCreate
#definexQueueCreate( uxQueueLength, uxItemSize )xQueueGenericCreate( uxQueueLength, uxItemSize, queueQUEUE_TYPE_BASE )```c
QueueHandle_t xQueueGenericCreate(const UBaseType_t uxQueueLength,const UBaseType_t uxItemSize,constuint8_t ucQueueType ){
Queue_t *pxNewQueue;size_t xQueueSizeInBytes;
QueueHandle_t xReturn =NULL;/* Remove compiler warnings about unused parameters shouldconfigUSE_TRACE_FACILITY not be set to 1. */(void) ucQueueType;configASSERT( uxQueueLength >( UBaseType_t )0);/* 如果队列项大小为0,就不需要存储区 */if( uxItemSize ==( UBaseType_t )0){/* There is not going to be a queue storage area. */xQueueSizeInBytes =(size_t)0;}else{/* The queue is one byte longer than asked for to make wrap checkingeasier/faster. *//* 数量乘以单个队列项大小,就是消息存储区的大小 */xQueueSizeInBytes =(size_t)( uxQueueLength * uxItemSize )+(size_t)1;/*lint !e961 MISRA exception as the casts are only redundant for some ports. */}/* Allocate the new queue structure and storage area. *//* 分配新的队列结构和存储区域 */pxNewQueue =( Queue_t *)pvPortMalloc(sizeof( Queue_t )+ xQueueSizeInBytes );if( pxNewQueue !=NULL)//内存申请成功{if( uxItemSize ==( UBaseType_t )0)/* 若队列项长度为0,说明没有队列存储区 */{/* No RAM was allocated for the queue storage area, but PC headcannot be set to NULL because NULL is used as a key to say the queueis used as a mutex. Therefore just set pcHead to point to the queueas a benign value that is known to be within the memory map. */pxNewQueue->pcHead =(int8_t*) pxNewQueue;/*只需将pcHead设置为指向队列*/}else{/* Jump past the queue structure to find the location of the queuestorage area. *//* 把队列空间首地址指向队列项存储区首地址 */pxNewQueue->pcHead =((int8_t*) pxNewQueue )+sizeof( Queue_t );}/* Initialise the queue members as described above where the queue typeis defined. *//* 初始化队列结构体相关成员变量 */pxNewQueue->uxLength = uxQueueLength;pxNewQueue->uxItemSize = uxItemSize;/* 队列复位函数*/(void)xQueueGenericReset( pxNewQueue, pdTRUE );#if( configUSE_TRACE_FACILITY ==1){pxNewQueue->ucQueueType = ucQueueType;}#endif/* configUSE_TRACE_FACILITY */#if( configUSE_QUEUE_SETS ==1){pxNewQueue->pxQueueSetContainer =NULL;}#endif/* configUSE_QUEUE_SETS */traceQUEUE_CREATE( pxNewQueue );xReturn = pxNewQueue;}else{mtCOVERAGE_TEST_MARKER();}configASSERT( xReturn );return xReturn;}BaseType_t xQueueGenericReset( QueueHandle_t xQueue, BaseType_t xNewQueue ){
Queue_t *const pxQueue =( Queue_t *) xQueue;configASSERT( pxQueue );/* 进入临界段 */taskENTER_CRITICAL();{/* 初始化队列相关成员变量*/pxQueue->pcTail = pxQueue->pcHead +( pxQueue->uxLength * pxQueue->uxItemSize );pxQueue->uxMessagesWaiting =( UBaseType_t )0U;pxQueue->pcWriteTo = pxQueue->pcHead;pxQueue->u.pcReadFrom = pxQueue->pcHead +(( pxQueue->uxLength -( UBaseType_t )1U)* pxQueue->uxItemSize );pxQueue->xRxLock = queueUNLOCKED;pxQueue->xTxLock = queueUNLOCKED;/* 判断是否为新建队列 */if( xNewQueue == pdFALSE ){/* If there are tasks blocked waiting to read from the queue, thenthe tasks will remain blocked as after this function exits the queuewill still be empty. If there are tasks blocked waiting to write tothe queue, then one should be unblocked as after this function exitsit will be possible to write to it. *//* 判断发送等待列表里面是否有任务 */if(listLIST_IS_EMPTY(&( pxQueue->xTasksWaitingToSend ))== pdFALSE ){/* 移除事件列表中的任务 */if(xTaskRemoveFromEventList(&( pxQueue->xTasksWaitingToSend ))== pdTRUE ){/* 进行上下文切 */queueYIELD_IF_USING_PREEMPTION();}else{mtCOVERAGE_TEST_MARKER();}}else{mtCOVERAGE_TEST_MARKER();}}else{/* Ensure the event queues start in the correct state. *//* 若是新建队列,则直接初始化发送和接受列表项 */vListInitialise(&( pxQueue->xTasksWaitingToSend ));vListInitialise(&( pxQueue->xTasksWaitingToReceive ));}}taskEXIT_CRITICAL();/* A value is returned for calling semantic consistency with previousversions. */return pdPASS;}
3.入队列 xQueueGenericSend
BaseType_t xQueueGenericSend( QueueHandle_t xQueue,constvoid*const pvItemToQueue, TickType_t xTicksToWait,const BaseType_t xCopyPosition ){
BaseType_t xEntryTimeSet = pdFALSE, xYieldRequired;
TimeOut_t xTimeOut;
Queue_t *const pxQueue =( Queue_t *) xQueue;configASSERT( pxQueue );configASSERT(!(( pvItemToQueue ==NULL)&&( pxQueue->uxItemSize !=( UBaseType_t )0U)));configASSERT(!(( xCopyPosition == queueOVERWRITE )&&( pxQueue->uxLength !=1)));#if(( INCLUDE_xTaskGetSchedulerState ==1)||( configUSE_TIMERS ==1)){configASSERT(!((xTaskGetSchedulerState()== taskSCHEDULER_SUSPENDED )&&( xTicksToWait !=0)));}#endif/* This function relaxes the coding standard somewhat to allow returnstatements within the function itself. This is done in the interestof execution time efficiency. */for(;;){taskENTER_CRITICAL();//进入了临界段{/* Is there room on the queue now? The running task must be thehighest priority task wanting to access the queue. If the head itemin the queue is to be overwritten then it does not matter if thequeue is full. *//* 判断消息队列是否满了以及是否允许覆盖入队,任一条件成立都执行入队操作 */if(( pxQueue->uxMessagesWaiting < pxQueue->uxLength )||( xCopyPosition == queueOVERWRITE )){traceQUEUE_SEND( pxQueue );/* 拷贝数据到队列操作空间内 */xYieldRequired =prvCopyDataToQueue( pxQueue, pvItemToQueue, xCopyPosition );#if( configUSE_QUEUE_SETS ==1)//队列集{if( pxQueue->pxQueueSetContainer !=NULL){if(prvNotifyQueueSetContainer( pxQueue, xCopyPosition )== pdTRUE ){/* The queue is a member of a queue set, and postingto the queue set caused a higher priority task tounblock. A context switch is required. */queueYIELD_IF_USING_PREEMPTION();}else{mtCOVERAGE_TEST_MARKER();}}else{/* If there was a task waiting for data to arrive on thequeue then unblock it now. */if(listLIST_IS_EMPTY(&( pxQueue->xTasksWaitingToReceive ))== pdFALSE ){if(xTaskRemoveFromEventList(&( pxQueue->xTasksWaitingToReceive ))== pdTRUE ){/* The unblocked task has a priority higher thanour own so yield immediately. Yes it is ok todo this from within the critical section - thekernel takes care of that. */queueYIELD_IF_USING_PREEMPTION();}else{mtCOVERAGE_TEST_MARKER();}}elseif( xYieldRequired != pdFALSE ){/* This path is a special case that will only getexecuted if the task was holding multiple mutexesand the mutexes were given back in an order that isdifferent to that in which they were taken. */queueYIELD_IF_USING_PREEMPTION();}else{mtCOVERAGE_TEST_MARKER();}}}#else/* configUSE_QUEUE_SETS */{/* If there was a task waiting for data to arrive on thequeue then unblock it now. *//* 判断等待接收的列表是否为空. */if(listLIST_IS_EMPTY(&( pxQueue->xTasksWaitingToReceive ))== pdFALSE ){/* 若不为空,表示有任务由于请求消息而阻塞,则改变阻塞态为就绪态. */if(xTaskRemoveFromEventList(&( pxQueue->xTasksWaitingToReceive ))== pdTRUE ){/* The unblocked task has a priority higher thanour own so yield immediately. Yes it is ok to dothis from within the critical section - the kerneltakes care of that. *//* 进行上下文切换*/queueYIELD_IF_USING_PREEMPTION();}else{mtCOVERAGE_TEST_MARKER();}}elseif( xYieldRequired != pdFALSE )//等待接收的列表不为空{/* This path is a special case that will only getexecuted if the task was holding multiple mutexes andthe mutexes were given back in an order that isdifferent to that in which they were taken. *//* 进行上下文切换*/queueYIELD_IF_USING_PREEMPTION();}else{mtCOVERAGE_TEST_MARKER();}}#endif/* configUSE_QUEUE_SETS */taskEXIT_CRITICAL();//退出临界return pdPASS;}else//队列已满{/* 为0表示,表示没有阻塞时间 */if( xTicksToWait ==( TickType_t )0){/* The queue was full and no block time is specified (orthe block time has expired) so leave now. */taskEXIT_CRITICAL();//退出临界段/* Return to the original privilege level before exitingthe function. */traceQUEUE_SEND_FAILED( pxQueue );return errQUEUE_FULL;//返回队列已满}elseif( xEntryTimeSet == pdFALSE ){/* The queue was full and a block time was specified soconfigure the timeout structure. *//* 若有阻塞时间,就初始化时间结构体*/vTaskSetTimeOutState(&xTimeOut );xEntryTimeSet = pdTRUE;}else{/* Entry time was already set. *//* 时间结构体已经初始化过了 */mtCOVERAGE_TEST_MARKER();}}}taskEXIT_CRITICAL();//退出临界段/* Interrupts and other tasks can send to and receive from the queuenow the critical section has been exited. *//* 当前队列已满,并且设置了不为0的阻塞时间 */vTaskSuspendAll();//挂起任务调度器prvLockQueue( pxQueue );//给队列上锁/* Update the timeout state to see if it has expired yet. *//* 判断阻塞时间是否超时了 */if(xTaskCheckForTimeOut(&xTimeOut,&xTicksToWait )== pdFALSE ){/* 若未超时则判断队列是否还是满的 */if(prvIsQueueFull( pxQueue )!= pdFALSE ){//队列满/* 若此时队仍满且未超时,则把当前任务添加到等待发送的事件列表和延时列表中去*/traceBLOCKING_ON_QUEUE_SEND( pxQueue );vTaskPlaceOnEventList(&( pxQueue->xTasksWaitingToSend ), xTicksToWait );/* Unlocking the queue means queue events can effect theevent list. It is possible that interrupts occurring nowremove this task from the event list again - but as thescheduler is suspended the task will go onto the pendingready last instead of the actual ready list. */prvUnlockQueue( pxQueue );//解锁队列/* Resuming the scheduler will move tasks from the pendingready list into the ready list - so it is feasible that thistask is already in a ready list before it yields - in whichcase the yield will not cause a context switch unless thereis also a higher priority task in the pending ready list. */if(xTaskResumeAll()== pdFALSE ){//恢复任务调度器{portYIELD_WITHIN_API();;//进行上下文切换}}else{/* Try again. *///队列未满,未超时prvUnlockQueue( pxQueue );(void)xTaskResumeAll();}}else{/* The timeout has expired. *//* 若已超时,则解锁队列,恢复任务调度器 */prvUnlockQueue( pxQueue );(void)xTaskResumeAll();/* Return to the original privilege level before exiting thefunction. */traceQUEUE_SEND_FAILED( pxQueue );return errQUEUE_FULL;}}}
4.出队列 xQueueGenericReceive
BaseType_t xQueueGenericReceive( QueueHandle_t xQueue,void*const pvBuffer, TickType_t xTicksToWait,const BaseType_t xJustPeeking ){
BaseType_t xEntryTimeSet = pdFALSE;
TimeOut_t xTimeOut;int8_t*pcOriginalReadPosition;
Queue_t *const pxQueue =( Queue_t *) xQueue;configASSERT( pxQueue );configASSERT(!(( pvBuffer ==NULL)&&( pxQueue->uxItemSize !=( UBaseType_t )0U)));#if(( INCLUDE_xTaskGetSchedulerState ==1)||( configUSE_TIMERS ==1)){configASSERT(!((xTaskGetSchedulerState()== taskSCHEDULER_SUSPENDED )&&( xTicksToWait !=0)));}#endif/* This function relaxes the coding standard somewhat to allow returnstatements within the function itself. This is done in the interestof execution time efficiency. */for(;;){taskENTER_CRITICAL();//进入临界区{/* Is there data in the queue now? To be running the calling taskmust be the highest priority task wanting to access the queue. *//* //判断队列中是否有数据*/if( pxQueue->uxMessagesWaiting >( UBaseType_t )0)//有数据{/* Remember the read position in case the queue is only beingpeeked. */pcOriginalReadPosition = pxQueue->u.pcReadFrom;//记录读取队列的位置/*将数据拷贝到缓冲区中*/prvCopyDataFromQueue( pxQueue, pvBuffer );if( xJustPeeking == pdFALSE )//如果读取后需要删除掉{traceQUEUE_RECEIVE( pxQueue );/* Actually removing data, not just peeking. */--( pxQueue->uxMessagesWaiting );//将队列中数据数量减一#if( configUSE_MUTEXES ==1)//如果是互斥信号量{if( pxQueue->uxQueueType == queueQUEUE_IS_MUTEX ){/* Record the information required to implementpriority inheritance should it become necessary. */pxQueue->pxMutexHolder =(int8_t*)pvTaskIncrementMutexHeldCount();/*lint !e961 Cast is not redundant as TaskHandle_t is a typedef. */}else{mtCOVERAGE_TEST_MARKER();}}#endif/* configUSE_MUTEXES *//* 队里中的发送链表是否为空*/if(listLIST_IS_EMPTY(&( pxQueue->xTasksWaitingToSend ))== pdFALSE )//不为空{/*从对应事件表或状态表删除并加入就绪表或挂起就绪表 */if(xTaskRemoveFromEventList(&( pxQueue->xTasksWaitingToSend ))== pdTRUE ){queueYIELD_IF_USING_PREEMPTION();//发起调度}else{mtCOVERAGE_TEST_MARKER();}}else{mtCOVERAGE_TEST_MARKER();}}else//读取后不需要删除掉{traceQUEUE_PEEK( pxQueue );/* The data is not being removed, so reset the readpointer. */pxQueue->u.pcReadFrom = pcOriginalReadPosition;//记录读取队列的位置/* The data is being left in the queue, so see if there areany other tasks waiting for the data. *//* 队里中的发送链表是否为空*/if(listLIST_IS_EMPTY(&( pxQueue->xTasksWaitingToReceive ))== pdFALSE ){if(xTaskRemoveFromEventList(&( pxQueue->xTasksWaitingToReceive ))!= pdFALSE ){/* The task waiting has a higher priority than this task. */queueYIELD_IF_USING_PREEMPTION();}else{mtCOVERAGE_TEST_MARKER();}}else{mtCOVERAGE_TEST_MARKER();}}taskEXIT_CRITICAL();return pdPASS;}else//如果队列中没有数据{if( xTicksToWait ==( TickType_t )0)//如果等待时间为0表示不等待{/* The queue was empty and no block time is specified (orthe block time has expired) so leave now. */taskEXIT_CRITICAL();traceQUEUE_RECEIVE_FAILED( pxQueue );return errQUEUE_EMPTY;//返回队列空}elseif( xEntryTimeSet == pdFALSE )//等待时间不为0的情况下如果时间结构体没有初始化{/* The queue was empty and a block time was specified soconfigure the timeout structure. */vTaskSetTimeOutState(&xTimeOut );//初始化时间结构体xEntryTimeSet = pdTRUE;}else{/* Entry time was already set. */mtCOVERAGE_TEST_MARKER();}}}taskEXIT_CRITICAL();/* Interrupts and other tasks can send to and receive from the queuenow the critical section has been exited. */vTaskSuspendAll();//暂停任务调度并给队列上锁prvLockQueue( pxQueue );//执行到这里说明队列不是空的并且等待时间不是0/* Update the timeout state to see if it has expired yet. */if(xTaskCheckForTimeOut(&xTimeOut,&xTicksToWait )== pdFALSE )//检查是否超时,返回pdFALSE表示还没超过//没超过的话就将任务添加到xTasksWaitingToReceive列表中{if(prvIsQueueEmpty( pxQueue )!= pdFALSE )//如果队列是空的{traceBLOCKING_ON_QUEUE_RECEIVE( pxQueue );#if( configUSE_MUTEXES ==1)//表示这是互斥信号量{if( pxQueue->uxQueueType == queueQUEUE_IS_MUTEX ){taskENTER_CRITICAL();{vTaskPriorityInherit((void*) pxQueue->pxMutexHolder );}taskEXIT_CRITICAL();}else{mtCOVERAGE_TEST_MARKER();}}#endifvTaskPlaceOnEventList(&( pxQueue->xTasksWaitingToReceive ), xTicksToWait );//将等待的任务添加到xTasksWaitingToReceive列表中prvUnlockQueue( pxQueue );//解锁队列if(xTaskResumeAll()== pdFALSE ){portYIELD_WITHIN_API();//任务切换}else{mtCOVERAGE_TEST_MARKER();}}else{/* Try again. *///队列不是空的就解锁队列再试一次prvUnlockQueue( pxQueue );(void)xTaskResumeAll();}}else//等待时间超过了直接返回{prvUnlockQueue( pxQueue );(void)xTaskResumeAll();traceQUEUE_RECEIVE_FAILED( pxQueue );return errQUEUE_EMPTY;}}}