mirror of
https://github.com/espressif/esp-idf.git
synced 2024-10-05 20:47:46 -04:00
freertos: pin timer task in core 0 plus fixed in SMP race conditions
freertos: replace the freertos regular malloc to the specific malloc from xtensa port for tcb and stack allocations freertos: avoid the cpu1 to unwind pended ticks when xTaskResumeAll is called insed of an ISR freertos: protected the xPortGetCoreID functions with missing critical sections tests: re-eanble the ignored tests that was failling before race-condition fixes
This commit is contained in:
parent
3057b76a7e
commit
dfa2d547a7
@ -371,7 +371,7 @@ static void accessDPORT2_stall_other_cpu(void *pvParameters)
|
||||
vTaskDelete(NULL);
|
||||
}
|
||||
|
||||
TEST_CASE("Check stall workaround DPORT and Hi-interrupt", "[esp32] [ignore]")
|
||||
TEST_CASE("Check stall workaround DPORT and Hi-interrupt", "[esp32]")
|
||||
{
|
||||
xt_highint5_read_apb = 0;
|
||||
dport_test_result = false;
|
||||
|
@ -282,7 +282,7 @@ static void check_wake_stub(void)
|
||||
TEST_ASSERT_NULL(esp_get_deep_sleep_wake_stub());
|
||||
}
|
||||
|
||||
TEST_CASE_MULTIPLE_STAGES("can set sleep wake stub", "[deepsleep][ignore][reset=DEEPSLEEP_RESET]",
|
||||
TEST_CASE_MULTIPLE_STAGES("can set sleep wake stub", "[deepsleep][reset=DEEPSLEEP_RESET]",
|
||||
prepare_wake_stub,
|
||||
check_wake_stub);
|
||||
|
||||
|
@ -742,7 +742,7 @@ void taskYIELD_OTHER_CORE( BaseType_t xCoreID, UBaseType_t uxPriority )
|
||||
/* Allocate space for the TCB. Where the memory comes from depends
|
||||
on the implementation of the port malloc function and whether or
|
||||
not static allocation is being used. */
|
||||
pxNewTCB = ( TCB_t * ) pvPortMalloc( sizeof( TCB_t ) );
|
||||
pxNewTCB = ( TCB_t * ) pvPortMallocTcbMem( sizeof( TCB_t ) );
|
||||
|
||||
if( pxNewTCB != NULL )
|
||||
{
|
||||
@ -799,14 +799,14 @@ void taskYIELD_OTHER_CORE( BaseType_t xCoreID, UBaseType_t uxPriority )
|
||||
/* Allocate space for the TCB. Where the memory comes from depends on
|
||||
the implementation of the port malloc function and whether or not static
|
||||
allocation is being used. */
|
||||
pxNewTCB = ( TCB_t * ) pvPortMalloc( sizeof( TCB_t ) );
|
||||
pxNewTCB = ( TCB_t * ) pvPortMallocTcbMem( sizeof( TCB_t ) );
|
||||
|
||||
if( pxNewTCB != NULL )
|
||||
{
|
||||
/* Allocate space for the stack used by the task being created.
|
||||
The base of the stack memory stored in the TCB so the task can
|
||||
be deleted later if required. */
|
||||
pxNewTCB->pxStack = ( StackType_t * ) pvPortMalloc( ( ( ( size_t ) usStackDepth ) * sizeof( StackType_t ) ) ); /*lint !e961 MISRA exception as the casts are only redundant for some ports. */
|
||||
pxNewTCB->pxStack = ( StackType_t * ) pvPortMallocStackMem( ( ( ( size_t ) usStackDepth ) * sizeof( StackType_t ) ) ); /*lint !e961 MISRA exception as the casts are only redundant for some ports. */
|
||||
|
||||
if( pxNewTCB->pxStack == NULL )
|
||||
{
|
||||
@ -821,12 +821,12 @@ void taskYIELD_OTHER_CORE( BaseType_t xCoreID, UBaseType_t uxPriority )
|
||||
StackType_t *pxStack;
|
||||
|
||||
/* Allocate space for the stack used by the task being created. */
|
||||
pxStack = pvPortMalloc( ( ( ( size_t ) usStackDepth ) * sizeof( StackType_t ) ) ); /*lint !e9079 All values returned by pvPortMalloc() have at least the alignment required by the MCU's stack and this allocation is the stack. */
|
||||
pxStack = pvPortMallocStackMem( ( ( ( size_t ) usStackDepth ) * sizeof( StackType_t ) ) ); /*lint !e9079 All values returned by pvPortMalloc() have at least the alignment required by the MCU's stack and this allocation is the stack. */
|
||||
|
||||
if( pxStack != NULL )
|
||||
{
|
||||
/* Allocate space for the TCB. */
|
||||
pxNewTCB = ( TCB_t * ) pvPortMalloc( sizeof( TCB_t ) ); /*lint !e9087 !e9079 All values returned by pvPortMalloc() have at least the alignment required by the MCU's stack, and the first member of TCB_t is always a pointer to the task's stack. */
|
||||
pxNewTCB = ( TCB_t * ) pvPortMallocTcbMem( sizeof( TCB_t ) ); /*lint !e9087 !e9079 All values returned by pvPortMalloc() have at least the alignment required by the MCU's stack, and the first member of TCB_t is always a pointer to the task's stack. */
|
||||
|
||||
if( pxNewTCB != NULL )
|
||||
{
|
||||
@ -1313,7 +1313,7 @@ static void prvAddNewTaskToReadyList( TCB_t *pxNewTCB, TaskFunction_t pxTaskCode
|
||||
not return. */
|
||||
uxTaskNumber++;
|
||||
|
||||
if( pxTCB == pxCurrentTCB[xPortGetCoreID()] ||
|
||||
if( pxTCB == pxCurrentTCB[core] ||
|
||||
(portNUM_PROCESSORS > 1 && pxTCB == pxCurrentTCB[ !core ]) ||
|
||||
(portNUM_PROCESSORS > 1 && pxTCB->xCoreID == (!core)) )
|
||||
{
|
||||
@ -1334,7 +1334,7 @@ static void prvAddNewTaskToReadyList( TCB_t *pxNewTCB, TaskFunction_t pxTaskCode
|
||||
after which it is not possible to yield away from this task -
|
||||
hence xYieldPending is used to latch that a context switch is
|
||||
required. */
|
||||
portPRE_TASK_DELETE_HOOK( pxTCB, &xYieldPending[xPortGetCoreID()] );
|
||||
portPRE_TASK_DELETE_HOOK( pxTCB, &xYieldPending[core] );
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -1362,7 +1362,7 @@ static void prvAddNewTaskToReadyList( TCB_t *pxNewTCB, TaskFunction_t pxTaskCode
|
||||
been deleted. */
|
||||
if( xSchedulerRunning != pdFALSE )
|
||||
{
|
||||
if( pxTCB == pxCurrentTCB[xPortGetCoreID()] )
|
||||
if( pxTCB == pxCurrentTCB[core] )
|
||||
{
|
||||
configASSERT( xTaskGetSchedulerState() != taskSCHEDULER_SUSPENDED );
|
||||
portYIELD_WITHIN_API();
|
||||
@ -1719,10 +1719,14 @@ static void prvAddNewTaskToReadyList( TCB_t *pxNewTCB, TaskFunction_t pxTaskCode
|
||||
/* The priority of a task other than the currently
|
||||
running task is being raised. Is the priority being
|
||||
raised above that of the running task? */
|
||||
if( uxNewPriority >= pxCurrentTCB[xPortGetCoreID()]->uxPriority )
|
||||
if ( tskCAN_RUN_HERE(pxTCB->xCoreID) && uxNewPriority >= pxCurrentTCB[ xPortGetCoreID() ]->uxPriority )
|
||||
{
|
||||
xYieldRequired = pdTRUE;
|
||||
}
|
||||
else if ( pxTCB->xCoreID != xPortGetCoreID() )
|
||||
{
|
||||
taskYIELD_OTHER_CORE( pxTCB->xCoreID, uxNewPriority );
|
||||
}
|
||||
else
|
||||
{
|
||||
mtCOVERAGE_TEST_MARKER();
|
||||
@ -1857,6 +1861,7 @@ static void prvAddNewTaskToReadyList( TCB_t *pxNewTCB, TaskFunction_t pxTaskCode
|
||||
void vTaskSuspend( TaskHandle_t xTaskToSuspend )
|
||||
{
|
||||
TCB_t *pxTCB;
|
||||
TCB_t *curTCB;
|
||||
|
||||
taskENTER_CRITICAL( &xTaskQueueMutex );
|
||||
{
|
||||
@ -1888,6 +1893,7 @@ static void prvAddNewTaskToReadyList( TCB_t *pxNewTCB, TaskFunction_t pxTaskCode
|
||||
}
|
||||
|
||||
vListInsertEnd( &xSuspendedTaskList, &( pxTCB->xStateListItem ) );
|
||||
curTCB = pxCurrentTCB[ xPortGetCoreID() ];
|
||||
|
||||
#if( configUSE_TASK_NOTIFICATIONS == 1 )
|
||||
{
|
||||
@ -1917,12 +1923,16 @@ static void prvAddNewTaskToReadyList( TCB_t *pxNewTCB, TaskFunction_t pxTaskCode
|
||||
mtCOVERAGE_TEST_MARKER();
|
||||
}
|
||||
|
||||
if( pxTCB == pxCurrentTCB[xPortGetCoreID()] )
|
||||
if( pxTCB == curTCB )
|
||||
{
|
||||
if( xSchedulerRunning != pdFALSE )
|
||||
{
|
||||
/* The current task has just been suspended. */
|
||||
configASSERT( uxSchedulerSuspended[xPortGetCoreID()] == 0 );
|
||||
taskENTER_CRITICAL(&xTaskQueueMutex);
|
||||
BaseType_t core = xPortGetCoreID();
|
||||
taskEXIT_CRITICAL(&xTaskQueueMutex);
|
||||
|
||||
configASSERT( uxSchedulerSuspended[core] == 0 );
|
||||
portYIELD_WITHIN_API();
|
||||
}
|
||||
else
|
||||
@ -1936,7 +1946,9 @@ static void prvAddNewTaskToReadyList( TCB_t *pxNewTCB, TaskFunction_t pxTaskCode
|
||||
NULL so when the next task is created pxCurrentTCB will
|
||||
be set to point to it no matter what its relative priority
|
||||
is. */
|
||||
pxCurrentTCB[xPortGetCoreID()] = NULL;
|
||||
taskENTER_CRITICAL(&xTaskQueueMutex);
|
||||
pxCurrentTCB[ xPortGetCoreID() ] = NULL;
|
||||
taskEXIT_CRITICAL(&xTaskQueueMutex);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -1946,7 +1958,21 @@ static void prvAddNewTaskToReadyList( TCB_t *pxNewTCB, TaskFunction_t pxTaskCode
|
||||
}
|
||||
else
|
||||
{
|
||||
mtCOVERAGE_TEST_MARKER();
|
||||
if( xSchedulerRunning != pdFALSE )
|
||||
{
|
||||
/* A task other than the currently running task was suspended,
|
||||
reset the next expected unblock time in case it referred to the
|
||||
task that is now in the Suspended state. */
|
||||
taskENTER_CRITICAL(&xTaskQueueMutex);
|
||||
{
|
||||
prvResetNextTaskUnblockTime();
|
||||
}
|
||||
taskEXIT_CRITICAL(&xTaskQueueMutex);
|
||||
}
|
||||
else
|
||||
{
|
||||
mtCOVERAGE_TEST_MARKER();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -2008,50 +2034,48 @@ static void prvAddNewTaskToReadyList( TCB_t *pxNewTCB, TaskFunction_t pxTaskCode
|
||||
|
||||
/* It does not make sense to resume the calling task. */
|
||||
configASSERT( xTaskToResume );
|
||||
taskENTER_CRITICAL( &xTaskQueueMutex );
|
||||
|
||||
/* The parameter cannot be NULL as it is impossible to resume the
|
||||
currently executing task. */
|
||||
if( ( pxTCB != pxCurrentTCB[xPortGetCoreID()] ) && ( pxTCB != NULL ) )
|
||||
{
|
||||
taskENTER_CRITICAL( &xTaskQueueMutex );
|
||||
if( prvTaskIsTaskSuspended( pxTCB ) != pdFALSE )
|
||||
{
|
||||
if( prvTaskIsTaskSuspended( pxTCB ) != pdFALSE )
|
||||
traceTASK_RESUME( pxTCB );
|
||||
|
||||
/* The ready list can be accessed even if the scheduler is
|
||||
suspended because this is inside a critical section. */
|
||||
( void ) uxListRemove( &( pxTCB->xStateListItem ) );
|
||||
prvAddTaskToReadyList( pxTCB );
|
||||
|
||||
/* We may have just resumed a higher priority task. */
|
||||
if( tskCAN_RUN_HERE(pxTCB->xCoreID) && pxTCB->uxPriority >= pxCurrentTCB[ xPortGetCoreID() ]->uxPriority )
|
||||
{
|
||||
traceTASK_RESUME( pxTCB );
|
||||
|
||||
/* The ready list can be accessed even if the scheduler is
|
||||
suspended because this is inside a critical section. */
|
||||
( void ) uxListRemove( &( pxTCB->xStateListItem ) );
|
||||
prvAddTaskToReadyList( pxTCB );
|
||||
|
||||
/* We may have just resumed a higher priority task. */
|
||||
if( tskCAN_RUN_HERE(pxTCB->xCoreID) && pxTCB->uxPriority >= pxCurrentTCB[ xPortGetCoreID() ]->uxPriority )
|
||||
{
|
||||
/* This yield may not cause the task just resumed to run,
|
||||
but will leave the lists in the correct state for the
|
||||
next yield. */
|
||||
taskYIELD_IF_USING_PREEMPTION();
|
||||
}
|
||||
else if( pxTCB->xCoreID != xPortGetCoreID() )
|
||||
{
|
||||
taskYIELD_OTHER_CORE( pxTCB->xCoreID, pxTCB->uxPriority );
|
||||
}
|
||||
else
|
||||
{
|
||||
mtCOVERAGE_TEST_MARKER();
|
||||
}
|
||||
/* This yield may not cause the task just resumed to run,
|
||||
but will leave the lists in the correct state for the
|
||||
next yield. */
|
||||
taskYIELD_IF_USING_PREEMPTION();
|
||||
}
|
||||
else if( pxTCB->xCoreID != xPortGetCoreID() )
|
||||
{
|
||||
taskYIELD_OTHER_CORE( pxTCB->xCoreID, pxTCB->uxPriority );
|
||||
}
|
||||
else
|
||||
{
|
||||
mtCOVERAGE_TEST_MARKER();
|
||||
}
|
||||
}
|
||||
taskEXIT_CRITICAL( &xTaskQueueMutex );
|
||||
else
|
||||
{
|
||||
mtCOVERAGE_TEST_MARKER();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
mtCOVERAGE_TEST_MARKER();
|
||||
}
|
||||
taskEXIT_CRITICAL( &xTaskQueueMutex );
|
||||
}
|
||||
|
||||
#endif /* INCLUDE_vTaskSuspend */
|
||||
@ -2314,64 +2338,63 @@ void vTaskSuspendAll( void )
|
||||
|
||||
#if ( configUSE_TICKLESS_IDLE != 0 )
|
||||
|
||||
#if ( portNUM_PROCESSORS > 1 )
|
||||
|
||||
static BaseType_t xHaveReadyTasks( void )
|
||||
{
|
||||
for (int i = tskIDLE_PRIORITY + 1; i < configMAX_PRIORITIES; ++i)
|
||||
{
|
||||
if( listCURRENT_LIST_LENGTH( &( pxReadyTasksLists[ i ] ) ) > 0 )
|
||||
{
|
||||
return pdTRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
mtCOVERAGE_TEST_MARKER();
|
||||
}
|
||||
}
|
||||
return pdFALSE;
|
||||
}
|
||||
|
||||
#endif // portNUM_PROCESSORS > 1
|
||||
|
||||
static TickType_t prvGetExpectedIdleTime( void )
|
||||
{
|
||||
TickType_t xReturn;
|
||||
UBaseType_t uxHigherPriorityReadyTasks = pdFALSE;
|
||||
|
||||
/* uxHigherPriorityReadyTasks takes care of the case where
|
||||
configUSE_PREEMPTION is 0, so there may be tasks above the idle priority
|
||||
task that are in the Ready state, even though the idle task is
|
||||
running. */
|
||||
#if( configUSE_PORT_OPTIMISED_TASK_SELECTION == 0 )
|
||||
{
|
||||
if( uxTopReadyPriority > tskIDLE_PRIORITY )
|
||||
{
|
||||
uxHigherPriorityReadyTasks = pdTRUE;
|
||||
}
|
||||
}
|
||||
#else
|
||||
{
|
||||
const UBaseType_t uxLeastSignificantBit = ( UBaseType_t ) 0x01;
|
||||
|
||||
/* When port optimised task selection is used the uxTopReadyPriority
|
||||
variable is used as a bit map. If bits other than the least
|
||||
significant bit are set then there are tasks that have a priority
|
||||
above the idle priority that are in the Ready state. This takes
|
||||
care of the case where the co-operative scheduler is in use. */
|
||||
if( uxTopReadyPriority > uxLeastSignificantBit )
|
||||
{
|
||||
uxHigherPriorityReadyTasks = pdTRUE;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if( pxCurrentTCB[xPortGetCoreID()]->uxPriority > tskIDLE_PRIORITY )
|
||||
taskENTER_CRITICAL(&xTaskQueueMutex);
|
||||
if( pxCurrentTCB[ xPortGetCoreID() ]->uxPriority > tskIDLE_PRIORITY )
|
||||
{
|
||||
xReturn = 0;
|
||||
}
|
||||
else if( listCURRENT_LIST_LENGTH( &( pxReadyTasksLists[ tskIDLE_PRIORITY ] ) ) > 1 )
|
||||
#if portNUM_PROCESSORS > 1
|
||||
/* This function is called from Idle task; in single core case this
|
||||
* means that no higher priority tasks are ready to run, and we can
|
||||
* enter sleep. In SMP case, there might be ready tasks waiting for
|
||||
* the other CPU, so need to check all ready lists.
|
||||
*/
|
||||
else if( xHaveReadyTasks() )
|
||||
{
|
||||
xReturn = 0;
|
||||
}
|
||||
#endif // portNUM_PROCESSORS > 1
|
||||
else if( listCURRENT_LIST_LENGTH( &( pxReadyTasksLists[ tskIDLE_PRIORITY ] ) ) > portNUM_PROCESSORS )
|
||||
{
|
||||
/* There are other idle priority tasks in the ready state. If
|
||||
time slicing is used then the very next tick interrupt must be
|
||||
processed. */
|
||||
xReturn = 0;
|
||||
}
|
||||
else if( uxHigherPriorityReadyTasks != pdFALSE )
|
||||
{
|
||||
/* There are tasks in the Ready state that have a priority above the
|
||||
idle priority. This path can only be reached if
|
||||
configUSE_PREEMPTION is 0. */
|
||||
xReturn = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
xReturn = xNextTaskUnblockTime - xTickCount;
|
||||
}
|
||||
taskEXIT_CRITICAL(&xTaskQueueMutex);
|
||||
|
||||
return xReturn;
|
||||
}
|
||||
|
||||
|
||||
#endif /* configUSE_TICKLESS_IDLE */
|
||||
/*----------------------------------------------------------*/
|
||||
|
||||
@ -2464,7 +2487,7 @@ TickType_t xTicksToNextUnblockTime;
|
||||
decremented below. */
|
||||
xTicksToNextUnblockTime = ( TickType_t ) 1;
|
||||
}
|
||||
else if( xTicksToNextUnblockTime > ( TickType_t ) 1 )
|
||||
else if( xTicksToNextUnblockTime > ( TickType_t ) 1)
|
||||
{
|
||||
/* Move the tick count one short of the next unblock
|
||||
time, then call xTaskIncrementTick() to move the tick
|
||||
@ -3170,7 +3193,7 @@ BaseType_t xSwitchRequired = pdFALSE;
|
||||
/* If xTask is NULL then we are calling our own task hook. */
|
||||
if( xTask == NULL )
|
||||
{
|
||||
xTCB = pxCurrentTCB[xPortGetCoreID()];
|
||||
xTCB = xTaskGetCurrentTaskHandle();
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -4429,23 +4452,27 @@ TCB_t *pxTCB;
|
||||
TaskHandle_t xTaskGetCurrentTaskHandle( void )
|
||||
{
|
||||
TaskHandle_t xReturn;
|
||||
unsigned state;
|
||||
|
||||
/* A critical section is not required as this is not called from
|
||||
an interrupt and the current TCB will always be the same for any
|
||||
individual execution thread. */
|
||||
xReturn = pxCurrentTCB[xPortGetCoreID()];
|
||||
state = portENTER_CRITICAL_NESTED();
|
||||
xReturn = pxCurrentTCB[ xPortGetCoreID() ];
|
||||
portEXIT_CRITICAL_NESTED(state);
|
||||
|
||||
return xReturn;
|
||||
}
|
||||
|
||||
TaskHandle_t xTaskGetCurrentTaskHandleForCPU( BaseType_t cpuid )
|
||||
{
|
||||
(void)cpuid;
|
||||
return xTaskGetCurrentTaskHandle();
|
||||
TaskHandle_t xReturn=NULL;
|
||||
|
||||
//Xtensa-specific: the pxCurrentPCB pointer is atomic so we shouldn't need a lock.
|
||||
if (cpuid < portNUM_PROCESSORS) {
|
||||
xReturn = pxCurrentTCB[ cpuid ];
|
||||
}
|
||||
|
||||
return xReturn;
|
||||
}
|
||||
|
||||
|
||||
|
||||
#endif /* ( ( INCLUDE_xTaskGetCurrentTaskHandle == 1 ) || ( configUSE_MUTEXES == 1 ) ) */
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
@ -4484,6 +4511,7 @@ TCB_t *pxTCB;
|
||||
TCB_t * const pxMutexHolderTCB = pxMutexHolder;
|
||||
BaseType_t xReturn = pdFALSE;
|
||||
|
||||
taskENTER_CRITICAL(&xTaskQueueMutex);
|
||||
/* If the mutex was given back by an interrupt while the queue was
|
||||
locked then the mutex holder might now be NULL. _RB_ Is this still
|
||||
needed as interrupts can no longer use mutexes? */
|
||||
@ -4560,6 +4588,7 @@ TCB_t *pxTCB;
|
||||
{
|
||||
mtCOVERAGE_TEST_MARKER();
|
||||
}
|
||||
taskEXIT_CRITICAL(&xTaskQueueMutex);
|
||||
|
||||
return xReturn;
|
||||
}
|
||||
@ -4574,6 +4603,7 @@ TCB_t *pxTCB;
|
||||
TCB_t * const pxTCB = pxMutexHolder;
|
||||
BaseType_t xReturn = pdFALSE;
|
||||
|
||||
taskENTER_CRITICAL(&xTaskQueueMutex);
|
||||
if( pxMutexHolder != NULL )
|
||||
{
|
||||
/* A task can only have an inherited priority if it holds the mutex.
|
||||
@ -4640,6 +4670,7 @@ TCB_t *pxTCB;
|
||||
{
|
||||
mtCOVERAGE_TEST_MARKER();
|
||||
}
|
||||
taskEXIT_CRITICAL(&xTaskQueueMutex);
|
||||
|
||||
return xReturn;
|
||||
}
|
||||
@ -4654,7 +4685,8 @@ TCB_t *pxTCB;
|
||||
TCB_t * const pxTCB = pxMutexHolder;
|
||||
UBaseType_t uxPriorityUsedOnEntry, uxPriorityToUse;
|
||||
const UBaseType_t uxOnlyOneMutexHeld = ( UBaseType_t ) 1;
|
||||
|
||||
|
||||
taskENTER_CRITICAL(&xTaskQueueMutex);
|
||||
if( pxMutexHolder != NULL )
|
||||
{
|
||||
/* If pxMutexHolder is not NULL then the holder must hold at least
|
||||
@ -4747,6 +4779,7 @@ TCB_t *pxTCB;
|
||||
{
|
||||
mtCOVERAGE_TEST_MARKER();
|
||||
}
|
||||
taskEXIT_CRITICAL(&xTaskQueueMutex);
|
||||
}
|
||||
|
||||
#endif /* configUSE_MUTEXES */
|
||||
@ -5071,11 +5104,13 @@ TickType_t uxTaskResetEventItemValue( void )
|
||||
{
|
||||
TickType_t uxReturn;
|
||||
|
||||
uxReturn = listGET_LIST_ITEM_VALUE( &( pxCurrentTCB[xPortGetCoreID()]->xEventListItem ) );
|
||||
taskENTER_CRITICAL(&xTaskQueueMutex);
|
||||
uxReturn = listGET_LIST_ITEM_VALUE( &( pxCurrentTCB[ xPortGetCoreID() ]->xEventListItem ) );
|
||||
|
||||
/* Reset the event list item to its normal value - so it can be used with
|
||||
queues and semaphores. */
|
||||
listSET_LIST_ITEM_VALUE( &( pxCurrentTCB[xPortGetCoreID()]->xEventListItem ), ( ( TickType_t ) configMAX_PRIORITIES - ( TickType_t ) pxCurrentTCB[xPortGetCoreID()]->uxPriority ) ); /*lint !e961 MISRA exception as the casts are only redundant for some ports. */
|
||||
listSET_LIST_ITEM_VALUE( &( pxCurrentTCB[ xPortGetCoreID() ]->xEventListItem ), ( ( TickType_t ) configMAX_PRIORITIES - ( TickType_t ) pxCurrentTCB[ xPortGetCoreID() ]->uxPriority ) ); /*lint !e961 MISRA exception as the casts are only redundant for some ports. */
|
||||
taskEXIT_CRITICAL(&xTaskQueueMutex);
|
||||
|
||||
return uxReturn;
|
||||
}
|
||||
@ -5083,16 +5118,21 @@ TickType_t uxReturn;
|
||||
|
||||
#if ( configUSE_MUTEXES == 1 )
|
||||
|
||||
TaskHandle_t pvTaskIncrementMutexHeldCount( void )
|
||||
void *pvTaskIncrementMutexHeldCount( void )
|
||||
{
|
||||
/* If xSemaphoreCreateMutex() is called before any tasks have been created
|
||||
then pxCurrentTCB[xPortGetCoreID()] will be NULL. */
|
||||
if( pxCurrentTCB[xPortGetCoreID()] != NULL )
|
||||
{
|
||||
( pxCurrentTCB[xPortGetCoreID()]->uxMutexesHeld )++;
|
||||
}
|
||||
TCB_t *curTCB;
|
||||
|
||||
return pxCurrentTCB[xPortGetCoreID()];
|
||||
/* If xSemaphoreCreateMutex() is called before any tasks have been created
|
||||
then pxCurrentTCB will be NULL. */
|
||||
taskENTER_CRITICAL(&xTaskQueueMutex);
|
||||
if( pxCurrentTCB[ xPortGetCoreID() ] != NULL )
|
||||
{
|
||||
( pxCurrentTCB[ xPortGetCoreID() ]->uxMutexesHeld )++;
|
||||
}
|
||||
curTCB = pxCurrentTCB[ xPortGetCoreID() ];
|
||||
taskEXIT_CRITICAL(&xTaskQueueMutex);
|
||||
|
||||
return curTCB;
|
||||
}
|
||||
|
||||
#endif /* configUSE_MUTEXES */
|
||||
@ -5615,7 +5655,10 @@ TickType_t uxReturn;
|
||||
|
||||
uint32_t ulTaskGetIdleRunTimeCounter( void )
|
||||
{
|
||||
taskENTER_CRITICAL(&xTaskQueueMutex);
|
||||
tskTCB *pxTCB = (tskTCB *)xIdleTaskHandle[xPortGetCoreID()];
|
||||
taskEXIT_CRITICAL(&xTaskQueueMutex);
|
||||
|
||||
return pxTCB->ulRunTimeCounter;
|
||||
}
|
||||
|
||||
@ -5794,7 +5837,7 @@ const TickType_t xConstTickCount = xTickCount;
|
||||
for (i = 0; i < portNUM_PROCESSORS; i++) {
|
||||
if( uxTask >= uxArraySize )
|
||||
break;
|
||||
prvTaskGetSnapshotsFromList( pxTaskSnapshotArray, &uxTask, uxArraySize, &( xPendingReadyList[xPortGetCoreID()]) );
|
||||
prvTaskGetSnapshotsFromList( pxTaskSnapshotArray, &uxTask, uxArraySize, &( xPendingReadyList[i]) );
|
||||
}
|
||||
|
||||
#if( INCLUDE_vTaskDelete == 1 )
|
||||
|
254
components/freertos/test/test_freertos_backported_functions.c
Normal file
254
components/freertos/test/test_freertos_backported_functions.c
Normal file
@ -0,0 +1,254 @@
|
||||
/*
|
||||
* Test features that are backported from version FreeRTOS 9.0.0.
|
||||
*
|
||||
* 1) Test backported timer functions
|
||||
* - xTimerCreateStatic(), vTimerSetTimerId(), xTimerGetPeriod(), xTimerGetExpiryTime()
|
||||
* 2) Test backported queue/semaphore functions
|
||||
* - xQueueCreateStatic()
|
||||
* - xSemaphoreCreateBinaryStatic(), xSemaphoreCreateCountingStatic(), uxSemaphoreGetCount()
|
||||
* - xSemaphoreCreateMutexStatic(), xSemaphoreCreateRecursiveMutexStatic()
|
||||
* 3) Test static allocation of tasks
|
||||
* - xTaskCreateStaticPinnedToCore()
|
||||
* 4) Test static allocation of event group
|
||||
* - xEventGroupCreateStatic()
|
||||
* 5) Test Thread Local Storage Pointers and Deletion Callbacks
|
||||
* - vTaskSetThreadLocalStoragePointerAndDelCallback()
|
||||
* - pvTaskGetThreadLocalStoragePointer()
|
||||
*
|
||||
* Note: The *pcQueueGetName() function is also backported, but is not tested in
|
||||
* the following test cases (see Queue Registry test cases instead)
|
||||
* For more details please refer the the ESP-IDF FreeRTOS changes documentation
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "freertos/timers.h"
|
||||
#include "freertos/queue.h"
|
||||
#include "freertos/semphr.h"
|
||||
#include "freertos/event_groups.h"
|
||||
#include "unity.h"
|
||||
#include "test_utils.h"
|
||||
|
||||
/* ---------------------Test 1: Backported Timer functions-----------------------
|
||||
* Test xTimerCreateStatic(), vTimerSetTimerId(), xTimerGetPeriod(), xTimerGetExpiryTime()
|
||||
*
|
||||
* This test creates a one-shot static timer, sets/checks the timer's id and period. Then ensures
|
||||
* the timer cb is executed in a timely fashion.
|
||||
*/
|
||||
#define TMR_PERIOD_TICKS 10
|
||||
#define TIMER_ID 0xFF
|
||||
#define TICK_DELTA 5
|
||||
|
||||
static StaticTimer_t timer_buffer;
|
||||
static TickType_t tmr_ideal_exp;
|
||||
|
||||
static void tmr_cb(TimerHandle_t xtimer)
|
||||
{
|
||||
//Check cb is called in timely fashion
|
||||
TEST_ASSERT_UINT32_WITHIN(TICK_DELTA, tmr_ideal_exp, xTaskGetTickCount());
|
||||
}
|
||||
|
||||
//No need for smp test as Timer Task always runs on core 0
|
||||
TEST_CASE("Test FreeRTOS backported timer functions", "[freertos]")
|
||||
{
|
||||
//Create one shot static timer with period TMR_PERIOD_TICKS
|
||||
TimerHandle_t tmr_handle = xTimerCreateStatic("static_tmr", TMR_PERIOD_TICKS, pdFALSE, NULL, tmr_cb, &timer_buffer);
|
||||
TEST_ASSERT_EQUAL(TMR_PERIOD_TICKS, xTimerGetPeriod(tmr_handle)); //Test xTimerGetPeriod()
|
||||
|
||||
vTimerSetTimerID(tmr_handle, (void *)TIMER_ID);
|
||||
TEST_ASSERT_EQUAL(TIMER_ID, (uint32_t)pvTimerGetTimerID(tmr_handle)); //Test vTimerSetTimerID()
|
||||
|
||||
TEST_ASSERT_EQUAL(pdTRUE, xTimerStart(tmr_handle, 1)); //Start Timer
|
||||
tmr_ideal_exp = xTaskGetTickCount() + TMR_PERIOD_TICKS; //Calculate ideal expiration time
|
||||
vTaskDelay(2); //Need to yield to allow daemon task to process start command, or else expiration time will be NULL
|
||||
|
||||
TEST_ASSERT_UINT32_WITHIN(TICK_DELTA, tmr_ideal_exp, xTimerGetExpiryTime(tmr_handle)); //Test xTimerGetExpiryTime()
|
||||
|
||||
vTaskDelay(2*TMR_PERIOD_TICKS); //Delay until one shot timer has triggered
|
||||
TEST_ASSERT_EQUAL(pdPASS, xTimerDelete(tmr_handle, portMAX_DELAY)); //Clean up
|
||||
|
||||
}
|
||||
|
||||
/* ---------------Test backported queue/semaphore functions-------------------
|
||||
* xQueueCreateStatic()
|
||||
* xSemaphoreCreateBinaryStatic(), xSemaphoreCreateCountingStatic()
|
||||
* xSemaphoreCreateMutexStatic(), xSemaphoreCreateRecursiveMutexStatic()
|
||||
* uxSemaphoreGetCount() is also tested on the static counting semaphore
|
||||
*
|
||||
* This test creates various static queue/semphrs listed above and tests them by
|
||||
* doing a simple send/give and rec/take.
|
||||
*/
|
||||
|
||||
#define ITEM_SIZE 3
|
||||
#define NO_OF_ITEMS 3
|
||||
#define DELAY_TICKS 2
|
||||
|
||||
static StaticQueue_t queue_buffer; //Queues, Semaphores, and Mutex use the same queue structure
|
||||
static uint8_t queue_storage_area[(ITEM_SIZE*NO_OF_ITEMS)]; //Queue storage provided in separate buffer to queue struct
|
||||
|
||||
TEST_CASE("Test FreeRTOS backported Queue and Semphr functions", "[freertos]")
|
||||
{
|
||||
//Test static queue
|
||||
uint8_t queue_item_to_send[ITEM_SIZE];
|
||||
uint8_t queue_item_received[ITEM_SIZE];
|
||||
for(int i = 0; i < ITEM_SIZE; i++){
|
||||
queue_item_to_send[i] = (0xF << i);
|
||||
}
|
||||
QueueHandle_t handle = xQueueCreateStatic(NO_OF_ITEMS, ITEM_SIZE,(uint8_t*) &queue_storage_area, &queue_buffer);
|
||||
TEST_ASSERT_EQUAL(pdTRUE, xQueueSendToBack(handle, &queue_item_to_send, DELAY_TICKS));
|
||||
vTaskDelay(1);
|
||||
TEST_ASSERT_EQUAL(pdTRUE, xQueueReceive(handle, queue_item_received, DELAY_TICKS));
|
||||
vTaskDelay(1);
|
||||
for(int i = 0; i < ITEM_SIZE; i++){
|
||||
TEST_ASSERT_EQUAL(queue_item_to_send[i], queue_item_received[i]); //Check received contents are correct
|
||||
}
|
||||
vQueueDelete(handle); //Technically not needed as deleting static queue/semphr doesn't clear static memory
|
||||
|
||||
//Test static binary semaphore
|
||||
handle = xSemaphoreCreateBinaryStatic(&queue_buffer); //Queue and Semphr handles are the same
|
||||
TEST_ASSERT_EQUAL(pdTRUE, xSemaphoreGive(handle));
|
||||
vTaskDelay(1);
|
||||
TEST_ASSERT_EQUAL(pdTRUE, xSemaphoreTake(handle, DELAY_TICKS));
|
||||
vTaskDelay(1);
|
||||
vSemaphoreDelete(handle);
|
||||
|
||||
//Test static counting semaphore and uxSemaphoreGetCount()
|
||||
handle = xSemaphoreCreateCountingStatic(NO_OF_ITEMS, 0, &queue_buffer);
|
||||
for(int i = 0; i < NO_OF_ITEMS; i++){
|
||||
TEST_ASSERT_EQUAL(pdTRUE, xSemaphoreGive(handle));
|
||||
}
|
||||
vTaskDelay(1);
|
||||
TEST_ASSERT_EQUAL(NO_OF_ITEMS, uxSemaphoreGetCount(handle)); //Test uxSemaphoreGetCount()
|
||||
for(int i = 0; i < NO_OF_ITEMS; i++){
|
||||
TEST_ASSERT_EQUAL(pdTRUE, xSemaphoreTake(handle, DELAY_TICKS));
|
||||
}
|
||||
vTaskDelay(1);
|
||||
TEST_ASSERT_EQUAL(0, uxSemaphoreGetCount(handle));
|
||||
vSemaphoreDelete(handle);
|
||||
|
||||
//Test static mutex
|
||||
handle = xSemaphoreCreateMutexStatic(&queue_buffer);
|
||||
TEST_ASSERT_EQUAL(pdTRUE, xSemaphoreTake(handle, DELAY_TICKS));
|
||||
vTaskDelay(1);
|
||||
TEST_ASSERT_EQUAL_PTR((void *)xTaskGetCurrentTaskHandle(), xSemaphoreGetMutexHolder(handle)); //Current task should now hold mutex
|
||||
TEST_ASSERT_EQUAL(pdTRUE, xSemaphoreGive(handle));
|
||||
vTaskDelay(1);
|
||||
TEST_ASSERT_EQUAL_PTR(NULL, xSemaphoreGetMutexHolder(handle)); //Mutex should have been released
|
||||
vSemaphoreDelete(handle);
|
||||
|
||||
//Test static mutex recursive
|
||||
handle = xSemaphoreCreateRecursiveMutexStatic(&queue_buffer);
|
||||
for(int i = 0; i < NO_OF_ITEMS; i++){
|
||||
TEST_ASSERT_EQUAL(pdTRUE, xSemaphoreTakeRecursive(handle, DELAY_TICKS));
|
||||
}
|
||||
vTaskDelay(1);
|
||||
TEST_ASSERT_EQUAL_PTR((void *)xTaskGetCurrentTaskHandle(), xSemaphoreGetMutexHolder(handle)); //Current task should hold mutex
|
||||
for(int i = 0; i < NO_OF_ITEMS; i++){
|
||||
TEST_ASSERT_EQUAL(pdTRUE, xSemaphoreGiveRecursive(handle));
|
||||
}
|
||||
vTaskDelay(1);
|
||||
TEST_ASSERT_EQUAL_PTR(NULL, xSemaphoreGetMutexHolder(handle)); //Mutex should have been released
|
||||
vSemaphoreDelete(handle);
|
||||
|
||||
}
|
||||
|
||||
/* -----------------Test backported static task allocation -------------------
|
||||
* Test xTaskCreateStaticPinnedToCore() but creating static task on each core
|
||||
* and checking the task cb has run successfully.
|
||||
*/
|
||||
|
||||
#define STACK_SIZE 2048 //Task stack size
|
||||
|
||||
static StackType_t task_stack[STACK_SIZE]; //Static buffer for task stack
|
||||
static StaticTask_t task_buffer; //Static buffer for TCB
|
||||
static bool has_run[portNUM_PROCESSORS];
|
||||
|
||||
static void task(void *arg)
|
||||
{
|
||||
has_run[xPortGetCoreID()] = true; //Signify static task cb has run
|
||||
vTaskDelete(NULL);
|
||||
}
|
||||
|
||||
TEST_CASE("Test FreeRTOS static task allocation", "[freertos]")
|
||||
{
|
||||
for(int core = 0; core < portNUM_PROCESSORS; core++){
|
||||
has_run[core] = false; //Clear has_run flag
|
||||
TaskHandle_t handle = xTaskCreateStaticPinnedToCore(task, "static task", STACK_SIZE, NULL,
|
||||
UNITY_FREERTOS_PRIORITY + 1, (StackType_t *)&task_stack,
|
||||
(StaticTask_t *)&task_buffer, core);
|
||||
vTaskDelay(5); //Allow for static task to run, delete, and idle to clean up
|
||||
TEST_ASSERT_NOT_EQUAL(NULL, handle); //Check static task was successfully allocated
|
||||
TEST_ASSERT_TRUE(has_run[core]) //Check static task has run
|
||||
}
|
||||
}
|
||||
|
||||
/* ------------- Test backported static event group allocation -------------------
|
||||
* Test xEventGroupCreateStatic() but creating static event group then waiting
|
||||
* for an event.
|
||||
*/
|
||||
|
||||
#define WAIT_BITS 0x01 //Wait for first bit
|
||||
|
||||
static StaticEventGroup_t event_group;
|
||||
static EventGroupHandle_t eg_handle;
|
||||
|
||||
TEST_CASE("Test FreeRTOS backported eventgroup functions", "[freertos]")
|
||||
{
|
||||
eg_handle = xEventGroupCreateStatic((StaticEventGroup_t *)&event_group);
|
||||
xEventGroupSetBits(eg_handle, WAIT_BITS);
|
||||
TEST_ASSERT_EQUAL(WAIT_BITS, xEventGroupWaitBits(eg_handle, WAIT_BITS, pdTRUE, pdTRUE, portMAX_DELAY));
|
||||
//Cleanup static event
|
||||
vEventGroupDelete(eg_handle);
|
||||
}
|
||||
|
||||
/* --------Test backported thread local storage pointer and deletion cb feature----------
|
||||
* vTaskSetThreadLocalStoragePointerAndDelCallback()
|
||||
* pvTaskGetThreadLocalStoragePointer(),
|
||||
*
|
||||
* This test creates a task and set's the task's TLSPs. The task is then deleted
|
||||
* which should trigger the deletion cb.
|
||||
*/
|
||||
|
||||
#define NO_OF_TLSP configNUM_THREAD_LOCAL_STORAGE_POINTERS
|
||||
#define TLSP_SET_BASE 0x0F //0b1111 to be bit shifted by index
|
||||
#define TLSP_DEL_BASE 0x05 //0b0101 to be bit shifted by index
|
||||
|
||||
//The variables pointed to by Thread Local Storage Pointer
|
||||
static uint32_t task_storage[portNUM_PROCESSORS][NO_OF_TLSP] = {0};
|
||||
|
||||
static void del_cb(int index, void *ptr)
|
||||
{
|
||||
*((uint32_t *)ptr) = (TLSP_DEL_BASE << index); //Indicate deletion by setting task storage element to a unique value
|
||||
}
|
||||
|
||||
static void task_cb(void *arg)
|
||||
{
|
||||
int core = xPortGetCoreID();
|
||||
for(int i = 0; i < NO_OF_TLSP; i++){
|
||||
task_storage[core][i] = (TLSP_SET_BASE << i); //Give each element of task_storage a unique number
|
||||
vTaskSetThreadLocalStoragePointerAndDelCallback(NULL, i, (void *)&task_storage[core][i], del_cb); //Set each TLSP to point to a task storage element
|
||||
}
|
||||
|
||||
for(int i = 0; i < NO_OF_TLSP; i++){
|
||||
uint32_t * tlsp = (uint32_t *)pvTaskGetThreadLocalStoragePointer(NULL, i);
|
||||
TEST_ASSERT_EQUAL(*tlsp, (TLSP_SET_BASE << i)); //Check if TLSP points to the correct task storage element by checking unique value
|
||||
}
|
||||
|
||||
vTaskDelete(NULL); //Delete Task to Trigger TSLP deletion callback
|
||||
}
|
||||
|
||||
TEST_CASE("Test FreeRTOS thread local storage pointers and del cb", "[freertos]")
|
||||
{
|
||||
//Create Task
|
||||
for(int core = 0; core < portNUM_PROCESSORS; core++){
|
||||
xTaskCreatePinnedToCore(task_cb, "task", 1024, NULL, UNITY_FREERTOS_PRIORITY+1, NULL, core);
|
||||
}
|
||||
vTaskDelay(10); //Delay long enough for tasks to run to completion
|
||||
|
||||
for(int core = 0; core < portNUM_PROCESSORS; core++){
|
||||
for(int i = 0; i < NO_OF_TLSP; i++){
|
||||
TEST_ASSERT_EQUAL((TLSP_DEL_BASE << i), task_storage[core][i]); //Check del_cb ran by checking task storage for unique value
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -246,13 +246,14 @@ BaseType_t xReturn = pdFAIL;
|
||||
uint32_t ulTimerTaskStackSize;
|
||||
|
||||
vApplicationGetTimerTaskMemory( &pxTimerTaskTCBBuffer, &pxTimerTaskStackBuffer, &ulTimerTaskStackSize );
|
||||
xTimerTaskHandle = xTaskCreateStatic( prvTimerTask,
|
||||
xTimerTaskHandle = xTaskCreateStaticPinnedToCore( prvTimerTask,
|
||||
configTIMER_SERVICE_TASK_NAME,
|
||||
ulTimerTaskStackSize,
|
||||
NULL,
|
||||
( ( UBaseType_t ) configTIMER_TASK_PRIORITY ) | portPRIVILEGE_BIT,
|
||||
pxTimerTaskStackBuffer,
|
||||
pxTimerTaskTCBBuffer );
|
||||
pxTimerTaskTCBBuffer,
|
||||
0 );
|
||||
|
||||
if( xTimerTaskHandle != NULL )
|
||||
{
|
||||
@ -261,12 +262,12 @@ BaseType_t xReturn = pdFAIL;
|
||||
}
|
||||
#else
|
||||
{
|
||||
xReturn = xTaskCreate( prvTimerTask,
|
||||
xReturn = xTaskCreatePinnedToCore( prvTimerTask,
|
||||
configTIMER_SERVICE_TASK_NAME,
|
||||
configTIMER_TASK_STACK_DEPTH,
|
||||
NULL,
|
||||
( ( UBaseType_t ) configTIMER_TASK_PRIORITY ) | portPRIVILEGE_BIT,
|
||||
&xTimerTaskHandle );
|
||||
&xTimerTaskHandle, 0 );
|
||||
}
|
||||
#endif /* configSUPPORT_STATIC_ALLOCATION */
|
||||
}
|
||||
|
@ -129,7 +129,7 @@ done:
|
||||
vTaskDelete(NULL);
|
||||
}
|
||||
|
||||
TEST_CASE("multiple tasks can access wl handle simultaneously", "[wear_levelling][ignore]")
|
||||
TEST_CASE("multiple tasks can access wl handle simultaneously", "[wear_levelling]")
|
||||
{
|
||||
const esp_partition_t *partition = get_test_data_partition();
|
||||
wl_handle_t handle;
|
||||
|
Loading…
Reference in New Issue
Block a user