feat(freertos-smp): Add support for queue direct transfer

This commit adds support for direct transfer for queue operations. A ew
config option configQUEUE_DIRECT_TRANSFER is introduced to enable this
option. With this feature, we enable directly copying data to a waiting
task's buffer and avoid copying data to the queue buffer. This helps in
avoiding priority inversions where a lower priority task can steal
a data from a higher priority task blocked on the queue. This also
reduces a copy operation and helps with the queue performance.
This commit is contained in:
Sudeep Mohanty 2025-10-30 14:08:02 +08:00
parent 4ee717950d
commit 53a44909aa
2 changed files with 310 additions and 22 deletions

View file

@ -3337,6 +3337,11 @@ typedef struct xSTATIC_QUEUE
#if ( ( portUSING_GRANULAR_LOCKS == 1 ) && ( configNUMBER_OF_CORES > 1 ) ) #if ( ( portUSING_GRANULAR_LOCKS == 1 ) && ( configNUMBER_OF_CORES > 1 ) )
portSPINLOCK_TYPE xDummySpinlock[ 2 ]; portSPINLOCK_TYPE xDummySpinlock[ 2 ];
#endif /* #if ( ( portUSING_GRANULAR_LOCKS == 1 ) && ( configNUMBER_OF_CORES > 1 ) ) */ #endif /* #if ( ( portUSING_GRANULAR_LOCKS == 1 ) && ( configNUMBER_OF_CORES > 1 ) ) */
#if ( configQUEUE_DIRECT_TRANSFER == 1 )
void * pvDummyDirectTransferBuffer;
BaseType_t xDummyDirectTransferPosition;
#endif
} StaticQueue_t; } StaticQueue_t;
typedef StaticQueue_t StaticSemaphore_t; typedef StaticQueue_t StaticSemaphore_t;

327
queue.c
View file

@ -53,6 +53,11 @@
#define queueLOCKED_UNMODIFIED ( ( int8_t ) 0 ) #define queueLOCKED_UNMODIFIED ( ( int8_t ) 0 )
#define queueINT8_MAX ( ( int8_t ) 127 ) #define queueINT8_MAX ( ( int8_t ) 127 )
#if ( configQUEUE_DIRECT_TRANSFER == 1 )
/* Initialization value for direct transfer position. */
#define queueDIRECT_TRANSFER_POSITION_INIT ( ( BaseType_t ) -1 )
#endif
/* When the Queue_t structure is used to represent a base queue its pcHead and /* When the Queue_t structure is used to represent a base queue its pcHead and
* pcTail members are used as pointers into the queue storage area. When the * pcTail members are used as pointers into the queue storage area. When the
* Queue_t structure is used to represent a mutex pcHead and pcTail pointers are * Queue_t structure is used to represent a mutex pcHead and pcTail pointers are
@ -62,8 +67,8 @@
* is maintained. The QueuePointers_t and SemaphoreData_t types are used to form * is maintained. The QueuePointers_t and SemaphoreData_t types are used to form
* a union as their usage is mutually exclusive dependent on what the queue is * a union as their usage is mutually exclusive dependent on what the queue is
* being used for. */ * being used for. */
#define uxQueueType pcHead #define uxQueueType pcHead
#define queueQUEUE_IS_MUTEX NULL #define queueQUEUE_IS_MUTEX NULL
typedef struct QueuePointers typedef struct QueuePointers
{ {
@ -138,6 +143,14 @@ typedef struct QueueDefinition /* The old naming convention is used to prevent b
portSPINLOCK_TYPE xTaskSpinlock; portSPINLOCK_TYPE xTaskSpinlock;
portSPINLOCK_TYPE xISRSpinlock; portSPINLOCK_TYPE xISRSpinlock;
#endif /* #if ( ( portUSING_GRANULAR_LOCKS == 1 ) && ( configNUMBER_OF_CORES > 1 ) ) */ #endif /* #if ( ( portUSING_GRANULAR_LOCKS == 1 ) && ( configNUMBER_OF_CORES > 1 ) ) */
#if ( configQUEUE_DIRECT_TRANSFER == 1 )
void * pvDirectTransferBuffer; /**< Direct transfer buffer pointer:
* - When queue is EMPTY: points to receiver's buffer
* - When queue is FULL: points to sender's data
* NULL when idle */
BaseType_t xDirectTransferPosition; /**< Position for direct transfer (queueSEND_TO_BACK, queueSEND_TO_FRONT, queueOVERWRITE) */
#endif
} xQUEUE; } xQUEUE;
/* The old xQUEUE name is maintained above then typedefed to the new Queue_t /* The old xQUEUE name is maintained above then typedefed to the new Queue_t
@ -256,16 +269,16 @@ static void prvInitialiseNewQueue( const UBaseType_t uxQueueLength,
static void prvInitialiseMutex( Queue_t * pxNewQueue ) PRIVILEGED_FUNCTION; static void prvInitialiseMutex( Queue_t * pxNewQueue ) PRIVILEGED_FUNCTION;
#endif #endif
#if ( configUSE_MUTEXES == 1 ) #if ( ( configUSE_MUTEXES == 1 ) || ( configQUEUE_DIRECT_TRANSFER == 1 ) )
/* /*
* If a task waiting for a mutex causes the mutex holder to inherit a * Returns the highest priority of any task waiting on the specified event list.
* priority, but the waiting task times out, then the holder should * Used for:
* disinherit the priority - but only down to the highest priority of any * - Mutex priority disinheritance (xTasksWaitingToReceive)
* other tasks that are waiting for the same mutex. This function returns * - Direct queue transfer (xTasksWaitingToReceive or xTasksWaitingToSend)
* that priority. * Returns tskIDLE_PRIORITY if the list is empty.
*/ */
static UBaseType_t prvGetHighestPriorityOfWaitToReceiveList( const Queue_t * const pxQueue ) PRIVILEGED_FUNCTION; static UBaseType_t prvGetHighestPriorityOfWaitingTasks( const List_t * const pxEventList ) PRIVILEGED_FUNCTION;
#endif #endif
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
@ -450,6 +463,13 @@ BaseType_t xQueueGenericReset( QueueHandle_t xQueue,
pxQueue->cRxLock = queueUNLOCKED; pxQueue->cRxLock = queueUNLOCKED;
pxQueue->cTxLock = queueUNLOCKED; pxQueue->cTxLock = queueUNLOCKED;
#if ( configQUEUE_DIRECT_TRANSFER == 1 )
{
pxQueue->pvDirectTransferBuffer = NULL;
pxQueue->xDirectTransferPosition = queueDIRECT_TRANSFER_POSITION_INIT;
}
#endif
if( xNewQueue == pdFALSE ) if( xNewQueue == pdFALSE )
{ {
/* If there are tasks blocked waiting to read from the queue, then /* If there are tasks blocked waiting to read from the queue, then
@ -1081,6 +1101,10 @@ BaseType_t xQueueGenericSend( QueueHandle_t xQueue,
TimeOut_t xTimeOut; TimeOut_t xTimeOut;
Queue_t * const pxQueue = xQueue; Queue_t * const pxQueue = xQueue;
#if ( configQUEUE_DIRECT_TRANSFER == 1 )
BaseType_t xDirectTransferArmed = pdFALSE;
#endif
traceENTER_xQueueGenericSend( xQueue, pvItemToQueue, xTicksToWait, xCopyPosition ); traceENTER_xQueueGenericSend( xQueue, pvItemToQueue, xTicksToWait, xCopyPosition );
configASSERT( pxQueue ); configASSERT( pxQueue );
@ -1096,6 +1120,35 @@ BaseType_t xQueueGenericSend( QueueHandle_t xQueue,
{ {
queueENTER_CRITICAL( pxQueue ); queueENTER_CRITICAL( pxQueue );
{ {
#if ( configQUEUE_DIRECT_TRANSFER == 1 )
{
/* Check if we were unblocked due to a direct transfer completion. */
if( ( pxQueue->pvDirectTransferBuffer == NULL ) && ( xDirectTransferArmed == pdTRUE ) )
{
/* Buffer pointer is cleared and we armed it. The receiver executed the
* direct transfer and our data was copied to the queue. */
xDirectTransferArmed = pdFALSE;
queueEXIT_CRITICAL( pxQueue );
traceQUEUE_SEND( pxQueue );
traceRETURN_xQueueGenericSend( pdPASS );
return pdPASS;
}
else if( pxQueue->pvDirectTransferBuffer == pvItemToQueue )
{
/* We armed direct transfer but receiver didn't execute it - clear and try normal path. */
pxQueue->pvDirectTransferBuffer = NULL;
xDirectTransferArmed = pdFALSE;
}
else
{
/* Buffer doesn't match our data (someone else armed it or it was cleared
* for another task) - just clear our flag and continue. */
xDirectTransferArmed = pdFALSE;
}
}
#endif /* if ( configQUEUE_DIRECT_TRANSFER == 1 ) */
/* Is there room on the queue now? The running task must be the /* Is there room on the queue now? The running task must be the
* highest priority task wanting to access the queue. If the head item * highest priority task wanting to access the queue. If the head item
* in the queue is to be overwritten then it does not matter if the * in the queue is to be overwritten then it does not matter if the
@ -1166,12 +1219,53 @@ BaseType_t xQueueGenericSend( QueueHandle_t xQueue,
} }
#else /* configUSE_QUEUE_SETS */ #else /* configUSE_QUEUE_SETS */
{ {
#if ( configQUEUE_DIRECT_TRANSFER == 1 )
{
/* Check if direct transfer is armed (receiver is waiting on empty queue). */
if( ( pxQueue->pvDirectTransferBuffer != NULL ) &&
( pxQueue->uxMessagesWaiting == ( UBaseType_t ) 0 ) &&
( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) == pdFALSE ) )
{
/* Direct copy to waiting receiver's buffer. */
( void ) memcpy( pxQueue->pvDirectTransferBuffer, pvItemToQueue, ( size_t ) pxQueue->uxItemSize );
/* Clear buffer pointer - receiver will detect this. */
pxQueue->pvDirectTransferBuffer = NULL;
/* Unblock the waiting receiver. */
if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) != pdFALSE )
{
queueYIELD_IF_USING_PREEMPTION();
}
else
{
mtCOVERAGE_TEST_MARKER();
}
queueEXIT_CRITICAL( pxQueue );
traceRETURN_xQueueGenericSend( pdPASS );
return pdPASS;
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
#endif /* configQUEUE_DIRECT_TRANSFER */
xYieldRequired = prvCopyDataToQueue( pxQueue, pvItemToQueue, xCopyPosition ); xYieldRequired = prvCopyDataToQueue( pxQueue, pvItemToQueue, xCopyPosition );
/* If there was a task waiting for data to arrive on the /* If there was a task waiting for data to arrive on the
* queue then unblock it now. */ * queue then unblock it now. */
if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) == pdFALSE ) if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) == pdFALSE )
{ {
#if ( configQUEUE_DIRECT_TRANSFER == 1 )
{
/* Clear direct transfer state as task being unblocked. */
pxQueue->pvDirectTransferBuffer = NULL;
}
#endif
if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) != pdFALSE ) if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) != pdFALSE )
{ {
/* The unblocked task has a priority higher than /* The unblocked task has a priority higher than
@ -1248,6 +1342,27 @@ BaseType_t xQueueGenericSend( QueueHandle_t xQueue,
if( prvIsQueueFull( pxQueue ) != pdFALSE ) if( prvIsQueueFull( pxQueue ) != pdFALSE )
{ {
traceBLOCKING_ON_QUEUE_SEND( pxQueue ); traceBLOCKING_ON_QUEUE_SEND( pxQueue );
#if ( configQUEUE_DIRECT_TRANSFER == 1 )
{
/* Arm direct transfer only if we'll be the highest priority waiter.
* This happens when: (1) list is empty, OR (2) our priority is higher
* than the current highest priority waiting task. */
const UBaseType_t uxCurrentPriority = uxTaskPriorityGet( NULL );
const UBaseType_t uxHighestWaitingPriority = prvGetHighestPriorityOfWaitingTasks( &( pxQueue->xTasksWaitingToSend ) );
if( uxCurrentPriority > uxHighestWaitingPriority )
{
/* We're higher priority than any current waiter (or list is empty,
* in which case uxHighestWaitingPriority is tskIDLE_PRIORITY).
* Arm direct transfer using pvDirectTransferBuffer (queue is full). */
pxQueue->pvDirectTransferBuffer = ( void * ) pvItemToQueue;
pxQueue->xDirectTransferPosition = xCopyPosition;
xDirectTransferArmed = pdTRUE;
}
}
#endif /* if ( configQUEUE_DIRECT_TRANSFER == 1 ) */
vTaskPlaceOnEventList( &( pxQueue->xTasksWaitingToSend ), xTicksToWait ); vTaskPlaceOnEventList( &( pxQueue->xTasksWaitingToSend ), xTicksToWait );
queueUNLOCK( pxQueue, pdTRUE ); queueUNLOCK( pxQueue, pdTRUE );
@ -1324,6 +1439,42 @@ BaseType_t xQueueGenericSendFromISR( QueueHandle_t xQueue,
* in a task disinheriting a priority and prvCopyDataToQueue() can be * in a task disinheriting a priority and prvCopyDataToQueue() can be
* called here even though the disinherit function does not check if * called here even though the disinherit function does not check if
* the scheduler is suspended before accessing the ready lists. */ * the scheduler is suspended before accessing the ready lists. */
#if ( configQUEUE_DIRECT_TRANSFER == 1 )
{
/* Check if direct transfer is armed (receiver is waiting on empty queue). */
if( ( pxQueue->pvDirectTransferBuffer != NULL ) &&
( pxQueue->uxMessagesWaiting == ( UBaseType_t ) 0 ) &&
( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) == pdFALSE ) &&
( cTxLock == queueUNLOCKED ) )
{
/* Direct copy to waiting receiver's buffer. */
( void ) memcpy( pxQueue->pvDirectTransferBuffer, pvItemToQueue, ( size_t ) pxQueue->uxItemSize );
/* Clear buffer pointer - receiver will detect this. */
pxQueue->pvDirectTransferBuffer = NULL;
/* Unblock the waiting receiver. */
if( xTaskRemoveFromEventListFromISR( &( pxQueue->xTasksWaitingToReceive ) ) != pdFALSE )
{
if( pxHigherPriorityTaskWoken != NULL )
{
*pxHigherPriorityTaskWoken = pdTRUE;
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
xReturn = pdPASS;
queueEXIT_CRITICAL_FROM_ISR( uxSavedInterruptStatus, pxQueue );
traceRETURN_xQueueGenericSendFromISR( xReturn );
return xReturn;
}
}
#endif /* configQUEUE_DIRECT_TRANSFER */
( void ) prvCopyDataToQueue( pxQueue, pvItemToQueue, xCopyPosition ); ( void ) prvCopyDataToQueue( pxQueue, pvItemToQueue, xCopyPosition );
/* The event list is not altered if the queue is locked. This will /* The event list is not altered if the queue is locked. This will
@ -1392,6 +1543,13 @@ BaseType_t xQueueGenericSendFromISR( QueueHandle_t xQueue,
{ {
if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) == pdFALSE ) if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) == pdFALSE )
{ {
#if ( configQUEUE_DIRECT_TRANSFER == 1 )
{
/* Clear direct transfer state as task being unblocked. */
pxQueue->pvDirectTransferBuffer = NULL;
}
#endif
if( xTaskRemoveFromEventListFromISR( &( pxQueue->xTasksWaitingToReceive ) ) != pdFALSE ) if( xTaskRemoveFromEventListFromISR( &( pxQueue->xTasksWaitingToReceive ) ) != pdFALSE )
{ {
/* The task waiting has a higher priority so record that a /* The task waiting has a higher priority so record that a
@ -1622,6 +1780,10 @@ BaseType_t xQueueReceive( QueueHandle_t xQueue,
TimeOut_t xTimeOut; TimeOut_t xTimeOut;
Queue_t * const pxQueue = xQueue; Queue_t * const pxQueue = xQueue;
#if ( configQUEUE_DIRECT_TRANSFER == 1 )
BaseType_t xDirectTransferArmed = pdFALSE;
#endif
traceENTER_xQueueReceive( xQueue, pvBuffer, xTicksToWait ); traceENTER_xQueueReceive( xQueue, pvBuffer, xTicksToWait );
/* Check the pointer is not NULL. */ /* Check the pointer is not NULL. */
@ -1642,6 +1804,47 @@ BaseType_t xQueueReceive( QueueHandle_t xQueue,
{ {
queueENTER_CRITICAL( pxQueue ); queueENTER_CRITICAL( pxQueue );
{ {
#if ( configQUEUE_DIRECT_TRANSFER == 1 )
{
/* Check if we were unblocked due to direct transfer completion. */
if( ( pxQueue->pvDirectTransferBuffer == NULL ) && ( xDirectTransferArmed == pdTRUE ) )
{
/* Buffer is cleared and we armed it. Verify this was actually a direct
* transfer to us by checking the queue is still empty. If queue has data,
* it means we were unblocked for normal receive (our buffer was overwritten
* by higher priority task, and data was queued normally). */
if( pxQueue->uxMessagesWaiting == ( UBaseType_t ) 0 )
{
/* Queue empty - direct transfer to us succeeded! */
xDirectTransferArmed = pdFALSE;
queueEXIT_CRITICAL( pxQueue );
traceQUEUE_RECEIVE( pxQueue );
traceRETURN_xQueueReceive( pdPASS );
return pdPASS;
}
else
{
/* Queue has data - this wasn't a direct transfer to us.
* Continue to normal receive path. */
xDirectTransferArmed = pdFALSE;
}
}
else if( pxQueue->pvDirectTransferBuffer == pvBuffer )
{
/* We armed direct transfer but sender didn't deliver - clear and try normal path. */
pxQueue->pvDirectTransferBuffer = NULL;
xDirectTransferArmed = pdFALSE;
}
else
{
/* Buffer doesn't match our buffer (someone else armed it or it was cleared
* for another task) - just clear our flag and continue. */
xDirectTransferArmed = pdFALSE;
}
}
#endif /* if ( configQUEUE_DIRECT_TRANSFER == 1 ) */
const UBaseType_t uxMessagesWaiting = pxQueue->uxMessagesWaiting; const UBaseType_t uxMessagesWaiting = pxQueue->uxMessagesWaiting;
/* Is there data in the queue now? To be running the calling task /* Is there data in the queue now? To be running the calling task
@ -1658,6 +1861,27 @@ BaseType_t xQueueReceive( QueueHandle_t xQueue,
* task. */ * task. */
if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToSend ) ) == pdFALSE ) if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToSend ) ) == pdFALSE )
{ {
#if ( configQUEUE_DIRECT_TRANSFER == 1 )
{
/* Check if a direct transfer is armed (sender is waiting on a full queue). */
if( pxQueue->pvDirectTransferBuffer != NULL )
{
/* Verify that position was set to a valid value */
configASSERT( pxQueue->xDirectTransferPosition != queueDIRECT_TRANSFER_POSITION_INIT );
configASSERT( ( pxQueue->xDirectTransferPosition == queueSEND_TO_BACK ) ||
( pxQueue->xDirectTransferPosition == queueSEND_TO_FRONT ) ||
( pxQueue->xDirectTransferPosition == queueOVERWRITE ) );
/* Direct copy from waiting sender's buffer to the queue. */
( void ) prvCopyDataToQueue( pxQueue, pxQueue->pvDirectTransferBuffer, pxQueue->xDirectTransferPosition );
/* Clear buffer pointer - sender will be unblocked below. */
pxQueue->pvDirectTransferBuffer = NULL;
}
}
#endif /* configQUEUE_DIRECT_TRANSFER */
/* Unblock the waiting sender. */
if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToSend ) ) != pdFALSE ) if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToSend ) ) != pdFALSE )
{ {
queueYIELD_IF_USING_PREEMPTION(); queueYIELD_IF_USING_PREEMPTION();
@ -1720,6 +1944,25 @@ BaseType_t xQueueReceive( QueueHandle_t xQueue,
if( prvIsQueueEmpty( pxQueue ) != pdFALSE ) if( prvIsQueueEmpty( pxQueue ) != pdFALSE )
{ {
traceBLOCKING_ON_QUEUE_RECEIVE( pxQueue ); traceBLOCKING_ON_QUEUE_RECEIVE( pxQueue );
#if ( configQUEUE_DIRECT_TRANSFER == 1 )
{
/* Arm direct transfer only if we'll be the highest priority waiter.
* This happens when: (1) list is empty, OR (2) our priority is higher
* than the current highest waiting task. */
const UBaseType_t uxCurrentPriority = uxTaskPriorityGet( NULL );
const UBaseType_t uxHighestWaitingPriority = prvGetHighestPriorityOfWaitingTasks( &( pxQueue->xTasksWaitingToReceive ) );
if( uxCurrentPriority > uxHighestWaitingPriority )
{
/* We're higher priority than any current waiter (or list is empty,
* in which case uxHighestWaitingPriority is tskIDLE_PRIORITY). */
pxQueue->pvDirectTransferBuffer = pvBuffer;
xDirectTransferArmed = pdTRUE;
}
}
#endif /* if ( configQUEUE_DIRECT_TRANSFER == 1 ) */
vTaskPlaceOnEventList( &( pxQueue->xTasksWaitingToReceive ), xTicksToWait ); vTaskPlaceOnEventList( &( pxQueue->xTasksWaitingToReceive ), xTicksToWait );
queueUNLOCK( pxQueue, pdTRUE ); queueUNLOCK( pxQueue, pdTRUE );
} }
@ -1931,13 +2174,13 @@ BaseType_t xQueueSemaphoreTake( QueueHandle_t xQueue,
* has timed out the priority should be disinherited * has timed out the priority should be disinherited
* again, but only as low as the next highest priority * again, but only as low as the next highest priority
* task that is waiting for the same mutex. */ * task that is waiting for the same mutex. */
uxHighestWaitingPriority = prvGetHighestPriorityOfWaitToReceiveList( pxQueue ); uxHighestWaitingPriority = prvGetHighestPriorityOfWaitingTasks( &( pxQueue->xTasksWaitingToReceive ) );
/* vTaskPriorityDisinheritAfterTimeout uses the uxHighestWaitingPriority /* vTaskPriorityDisinheritAfterTimeout uses the uxHighestWaitingPriority
* parameter to index pxReadyTasksLists when adding the task holding * parameter to index pxReadyTasksLists when adding the task holding
* mutex to the ready list for its new priority. Coverity thinks that * mutex to the ready list for its new priority. Coverity thinks that
* it can result in out-of-bounds access which is not true because * it can result in out-of-bounds access which is not true because
* uxHighestWaitingPriority, as returned by prvGetHighestPriorityOfWaitToReceiveList, * uxHighestWaitingPriority, as returned by prvGetHighestPriorityOfWaitingTasks,
* is capped at ( configMAX_PRIORITIES - 1 ). */ * is capped at ( configMAX_PRIORITIES - 1 ). */
/* coverity[overrun] */ /* coverity[overrun] */
vTaskPriorityDisinheritAfterTimeout( pxQueue->u.xSemaphore.xMutexHolder, uxHighestWaitingPriority ); vTaskPriorityDisinheritAfterTimeout( pxQueue->u.xSemaphore.xMutexHolder, uxHighestWaitingPriority );
@ -2158,6 +2401,28 @@ BaseType_t xQueueReceiveFromISR( QueueHandle_t xQueue,
{ {
if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToSend ) ) == pdFALSE ) if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToSend ) ) == pdFALSE )
{ {
#if ( configQUEUE_DIRECT_TRANSFER == 1 )
{
/* Check if a direct transfer is armed (sender is waiting on full queue).
* When queue is not empty, pvDirectTransferBuffer is used to point to sender's data. */
if( pxQueue->pvDirectTransferBuffer != NULL )
{
/* Verify that position was set to a valid value. */
configASSERT( pxQueue->xDirectTransferPosition != queueDIRECT_TRANSFER_POSITION_INIT );
configASSERT( ( pxQueue->xDirectTransferPosition == queueSEND_TO_BACK ) ||
( pxQueue->xDirectTransferPosition == queueSEND_TO_FRONT ) ||
( pxQueue->xDirectTransferPosition == queueOVERWRITE ) );
/* Direct copy from waiting sender's buffer to the queue. */
( void ) prvCopyDataToQueue( pxQueue, pxQueue->pvDirectTransferBuffer, pxQueue->xDirectTransferPosition );
/* Clear buffer pointer - sender will be unblocked below. */
pxQueue->pvDirectTransferBuffer = NULL;
}
}
#endif /* configQUEUE_DIRECT_TRANSFER */
/* Unblock the waiting sender. */
if( xTaskRemoveFromEventListFromISR( &( pxQueue->xTasksWaitingToSend ) ) != pdFALSE ) if( xTaskRemoveFromEventListFromISR( &( pxQueue->xTasksWaitingToSend ) ) != pdFALSE )
{ {
/* The task waiting has a higher priority than us so /* The task waiting has a higher priority than us so
@ -2331,6 +2596,13 @@ void vQueueDelete( QueueHandle_t xQueue )
configASSERT( pxQueue ); configASSERT( pxQueue );
traceQUEUE_DELETE( pxQueue ); traceQUEUE_DELETE( pxQueue );
#if ( configQUEUE_DIRECT_TRANSFER == 1 )
{
/* Clear direct transfer state before deleting queue. */
pxQueue->pvDirectTransferBuffer = NULL;
}
#endif
#if ( configQUEUE_REGISTRY_SIZE > 0 ) #if ( configQUEUE_REGISTRY_SIZE > 0 )
{ {
vQueueUnregisterQueue( pxQueue ); vQueueUnregisterQueue( pxQueue );
@ -2431,21 +2703,18 @@ UBaseType_t uxQueueGetQueueLength( QueueHandle_t xQueue ) /* PRIVILEGED_FUNCTION
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
#if ( configUSE_MUTEXES == 1 ) #if ( ( configUSE_MUTEXES == 1 ) || ( configQUEUE_DIRECT_TRANSFER == 1 ) )
static UBaseType_t prvGetHighestPriorityOfWaitToReceiveList( const Queue_t * const pxQueue ) static UBaseType_t prvGetHighestPriorityOfWaitingTasks( const List_t * const pxEventList )
{ {
UBaseType_t uxHighestPriorityOfWaitingTasks; UBaseType_t uxHighestPriorityOfWaitingTasks;
/* If a task waiting for a mutex causes the mutex holder to inherit a /* Returns the priority of the highest priority task waiting on the given
* priority, but the waiting task times out, then the holder should * event list. If the list is empty, returns tskIDLE_PRIORITY.
* disinherit the priority - but only down to the highest priority of any * Used for mutex priority disinheritance and direct transfer optimization. */
* other tasks that are waiting for the same mutex. For this purpose, if( listCURRENT_LIST_LENGTH( pxEventList ) > 0U )
* return the priority of the highest priority task that is waiting for the
* mutex. */
if( listCURRENT_LIST_LENGTH( &( pxQueue->xTasksWaitingToReceive ) ) > 0U )
{ {
uxHighestPriorityOfWaitingTasks = ( UBaseType_t ) ( ( UBaseType_t ) configMAX_PRIORITIES - ( UBaseType_t ) listGET_ITEM_VALUE_OF_HEAD_ENTRY( &( pxQueue->xTasksWaitingToReceive ) ) ); uxHighestPriorityOfWaitingTasks = ( UBaseType_t ) ( ( UBaseType_t ) configMAX_PRIORITIES - ( UBaseType_t ) listGET_ITEM_VALUE_OF_HEAD_ENTRY( pxEventList ) );
} }
else else
{ {
@ -2455,7 +2724,7 @@ UBaseType_t uxQueueGetQueueLength( QueueHandle_t xQueue ) /* PRIVILEGED_FUNCTION
return uxHighestPriorityOfWaitingTasks; return uxHighestPriorityOfWaitingTasks;
} }
#endif /* configUSE_MUTEXES */ #endif /* ( configUSE_MUTEXES == 1 ) || ( configQUEUE_DIRECT_TRANSFER == 1 ) */
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
static BaseType_t prvCopyDataToQueue( Queue_t * const pxQueue, static BaseType_t prvCopyDataToQueue( Queue_t * const pxQueue,
@ -2610,6 +2879,13 @@ static void prvUnlockQueue( Queue_t * const pxQueue )
* suspended. */ * suspended. */
if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) == pdFALSE ) if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) == pdFALSE )
{ {
#if ( configQUEUE_DIRECT_TRANSFER == 1 )
{
/* Clear direct transfer state as task being unblocked. */
pxQueue->pvDirectTransferBuffer = NULL;
}
#endif
if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) != pdFALSE ) if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) != pdFALSE )
{ {
/* The task waiting has a higher priority so record that a /* The task waiting has a higher priority so record that a
@ -2633,6 +2909,13 @@ static void prvUnlockQueue( Queue_t * const pxQueue )
* the pending ready list as the scheduler is still suspended. */ * the pending ready list as the scheduler is still suspended. */
if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) == pdFALSE ) if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) == pdFALSE )
{ {
#if ( configQUEUE_DIRECT_TRANSFER == 1 )
{
/* Clear direct transfer state as task being unblocked. */
pxQueue->pvDirectTransferBuffer = NULL;
}
#endif
if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) != pdFALSE ) if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) != pdFALSE )
{ {
/* The task waiting has a higher priority so record that /* The task waiting has a higher priority so record that