From 80457ca165e53907e332a79f5af6106a7c5c95cf Mon Sep 17 00:00:00 2001 From: Joseph Julicher Date: Wed, 12 May 2021 12:03:08 -0700 Subject: [PATCH 1/3] added multiple idle tasks --- tasks.c | 112 ++++++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 96 insertions(+), 16 deletions(-) diff --git a/tasks.c b/tasks.c index e2245bcf59..0a88bfbf4e 100644 --- a/tasks.c +++ b/tasks.c @@ -467,6 +467,9 @@ static void prvInitialiseTaskLists( void ) PRIVILEGED_FUNCTION; * */ static portTASK_FUNCTION_PROTO( prvIdleTask, pvParameters ) PRIVILEGED_FUNCTION; +#if ( configNUM_CORES > 1 ) +static portTASK_FUNCTION_PROTO( prvMinimalIdleTask, pvParameters ) PRIVILEGED_FUNCTION; +#endif /* * Utility to free all memory allocated by the scheduler to hold a TCB, @@ -1545,7 +1548,11 @@ static void prvInitialiseNewTask( TaskFunction_t pxTaskCode, pxNewTCB->xTaskRunState = taskTASK_NOT_RUNNING; /* Is this an idle task? */ + #if(configNUM_CORES > 1) + pxNewTCB->xIsIdle = ( pxTaskCode == prvIdleTask ) || (pxTaskCode == prvMinimalIdleTask); + #else pxNewTCB->xIsIdle = ( pxTaskCode == prvIdleTask ); + #endif if( pxCreatedTask != NULL ) { @@ -2663,22 +2670,40 @@ void vTaskStartScheduler( void ) #if ( configSUPPORT_STATIC_ALLOCATION == 1 ) { - #error User must specify an array of buffers for idle task TCBs and stacks - StaticTask_t * pxIdleTaskTCBBuffer = NULL; - StackType_t * pxIdleTaskStackBuffer = NULL; - uint32_t ulIdleTaskStackSize; - - /* The Idle task is created using user provided RAM - obtain the - * address of the RAM then create the idle task. */ - vApplicationGetIdleTaskMemory( &pxIdleTaskTCBBuffer, &pxIdleTaskStackBuffer, &ulIdleTaskStackSize ); - xIdleTaskHandle[ xCoreID ] = xTaskCreateStatic( prvIdleTask, - cIdleName, - ulIdleTaskStackSize, - ( void * ) NULL, /*lint !e961. The cast is not redundant for all compilers. */ - portPRIVILEGE_BIT, /* In effect ( tskIDLE_PRIORITY | portPRIVILEGE_BIT ), but tskIDLE_PRIORITY is zero. */ - pxIdleTaskStackBuffer, - pxIdleTaskTCBBuffer ); /*lint !e961 MISRA exception, justified as it is not a redundant explicit cast to all supported compilers. */ - + if(xCoreID == 0) + { + StaticTask_t * pxIdleTaskTCBBuffer = NULL; + StackType_t * pxIdleTaskStackBuffer = NULL; + uint32_t ulIdleTaskStackSize; + + /* The Idle task is created using user provided RAM - obtain the + * address of the RAM then create the idle task. */ + vApplicationGetIdleTaskMemory( &pxIdleTaskTCBBuffer, &pxIdleTaskStackBuffer, &ulIdleTaskStackSize ); + xIdleTaskHandle[ xCoreID ] = xTaskCreateStatic( prvIdleTask, + cIdleName, + ulIdleTaskStackSize, + ( void * ) NULL, /*lint !e961. The cast is not redundant for all compilers. */ + portPRIVILEGE_BIT, /* In effect ( tskIDLE_PRIORITY | portPRIVILEGE_BIT ), but tskIDLE_PRIORITY is zero. */ + pxIdleTaskStackBuffer, + pxIdleTaskTCBBuffer ); /*lint !e961 MISRA exception, justified as it is not a redundant explicit cast to all supported compilers. */ + } + #if( configNUM_CORES > 1) + else + { + struct taskMemory{ + StaticTask_t TCB; + StackType_t stack[configMINIMAL_STACK_SIZE]; + }; + static struct taskMemory idleMemory[configNUM_CORES]; + xIdleTaskHandle[ xCoreID ] = xTaskCreateStatic( prvMinimalIdleTask, + cIdleName, + configMINIMAL_STACK_SIZE, + ( void * ) NULL, /*lint !e961. The cast is not redundant for all compilers. */ + portPRIVILEGE_BIT, /* In effect ( tskIDLE_PRIORITY | portPRIVILEGE_BIT ), but tskIDLE_PRIORITY is zero. */ + idleMemory[xCoreID].stack, + &idleMemory[xCoreID].TCB ); /*lint !e961 MISRA exception, justified as it is not a redundant explicit cast to all supported compilers. */ + } + #endif if( xIdleTaskHandle[ xCoreID ] != NULL ) { xReturn = pdPASS; @@ -4146,6 +4171,61 @@ void vTaskMissedYield( void ) #endif /* configUSE_TRACE_FACILITY */ +/* + * ----------------------------------------------------------- + * The MinimalIdle task. + * ---------------------------------------------------------- + * + * The portTASK_FUNCTION() macro is used to allow port/compiler specific + * language extensions. The equivalent prototype for this function is: + * + * void prvMinimalIdleTask( void *pvParameters ); + * + * The minimal idle task is used for all the additional Cores in a SMP system. + * There must be only 1 idle task and the rest are minimal idle tasks. + * + * @todo additional conditional compiles to remove this function. + */ +#if (configNUM_CORES > 1) +static portTASK_FUNCTION( prvMinimalIdleTask, pvParameters ) +{ + for(;;) + { + #if ( configUSE_PREEMPTION == 0 ) + { + /* If we are not using preemption we keep forcing a task switch to + * see if any other task has become available. If we are using + * preemption we don't need to do this as any task becoming available + * will automatically get the processor anyway. */ + taskYIELD(); + } + #endif /* configUSE_PREEMPTION */ + + #if ( ( configUSE_PREEMPTION == 1 ) && ( configIDLE_SHOULD_YIELD == 1 ) ) + { + /* When using preemption tasks of equal priority will be + * timesliced. If a task that is sharing the idle priority is ready + * to run then the idle task should yield before the end of the + * timeslice. + * + * A critical region is not required here as we are just reading from + * the list, and an occasional incorrect value will not matter. If + * the ready list at the idle priority contains one more task than the + * number of idle tasks, which is equal to the configured numbers of cores + * then a task other than the idle task is ready to execute. */ + if( listCURRENT_LIST_LENGTH( &( pxReadyTasksLists[ tskIDLE_PRIORITY ] ) ) > ( UBaseType_t ) configNUM_CORES ) + { + taskYIELD(); + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + #endif /* ( ( configUSE_PREEMPTION == 1 ) && ( configIDLE_SHOULD_YIELD == 1 ) ) */ + } +} +#endif /* * ----------------------------------------------------------- * The Idle task. From ad317efd627bdaa2400046d7f1e850a449607010 Mon Sep 17 00:00:00 2001 From: Joseph Julicher Date: Wed, 12 May 2021 12:13:44 -0700 Subject: [PATCH 2/3] Added multiple IDLE tasks to non-static allocation --- tasks.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/tasks.c b/tasks.c index 0a88bfbf4e..ba16ce2e18 100644 --- a/tasks.c +++ b/tasks.c @@ -2715,6 +2715,8 @@ void vTaskStartScheduler( void ) } #else /* if ( configSUPPORT_STATIC_ALLOCATION == 1 ) */ { + if(xCoreID == 0) + { /* The Idle task is being created using dynamically allocated RAM. */ xReturn = xTaskCreate( prvIdleTask, cIdleName, @@ -2722,6 +2724,18 @@ void vTaskStartScheduler( void ) ( void * ) NULL, portPRIVILEGE_BIT, /* In effect ( tskIDLE_PRIORITY | portPRIVILEGE_BIT ), but tskIDLE_PRIORITY is zero. */ &xIdleTaskHandle[ xCoreID ] ); /*lint !e961 MISRA exception, justified as it is not a redundant explicit cast to all supported compilers. */ + } + #if( configNUM_CORES > 1 ) + else + { + xReturn = xTaskCreate( prvMinimalIdleTask, + cIdleName, + configMINIMAL_STACK_SIZE, + ( void * ) NULL, + portPRIVILEGE_BIT, /* In effect ( tskIDLE_PRIORITY | portPRIVILEGE_BIT ), but tskIDLE_PRIORITY is zero. */ + &xIdleTaskHandle[ xCoreID ] ); /*lint !e961 MISRA exception, justified as it is not a redundant explicit cast to all supported compilers. */ + } + #endif } #endif /* configSUPPORT_STATIC_ALLOCATION */ } From b9a17479a0a34d0309731f7d4e26e973e9daa68d Mon Sep 17 00:00:00 2001 From: Joseph Julicher Date: Wed, 12 May 2021 17:01:00 -0700 Subject: [PATCH 3/3] Adjustments to tasks from PR review --- tasks.c | 72 +++++++++++++++++++++++++++++++-------------------------- 1 file changed, 39 insertions(+), 33 deletions(-) diff --git a/tasks.c b/tasks.c index ba16ce2e18..13e2535d02 100644 --- a/tasks.c +++ b/tasks.c @@ -410,6 +410,11 @@ PRIVILEGED_DATA static volatile UBaseType_t uxSchedulerSuspended = ( UBaseType_t /* File private functions. --------------------------------*/ +/* + * Creates the idle tasks during scheduler start + */ +static BaseType_t prvCreateIdleTasks( void ); + /* * Returns the yield pending count for the calling core. */ @@ -460,11 +465,6 @@ static void prvInitialiseTaskLists( void ) PRIVILEGED_FUNCTION; * The idle task is automatically created and added to the ready lists upon * creation of the first user task. * - * The portTASK_FUNCTION_PROTO() macro is used to allow port/compiler specific - * language extensions. The equivalent prototype for this function is: - * - * void prvIdleTask( void *pvParameters ); - * */ static portTASK_FUNCTION_PROTO( prvIdleTask, pvParameters ) PRIVILEGED_FUNCTION; #if ( configNUM_CORES > 1 ) @@ -1548,11 +1548,20 @@ static void prvInitialiseNewTask( TaskFunction_t pxTaskCode, pxNewTCB->xTaskRunState = taskTASK_NOT_RUNNING; /* Is this an idle task? */ + if(pxTaskCode == prvIdleTask) + { + pxNewTCB->xIsIdle = pdTRUE; + } #if(configNUM_CORES > 1) - pxNewTCB->xIsIdle = ( pxTaskCode == prvIdleTask ) || (pxTaskCode == prvMinimalIdleTask); - #else - pxNewTCB->xIsIdle = ( pxTaskCode == prvIdleTask ); + else if(pxTaskCode == prvMinimalIdleTask) + { + pxNewTCB->xIsIdle = pdTRUE; + } #endif + else + { + pxNewTCB->xIsIdle = pdFALSE; + } if( pxCreatedTask != NULL ) { @@ -2605,19 +2614,13 @@ static void prvAddNewTaskToReadyList( TCB_t * pxNewTCB ) #endif /* ( ( INCLUDE_xTaskResumeFromISR == 1 ) && ( INCLUDE_vTaskSuspend == 1 ) ) */ /*-----------------------------------------------------------*/ -void vTaskStartScheduler( void ) +static BaseType_t prvCreateIdleTasks( void ) { - BaseType_t xReturn; + BaseType_t xReturn = pdPASS; BaseType_t xCoreID; char cIdleName[ configMAX_TASK_NAME_LEN ]; - #if ( configUSE_TIMERS == 1 ) - { - xReturn = xTimerCreateTimerTask(); - } - #endif /* configUSE_TIMERS */ - - /* Add each idle task at the lowest priority. */ + /* Add each idle task at the lowest priority. */ for( xCoreID = ( BaseType_t ) 0; xCoreID < ( BaseType_t ) configNUM_CORES; xCoreID++ ) { BaseType_t x; @@ -2690,18 +2693,16 @@ void vTaskStartScheduler( void ) #if( configNUM_CORES > 1) else { - struct taskMemory{ - StaticTask_t TCB; - StackType_t stack[configMINIMAL_STACK_SIZE]; - }; - static struct taskMemory idleMemory[configNUM_CORES]; + static StaticTask_t xIdleTCBBuffers[configNUM_CORES-1]; + static StackType_t xIdleTaskStackBuffers[configMINIMAL_STACK_SIZE][configNUM_CORES-1]; + xIdleTaskHandle[ xCoreID ] = xTaskCreateStatic( prvMinimalIdleTask, cIdleName, configMINIMAL_STACK_SIZE, ( void * ) NULL, /*lint !e961. The cast is not redundant for all compilers. */ portPRIVILEGE_BIT, /* In effect ( tskIDLE_PRIORITY | portPRIVILEGE_BIT ), but tskIDLE_PRIORITY is zero. */ - idleMemory[xCoreID].stack, - &idleMemory[xCoreID].TCB ); /*lint !e961 MISRA exception, justified as it is not a redundant explicit cast to all supported compilers. */ + xIdleTaskStackBuffers[xCoreID-1], + &xIdleTCBBuffers[xCoreID-1] ); /*lint !e961 MISRA exception, justified as it is not a redundant explicit cast to all supported compilers. */ } #endif if( xIdleTaskHandle[ xCoreID ] != NULL ) @@ -2739,6 +2740,20 @@ void vTaskStartScheduler( void ) } #endif /* configSUPPORT_STATIC_ALLOCATION */ } + return xReturn; +} + +void vTaskStartScheduler( void ) +{ + BaseType_t xReturn; + + #if ( configUSE_TIMERS == 1 ) + { + xReturn = xTimerCreateTimerTask(); + } + #endif /* configUSE_TIMERS */ + + xReturn = prvCreateIdleTasks(); if( xReturn == pdPASS ) { @@ -4190,11 +4205,6 @@ void vTaskMissedYield( void ) * The MinimalIdle task. * ---------------------------------------------------------- * - * The portTASK_FUNCTION() macro is used to allow port/compiler specific - * language extensions. The equivalent prototype for this function is: - * - * void prvMinimalIdleTask( void *pvParameters ); - * * The minimal idle task is used for all the additional Cores in a SMP system. * There must be only 1 idle task and the rest are minimal idle tasks. * @@ -4245,10 +4255,6 @@ static portTASK_FUNCTION( prvMinimalIdleTask, pvParameters ) * The Idle task. * ---------------------------------------------------------- * - * The portTASK_FUNCTION() macro is used to allow port/compiler specific - * language extensions. The equivalent prototype for this function is: - * - * void prvIdleTask( void *pvParameters ); * */ static portTASK_FUNCTION( prvIdleTask, pvParameters )