📄 queue.c
字号:
{
/* If there are no messages in the queue we may have to block. */
if( prvIsQueueEmpty( pxQueue ) )
{
/* There are no messages in the queue, do we want to block or just
leave with nothing? */
if( xTicksToWait > ( portTickType ) 0 )
{
vTaskPlaceOnEventList( &( pxQueue->xTasksWaitingToReceive ), xTicksToWait );
taskENTER_CRITICAL();
{
prvUnlockQueue( pxQueue );
if( !xTaskResumeAll() )
{
taskYIELD();
}
vTaskSuspendAll();
prvLockQueue( pxQueue );
}
taskEXIT_CRITICAL();
}
}
taskENTER_CRITICAL();
{
if( pxQueue->uxMessagesWaiting > ( unsigned portBASE_TYPE ) 0 )
{
pxQueue->pcReadFrom += pxQueue->uxItemSize;
if( pxQueue->pcReadFrom >= pxQueue->pcTail )
{
pxQueue->pcReadFrom = pxQueue->pcHead;
}
--( pxQueue->uxMessagesWaiting );
memcpy( ( void * ) pvBuffer, ( void * ) pxQueue->pcReadFrom, ( unsigned ) pxQueue->uxItemSize );
/* Increment the lock count so prvUnlockQueue knows to check for
tasks waiting for space to become available on the queue. */
++( pxQueue->xRxLock );
xReturn = pdPASS;
}
else
{
xReturn = errQUEUE_EMPTY;
}
}
taskEXIT_CRITICAL();
if( xReturn == errQUEUE_EMPTY )
{
if( xTicksToWait > 0 )
{
if( xTaskCheckForTimeOut( &xTimeOut, &xTicksToWait ) == pdFALSE )
{
xReturn = queueERRONEOUS_UNBLOCK;
}
}
}
} while( xReturn == queueERRONEOUS_UNBLOCK );
/* We no longer require exclusive access to the queue. */
prvUnlockQueue( pxQueue );
xTaskResumeAll();
return xReturn;
}
/*-----------------------------------------------------------*/
signed portBASE_TYPE xQueueReceiveFromISR( xQueueHandle pxQueue, void *pvBuffer, signed portBASE_TYPE *pxTaskWoken )
{
signed portBASE_TYPE xReturn;
/* We cannot block from an ISR, so check there is data available. */
if( pxQueue->uxMessagesWaiting > ( unsigned portBASE_TYPE ) 0 )
{
/* Copy the data from the queue. */
pxQueue->pcReadFrom += pxQueue->uxItemSize;
if( pxQueue->pcReadFrom >= pxQueue->pcTail )
{
pxQueue->pcReadFrom = pxQueue->pcHead;
}
--( pxQueue->uxMessagesWaiting );
memcpy( ( void * ) pvBuffer, ( void * ) pxQueue->pcReadFrom, ( unsigned ) pxQueue->uxItemSize );
/* If the queue is locked we will not modify the event list. Instead
we update the lock count so the task that unlocks the queue will know
that an ISR has removed data while the queue was locked. */
if( pxQueue->xRxLock == queueUNLOCKED )
{
/* We only want to wake one task per ISR, so check that a task has
not already been woken. */
if( !( *pxTaskWoken ) )
{
if( !listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToSend ) ) )
{
if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToSend ) ) != pdFALSE )
{
/* The task waiting has a higher priority than us so
force a context switch. */
*pxTaskWoken = pdTRUE;
}
}
}
}
else
{
/* Increment the lock count so the task that unlocks the queue
knows that data was removed while it was locked. */
++( pxQueue->xRxLock );
}
xReturn = pdPASS;
}
else
{
xReturn = pdFAIL;
}
return xReturn;
}
/*-----------------------------------------------------------*/
unsigned portBASE_TYPE uxQueueMessagesWaiting( xQueueHandle pxQueue )
{
unsigned portBASE_TYPE uxReturn;
taskENTER_CRITICAL();
uxReturn = pxQueue->uxMessagesWaiting;
taskEXIT_CRITICAL();
return uxReturn;
}
/*-----------------------------------------------------------*/
void vQueueDelete( xQueueHandle pxQueue )
{
vPortFree( pxQueue->pcHead );
vPortFree( pxQueue );
}
/*-----------------------------------------------------------*/
static void prvUnlockQueue( xQueueHandle pxQueue )
{
/* THIS FUNCTION MUST BE CALLED WITH THE SCHEDULER SUSPENDED. */
/* The lock counts contains the number of extra data items placed or
removed from the queue while the queue was locked. When a queue is
locked items can be added or removed, but the event lists cannot be
updated. */
taskENTER_CRITICAL();
{
--( pxQueue->xTxLock );
/* See if data was added to the queue while it was locked. */
if( pxQueue->xTxLock > queueUNLOCKED )
{
pxQueue->xTxLock = queueUNLOCKED;
/* Data was posted while the queue was locked. Are any tasks
blocked waiting for data to become available? */
if( !listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) )
{
/* Tasks that are removed from the event list will get added to
the pending ready list as the scheduler is still suspended. */
if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) != pdFALSE )
{
/* The task waiting has a higher priority so record that a
context switch is required. */
vTaskMissedYield();
}
}
}
}
taskEXIT_CRITICAL();
/* Do the same for the Rx lock. */
taskENTER_CRITICAL();
{
--( pxQueue->xRxLock );
if( pxQueue->xRxLock > queueUNLOCKED )
{
pxQueue->xRxLock = queueUNLOCKED;
if( !listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToSend ) ) )
{
if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToSend ) ) != pdFALSE )
{
vTaskMissedYield();
}
}
}
}
taskEXIT_CRITICAL();
}
/*-----------------------------------------------------------*/
static signed portBASE_TYPE prvIsQueueEmpty( const xQueueHandle pxQueue )
{
signed portBASE_TYPE xReturn;
taskENTER_CRITICAL();
xReturn = ( pxQueue->uxMessagesWaiting == ( unsigned portBASE_TYPE ) 0 );
taskEXIT_CRITICAL();
return xReturn;
}
/*-----------------------------------------------------------*/
static signed portBASE_TYPE prvIsQueueFull( const xQueueHandle pxQueue )
{
signed portBASE_TYPE xReturn;
taskENTER_CRITICAL();
xReturn = ( pxQueue->uxMessagesWaiting == pxQueue->uxLength );
taskEXIT_CRITICAL();
return xReturn;
}
/*-----------------------------------------------------------*/
#if configUSE_CO_ROUTINES == 1
signed portBASE_TYPE xQueueCRSend( xQueueHandle pxQueue, const void *pvItemToQueue, portTickType xTicksToWait )
{
signed portBASE_TYPE xReturn;
/* If the queue is already full we may have to block. A critical section
is required to prevent an interrupt removing something from the queue
between the check to see if the queue is full and blocking on the queue. */
portDISABLE_INTERRUPTS();
{
if( prvIsQueueFull( pxQueue ) )
{
/* The queue is full - do we want to block or just leave without
posting? */
if( xTicksToWait > ( portTickType ) 0 )
{
/* As this is called from a coroutine we cannot block directly, but
return indicating that we need to block. */
vCoRoutineAddToDelayedList( xTicksToWait, &( pxQueue->xTasksWaitingToSend ) );
portENABLE_INTERRUPTS();
return errQUEUE_BLOCKED;
}
else
{
portENABLE_INTERRUPTS();
return errQUEUE_FULL;
}
}
}
portENABLE_INTERRUPTS();
portNOP();
portDISABLE_INTERRUPTS();
{
if( pxQueue->uxMessagesWaiting < pxQueue->uxLength )
{
/* There is room in the queue, copy the data into the queue. */
prvCopyQueueData( pxQueue, pvItemToQueue );
xReturn = pdPASS;
/* Were any co-routines waiting for data to become available? */
if( !listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) )
{
/* In this instance the co-routine could be placed directly
into the ready list as we are within a critical section.
Instead the same pending ready list mechansim is used as if
the event were caused from within an interrupt. */
if( xCoRoutineRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) != pdFALSE )
{
/* The co-routine waiting has a higher priority so record
that a yield might be appropriate. */
xReturn = errQUEUE_YIELD;
}
}
}
else
{
xReturn = errQUEUE_FULL;
}
}
portENABLE_INTERRUPTS();
return xReturn;
}
#endif
/*-----------------------------------------------------------*/
#if configUSE_CO_ROUTINES == 1
signed portBASE_TYPE xQueueCRReceive( xQueueHandle pxQueue, void *pvBuffer, portTickType xTicksToWait )
{
signed portBASE_TYPE xReturn;
/* If the queue is already empty we may have to block. A critical section
is required to prevent an interrupt adding something to the queue
between the check to see if the queue is empty and blocking on the queue. */
portDISABLE_INTERRUPTS();
{
if( prvIsQueueEmpty( pxQueue ) )
{
/* There are no messages in the queue, do we want to block or just
leave with nothing? */
if( xTicksToWait > ( portTickType ) 0 )
{
/* As this is a co-routine we cannot block directly, but return
indicating that we need to block. */
vCoRoutineAddToDelayedList( xTicksToWait, &( pxQueue->xTasksWaitingToReceive ) );
portENABLE_INTERRUPTS();
return errQUEUE_BLOCKED;
}
else
{
portENABLE_INTERRUPTS();
return errQUEUE_FULL;
}
}
}
portENABLE_INTERRUPTS();
portNOP();
portDISABLE_INTERRUPTS();
{
if( pxQueue->uxMessagesWaiting > ( unsigned portBASE_TYPE ) 0 )
{
/* Data is available from the queue. */
pxQueue->pcReadFrom += pxQueue->uxItemSize;
if( pxQueue->pcReadFrom >= pxQueue->pcTail )
{
pxQueue->pcReadFrom = pxQueue->pcHead;
}
--( pxQueue->uxMessagesWaiting );
memcpy( ( void * ) pvBuffer, ( void * ) pxQueue->pcReadFrom, ( unsigned ) pxQueue->uxItemSize );
xReturn = pdPASS;
/* Were any co-routines waiting for space to become available? */
if( !listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToSend ) ) )
{
/* In this instance the co-routine could be placed directly
into the ready list as we are within a critical section.
Instead the same pending ready list mechansim is used as if
the event were caused from within an interrupt. */
if( xCoRoutineRemoveFromEventList( &( pxQueue->xTasksWaitingToSend ) ) != pdFALSE )
{
xReturn = errQUEUE_YIELD;
}
}
}
else
{
xReturn = pdFAIL;
}
}
portENABLE_INTERRUPTS();
return xReturn;
}
#endif
/*-----------------------------------------------------------*/
#if configUSE_CO_ROUTINES == 1
signed portBASE_TYPE xQueueCRSendFromISR( xQueueHandle pxQueue, const void *pvItemToQueue, signed portBASE_TYPE xCoRoutinePreviouslyWoken )
{
/* Cannot block within an ISR so if there is no space on the queue then
exit without doing anything. */
if( pxQueue->uxMessagesWaiting < pxQueue->uxLength )
{
prvCopyQueueData( pxQueue, pvItemToQueue );
/* We only want to wake one co-routine per ISR, so check that a
co-routine has not already been woken. */
if( !xCoRoutinePreviouslyWoken )
{
if( !listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) )
{
if( xCoRoutineRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) != pdFALSE )
{
return pdTRUE;
}
}
}
}
return xCoRoutinePreviouslyWoken;
}
#endif
/*-----------------------------------------------------------*/
#if configUSE_CO_ROUTINES == 1
signed portBASE_TYPE xQueueCRReceiveFromISR( xQueueHandle pxQueue, void *pvBuffer, signed portBASE_TYPE *pxCoRoutineWoken )
{
signed portBASE_TYPE xReturn;
/* We cannot block from an ISR, so check there is data available. If
not then just leave without doing anything. */
if( pxQueue->uxMessagesWaiting > ( unsigned portBASE_TYPE ) 0 )
{
/* Copy the data from the queue. */
pxQueue->pcReadFrom += pxQueue->uxItemSize;
if( pxQueue->pcReadFrom >= pxQueue->pcTail )
{
pxQueue->pcReadFrom = pxQueue->pcHead;
}
--( pxQueue->uxMessagesWaiting );
memcpy( ( void * ) pvBuffer, ( void * ) pxQueue->pcReadFrom, ( unsigned ) pxQueue->uxItemSize );
if( !( *pxCoRoutineWoken ) )
{
if( !listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToSend ) ) )
{
if( xCoRoutineRemoveFromEventList( &( pxQueue->xTasksWaitingToSend ) ) != pdFALSE )
{
*pxCoRoutineWoken = pdTRUE;
}
}
}
xReturn = pdPASS;
}
else
{
xReturn = pdFAIL;
}
return xReturn;
}
#endif
/*-----------------------------------------------------------*/
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -