mirror of
https://github.com/FreeRTOS/FreeRTOS-Kernel.git
synced 2025-12-06 13:15:19 -05:00
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:
parent
4ee717950d
commit
53a44909aa
2 changed files with 310 additions and 22 deletions
|
|
@ -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
327
queue.c
|
|
@ -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
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue