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 buffer in task TCB
This commit adds support for queue direct transfer buffer being owned by the task's TCB. This inherently solves some design issues with the buffer being owned by the queue's object. On the flip side, this adds memory cost to the task's TCB.
This commit is contained in:
parent
53a44909aa
commit
e850728909
4 changed files with 365 additions and 192 deletions
|
|
@ -3291,6 +3291,11 @@ typedef struct xSTATIC_TCB
|
|||
#if ( configUSE_POSIX_ERRNO == 1 )
|
||||
int iDummy22;
|
||||
#endif
|
||||
|
||||
#if ( configQUEUE_DIRECT_TRANSFER == 1 )
|
||||
void * pvDummyDirectTransferBuffer;
|
||||
BaseType_t xDummyDirectTransferPosition;
|
||||
#endif
|
||||
} StaticTask_t;
|
||||
|
||||
/*
|
||||
|
|
@ -3337,11 +3342,6 @@ typedef struct xSTATIC_QUEUE
|
|||
#if ( ( portUSING_GRANULAR_LOCKS == 1 ) && ( configNUMBER_OF_CORES > 1 ) )
|
||||
portSPINLOCK_TYPE xDummySpinlock[ 2 ];
|
||||
#endif /* #if ( ( portUSING_GRANULAR_LOCKS == 1 ) && ( configNUMBER_OF_CORES > 1 ) ) */
|
||||
|
||||
#if ( configQUEUE_DIRECT_TRANSFER == 1 )
|
||||
void * pvDummyDirectTransferBuffer;
|
||||
BaseType_t xDummyDirectTransferPosition;
|
||||
#endif
|
||||
} StaticQueue_t;
|
||||
typedef StaticQueue_t StaticSemaphore_t;
|
||||
|
||||
|
|
|
|||
|
|
@ -3758,6 +3758,68 @@ BaseType_t xTaskRemoveFromEventListFromISR( const List_t * const pxEventList ) P
|
|||
void vTaskRemoveFromUnorderedEventList( ListItem_t * pxEventListItem,
|
||||
const TickType_t xItemValue ) PRIVILEGED_FUNCTION;
|
||||
|
||||
#if ( configQUEUE_DIRECT_TRANSFER == 1 )
|
||||
|
||||
/*
|
||||
* THIS FUNCTION MUST NOT BE USED FROM APPLICATION CODE. IT IS AN
|
||||
* INTERFACE FOR THE EXCLUSIVE USE OF THE QUEUE IMPLEMENTATION.
|
||||
*
|
||||
* Set the direct transfer buffer for the current task.
|
||||
* Called when a task is about to block on a queue operation.
|
||||
*/
|
||||
void vTaskSetDirectTransferBuffer( void * pvBuffer,
|
||||
BaseType_t xPosition,
|
||||
TaskHandle_t xTask ) PRIVILEGED_FUNCTION;
|
||||
|
||||
/*
|
||||
* THIS FUNCTION MUST NOT BE USED FROM APPLICATION CODE. IT IS AN
|
||||
* INTERFACE FOR THE EXCLUSIVE USE OF THE QUEUE IMPLEMENTATION.
|
||||
*
|
||||
* Clear the direct transfer buffer for a task.
|
||||
* @param xTask The task handle
|
||||
*/
|
||||
void vTaskClearDirectTransferBuffer( TaskHandle_t xTask ) PRIVILEGED_FUNCTION;
|
||||
|
||||
/*
|
||||
* THIS FUNCTION MUST NOT BE USED FROM APPLICATION CODE. IT IS AN
|
||||
* INTERFACE FOR THE EXCLUSIVE USE OF THE QUEUE IMPLEMENTATION.
|
||||
*
|
||||
* Get the direct transfer buffer pointer from a task.
|
||||
* @param xTask The task handle
|
||||
* @return The buffer pointer, or NULL if not set
|
||||
*
|
||||
*/
|
||||
void * pvTaskGetDirectTransferBuffer( TaskHandle_t xTask ) PRIVILEGED_FUNCTION;
|
||||
|
||||
/*
|
||||
* THIS FUNCTION MUST NOT BE USED FROM APPLICATION CODE. IT IS AN
|
||||
* INTERFACE FOR THE EXCLUSIVE USE OF THE QUEUE IMPLEMENTATION.
|
||||
*
|
||||
* Get the direct transfer position from a task.
|
||||
* @param xTask The task handle
|
||||
* @return The position, or -1 if not set
|
||||
*
|
||||
*/
|
||||
BaseType_t xTaskGetDirectTransferPosition( TaskHandle_t xTask ) PRIVILEGED_FUNCTION;
|
||||
|
||||
/*
|
||||
* THIS FUNCTION MUST NOT BE USED FROM APPLICATION CODE. IT IS AN
|
||||
* INTERFACE FOR THE EXCLUSIVE USE OF THE QUEUE IMPLEMENTATION.
|
||||
*
|
||||
* Get the highest priority task from an event list if it has armed direct transfer.
|
||||
* Checks only the head of the event list (O(1) operation) for deterministic behavior.
|
||||
*
|
||||
* If the highest priority task hasn't armed direct transfer (e.g., using xQueuePeek()),
|
||||
* returns NULL and direct transfer is skipped for this operation. This is acceptable since
|
||||
* direct transfer is an optimization, not a requirement.
|
||||
*
|
||||
* @param pxEventList The event list to check
|
||||
* @return Task handle of highest priority task if it has armed transfer, or NULL otherwise
|
||||
*/
|
||||
TaskHandle_t xTaskGetHighestPriorityTaskWithDirectTransferArmed( const List_t * const pxEventList ) PRIVILEGED_FUNCTION;
|
||||
|
||||
#endif /* configQUEUE_DIRECT_TRANSFER */
|
||||
|
||||
/*
|
||||
* THIS FUNCTION MUST NOT BE USED FROM APPLICATION CODE. IT IS ONLY
|
||||
* INTENDED FOR USE WHEN IMPLEMENTING A PORT OF THE SCHEDULER AND IS
|
||||
|
|
|
|||
325
queue.c
325
queue.c
|
|
@ -143,14 +143,6 @@ typedef struct QueueDefinition /* The old naming convention is used to prevent b
|
|||
portSPINLOCK_TYPE xTaskSpinlock;
|
||||
portSPINLOCK_TYPE xISRSpinlock;
|
||||
#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;
|
||||
|
||||
/* The old xQUEUE name is maintained above then typedefed to the new Queue_t
|
||||
|
|
@ -463,13 +455,6 @@ BaseType_t xQueueGenericReset( QueueHandle_t xQueue,
|
|||
pxQueue->cRxLock = queueUNLOCKED;
|
||||
pxQueue->cTxLock = queueUNLOCKED;
|
||||
|
||||
#if ( configQUEUE_DIRECT_TRANSFER == 1 )
|
||||
{
|
||||
pxQueue->pvDirectTransferBuffer = NULL;
|
||||
pxQueue->xDirectTransferPosition = queueDIRECT_TRANSFER_POSITION_INIT;
|
||||
}
|
||||
#endif
|
||||
|
||||
if( xNewQueue == pdFALSE )
|
||||
{
|
||||
/* If there are tasks blocked waiting to read from the queue, then
|
||||
|
|
@ -1102,6 +1087,9 @@ BaseType_t xQueueGenericSend( QueueHandle_t xQueue,
|
|||
Queue_t * const pxQueue = xQueue;
|
||||
|
||||
#if ( configQUEUE_DIRECT_TRANSFER == 1 )
|
||||
|
||||
/* Track whether we've armed direct transfer in task's TCB.
|
||||
* This prevents false positives on first loop iteration. */
|
||||
BaseType_t xDirectTransferArmed = pdFALSE;
|
||||
#endif
|
||||
|
||||
|
|
@ -1122,29 +1110,33 @@ BaseType_t xQueueGenericSend( QueueHandle_t xQueue,
|
|||
{
|
||||
#if ( configQUEUE_DIRECT_TRANSFER == 1 )
|
||||
{
|
||||
/* Check if we were unblocked due to a direct transfer completion. */
|
||||
if( ( pxQueue->pvDirectTransferBuffer == NULL ) && ( xDirectTransferArmed == pdTRUE ) )
|
||||
/* Check if we were unblocked due to a direct transfer completion.
|
||||
* Only check if we actually armed the buffer (to avoid false positives on first iteration). */
|
||||
if( 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 );
|
||||
void * pvCurrentBuffer = pvTaskGetDirectTransferBuffer( NULL );
|
||||
|
||||
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;
|
||||
if( pvCurrentBuffer == NULL )
|
||||
{
|
||||
/* Our buffer was cleared - direct transfer completed successfully. */
|
||||
xDirectTransferArmed = pdFALSE;
|
||||
queueEXIT_CRITICAL( pxQueue );
|
||||
|
||||
traceQUEUE_SEND( pxQueue );
|
||||
traceRETURN_xQueueGenericSend( pdPASS );
|
||||
return pdPASS;
|
||||
}
|
||||
else if( pvCurrentBuffer == pvItemToQueue )
|
||||
{
|
||||
/* We armed direct transfer but receiver didn't use it - clear and try normal path. */
|
||||
vTaskClearDirectTransferBuffer( NULL );
|
||||
xDirectTransferArmed = pdFALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Buffer doesn't match - shouldn't happen, but clear our flag. */
|
||||
xDirectTransferArmed = pdFALSE;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif /* if ( configQUEUE_DIRECT_TRANSFER == 1 ) */
|
||||
|
|
@ -1221,34 +1213,37 @@ BaseType_t xQueueGenericSend( QueueHandle_t xQueue,
|
|||
{
|
||||
#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 ) &&
|
||||
/* Check if there's a receiver waiting with armed direct transfer. */
|
||||
if( ( 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 );
|
||||
/* Find highest priority receiver with armed direct transfer. */
|
||||
TaskHandle_t xReceivingTask = xTaskGetHighestPriorityTaskWithDirectTransferArmed( &( pxQueue->xTasksWaitingToReceive ) );
|
||||
|
||||
/* Clear buffer pointer - receiver will detect this. */
|
||||
pxQueue->pvDirectTransferBuffer = NULL;
|
||||
|
||||
/* Unblock the waiting receiver. */
|
||||
if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) != pdFALSE )
|
||||
if( xReceivingTask != NULL )
|
||||
{
|
||||
queueYIELD_IF_USING_PREEMPTION();
|
||||
}
|
||||
else
|
||||
{
|
||||
mtCOVERAGE_TEST_MARKER();
|
||||
}
|
||||
void * pvReceiverBuffer = pvTaskGetDirectTransferBuffer( xReceivingTask );
|
||||
|
||||
queueEXIT_CRITICAL( pxQueue );
|
||||
traceRETURN_xQueueGenericSend( pdPASS );
|
||||
return pdPASS;
|
||||
}
|
||||
else
|
||||
{
|
||||
mtCOVERAGE_TEST_MARKER();
|
||||
/* Direct copy to waiting receiver's buffer. */
|
||||
( void ) memcpy( pvReceiverBuffer, pvItemToQueue, ( size_t ) pxQueue->uxItemSize );
|
||||
|
||||
/* Clear receiver's buffer pointer. */
|
||||
vTaskClearDirectTransferBuffer( xReceivingTask );
|
||||
|
||||
/* 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif /* configQUEUE_DIRECT_TRANSFER */
|
||||
|
|
@ -1259,13 +1254,6 @@ BaseType_t xQueueGenericSend( QueueHandle_t xQueue,
|
|||
* queue then unblock it now. */
|
||||
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 )
|
||||
{
|
||||
/* The unblocked task has a priority higher than
|
||||
|
|
@ -1345,21 +1333,9 @@ BaseType_t xQueueGenericSend( QueueHandle_t xQueue,
|
|||
|
||||
#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;
|
||||
}
|
||||
/* Arm direct transfer in current task's TCB. Any receiver that unblocks us can check our TCB for the buffer. */
|
||||
vTaskSetDirectTransferBuffer( ( void * ) pvItemToQueue, xCopyPosition, NULL );
|
||||
xDirectTransferArmed = pdTRUE;
|
||||
}
|
||||
#endif /* if ( configQUEUE_DIRECT_TRANSFER == 1 ) */
|
||||
|
||||
|
|
@ -1442,35 +1418,42 @@ BaseType_t xQueueGenericSendFromISR( QueueHandle_t xQueue,
|
|||
|
||||
#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 ) &&
|
||||
/* Check if there's a receiver waiting with armed direct transfer. */
|
||||
if( ( 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 );
|
||||
/* Find highest priority receiver with armed direct transfer. */
|
||||
TaskHandle_t xReceivingTask = xTaskGetHighestPriorityTaskWithDirectTransferArmed( &( pxQueue->xTasksWaitingToReceive ) );
|
||||
|
||||
/* Clear buffer pointer - receiver will detect this. */
|
||||
pxQueue->pvDirectTransferBuffer = NULL;
|
||||
|
||||
/* Unblock the waiting receiver. */
|
||||
if( xTaskRemoveFromEventListFromISR( &( pxQueue->xTasksWaitingToReceive ) ) != pdFALSE )
|
||||
if( xReceivingTask != NULL )
|
||||
{
|
||||
if( pxHigherPriorityTaskWoken != NULL )
|
||||
{
|
||||
*pxHigherPriorityTaskWoken = pdTRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
mtCOVERAGE_TEST_MARKER();
|
||||
}
|
||||
}
|
||||
void * pvReceiverBuffer = pvTaskGetDirectTransferBuffer( xReceivingTask );
|
||||
|
||||
xReturn = pdPASS;
|
||||
queueEXIT_CRITICAL_FROM_ISR( uxSavedInterruptStatus, pxQueue );
|
||||
traceRETURN_xQueueGenericSendFromISR( xReturn );
|
||||
return xReturn;
|
||||
/* Direct copy to waiting receiver's buffer. */
|
||||
( void ) memcpy( pvReceiverBuffer, pvItemToQueue, ( size_t ) pxQueue->uxItemSize );
|
||||
|
||||
/* Clear receiver's buffer pointer. */
|
||||
vTaskClearDirectTransferBuffer( xReceivingTask );
|
||||
|
||||
/* 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 */
|
||||
|
|
@ -1543,13 +1526,6 @@ BaseType_t xQueueGenericSendFromISR( QueueHandle_t xQueue,
|
|||
{
|
||||
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 )
|
||||
{
|
||||
/* The task waiting has a higher priority so record that a
|
||||
|
|
@ -1781,6 +1757,9 @@ BaseType_t xQueueReceive( QueueHandle_t xQueue,
|
|||
Queue_t * const pxQueue = xQueue;
|
||||
|
||||
#if ( configQUEUE_DIRECT_TRANSFER == 1 )
|
||||
|
||||
/* Track whether we've armed direct transfer in task's TCB.
|
||||
* This prevents false positives on first loop iteration. */
|
||||
BaseType_t xDirectTransferArmed = pdFALSE;
|
||||
#endif
|
||||
|
||||
|
|
@ -1806,16 +1785,15 @@ BaseType_t xQueueReceive( QueueHandle_t xQueue,
|
|||
{
|
||||
#if ( configQUEUE_DIRECT_TRANSFER == 1 )
|
||||
{
|
||||
/* Check if we were unblocked due to direct transfer completion. */
|
||||
if( ( pxQueue->pvDirectTransferBuffer == NULL ) && ( xDirectTransferArmed == pdTRUE ) )
|
||||
/* Check if we were unblocked due to a direct transfer completion.
|
||||
* Only check if we actually armed the buffer (to avoid false positives on first iteration). */
|
||||
if( 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 )
|
||||
void * pvCurrentBuffer = pvTaskGetDirectTransferBuffer( NULL );
|
||||
|
||||
if( pvCurrentBuffer == NULL )
|
||||
{
|
||||
/* Queue empty - direct transfer to us succeeded! */
|
||||
/* Our buffer was cleared - direct transfer completed successfully. */
|
||||
xDirectTransferArmed = pdFALSE;
|
||||
queueEXIT_CRITICAL( pxQueue );
|
||||
|
||||
|
|
@ -1823,24 +1801,17 @@ BaseType_t xQueueReceive( QueueHandle_t xQueue,
|
|||
traceRETURN_xQueueReceive( pdPASS );
|
||||
return pdPASS;
|
||||
}
|
||||
else
|
||||
else if( pvCurrentBuffer == pvBuffer )
|
||||
{
|
||||
/* Queue has data - this wasn't a direct transfer to us.
|
||||
* Continue to normal receive path. */
|
||||
/* We armed direct transfer but sender didn't use it - clear and try normal path. */
|
||||
vTaskClearDirectTransferBuffer( NULL );
|
||||
xDirectTransferArmed = pdFALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Buffer doesn't match - shouldn't happen, but clear our flag. */
|
||||
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 ) */
|
||||
|
|
@ -1863,20 +1834,26 @@ BaseType_t xQueueReceive( QueueHandle_t xQueue,
|
|||
{
|
||||
#if ( configQUEUE_DIRECT_TRANSFER == 1 )
|
||||
{
|
||||
/* Check if a direct transfer is armed (sender is waiting on a full queue). */
|
||||
if( pxQueue->pvDirectTransferBuffer != NULL )
|
||||
/* Check if there's a sender waiting with armed direct transfer.
|
||||
* Find highest priority sender with armed direct transfer. */
|
||||
TaskHandle_t xSendingTask = xTaskGetHighestPriorityTaskWithDirectTransferArmed( &( pxQueue->xTasksWaitingToSend ) );
|
||||
|
||||
if( xSendingTask != NULL )
|
||||
{
|
||||
void * pvSenderBuffer = pvTaskGetDirectTransferBuffer( xSendingTask );
|
||||
BaseType_t xPosition = xTaskGetDirectTransferPosition( xSendingTask );
|
||||
|
||||
/* 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 ) );
|
||||
configASSERT( xPosition != queueDIRECT_TRANSFER_POSITION_INIT );
|
||||
configASSERT( ( xPosition == queueSEND_TO_BACK ) ||
|
||||
( xPosition == queueSEND_TO_FRONT ) ||
|
||||
( xPosition == queueOVERWRITE ) );
|
||||
|
||||
/* Direct copy from waiting sender's buffer to the queue. */
|
||||
( void ) prvCopyDataToQueue( pxQueue, pxQueue->pvDirectTransferBuffer, pxQueue->xDirectTransferPosition );
|
||||
( void ) prvCopyDataToQueue( pxQueue, pvSenderBuffer, xPosition );
|
||||
|
||||
/* Clear buffer pointer - sender will be unblocked below. */
|
||||
pxQueue->pvDirectTransferBuffer = NULL;
|
||||
/* Clear sender's buffer pointer. */
|
||||
vTaskClearDirectTransferBuffer( xSendingTask );
|
||||
}
|
||||
}
|
||||
#endif /* configQUEUE_DIRECT_TRANSFER */
|
||||
|
|
@ -1947,19 +1924,9 @@ BaseType_t xQueueReceive( QueueHandle_t xQueue,
|
|||
|
||||
#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;
|
||||
}
|
||||
/* Arm direct transfer in current task's TCB. Any sender that unblocks us can check our TCB for the buffer. */
|
||||
vTaskSetDirectTransferBuffer( pvBuffer, queueDIRECT_TRANSFER_POSITION_INIT, NULL );
|
||||
xDirectTransferArmed = pdTRUE;
|
||||
}
|
||||
#endif /* if ( configQUEUE_DIRECT_TRANSFER == 1 ) */
|
||||
|
||||
|
|
@ -2403,21 +2370,26 @@ BaseType_t xQueueReceiveFromISR( QueueHandle_t xQueue,
|
|||
{
|
||||
#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 )
|
||||
/* Check if there's a sender waiting with armed direct transfer.
|
||||
* Find highest priority sender with armed direct transfer. */
|
||||
TaskHandle_t xSendingTask = xTaskGetHighestPriorityTaskWithDirectTransferArmed( &( pxQueue->xTasksWaitingToSend ) );
|
||||
|
||||
if( xSendingTask != NULL )
|
||||
{
|
||||
void * pvSenderBuffer = pvTaskGetDirectTransferBuffer( xSendingTask );
|
||||
BaseType_t xPosition = xTaskGetDirectTransferPosition( xSendingTask );
|
||||
|
||||
/* 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 ) );
|
||||
configASSERT( xPosition != queueDIRECT_TRANSFER_POSITION_INIT );
|
||||
configASSERT( ( xPosition == queueSEND_TO_BACK ) ||
|
||||
( xPosition == queueSEND_TO_FRONT ) ||
|
||||
( xPosition == queueOVERWRITE ) );
|
||||
|
||||
/* Direct copy from waiting sender's buffer to the queue. */
|
||||
( void ) prvCopyDataToQueue( pxQueue, pxQueue->pvDirectTransferBuffer, pxQueue->xDirectTransferPosition );
|
||||
( void ) prvCopyDataToQueue( pxQueue, pvSenderBuffer, xPosition );
|
||||
|
||||
/* Clear buffer pointer - sender will be unblocked below. */
|
||||
pxQueue->pvDirectTransferBuffer = NULL;
|
||||
/* Clear sender's buffer pointer. */
|
||||
vTaskClearDirectTransferBuffer( xSendingTask );
|
||||
}
|
||||
}
|
||||
#endif /* configQUEUE_DIRECT_TRANSFER */
|
||||
|
|
@ -2596,13 +2568,6 @@ void vQueueDelete( QueueHandle_t xQueue )
|
|||
configASSERT( 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 )
|
||||
{
|
||||
vQueueUnregisterQueue( pxQueue );
|
||||
|
|
@ -2879,13 +2844,6 @@ static void prvUnlockQueue( Queue_t * const pxQueue )
|
|||
* suspended. */
|
||||
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 )
|
||||
{
|
||||
/* The task waiting has a higher priority so record that a
|
||||
|
|
@ -2909,13 +2867,6 @@ static void prvUnlockQueue( Queue_t * const pxQueue )
|
|||
* the pending ready list as the scheduler is still suspended. */
|
||||
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 )
|
||||
{
|
||||
/* The task waiting has a higher priority so record that
|
||||
|
|
|
|||
160
tasks.c
160
tasks.c
|
|
@ -516,6 +516,14 @@ typedef struct tskTaskControlBlock /* The old naming convention is used to
|
|||
#if ( configUSE_POSIX_ERRNO == 1 )
|
||||
int iTaskErrno;
|
||||
#endif
|
||||
|
||||
#if ( configQUEUE_DIRECT_TRANSFER == 1 )
|
||||
void * pvDirectTransferBuffer; /**< Direct transfer buffer pointer for data group send/receive operations:
|
||||
* - When waiting to RECEIVE: points to this task's receive buffer
|
||||
* - When waiting to SEND: points to this task's send data
|
||||
* NULL when not using direct transfer */
|
||||
BaseType_t xDirectTransferPosition; /**< Position for direct transfer (queueSEND_TO_BACK, queueSEND_TO_FRONT, queueOVERWRITE) */
|
||||
#endif
|
||||
} tskTCB;
|
||||
|
||||
/* The old tskTCB name is maintained above then typedefed to the new TCB_t name
|
||||
|
|
@ -717,6 +725,31 @@ static BaseType_t prvTaskRemoveFromEventList( const List_t * const pxEventList )
|
|||
static void prvAddCurrentTaskToDelayedList( TickType_t xTicksToWait,
|
||||
const BaseType_t xCanBlockIndefinitely ) PRIVILEGED_FUNCTION;
|
||||
|
||||
#if ( configQUEUE_DIRECT_TRANSFER == 1 )
|
||||
|
||||
/*
|
||||
* Set the direct transfer buffer for a task.
|
||||
* Called when a task is about to block on a data group operation.
|
||||
*/
|
||||
void vTaskSetDirectTransferBuffer( void * pvBuffer,
|
||||
BaseType_t xPosition,
|
||||
TaskHandle_t xTask );
|
||||
|
||||
/*
|
||||
* Clear the direct transfer buffer for a task.
|
||||
* This function should be called from data group send/receive operations when cleaning up.
|
||||
*/
|
||||
void vTaskClearDirectTransferBuffer( TaskHandle_t xTask );
|
||||
|
||||
/*
|
||||
* Get the highest priority task from an event list that has armed direct transfer.
|
||||
* Returns NULL if no task with armed direct transfer is found.
|
||||
* This function should be called from data group send/receive operations to find a task with direct transfer armed.
|
||||
*/
|
||||
TaskHandle_t xTaskGetHighestPriorityTaskWithDirectTransferArmed( const List_t * const pxEventList );
|
||||
|
||||
#endif /* configQUEUE_DIRECT_TRANSFER */
|
||||
|
||||
/*
|
||||
* Fills an TaskStatus_t structure with information on each task that is
|
||||
* referenced from the pxList list (which may be a ready list, a delayed list,
|
||||
|
|
@ -9256,6 +9289,133 @@ TickType_t uxTaskResetEventItemValue( void )
|
|||
#endif /* if ( ( configGENERATE_RUN_TIME_STATS == 1 ) && ( INCLUDE_xTaskGetIdleTaskHandle == 1 ) ) */
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
#if ( configQUEUE_DIRECT_TRANSFER == 1 )
|
||||
|
||||
void vTaskSetDirectTransferBuffer( void * pvBuffer,
|
||||
BaseType_t xPosition,
|
||||
TaskHandle_t xTask )
|
||||
{
|
||||
TCB_t * pxTCB;
|
||||
|
||||
/* With granular locks, we need kernel critical section for TCB access. */
|
||||
#if ( portUSING_GRANULAR_LOCKS == 1 )
|
||||
kernelENTER_CRITICAL();
|
||||
#endif
|
||||
{
|
||||
pxTCB = prvGetTCBFromHandle( xTask );
|
||||
|
||||
if( pxTCB != NULL )
|
||||
{
|
||||
pxTCB->pvDirectTransferBuffer = pvBuffer;
|
||||
pxTCB->xDirectTransferPosition = xPosition;
|
||||
}
|
||||
}
|
||||
#if ( portUSING_GRANULAR_LOCKS == 1 )
|
||||
kernelEXIT_CRITICAL();
|
||||
#endif
|
||||
}
|
||||
|
||||
void vTaskClearDirectTransferBuffer( TaskHandle_t xTask )
|
||||
{
|
||||
TCB_t * pxTCB;
|
||||
|
||||
/* With granular locks, we need kernel critical section for TCB access. */
|
||||
#if ( portUSING_GRANULAR_LOCKS == 1 )
|
||||
kernelENTER_CRITICAL();
|
||||
#endif
|
||||
{
|
||||
pxTCB = prvGetTCBFromHandle( xTask );
|
||||
|
||||
if( pxTCB != NULL )
|
||||
{
|
||||
pxTCB->pvDirectTransferBuffer = NULL;
|
||||
}
|
||||
}
|
||||
#if ( portUSING_GRANULAR_LOCKS == 1 )
|
||||
kernelEXIT_CRITICAL();
|
||||
#endif
|
||||
}
|
||||
|
||||
void * pvTaskGetDirectTransferBuffer( TaskHandle_t xTask )
|
||||
{
|
||||
TCB_t * pxTCB;
|
||||
void * pvReturn = NULL;
|
||||
|
||||
pxTCB = prvGetTCBFromHandle( xTask );
|
||||
configASSERT( pxTCB != NULL );
|
||||
|
||||
#if ( portUSING_GRANULAR_LOCKS == 1 )
|
||||
kernelENTER_CRITICAL();
|
||||
#endif
|
||||
{
|
||||
pvReturn = pxTCB->pvDirectTransferBuffer;
|
||||
}
|
||||
#if ( portUSING_GRANULAR_LOCKS == 1 )
|
||||
kernelEXIT_CRITICAL();
|
||||
#endif
|
||||
|
||||
return pvReturn;
|
||||
}
|
||||
|
||||
BaseType_t xTaskGetDirectTransferPosition( TaskHandle_t xTask )
|
||||
{
|
||||
TCB_t * pxTCB;
|
||||
BaseType_t xReturn = ( ( BaseType_t ) -1 );
|
||||
|
||||
pxTCB = prvGetTCBFromHandle( xTask );
|
||||
configASSERT( pxTCB != NULL );
|
||||
|
||||
#if ( portUSING_GRANULAR_LOCKS == 1 )
|
||||
kernelENTER_CRITICAL();
|
||||
#endif
|
||||
{
|
||||
xReturn = pxTCB->xDirectTransferPosition;
|
||||
}
|
||||
#if ( portUSING_GRANULAR_LOCKS == 1 )
|
||||
kernelEXIT_CRITICAL();
|
||||
#endif
|
||||
|
||||
return xReturn;
|
||||
}
|
||||
|
||||
TaskHandle_t xTaskGetHighestPriorityTaskWithDirectTransferArmed( const List_t * const pxEventList )
|
||||
{
|
||||
TaskHandle_t xReturn = NULL;
|
||||
|
||||
if( listCURRENT_LIST_LENGTH( pxEventList ) > 0U )
|
||||
{
|
||||
TCB_t * pxTCB;
|
||||
|
||||
/* Event lists are sorted by priority (highest first).
|
||||
* Get the head (highest priority task) and check if it has armed direct transfer.
|
||||
* This is O(1) operation, making it deterministic for RTOS requirements.
|
||||
*
|
||||
* If the highest priority task hasn't armed direct transfer (e.g., it's using
|
||||
* xQueuePeek instead of xQueueReceive), we skip direct transfer for this operation.
|
||||
* This is acceptable since direct transfer is an optimization, not a requirement. */
|
||||
pxTCB = ( TCB_t * ) listGET_OWNER_OF_HEAD_ENTRY( pxEventList );
|
||||
|
||||
#if ( portUSING_GRANULAR_LOCKS == 1 )
|
||||
/* Check if armed within kernel critical section */
|
||||
kernelENTER_CRITICAL();
|
||||
#endif
|
||||
{
|
||||
if( pxTCB->pvDirectTransferBuffer != NULL )
|
||||
{
|
||||
xReturn = ( TaskHandle_t ) pxTCB;
|
||||
}
|
||||
}
|
||||
#if ( portUSING_GRANULAR_LOCKS == 1 )
|
||||
kernelEXIT_CRITICAL();
|
||||
#endif
|
||||
}
|
||||
|
||||
return xReturn;
|
||||
}
|
||||
|
||||
#endif /* configQUEUE_DIRECT_TRANSFER */
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void prvAddCurrentTaskToDelayedList( TickType_t xTicksToWait,
|
||||
const BaseType_t xCanBlockIndefinitely )
|
||||
{
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue