BaseType_t xQueueGenericReceive( QueueHandle_t xQueue, void * const pvBuffer, TickType_t xTicksToWait, const BaseType_t xJustPeeking )
{ //出队:xQueue:操作的队列的句柄 pvBuffer:缓冲区 xTicksToWait:等待时间 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 return
statements within the function itself. This is done in the interest
of execution time efficiency. */
for( ;; )
{
taskENTER_CRITICAL(); //进入临界区
{
const UBaseType_t uxMessagesWaiting = pxQueue->uxMessagesWaiting; //uxMessagesWaiting储存队列中的数据数量
/* Is there data in the queue now? To be running the calling task
must be the highest priority task wanting to access the queue. */
if( uxMessagesWaiting > ( UBaseType_t ) 0 ) //如果队列中有数据
{
/* Remember the read position in case the queue is only being
peeked. */
pcOriginalReadPosition = pxQueue->u.pcReadFrom; //记录读取队列的位置
prvCopyDataFromQueue( pxQueue, pvBuffer ); //将数据拷贝到缓冲区中
if( xJustPeeking == pdFALSE ) //如果读取后需要删除掉
{
traceQUEUE_RECEIVE( pxQueue );
/* Actually removing data, not just peeking. */
pxQueue->uxMessagesWaiting = uxMessagesWaiting - 1; //将队列中数据数量减一
#if ( configUSE_MUTEXES == 1 ) //如果是互斥信号量
{
if( pxQueue->uxQueueType == queueQUEUE_IS_MUTEX ) //如果是互斥信号量
{
/* Record the information required to implement
priority inheritance should it become necessary. */
pxQueue->pxMutexHolder = ( int8_t * ) pvTaskIncrementMutexHeldCount(); /*lint !e961 Cast is not redundant as TaskHandle_t is a typedef. */
} //标记谁获取了互斥信号量的钥匙,并且将此任务的uxMutexesHeld加1
//uxMutexesHeld表示任务拥有互斥信号量的钥匙的数量,一个任务可能获取多个互斥信号量
else
{
mtCOVERAGE_TEST_MARKER();
}
}
#endif /* configUSE_MUTEXES */
if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToSend ) ) == pdFALSE )
{ //出队之后看是不是有没有任务等待入队而阻塞
if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToSend ) ) != pdFALSE )
{ //有阻塞的任务的话将此任务解除从阻塞列表中移除,并判断是不是要进行任务切换
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 read
pointer. */
pxQueue->u.pcReadFrom = pcOriginalReadPosition; //重置读取队列的位置
/* The data is being left in the queue, so see if there are
any 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 (or
the block time has expired) so leave now. */
taskEXIT_CRITICAL(); //不等待的话直接退出
traceQUEUE_RECEIVE_FAILED( pxQueue );
return errQUEUE_EMPTY; //返回队列空
}
else if( xEntryTimeSet == pdFALSE ) //等待时间不为0的情况下如果时间结构体没有初始化
{
/* The queue was empty and a block time was specified so
configure the timeout structure. */
vTaskSetTimeOutState( &xTimeOut ); //初始化时间结构体
xEntryTimeSet = pdTRUE;
}
else //等待时间不为0并且时间结构体已经初始化
{
/* Entry time was already set. */
mtCOVERAGE_TEST_MARKER(); //继续操作
}
}
}
taskEXIT_CRITICAL(); //退出临界区
/* Interrupts and other tasks can send to and receive from the queue
now 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 ); //执行到这里说明队列是空的也就是
//互斥信号量的钥匙在其他任务那里
//vTaskPriorityInherit用于判断当前任务的优先级
//是否比拥有钥匙的那个任务的优先级高
//如果是则进行优先级继承使拥有钥匙的任务尽快完成归还钥匙
//从而避免优先级反转的情况
}
taskEXIT_CRITICAL(); //退出临界区
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
#endif
vTaskPlaceOnEventList( &( 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();
if( prvIsQueueEmpty( pxQueue ) != pdFALSE )
{
traceQUEUE_RECEIVE_FAILED( pxQueue );
return errQUEUE_EMPTY;
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
}
}
freeRtos中读队列函数xQueueGenericReceive解析
最新推荐文章于 2023-09-21 18:07:19 发布