📄 queue.c
字号:
/* There is room in the queue, copy the data into the queue. */
prvCopyQueueData( pxQueue, pvItemToQueue );
xReturn = pdPASS;
/* Update the TxLock count so prvUnlockQueue knows to check for
tasks waiting for data to become available in the queue. */
++( pxQueue->xTxLock );
}
else
{
xReturn = errQUEUE_FULL;
}
}
taskEXIT_CRITICAL();
/* We no longer require exclusive access to the queue. prvUnlockQueue
will remove any tasks suspended on a receive if either this function
or an ISR has posted onto the queue. */
if( prvUnlockQueue( pxQueue ) )
{
/* Resume the scheduler - making ready any tasks that were woken
by an event while the scheduler was locked. Resuming the
scheduler may cause a yield, in which case there is no point
yielding again here. */
if( !xTaskResumeAll() )
{
taskYIELD();
}
}
else
{
/* Resume the scheduler - making ready any tasks that were woken
by an event while the scheduler was locked. */
xTaskResumeAll();
}
return xReturn;
}
/*-----------------------------------------------------------*/
signed portBASE_TYPE xQueueSendFromISR( xQueueHandle pxQueue, const void *pvItemToQueue, signed portBASE_TYPE xTaskPreviouslyWoken )
{
/* Similar to xQueueSend, except we don't block if there is no room in the
queue. Also we don't directly wake a task that was blocked on a queue
read, instead we return a flag to say whether a context switch is required
or not (i.e. has a task with a higher priority than us been woken by this
post). */
if( pxQueue->uxMessagesWaiting < pxQueue->uxLength )
{
prvCopyQueueData( pxQueue, pvItemToQueue );
/* If the queue is locked we do not alter the event list. This will
be done when the queue is unlocked later. */
if( pxQueue->xTxLock == queueUNLOCKED )
{
/* We only want to wake one task per ISR, so check that a task has
not already been woken. */
if( !xTaskPreviouslyWoken )
{
if( !listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) )
{
if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) != pdFALSE )
{
/* The task waiting has a higher priority so record that a
context switch is required. */
return pdTRUE;
}
}
}
}
else
{
/* Increment the lock count so the task that unlocks the queue
knows that data was posted while it was locked. */
++( pxQueue->xTxLock );
}
}
return xTaskPreviouslyWoken;
}
/*-----------------------------------------------------------*/
signed portBASE_TYPE xQueueReceive( xQueueHandle pxQueue, void *pcBuffer, portTickType xTicksToWait )
{
signed portBASE_TYPE xReturn;
/* This function is very similar to xQueueSend(). See comments within
xQueueSend() for a more detailed explanation.
Make sure other tasks do not access the queue. */
vTaskSuspendAll();
/* Make sure interrupts do not access the queue. */
prvLockQueue( pxQueue );
/* 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 * ) pcBuffer, ( 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 = pdFAIL;
}
}
taskEXIT_CRITICAL();
/* We no longer require exclusive access to the queue. */
if( prvUnlockQueue( pxQueue ) )
{
if( !xTaskResumeAll() )
{
taskYIELD();
}
}
else
{
xTaskResumeAll();
}
return xReturn;
}
/*-----------------------------------------------------------*/
signed portBASE_TYPE xQueueReceiveFromISR( xQueueHandle pxQueue, void *pcBuffer, 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 * ) pcBuffer, ( 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 signed portBASE_TYPE prvUnlockQueue( xQueueHandle pxQueue )
{
signed portBASE_TYPE xYieldRequired = pdFALSE;
/* 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. */
xYieldRequired = pdTRUE;
}
}
}
}
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 )
{
xYieldRequired = pdTRUE;
}
}
}
}
taskEXIT_CRITICAL();
return xYieldRequired;
}
/*-----------------------------------------------------------*/
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;
}
/*
* sthhevs: Need the functions prvIsQueueEmpty and prvIsQueueFull!
* Export them with the following 'public' wrappers.
*/
signed portBASE_TYPE prvIsQueueEmptyPublic(const xQueueHandle pxQueue)
{
return prvIsQueueEmpty(pxQueue);
}
signed portBASE_TYPE prvIsQueueFullPublic(const xQueueHandle pxQueue)
{
return prvIsQueueFull(pxQueue);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -