change(freertos/smp): Update queue.c locking

Updated queue.c to use granular locking

- Added xTaskSpinlock and xISRSpinlock
- Replaced  critical section macros with data group critical section macros
such as taskENTER/EXIT_CRITICAL/_FROM_ISR() with queueENTER/EXIT_CRITICAL_FROM_ISR().
- Added vQueueEnterCritical/FromISR() and vQueueExitCritical/FromISR()
  which map to the data group critical section macros.
- Added prvLockQueueForTasks() and prvUnlockQueueForTasks() as the granular locking equivalents
to prvLockQueue() and prvUnlockQueue() respectively

Co-authored-by: Sudeep Mohanty <sudeep.mohanty@espressif.com>
This commit is contained in:
Darian Leung 2024-06-16 00:53:03 +08:00 committed by Sudeep Mohanty
parent 1ae917325c
commit 813017082e
2 changed files with 288 additions and 244 deletions

View file

@ -2150,10 +2150,18 @@
#define traceENTER_xTaskRemoveFromEventList( pxEventList )
#endif
#ifndef traceENTER_xTaskRemoveFromEventListFromISR
#define traceENTER_xTaskRemoveFromEventListFromISR( pxEventList )
#endif
#ifndef traceRETURN_xTaskRemoveFromEventList
#define traceRETURN_xTaskRemoveFromEventList( xReturn )
#endif
#ifndef traceRETURN_xTaskRemoveFromEventListFromISR
#define traceRETURN_xTaskRemoveFromEventListFromISR( xReturn )
#endif
#ifndef traceENTER_vTaskRemoveFromUnorderedEventList
#define traceENTER_vTaskRemoveFromUnorderedEventList( pxEventListItem, xItemValue )
#endif
@ -3324,6 +3332,10 @@ typedef struct xSTATIC_QUEUE
UBaseType_t uxDummy8;
uint8_t ucDummy9;
#endif
#if ( ( portUSING_GRANULAR_LOCKS == 1 ) && ( configNUMBER_OF_CORES > 1 ) )
portSPINLOCK_TYPE xDummySpinlock[ 2 ];
#endif /* #if ( ( portUSING_GRANULAR_LOCKS == 1 ) && ( configNUMBER_OF_CORES > 1 ) ) */
} StaticQueue_t;
typedef StaticQueue_t StaticSemaphore_t;
@ -3353,6 +3365,10 @@ typedef struct xSTATIC_EVENT_GROUP
#if ( ( configSUPPORT_STATIC_ALLOCATION == 1 ) && ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) )
uint8_t ucDummy4;
#endif
#if ( ( portUSING_GRANULAR_LOCKS == 1 ) && ( configNUMBER_OF_CORES > 1 ) )
portSPINLOCK_TYPE xDummySpinlock[ 2 ];
#endif /* #if ( ( portUSING_GRANULAR_LOCKS == 1 ) && ( configNUMBER_OF_CORES > 1 ) ) */
} StaticEventGroup_t;
/*
@ -3408,6 +3424,9 @@ typedef struct xSTATIC_STREAM_BUFFER
void * pvDummy5[ 2 ];
#endif
UBaseType_t uxDummy6;
#if ( ( portUSING_GRANULAR_LOCKS == 1 ) && ( configNUMBER_OF_CORES > 1 ) )
portSPINLOCK_TYPE xDummySpinlock[ 2 ];
#endif /* #if ( ( portUSING_GRANULAR_LOCKS == 1 ) && ( configNUMBER_OF_CORES > 1 ) ) */
} StaticStreamBuffer_t;
/* Message buffers are built on stream buffers. */

435
queue.c
View file

@ -133,6 +133,11 @@ typedef struct QueueDefinition /* The old naming convention is used to prevent b
UBaseType_t uxQueueNumber;
uint8_t ucQueueType;
#endif
#if ( ( portUSING_GRANULAR_LOCKS == 1 ) && ( configNUMBER_OF_CORES > 1 ) )
portSPINLOCK_TYPE xTaskSpinlock;
portSPINLOCK_TYPE xISRSpinlock;
#endif /* #if ( ( portUSING_GRANULAR_LOCKS == 1 ) && ( configNUMBER_OF_CORES > 1 ) ) */
} xQUEUE;
/* The old xQUEUE name is maintained above then typedefed to the new Queue_t
@ -187,7 +192,7 @@ static void prvUnlockQueue( Queue_t * const pxQueue ) PRIVILEGED_FUNCTION;
*
* @return pdTRUE if the queue contains no items, otherwise pdFALSE.
*/
static BaseType_t prvIsQueueEmpty( const Queue_t * pxQueue ) PRIVILEGED_FUNCTION;
static BaseType_t prvIsQueueEmpty( Queue_t * pxQueue ) PRIVILEGED_FUNCTION;
/*
* Uses a critical section to determine if there is any space in a queue.
@ -217,7 +222,20 @@ static void prvCopyDataFromQueue( Queue_t * const pxQueue,
* the queue set that the queue contains data.
*/
static BaseType_t prvNotifyQueueSetContainer( const Queue_t * const pxQueue ) PRIVILEGED_FUNCTION;
#endif
/*
* A version of prvNotifyQueueSetContainer() that can be called from an
* interrupt service routine (ISR).
*/
static BaseType_t prvNotifyQueueSetContainerFromISR( const Queue_t * const pxQueue ) PRIVILEGED_FUNCTION;
/*
* This function serves as a generic implementation for prvNotifyQueueSetContainer()
* and prvNotifyQueueSetContainerFromISR().
*/
static BaseType_t prvNotifyQueueSetContainerGeneric( const Queue_t * const pxQueue,
const BaseType_t xIsISR ) PRIVILEGED_FUNCTION;
#endif /* if ( configUSE_QUEUE_SETS == 1 ) */
/*
* Called after a Queue_t structure has been allocated either statically or
@ -251,12 +269,39 @@ static void prvInitialiseNewQueue( const UBaseType_t uxQueueLength,
#endif
/*-----------------------------------------------------------*/
/*
* Macros to mark the start and end of a critical code region.
*/
#if ( portUSING_GRANULAR_LOCKS == 1 )
#define queueENTER_CRITICAL( pxQueue ) taskDATA_GROUP_ENTER_CRITICAL( ( portSPINLOCK_TYPE * ) &( pxQueue )->xTaskSpinlock, ( portSPINLOCK_TYPE * ) &( pxQueue )->xISRSpinlock )
#define queueENTER_CRITICAL_FROM_ISR( pxQueue, puxSavedInterruptStatus ) taskDATA_GROUP_ENTER_CRITICAL_FROM_ISR( ( portSPINLOCK_TYPE * ) &( pxQueue )->xISRSpinlock, puxSavedInterruptStatus )
#define queueEXIT_CRITICAL( pxQueue ) taskDATA_GROUP_EXIT_CRITICAL( ( portSPINLOCK_TYPE * ) &( pxQueue )->xTaskSpinlock, ( portSPINLOCK_TYPE * ) &( pxQueue )->xISRSpinlock )
#define queueEXIT_CRITICAL_FROM_ISR( uxSavedInterruptStatus, pxQueue ) taskDATA_GROUP_EXIT_CRITICAL_FROM_ISR( uxSavedInterruptStatus, ( portSPINLOCK_TYPE * ) &( pxQueue )->xISRSpinlock )
#else /* #if ( portUSING_GRANULAR_LOCKS == 1 ) */
#define queueENTER_CRITICAL( pxQueue ) taskENTER_CRITICAL()
#define queueENTER_CRITICAL_FROM_ISR( pxQueue, puxSavedInterruptStatus ) do { *( puxSavedInterruptStatus ) = taskENTER_CRITICAL_FROM_ISR(); } while( 0 )
#define queueEXIT_CRITICAL( pxQueue ) taskEXIT_CRITICAL()
#define queueEXIT_CRITICAL_FROM_ISR( uxSavedInterruptStatus, pxQueue ) taskEXIT_CRITICAL_FROM_ISR( uxSavedInterruptStatus )
#endif /* #if ( portUSING_GRANULAR_LOCKS == 1 ) */
/*
* Macro to mark a queue as locked. Locking a queue prevents an ISR from
* accessing the queue event lists.
*
* Under granular locks, queueLOCK()/queueUNLOCK() already surround this with
* task-level spinlock + preemption-disabled region. To avoid redundant
* data-group enter/exit (which would re-disable preemption and re-acquire the
* same task spinlock), we minimize to interrupt masking only for the small
* metadata updates here. For the non-granular path, retain the full
* queueENTER_CRITICAL/queueEXIT_CRITICAL.
*/
#define prvLockQueue( pxQueue ) \
taskENTER_CRITICAL(); \
#if ( ( portUSING_GRANULAR_LOCKS == 1 ) && ( configNUMBER_OF_CORES > 1 ) )
#define prvLockQueue( pxQueue ) \
do { \
UBaseType_t ulState = portSET_INTERRUPT_MASK(); \
const BaseType_t xCoreID = ( BaseType_t ) portGET_CORE_ID(); \
portINCREMENT_CRITICAL_NESTING_COUNT( xCoreID ); \
portGET_SPINLOCK( xCoreID, ( portSPINLOCK_TYPE * ) &( ( pxQueue )->xISRSpinlock ) ); \
{ \
if( ( pxQueue )->cRxLock == queueUNLOCKED ) \
{ \
@ -267,7 +312,28 @@ static void prvInitialiseNewQueue( const UBaseType_t uxQueueLength,
( pxQueue )->cTxLock = queueLOCKED_UNMODIFIED; \
} \
} \
taskEXIT_CRITICAL()
portRELEASE_SPINLOCK( xCoreID, ( portSPINLOCK_TYPE * ) &( ( pxQueue )->xISRSpinlock ) ); \
portDECREMENT_CRITICAL_NESTING_COUNT( xCoreID ); \
if( portGET_CRITICAL_NESTING_COUNT( xCoreID ) == 0 ) \
{ \
portCLEAR_INTERRUPT_MASK( ulState ); \
} \
} while( 0 )
#else /* if ( ( portUSING_GRANULAR_LOCKS == 1 ) && ( configNUMBER_OF_CORES > 1 ) ) */
#define prvLockQueue( pxQueue ) \
queueENTER_CRITICAL( pxQueue ); \
{ \
if( ( pxQueue )->cRxLock == queueUNLOCKED ) \
{ \
( pxQueue )->cRxLock = queueLOCKED_UNMODIFIED; \
} \
if( ( pxQueue )->cTxLock == queueUNLOCKED ) \
{ \
( pxQueue )->cTxLock = queueLOCKED_UNMODIFIED; \
} \
} \
queueEXIT_CRITICAL( pxQueue )
#endif /* if ( ( portUSING_GRANULAR_LOCKS == 1 ) && ( configNUMBER_OF_CORES > 1 ) ) */
/*
* Macro to increment cTxLock member of the queue data structure. It is
@ -298,6 +364,56 @@ static void prvInitialiseNewQueue( const UBaseType_t uxQueueLength,
( pxQueue )->cRxLock = ( int8_t ) ( ( cRxLock ) + ( int8_t ) 1 ); \
} \
} while( 0 )
/*
* Macro used to lock and unlock a queue. When a task locks a queue, the
* task will have thread safe non-deterministic access to the queue.
* - Concurrent access from other tasks will be blocked by the xTaskSpinlock
* - Concurrent access from ISRs will be pended
*
* When the tasks unlocks the queue, all pended access attempts are handled.
*/
#if ( ( portUSING_GRANULAR_LOCKS == 1 ) && ( configNUMBER_OF_CORES > 1 ) )
#define queueLOCK( pxQueue ) \
do { \
taskDATA_GROUP_LOCK( &( ( pxQueue )->xTaskSpinlock ) ); \
prvLockQueue( ( pxQueue ) ); \
} while( 0 )
#define queueUNLOCK( pxQueue, xYieldAPI ) \
do { \
BaseType_t xAlreadyYielded; \
prvUnlockQueue( ( pxQueue ) ); \
xAlreadyYielded = taskDATA_GROUP_UNLOCK( &( ( pxQueue )->xTaskSpinlock ) ); \
if( ( xAlreadyYielded == pdFALSE ) && ( ( xYieldAPI ) == pdTRUE ) ) \
{ \
taskYIELD_WITHIN_API(); \
} \
else \
{ \
mtCOVERAGE_TEST_MARKER(); \
} \
} while( 0 )
#else /* #if ( ( portUSING_GRANULAR_LOCKS == 1 ) && ( configNUMBER_OF_CORES > 1 ) ) */
#define queueLOCK( pxQueue ) \
do { \
vTaskSuspendAll(); \
prvLockQueue( ( pxQueue ) ); \
} while( 0 )
#define queueUNLOCK( pxQueue, xYieldAPI ) \
do { \
BaseType_t xAlreadyYielded; \
prvUnlockQueue( ( pxQueue ) ); \
xAlreadyYielded = xTaskResumeAll(); \
if( ( xAlreadyYielded == pdFALSE ) && ( ( xYieldAPI ) == pdTRUE ) ) \
{ \
taskYIELD_WITHIN_API(); \
} \
else \
{ \
mtCOVERAGE_TEST_MARKER(); \
} \
} while( 0 )
#endif /* #if ( ( portUSING_GRANULAR_LOCKS == 1 ) && ( configNUMBER_OF_CORES > 1 ) ) */
/*-----------------------------------------------------------*/
BaseType_t xQueueGenericReset( QueueHandle_t xQueue,
@ -310,12 +426,22 @@ BaseType_t xQueueGenericReset( QueueHandle_t xQueue,
configASSERT( pxQueue );
#if ( ( portUSING_GRANULAR_LOCKS == 1 ) && ( configNUMBER_OF_CORES > 1 ) )
{
if( xNewQueue == pdTRUE )
{
portINIT_SPINLOCK( &( pxQueue->xTaskSpinlock ) );
portINIT_SPINLOCK( &( pxQueue->xISRSpinlock ) );
}
}
#endif /* #if ( ( portUSING_GRANULAR_LOCKS == 1 ) && ( configNUMBER_OF_CORES > 1 ) ) */
if( ( pxQueue != NULL ) &&
( pxQueue->uxLength >= 1U ) &&
/* Check for multiplication overflow. */
( ( SIZE_MAX / pxQueue->uxLength ) >= pxQueue->uxItemSize ) )
{
taskENTER_CRITICAL();
queueENTER_CRITICAL( pxQueue );
{
pxQueue->u.xQueue.pcTail = pxQueue->pcHead + ( pxQueue->uxLength * pxQueue->uxItemSize );
pxQueue->uxMessagesWaiting = ( UBaseType_t ) 0U;
@ -331,8 +457,6 @@ BaseType_t xQueueGenericReset( QueueHandle_t xQueue,
* will still be empty. If there are tasks blocked waiting to write to
* the queue, then one should be unblocked as after this function exits
* it will be possible to write to it. */
if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToSend ) ) == pdFALSE )
{
if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToSend ) ) != pdFALSE )
{
queueYIELD_IF_USING_PREEMPTION();
@ -343,18 +467,13 @@ BaseType_t xQueueGenericReset( QueueHandle_t xQueue,
}
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
else
{
/* Ensure the event queues start in the correct state. */
vListInitialise( &( pxQueue->xTasksWaitingToSend ) );
vListInitialise( &( pxQueue->xTasksWaitingToReceive ) );
}
}
taskEXIT_CRITICAL();
queueEXIT_CRITICAL( pxQueue );
}
else
{
@ -703,7 +822,7 @@ static void prvInitialiseNewQueue( const UBaseType_t uxQueueLength,
* calling task is the mutex holder, but not a good way of determining the
* identity of the mutex holder, as the holder may change between the
* following critical section exiting and the function returning. */
taskENTER_CRITICAL();
queueENTER_CRITICAL( pxSemaphore );
{
if( pxSemaphore->uxQueueType == queueQUEUE_IS_MUTEX )
{
@ -714,7 +833,7 @@ static void prvInitialiseNewQueue( const UBaseType_t uxQueueLength,
pxReturn = NULL;
}
}
taskEXIT_CRITICAL();
queueEXIT_CRITICAL( pxSemaphore );
traceRETURN_xQueueGetMutexHolder( pxReturn );
@ -968,7 +1087,7 @@ BaseType_t xQueueGenericSend( QueueHandle_t xQueue,
for( ; ; )
{
taskENTER_CRITICAL();
queueENTER_CRITICAL( pxQueue );
{
/* 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
@ -1009,8 +1128,6 @@ BaseType_t xQueueGenericSend( QueueHandle_t xQueue,
{
/* If there was a task waiting for data to arrive on the
* queue then unblock it now. */
if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) == pdFALSE )
{
if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) != pdFALSE )
{
/* The unblocked task has a priority higher than
@ -1019,11 +1136,6 @@ BaseType_t xQueueGenericSend( QueueHandle_t xQueue,
* kernel takes care of that. */
queueYIELD_IF_USING_PREEMPTION();
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
else if( xYieldRequired != pdFALSE )
{
/* This path is a special case that will only get
@ -1044,8 +1156,6 @@ BaseType_t xQueueGenericSend( QueueHandle_t xQueue,
/* If there was a task waiting for data to arrive on the
* queue then unblock it now. */
if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) == pdFALSE )
{
if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) != pdFALSE )
{
/* The unblocked task has a priority higher than
@ -1054,11 +1164,6 @@ BaseType_t xQueueGenericSend( QueueHandle_t xQueue,
* takes care of that. */
queueYIELD_IF_USING_PREEMPTION();
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
else if( xYieldRequired != pdFALSE )
{
/* This path is a special case that will only get
@ -1074,7 +1179,7 @@ BaseType_t xQueueGenericSend( QueueHandle_t xQueue,
}
#endif /* configUSE_QUEUE_SETS */
taskEXIT_CRITICAL();
queueEXIT_CRITICAL( pxQueue );
traceRETURN_xQueueGenericSend( pdPASS );
@ -1086,7 +1191,7 @@ BaseType_t xQueueGenericSend( QueueHandle_t xQueue,
{
/* The queue was full and no block time is specified (or
* the block time has expired) so leave now. */
taskEXIT_CRITICAL();
queueEXIT_CRITICAL( pxQueue );
/* Return to the original privilege level before exiting
* the function. */
@ -1109,13 +1214,12 @@ BaseType_t xQueueGenericSend( QueueHandle_t xQueue,
}
}
}
taskEXIT_CRITICAL();
queueEXIT_CRITICAL( pxQueue );
/* Interrupts and other tasks can send to and receive from the queue
* now the critical section has been exited. */
vTaskSuspendAll();
prvLockQueue( pxQueue );
queueLOCK( pxQueue );
/* Update the timeout state to see if it has expired yet. */
if( xTaskCheckForTimeOut( &xTimeOut, &xTicksToWait ) == pdFALSE )
@ -1125,35 +1229,18 @@ BaseType_t xQueueGenericSend( QueueHandle_t xQueue,
traceBLOCKING_ON_QUEUE_SEND( pxQueue );
vTaskPlaceOnEventList( &( pxQueue->xTasksWaitingToSend ), xTicksToWait );
/* Unlocking the queue means queue events can effect the
* event list. It is possible that interrupts occurring now
* remove this task from the event list again - but as the
* scheduler is suspended the task will go onto the pending
* ready list instead of the actual ready list. */
prvUnlockQueue( pxQueue );
/* Resuming the scheduler will move tasks from the pending
* ready list into the ready list - so it is feasible that this
* task is already in the ready list before it yields - in which
* case the yield will not cause a context switch unless there
* is also a higher priority task in the pending ready list. */
if( xTaskResumeAll() == pdFALSE )
{
taskYIELD_WITHIN_API();
}
queueUNLOCK( pxQueue, pdTRUE );
}
else
{
/* Try again. */
prvUnlockQueue( pxQueue );
( void ) xTaskResumeAll();
queueUNLOCK( pxQueue, pdFALSE );
}
}
else
{
/* The timeout has expired. */
prvUnlockQueue( pxQueue );
( void ) xTaskResumeAll();
queueUNLOCK( pxQueue, pdFALSE );
traceQUEUE_SEND_FAILED( pxQueue );
traceRETURN_xQueueGenericSend( errQUEUE_FULL );
@ -1202,7 +1289,7 @@ BaseType_t xQueueGenericSendFromISR( QueueHandle_t xQueue,
/* MISRA Ref 4.7.1 [Return value shall be checked] */
/* More details at: https://github.com/FreeRTOS/FreeRTOS-Kernel/blob/main/MISRA.md#dir-47 */
/* coverity[misra_c_2012_directive_4_7_violation] */
uxSavedInterruptStatus = ( UBaseType_t ) taskENTER_CRITICAL_FROM_ISR();
queueENTER_CRITICAL_FROM_ISR( pxQueue, &uxSavedInterruptStatus );
{
if( ( pxQueue->uxMessagesWaiting < pxQueue->uxLength ) || ( xCopyPosition == queueOVERWRITE ) )
{
@ -1233,7 +1320,7 @@ BaseType_t xQueueGenericSendFromISR( QueueHandle_t xQueue,
* in the queue has not changed. */
mtCOVERAGE_TEST_MARKER();
}
else if( prvNotifyQueueSetContainer( pxQueue ) != pdFALSE )
else if( prvNotifyQueueSetContainerFromISR( pxQueue ) != pdFALSE )
{
/* The queue is a member of a queue set, and posting
* to the queue set caused a higher priority task to
@ -1254,9 +1341,7 @@ BaseType_t xQueueGenericSendFromISR( QueueHandle_t xQueue,
}
else
{
if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) == pdFALSE )
{
if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) != pdFALSE )
if( xTaskRemoveFromEventListFromISR( &( pxQueue->xTasksWaitingToReceive ) ) != pdFALSE )
{
/* The task waiting has a higher priority so
* record that a context switch is required. */
@ -1274,17 +1359,10 @@ BaseType_t xQueueGenericSendFromISR( QueueHandle_t xQueue,
mtCOVERAGE_TEST_MARKER();
}
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
}
#else /* configUSE_QUEUE_SETS */
{
if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) == pdFALSE )
{
if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) != pdFALSE )
if( xTaskRemoveFromEventListFromISR( &( pxQueue->xTasksWaitingToReceive ) ) != pdFALSE )
{
/* The task waiting has a higher priority so record that a
* context switch is required. */
@ -1301,11 +1379,6 @@ BaseType_t xQueueGenericSendFromISR( QueueHandle_t xQueue,
{
mtCOVERAGE_TEST_MARKER();
}
}
else
{
mtCOVERAGE_TEST_MARKER();
}
/* Not used in this path. */
( void ) uxPreviousMessagesWaiting;
@ -1327,7 +1400,7 @@ BaseType_t xQueueGenericSendFromISR( QueueHandle_t xQueue,
xReturn = errQUEUE_FULL;
}
}
taskEXIT_CRITICAL_FROM_ISR( uxSavedInterruptStatus );
queueEXIT_CRITICAL_FROM_ISR( uxSavedInterruptStatus, pxQueue );
traceRETURN_xQueueGenericSendFromISR( xReturn );
@ -1378,7 +1451,7 @@ BaseType_t xQueueGiveFromISR( QueueHandle_t xQueue,
/* MISRA Ref 4.7.1 [Return value shall be checked] */
/* More details at: https://github.com/FreeRTOS/FreeRTOS-Kernel/blob/main/MISRA.md#dir-47 */
/* coverity[misra_c_2012_directive_4_7_violation] */
uxSavedInterruptStatus = ( UBaseType_t ) taskENTER_CRITICAL_FROM_ISR();
queueENTER_CRITICAL_FROM_ISR( pxQueue, &uxSavedInterruptStatus );
{
const UBaseType_t uxMessagesWaiting = pxQueue->uxMessagesWaiting;
@ -1407,7 +1480,7 @@ BaseType_t xQueueGiveFromISR( QueueHandle_t xQueue,
{
if( pxQueue->pxQueueSetContainer != NULL )
{
if( prvNotifyQueueSetContainer( pxQueue ) != pdFALSE )
if( prvNotifyQueueSetContainerFromISR( pxQueue ) != pdFALSE )
{
/* The semaphore is a member of a queue set, and
* posting to the queue set caused a higher priority
@ -1428,9 +1501,7 @@ BaseType_t xQueueGiveFromISR( QueueHandle_t xQueue,
}
else
{
if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) == pdFALSE )
{
if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) != pdFALSE )
if( xTaskRemoveFromEventListFromISR( &( pxQueue->xTasksWaitingToReceive ) ) != pdFALSE )
{
/* The task waiting has a higher priority so
* record that a context switch is required. */
@ -1448,17 +1519,10 @@ BaseType_t xQueueGiveFromISR( QueueHandle_t xQueue,
mtCOVERAGE_TEST_MARKER();
}
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
}
#else /* configUSE_QUEUE_SETS */
{
if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) == pdFALSE )
{
if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) != pdFALSE )
if( xTaskRemoveFromEventListFromISR( &( pxQueue->xTasksWaitingToReceive ) ) != pdFALSE )
{
/* The task waiting has a higher priority so record that a
* context switch is required. */
@ -1476,11 +1540,6 @@ BaseType_t xQueueGiveFromISR( QueueHandle_t xQueue,
mtCOVERAGE_TEST_MARKER();
}
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
#endif /* configUSE_QUEUE_SETS */
}
else
@ -1498,7 +1557,7 @@ BaseType_t xQueueGiveFromISR( QueueHandle_t xQueue,
xReturn = errQUEUE_FULL;
}
}
taskEXIT_CRITICAL_FROM_ISR( uxSavedInterruptStatus );
queueEXIT_CRITICAL_FROM_ISR( uxSavedInterruptStatus, pxQueue );
traceRETURN_xQueueGiveFromISR( xReturn );
@ -1532,7 +1591,7 @@ BaseType_t xQueueReceive( QueueHandle_t xQueue,
for( ; ; )
{
taskENTER_CRITICAL();
queueENTER_CRITICAL( pxQueue );
{
const UBaseType_t uxMessagesWaiting = pxQueue->uxMessagesWaiting;
@ -1564,7 +1623,7 @@ BaseType_t xQueueReceive( QueueHandle_t xQueue,
mtCOVERAGE_TEST_MARKER();
}
taskEXIT_CRITICAL();
queueEXIT_CRITICAL( pxQueue );
traceRETURN_xQueueReceive( pdPASS );
@ -1576,7 +1635,7 @@ BaseType_t xQueueReceive( QueueHandle_t xQueue,
{
/* The queue was empty and no block time is specified (or
* the block time has expired) so leave now. */
taskEXIT_CRITICAL();
queueEXIT_CRITICAL( pxQueue );
traceQUEUE_RECEIVE_FAILED( pxQueue );
traceRETURN_xQueueReceive( errQUEUE_EMPTY );
@ -1597,13 +1656,12 @@ BaseType_t xQueueReceive( QueueHandle_t xQueue,
}
}
}
taskEXIT_CRITICAL();
queueEXIT_CRITICAL( pxQueue );
/* Interrupts and other tasks can send to and receive from the queue
* now the critical section has been exited. */
vTaskSuspendAll();
prvLockQueue( pxQueue );
queueLOCK( pxQueue );
/* Update the timeout state to see if it has expired yet. */
if( xTaskCheckForTimeOut( &xTimeOut, &xTicksToWait ) == pdFALSE )
@ -1614,31 +1672,20 @@ BaseType_t xQueueReceive( QueueHandle_t xQueue,
{
traceBLOCKING_ON_QUEUE_RECEIVE( pxQueue );
vTaskPlaceOnEventList( &( pxQueue->xTasksWaitingToReceive ), xTicksToWait );
prvUnlockQueue( pxQueue );
if( xTaskResumeAll() == pdFALSE )
{
taskYIELD_WITHIN_API();
}
else
{
mtCOVERAGE_TEST_MARKER();
}
queueUNLOCK( pxQueue, pdTRUE );
}
else
{
/* The queue contains data again. Loop back to try and read the
* data. */
prvUnlockQueue( pxQueue );
( void ) xTaskResumeAll();
queueUNLOCK( pxQueue, pdFALSE );
}
}
else
{
/* Timed out. If there is no data in the queue exit, otherwise loop
* back and attempt to read the data. */
prvUnlockQueue( pxQueue );
( void ) xTaskResumeAll();
queueUNLOCK( pxQueue, pdFALSE );
if( prvIsQueueEmpty( pxQueue ) != pdFALSE )
{
@ -1685,7 +1732,7 @@ BaseType_t xQueueSemaphoreTake( QueueHandle_t xQueue,
for( ; ; )
{
taskENTER_CRITICAL();
queueENTER_CRITICAL( pxQueue );
{
/* Semaphores are queues with an item size of 0, and where the
* number of messages in the queue is the semaphore's count value. */
@ -1718,8 +1765,6 @@ BaseType_t xQueueSemaphoreTake( QueueHandle_t xQueue,
/* Check to see if other tasks are blocked waiting to give the
* semaphore, and if so, unblock the highest priority such task. */
if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToSend ) ) == pdFALSE )
{
if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToSend ) ) != pdFALSE )
{
queueYIELD_IF_USING_PREEMPTION();
@ -1728,13 +1773,8 @@ BaseType_t xQueueSemaphoreTake( QueueHandle_t xQueue,
{
mtCOVERAGE_TEST_MARKER();
}
}
else
{
mtCOVERAGE_TEST_MARKER();
}
taskEXIT_CRITICAL();
queueEXIT_CRITICAL( pxQueue );
traceRETURN_xQueueSemaphoreTake( pdPASS );
@ -1746,7 +1786,7 @@ BaseType_t xQueueSemaphoreTake( QueueHandle_t xQueue,
{
/* The semaphore count was 0 and no block time is specified
* (or the block time has expired) so exit now. */
taskEXIT_CRITICAL();
queueEXIT_CRITICAL( pxQueue );
traceQUEUE_RECEIVE_FAILED( pxQueue );
traceRETURN_xQueueSemaphoreTake( errQUEUE_EMPTY );
@ -1767,13 +1807,12 @@ BaseType_t xQueueSemaphoreTake( QueueHandle_t xQueue,
}
}
}
taskEXIT_CRITICAL();
queueEXIT_CRITICAL( pxQueue );
/* Interrupts and other tasks can give to and take from the semaphore
* now the critical section has been exited. */
vTaskSuspendAll();
prvLockQueue( pxQueue );
queueLOCK( pxQueue );
/* Update the timeout state to see if it has expired yet. */
if( xTaskCheckForTimeOut( &xTimeOut, &xTicksToWait ) == pdFALSE )
@ -1800,30 +1839,19 @@ BaseType_t xQueueSemaphoreTake( QueueHandle_t xQueue,
#endif /* if ( configUSE_MUTEXES == 1 ) */
vTaskPlaceOnEventList( &( pxQueue->xTasksWaitingToReceive ), xTicksToWait );
prvUnlockQueue( pxQueue );
if( xTaskResumeAll() == pdFALSE )
{
taskYIELD_WITHIN_API();
}
else
{
mtCOVERAGE_TEST_MARKER();
}
queueUNLOCK( pxQueue, pdTRUE );
}
else
{
/* There was no timeout and the semaphore count was not 0, so
* attempt to take the semaphore again. */
prvUnlockQueue( pxQueue );
( void ) xTaskResumeAll();
queueUNLOCK( pxQueue, pdFALSE );
}
}
else
{
/* Timed out. */
prvUnlockQueue( pxQueue );
( void ) xTaskResumeAll();
queueUNLOCK( pxQueue, pdFALSE );
/* If the semaphore count is 0 exit now as the timeout has
* expired. Otherwise return to attempt to take the semaphore that is
@ -1838,7 +1866,7 @@ BaseType_t xQueueSemaphoreTake( QueueHandle_t xQueue,
* test the mutex type again to check it is actually a mutex. */
if( xInheritanceOccurred != pdFALSE )
{
taskENTER_CRITICAL();
queueENTER_CRITICAL( pxQueue );
{
UBaseType_t uxHighestWaitingPriority;
@ -1858,7 +1886,7 @@ BaseType_t xQueueSemaphoreTake( QueueHandle_t xQueue,
/* coverity[overrun] */
vTaskPriorityDisinheritAfterTimeout( pxQueue->u.xSemaphore.xMutexHolder, uxHighestWaitingPriority );
}
taskEXIT_CRITICAL();
queueEXIT_CRITICAL( pxQueue );
}
}
#endif /* configUSE_MUTEXES */
@ -1901,7 +1929,7 @@ BaseType_t xQueuePeek( QueueHandle_t xQueue,
for( ; ; )
{
taskENTER_CRITICAL();
queueENTER_CRITICAL( pxQueue );
{
const UBaseType_t uxMessagesWaiting = pxQueue->uxMessagesWaiting;
@ -1922,8 +1950,6 @@ BaseType_t xQueuePeek( QueueHandle_t xQueue,
/* The data is being left in the queue, so see if there are
* any other tasks waiting for the data. */
if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) == pdFALSE )
{
if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) != pdFALSE )
{
/* The task waiting has a higher priority than this task. */
@ -1933,13 +1959,8 @@ BaseType_t xQueuePeek( QueueHandle_t xQueue,
{
mtCOVERAGE_TEST_MARKER();
}
}
else
{
mtCOVERAGE_TEST_MARKER();
}
taskEXIT_CRITICAL();
queueEXIT_CRITICAL( pxQueue );
traceRETURN_xQueuePeek( pdPASS );
@ -1951,7 +1972,7 @@ BaseType_t xQueuePeek( QueueHandle_t xQueue,
{
/* The queue was empty and no block time is specified (or
* the block time has expired) so leave now. */
taskEXIT_CRITICAL();
queueEXIT_CRITICAL( pxQueue );
traceQUEUE_PEEK_FAILED( pxQueue );
traceRETURN_xQueuePeek( errQUEUE_EMPTY );
@ -1973,13 +1994,12 @@ BaseType_t xQueuePeek( QueueHandle_t xQueue,
}
}
}
taskEXIT_CRITICAL();
queueEXIT_CRITICAL( pxQueue );
/* Interrupts and other tasks can send to and receive from the queue
* now that the critical section has been exited. */
vTaskSuspendAll();
prvLockQueue( pxQueue );
queueLOCK( pxQueue );
/* Update the timeout state to see if it has expired yet. */
if( xTaskCheckForTimeOut( &xTimeOut, &xTicksToWait ) == pdFALSE )
@ -1990,31 +2010,20 @@ BaseType_t xQueuePeek( QueueHandle_t xQueue,
{
traceBLOCKING_ON_QUEUE_PEEK( pxQueue );
vTaskPlaceOnEventList( &( pxQueue->xTasksWaitingToReceive ), xTicksToWait );
prvUnlockQueue( pxQueue );
if( xTaskResumeAll() == pdFALSE )
{
taskYIELD_WITHIN_API();
}
else
{
mtCOVERAGE_TEST_MARKER();
}
queueUNLOCK( pxQueue, pdTRUE );
}
else
{
/* There is data in the queue now, so don't enter the blocked
* state, instead return to try and obtain the data. */
prvUnlockQueue( pxQueue );
( void ) xTaskResumeAll();
queueUNLOCK( pxQueue, pdFALSE );
}
}
else
{
/* The timeout has expired. If there is still no data in the queue
* exit, otherwise go back and try to read the data again. */
prvUnlockQueue( pxQueue );
( void ) xTaskResumeAll();
queueUNLOCK( pxQueue, pdFALSE );
if( prvIsQueueEmpty( pxQueue ) != pdFALSE )
{
@ -2064,7 +2073,7 @@ BaseType_t xQueueReceiveFromISR( QueueHandle_t xQueue,
/* MISRA Ref 4.7.1 [Return value shall be checked] */
/* More details at: https://github.com/FreeRTOS/FreeRTOS-Kernel/blob/main/MISRA.md#dir-47 */
/* coverity[misra_c_2012_directive_4_7_violation] */
uxSavedInterruptStatus = ( UBaseType_t ) taskENTER_CRITICAL_FROM_ISR();
queueENTER_CRITICAL_FROM_ISR( pxQueue, &uxSavedInterruptStatus );
{
const UBaseType_t uxMessagesWaiting = pxQueue->uxMessagesWaiting;
@ -2086,7 +2095,7 @@ BaseType_t xQueueReceiveFromISR( QueueHandle_t xQueue,
{
if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToSend ) ) == pdFALSE )
{
if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToSend ) ) != pdFALSE )
if( xTaskRemoveFromEventListFromISR( &( pxQueue->xTasksWaitingToSend ) ) != pdFALSE )
{
/* The task waiting has a higher priority than us so
* force a context switch. */
@ -2124,7 +2133,7 @@ BaseType_t xQueueReceiveFromISR( QueueHandle_t xQueue,
traceQUEUE_RECEIVE_FROM_ISR_FAILED( pxQueue );
}
}
taskEXIT_CRITICAL_FROM_ISR( uxSavedInterruptStatus );
queueEXIT_CRITICAL_FROM_ISR( uxSavedInterruptStatus, pxQueue );
traceRETURN_xQueueReceiveFromISR( xReturn );
@ -2164,7 +2173,7 @@ BaseType_t xQueuePeekFromISR( QueueHandle_t xQueue,
/* MISRA Ref 4.7.1 [Return value shall be checked] */
/* More details at: https://github.com/FreeRTOS/FreeRTOS-Kernel/blob/main/MISRA.md#dir-47 */
/* coverity[misra_c_2012_directive_4_7_violation] */
uxSavedInterruptStatus = ( UBaseType_t ) taskENTER_CRITICAL_FROM_ISR();
queueENTER_CRITICAL_FROM_ISR( pxQueue, &uxSavedInterruptStatus );
{
/* Cannot block in an ISR, so check there is data available. */
if( pxQueue->uxMessagesWaiting > ( UBaseType_t ) 0 )
@ -2185,7 +2194,7 @@ BaseType_t xQueuePeekFromISR( QueueHandle_t xQueue,
traceQUEUE_PEEK_FROM_ISR_FAILED( pxQueue );
}
}
taskEXIT_CRITICAL_FROM_ISR( uxSavedInterruptStatus );
queueEXIT_CRITICAL_FROM_ISR( uxSavedInterruptStatus, pxQueue );
traceRETURN_xQueuePeekFromISR( xReturn );
@ -2201,11 +2210,11 @@ UBaseType_t uxQueueMessagesWaiting( const QueueHandle_t xQueue )
configASSERT( xQueue );
portBASE_TYPE_ENTER_CRITICAL();
queueENTER_CRITICAL( xQueue );
{
uxReturn = ( ( Queue_t * ) xQueue )->uxMessagesWaiting;
}
portBASE_TYPE_EXIT_CRITICAL();
queueEXIT_CRITICAL( xQueue );
traceRETURN_uxQueueMessagesWaiting( uxReturn );
@ -2222,11 +2231,11 @@ UBaseType_t uxQueueSpacesAvailable( const QueueHandle_t xQueue )
configASSERT( pxQueue );
portBASE_TYPE_ENTER_CRITICAL();
queueENTER_CRITICAL( pxQueue );
{
uxReturn = ( UBaseType_t ) ( pxQueue->uxLength - pxQueue->uxMessagesWaiting );
}
portBASE_TYPE_EXIT_CRITICAL();
queueEXIT_CRITICAL( pxQueue );
traceRETURN_uxQueueSpacesAvailable( uxReturn );
@ -2492,7 +2501,8 @@ static void prvCopyDataFromQueue( Queue_t * const pxQueue,
static void prvUnlockQueue( Queue_t * const pxQueue )
{
/* THIS FUNCTION MUST BE CALLED WITH THE SCHEDULER SUSPENDED. */
/* THIS FUNCTION MUST BE CALLED WITH THE SCHEDULER SUSPENDED WHEN portUSING_GRANULAR_LOCKS IS 0.
* IT MUST BE CALLED WITH TASK PREEMTION DISABLED WHEN portUSING_GRANULAR_LOCKS IS 1. */
/* 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
@ -2630,15 +2640,25 @@ static void prvUnlockQueue( Queue_t * const pxQueue )
pxQueue->cRxLock = queueUNLOCKED;
}
taskEXIT_CRITICAL();
#if ( ( portUSING_GRANULAR_LOCKS == 1 ) && ( configNUMBER_OF_CORES > 1 ) )
portRELEASE_SPINLOCK( xCoreID, ( portSPINLOCK_TYPE * ) &( pxQueue->xISRSpinlock ) );
portDECREMENT_CRITICAL_NESTING_COUNT( xCoreID );
if( portGET_CRITICAL_NESTING_COUNT( xCoreID ) == 0 )
{
portENABLE_INTERRUPTS();
}
#else
queueEXIT_CRITICAL( pxQueue );
#endif
}
/*-----------------------------------------------------------*/
static BaseType_t prvIsQueueEmpty( const Queue_t * pxQueue )
static BaseType_t prvIsQueueEmpty( Queue_t * pxQueue )
{
BaseType_t xReturn;
taskENTER_CRITICAL();
queueENTER_CRITICAL( pxQueue );
{
if( pxQueue->uxMessagesWaiting == ( UBaseType_t ) 0 )
{
@ -2649,7 +2669,7 @@ static BaseType_t prvIsQueueEmpty( const Queue_t * pxQueue )
xReturn = pdFALSE;
}
}
taskEXIT_CRITICAL();
queueEXIT_CRITICAL( pxQueue );
return xReturn;
}
@ -2683,7 +2703,7 @@ static BaseType_t prvIsQueueFull( const Queue_t * pxQueue )
{
BaseType_t xReturn;
taskENTER_CRITICAL();
queueENTER_CRITICAL( pxQueue );
{
if( pxQueue->uxMessagesWaiting == pxQueue->uxLength )
{
@ -2694,7 +2714,7 @@ static BaseType_t prvIsQueueFull( const Queue_t * pxQueue )
xReturn = pdFALSE;
}
}
taskEXIT_CRITICAL();
queueEXIT_CRITICAL( pxQueue );
return xReturn;
}
@ -3174,7 +3194,7 @@ BaseType_t xQueueIsQueueFullFromISR( const QueueHandle_t xQueue )
* time a yield will be performed. If an item is added to the queue while
* the queue is locked, and the calling task blocks on the queue, then the
* calling task will be immediately unblocked when the queue is unlocked. */
prvLockQueue( pxQueue );
queueLOCK( pxQueue );
if( pxQueue->uxMessagesWaiting == ( UBaseType_t ) 0U )
{
@ -3186,7 +3206,7 @@ BaseType_t xQueueIsQueueFullFromISR( const QueueHandle_t xQueue )
mtCOVERAGE_TEST_MARKER();
}
prvUnlockQueue( pxQueue );
queueUNLOCK( pxQueue, pdFALSE );
traceRETURN_vQueueWaitForMessageRestricted();
}
@ -3238,17 +3258,18 @@ BaseType_t xQueueIsQueueFullFromISR( const QueueHandle_t xQueue )
QueueSetHandle_t xQueueSet )
{
BaseType_t xReturn;
Queue_t * const pxQueue = xQueueOrSemaphore;
traceENTER_xQueueAddToSet( xQueueOrSemaphore, xQueueSet );
taskENTER_CRITICAL();
queueENTER_CRITICAL( pxQueue );
{
if( ( ( Queue_t * ) xQueueOrSemaphore )->pxQueueSetContainer != NULL )
if( pxQueue->pxQueueSetContainer != NULL )
{
/* Cannot add a queue/semaphore to more than one queue set. */
xReturn = pdFAIL;
}
else if( ( ( Queue_t * ) xQueueOrSemaphore )->uxMessagesWaiting != ( UBaseType_t ) 0 )
else if( pxQueue->uxMessagesWaiting != ( UBaseType_t ) 0 )
{
/* Cannot add a queue/semaphore to a queue set if there are already
* items in the queue/semaphore. */
@ -3256,11 +3277,11 @@ BaseType_t xQueueIsQueueFullFromISR( const QueueHandle_t xQueue )
}
else
{
( ( Queue_t * ) xQueueOrSemaphore )->pxQueueSetContainer = xQueueSet;
pxQueue->pxQueueSetContainer = xQueueSet;
xReturn = pdPASS;
}
}
taskEXIT_CRITICAL();
queueEXIT_CRITICAL( pxQueue );
traceRETURN_xQueueAddToSet( xReturn );
@ -3294,12 +3315,12 @@ BaseType_t xQueueIsQueueFullFromISR( const QueueHandle_t xQueue )
}
else
{
taskENTER_CRITICAL();
queueENTER_CRITICAL( pxQueueOrSemaphore );
{
/* The queue is no longer contained in the set. */
pxQueueOrSemaphore->pxQueueSetContainer = NULL;
}
taskEXIT_CRITICAL();
queueEXIT_CRITICAL( pxQueueOrSemaphore );
xReturn = pdPASS;
}
@ -3363,15 +3384,15 @@ BaseType_t xQueueIsQueueFullFromISR( const QueueHandle_t xQueue )
{
const BaseType_t xCoreID = portGET_CORE_ID();
/* This API must be called in a critical section which already has preemption
* and interrupt disabled. */
portGET_SPINLOCK( xCoreID, ( portSPINLOCK_TYPE * ) &( pxQueue->pxQueueSetContainer->xTaskSpinlock ) );
/* This API is called within the queue critical section (which
* already holds the source queue's task spinlock and disables
* interrupts), so only the queue-set container's ISR spinlock
* needs to be acquired here. */
portGET_SPINLOCK( xCoreID, ( portSPINLOCK_TYPE * ) &( pxQueue->pxQueueSetContainer->xISRSpinlock ) );
{
xReturn = prvNotifyQueueSetContainerGeneric( pxQueue, pdFALSE );
}
portRELEASE_SPINLOCK( xCoreID, ( portSPINLOCK_TYPE * ) &( pxQueue->pxQueueSetContainer->xISRSpinlock ) );
portRELEASE_SPINLOCK( xCoreID, ( portSPINLOCK_TYPE * ) &( pxQueue->pxQueueSetContainer->xTaskSpinlock ) );
}
#endif /* if ( portUSING_GRANULAR_LOCKS == 0 ) */
@ -3431,17 +3452,21 @@ BaseType_t xQueueIsQueueFullFromISR( const QueueHandle_t xQueue )
if( cTxLock == queueUNLOCKED )
{
if( listLIST_IS_EMPTY( &( pxQueueSetContainer->xTasksWaitingToReceive ) ) == pdFALSE )
BaseType_t xHigherPriorityTaskWoken;
if( xIsISR == pdTRUE )
{
if( xTaskRemoveFromEventList( &( pxQueueSetContainer->xTasksWaitingToReceive ) ) != pdFALSE )
{
/* The task waiting has a higher priority. */
xReturn = pdTRUE;
xHigherPriorityTaskWoken = xTaskRemoveFromEventListFromISR( &( pxQueueSetContainer->xTasksWaitingToReceive ) );
}
else
{
mtCOVERAGE_TEST_MARKER();
xHigherPriorityTaskWoken = xTaskRemoveFromEventList( &( pxQueueSetContainer->xTasksWaitingToReceive ) );
}
if( xHigherPriorityTaskWoken != pdFALSE )
{
/* The task waiting has a higher priority. */
xReturn = pdTRUE;
}
else
{