diff --git a/cmake_example/CMakeLists.txt b/cmake_example/CMakeLists.txt new file mode 100644 index 00000000000..7230120390f --- /dev/null +++ b/cmake_example/CMakeLists.txt @@ -0,0 +1,28 @@ +cmake_minimum_required(VERSION 3.15) + +project(example) + +set(FREERTOS_KERNEL_PATH "../") + +# Add the freertos_config for FreeRTOS-Kernel +add_library(freertos_config INTERFACE) + +target_include_directories(freertos_config + INTERFACE + ../sample_configuration +) + +# Select the heap port. values between 1-4 will pick a heap. +# set(FREERTOS_HEAP "4" CACHE STRING "" FORCE) + +# Select the native compile PORT +set(FREERTOS_PORT "TEMPLATE" CACHE STRING "" FORCE) + +# Adding the FreeRTOS-Kernel subdirectory +add_subdirectory(${FREERTOS_KERNEL_PATH} FreeRTOS-Kernel) + +add_executable(${PROJECT_NAME} + main.c +) + +target_link_libraries(${PROJECT_NAME} freertos_kernel freertos_config) diff --git a/cmake_example/main.c b/cmake_example/main.c new file mode 100644 index 00000000000..d00aeae7206 --- /dev/null +++ b/cmake_example/main.c @@ -0,0 +1,111 @@ +/* + * FreeRTOS Kernel + * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * SPDX-License-Identifier: MIT + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * https://www.FreeRTOS.org + * https://github.com/FreeRTOS + * + */ + +/* + * This is a simple main that will start the FreeRTOS-Kernel and run a periodic task + * that only delays if compiled with the template port, this project will do nothing. + * For more information on getting started please look here: + * https://freertos.org/FreeRTOS-quick-start-guide.html + */ + +#include +#include +#include +#include +#include + +#include + +static StaticTask_t exampleTaskTCB; +static StackType_t exampleTaskStack[ configMINIMAL_STACK_SIZE ]; + +static StaticTask_t xTimerTaskTCB; +static StackType_t uxTimerTaskStack[ configTIMER_TASK_STACK_DEPTH ]; + +static StaticTask_t xIdleTaskTCB; +static StackType_t uxIdleTaskStack[ configMINIMAL_STACK_SIZE ]; + +void exampleTask( void * parameters ) +{ + /* Unused parameters. */ + ( void ) parameters; + + for( ; ; ) + { + /* Example Task Code */ + vTaskDelay( 100 ); /* delay 100 ticks */ + } +} + +void main( void ) +{ + printf( "Example FreeRTOS Project\n" ); + + xTaskCreateStatic( exampleTask, + "example", + configMINIMAL_STACK_SIZE, + NULL, + configMAX_PRIORITIES - 1, + exampleTaskStack, + &exampleTaskTCB ); + + /* Start the scheduler. */ + vTaskStartScheduler(); + + for( ; ; ) + { + /* Should not reach here. */ + } +} + +void vApplicationStackOverflowHook( TaskHandle_t xTask, + char * pcTaskName ) +{ + /* Check pcTaskName for the name of the offending task, + * or pxCurrentTCB if pcTaskName has itself been corrupted. */ + ( void ) xTask; + ( void ) pcTaskName; +} + +void vApplicationGetTimerTaskMemory( StaticTask_t ** ppxTimerTaskTCBBuffer, + StackType_t ** ppxTimerTaskStackBuffer, + uint32_t * pulTimerTaskStackSize ) +{ + *ppxTimerTaskTCBBuffer = &xTimerTaskTCB; + *ppxTimerTaskStackBuffer = uxTimerTaskStack; + *pulTimerTaskStackSize = configTIMER_TASK_STACK_DEPTH; +} + +void vApplicationGetIdleTaskMemory( StaticTask_t ** ppxIdleTaskTCBBuffer, + StackType_t ** ppxIdleTaskStackBuffer, + uint32_t * pulIdleTaskStackSize ) +{ + *ppxIdleTaskTCBBuffer = &xIdleTaskTCB; + *ppxIdleTaskStackBuffer = uxIdleTaskStack; + *pulIdleTaskStackSize = configMINIMAL_STACK_SIZE; +} diff --git a/include/FreeRTOS.h b/include/FreeRTOS.h index f575863758c..ba7d083a625 100644 --- a/include/FreeRTOS.h +++ b/include/FreeRTOS.h @@ -175,8 +175,8 @@ #endif #if ( configNUMBER_OF_CORES > 1 ) - #ifndef configUSE_MINIMAL_IDLE_HOOK - #error Missing definition: configUSE_MINIMAL_IDLE_HOOK must be defined in FreeRTOSConfig.h as either 1 or 0. See the Configuration section of the FreeRTOS API documentation for details. + #ifndef configUSE_PASSIVE_IDLE_HOOK + #error Missing definition: configUSE_PASSIVE_IDLE_HOOK must be defined in FreeRTOSConfig.h as either 1 or 0. See the Configuration section of the FreeRTOS API documentation for details. #endif #endif @@ -473,9 +473,9 @@ #define configUSE_CORE_AFFINITY 0 #endif /* configUSE_CORE_AFFINITY */ -#ifndef configUSE_MINIMAL_IDLE_HOOK - #define configUSE_MINIMAL_IDLE_HOOK 0 -#endif /* configUSE_MINIMAL_IDLE_HOOK */ +#ifndef configUSE_PASSIVE_IDLE_HOOK + #define configUSE_PASSIVE_IDLE_HOOK 0 +#endif /* configUSE_PASSIVE_IDLE_HOOK */ /* The timers module relies on xTaskGetSchedulerState(). */ #if configUSE_TIMERS == 1 @@ -1610,6 +1610,14 @@ #define traceRETURN_xTaskCreateStatic( xReturn ) #endif +#ifndef traceENTER_xTaskCreateStaticAffinitySet + #define traceENTER_xTaskCreateStaticAffinitySet( pxTaskCode, pcName, ulStackDepth, pvParameters, uxPriority, puxStackBuffer, pxTaskBuffer, uxCoreAffinityMask ) +#endif + +#ifndef traceRETURN_xTaskCreateStaticAffinitySet + #define traceRETURN_xTaskCreateStaticAffinitySet( xReturn ) +#endif + #ifndef traceENTER_xTaskCreateRestrictedStatic #define traceENTER_xTaskCreateRestrictedStatic( pxTaskDefinition, pxCreatedTask ) #endif @@ -1618,6 +1626,14 @@ #define traceRETURN_xTaskCreateRestrictedStatic( xReturn ) #endif +#ifndef traceENTER_xTaskCreateRestrictedStaticAffinitySet + #define traceENTER_xTaskCreateRestrictedStaticAffinitySet( pxTaskDefinition, uxCoreAffinityMask, pxCreatedTask ) +#endif + +#ifndef traceRETURN_xTaskCreateRestrictedStaticAffinitySet + #define traceRETURN_xTaskCreateRestrictedStaticAffinitySet( xReturn ) +#endif + #ifndef traceENTER_xTaskCreateRestricted #define traceENTER_xTaskCreateRestricted( pxTaskDefinition, pxCreatedTask ) #endif @@ -1626,6 +1642,14 @@ #define traceRETURN_xTaskCreateRestricted( xReturn ) #endif +#ifndef traceENTER_xTaskCreateRestrictedAffinitySet + #define traceENTER_xTaskCreateRestrictedAffinitySet( pxTaskDefinition, uxCoreAffinityMask, pxCreatedTask ) +#endif + +#ifndef traceRETURN_xTaskCreateRestrictedAffinitySet + #define traceRETURN_xTaskCreateRestrictedAffinitySet( xReturn ) +#endif + #ifndef traceENTER_xTaskCreate #define traceENTER_xTaskCreate( pxTaskCode, pcName, usStackDepth, pvParameters, uxPriority, pxCreatedTask ) #endif @@ -1634,6 +1658,14 @@ #define traceRETURN_xTaskCreate( xReturn ) #endif +#ifndef traceENTER_xTaskCreateAffinitySet + #define traceENTER_xTaskCreateAffinitySet( pxTaskCode, pcName, usStackDepth, pvParameters, uxPriority, uxCoreAffinityMask, pxCreatedTask ) +#endif + +#ifndef traceRETURN_xTaskCreateAffinitySet + #define traceRETURN_xTaskCreateAffinitySet( xReturn ) +#endif + #ifndef traceENTER_vTaskDelete #define traceENTER_vTaskDelete( xTaskToDelete ) #endif @@ -1682,6 +1714,22 @@ #define traceRETURN_uxTaskPriorityGetFromISR( uxReturn ) #endif +#ifndef traceENTER_uxTaskBasePriorityGet + #define traceENTER_uxTaskBasePriorityGet( xTask ) +#endif + +#ifndef traceRETURN_uxTaskBasePriorityGet + #define traceRETURN_uxTaskBasePriorityGet( uxReturn ) +#endif + +#ifndef traceENTER_uxTaskBasePriorityGetFromISR + #define traceENTER_uxTaskBasePriorityGetFromISR( xTask ) +#endif + +#ifndef traceRETURN_uxTaskBasePriorityGetFromISR + #define traceRETURN_uxTaskBasePriorityGetFromISR( uxReturn ) +#endif + #ifndef traceENTER_vTaskPrioritySet #define traceENTER_vTaskPrioritySet( xTask, uxNewPriority ) #endif @@ -1834,8 +1882,14 @@ #define traceRETURN_uxTaskGetSystemState( uxTask ) #endif -#ifndef traceENTER_xTaskGetIdleTaskHandle - #define traceENTER_xTaskGetIdleTaskHandle() +#if ( configNUMBER_OF_CORES == 1 ) + #ifndef traceENTER_xTaskGetIdleTaskHandle + #define traceENTER_xTaskGetIdleTaskHandle() + #endif +#else + #ifndef traceENTER_xTaskGetIdleTaskHandle + #define traceENTER_xTaskGetIdleTaskHandle( xCoreID ) + #endif #endif #ifndef traceRETURN_xTaskGetIdleTaskHandle diff --git a/include/mpu_prototypes.h b/include/mpu_prototypes.h index 863bb567810..1c9d8c048b7 100644 --- a/include/mpu_prototypes.h +++ b/include/mpu_prototypes.h @@ -128,6 +128,8 @@ BaseType_t MPU_xTaskGetStaticBuffers( TaskHandle_t xTask, StackType_t ** ppuxStackBuffer, StaticTask_t ** ppxTaskBuffer ) PRIVILEGED_FUNCTION; UBaseType_t MPU_uxTaskPriorityGetFromISR( const TaskHandle_t xTask ) PRIVILEGED_FUNCTION; +UBaseType_t MPU_uxTaskBasePriorityGet( const TaskHandle_t xTask ) PRIVILEGED_FUNCTION; +UBaseType_t MPU_uxTaskBasePriorityGetFromISR( const TaskHandle_t xTask ) PRIVILEGED_FUNCTION; BaseType_t MPU_xTaskResumeFromISR( TaskHandle_t xTaskToResume ) PRIVILEGED_FUNCTION; TaskHookFunction_t MPU_xTaskGetApplicationTaskTagFromISR( TaskHandle_t xTask ) PRIVILEGED_FUNCTION; BaseType_t MPU_xTaskGenericNotifyFromISR( TaskHandle_t xTaskToNotify, diff --git a/include/mpu_wrappers.h b/include/mpu_wrappers.h index 162f57ff31c..51e7bcf4054 100644 --- a/include/mpu_wrappers.h +++ b/include/mpu_wrappers.h @@ -99,6 +99,8 @@ #define vTaskAllocateMPURegions MPU_vTaskAllocateMPURegions #define xTaskGetStaticBuffers MPU_xTaskGetStaticBuffers #define uxTaskPriorityGetFromISR MPU_uxTaskPriorityGetFromISR + #define uxTaskBasePriorityGet MPU_uxTaskBasePriorityGet + #define uxTaskBasePriorityGetFromISR MPU_uxTaskBasePriorityGetFromISR #define xTaskResumeFromISR MPU_xTaskResumeFromISR #define xTaskGetApplicationTaskTagFromISR MPU_xTaskGetApplicationTaskTagFromISR #define xTaskGenericNotifyFromISR MPU_xTaskGenericNotifyFromISR diff --git a/include/task.h b/include/task.h index 44835187676..b6850e8bdb7 100644 --- a/include/task.h +++ b/include/task.h @@ -1021,6 +1021,37 @@ UBaseType_t uxTaskPriorityGet( const TaskHandle_t xTask ) PRIVILEGED_FUNCTION; */ UBaseType_t uxTaskPriorityGetFromISR( const TaskHandle_t xTask ) PRIVILEGED_FUNCTION; +/** + * task. h + * @code{c} + * UBaseType_t uxTaskBasePriorityGet( const TaskHandle_t xTask ); + * @endcode + * + * INCLUDE_uxTaskPriorityGet and configUSE_MUTEXES must be defined as 1 for this + * function to be available. See the configuration section for more information. + * + * Obtain the base priority of any task. + * + * @param xTask Handle of the task to be queried. Passing a NULL + * handle results in the base priority of the calling task being returned. + * + * @return The base priority of xTask. + * + * \defgroup uxTaskPriorityGet uxTaskBasePriorityGet + * \ingroup TaskCtrl + */ +UBaseType_t uxTaskBasePriorityGet( const TaskHandle_t xTask ) PRIVILEGED_FUNCTION; + +/** + * task. h + * @code{c} + * UBaseType_t uxTaskBasePriorityGetFromISR( const TaskHandle_t xTask ); + * @endcode + * + * A version of uxTaskBasePriorityGet() that can be used from an ISR. + */ +UBaseType_t uxTaskBasePriorityGetFromISR( const TaskHandle_t xTask ) PRIVILEGED_FUNCTION; + /** * task. h * @code{c} @@ -1930,6 +1961,8 @@ configSTACK_DEPTH_TYPE uxTaskGetStackHighWaterMark2( TaskHandle_t xTask ) PRIVIL #if ( configSUPPORT_STATIC_ALLOCATION == 1 ) + #if ( configNUMBER_OF_CORES == 1 ) + /** * task.h * @code{c} @@ -1943,10 +1976,41 @@ configSTACK_DEPTH_TYPE uxTaskGetStackHighWaterMark2( TaskHandle_t xTask ) PRIVIL * @param ppxIdleTaskStackBuffer A handle to a statically allocated Stack buffer for the idle task * @param pulIdleTaskStackSize A pointer to the number of elements that will fit in the allocated stack buffer */ - void vApplicationGetIdleTaskMemory( StaticTask_t ** ppxIdleTaskTCBBuffer, - StackType_t ** ppxIdleTaskStackBuffer, - uint32_t * pulIdleTaskStackSize ); /*lint !e526 Symbol not defined as it is an application callback. */ -#endif + void vApplicationGetIdleTaskMemory( StaticTask_t ** ppxIdleTaskTCBBuffer, + StackType_t ** ppxIdleTaskStackBuffer, + uint32_t * pulIdleTaskStackSize ); /*lint !e526 Symbol not defined as it is an application callback. */ + #else /* #if ( configNUMBER_OF_CORES == 1 ) */ + +/** + * task.h + * @code{c} + * void vApplicationGetIdleTaskMemory( StaticTask_t ** ppxIdleTaskTCBBuffer, StackType_t ** ppxIdleTaskStackBuffer, uint32_t *pulIdleTaskStackSize, BaseType_t xCoreID ) + * @endcode + * + * This function is used to provide a statically allocated block of memory to FreeRTOS to hold the Idle Tasks TCB. This function is required when + * configSUPPORT_STATIC_ALLOCATION is set. For more information see this URI: https://www.FreeRTOS.org/a00110.html#configSUPPORT_STATIC_ALLOCATION + * + * In the FreeRTOS SMP, there are a total of configNUMBER_OF_CORES idle tasks: + * 1. 1 Active idle task which does all the housekeeping. + * 2. ( configNUMBER_OF_CORES - 1 ) Passive idle tasks which do nothing. + * These idle tasks are created to ensure that each core has an idle task to run when + * no other task is available to run. + * + * The function vApplicationGetIdleTaskMemory is called with xCoreID 0 to get the + * memory for Active idle task. It is called with xCoreID 1, 2 ... ( configNUMBER_OF_CORES - 1 ) + * to get memory for passive idle tasks. + * + * @param ppxIdleTaskTCBBuffer A handle to a statically allocated TCB buffer + * @param ppxIdleTaskStackBuffer A handle to a statically allocated Stack buffer for the idle task + * @param pulIdleTaskStackSize A pointer to the number of elements that will fit in the allocated stack buffer + * @param xCoreId The core index of the idle task buffer + */ + void vApplicationGetIdleTaskMemory( StaticTask_t ** ppxIdleTaskTCBBuffer, + StackType_t ** ppxIdleTaskStackBuffer, + uint32_t * pulIdleTaskStackSize, /*lint !e526 Symbol not defined as it is an application callback. */ + BaseType_t xCoreID ); + #endif /* #if ( configNUMBER_OF_CORES == 1 ) */ +#endif /* if ( configSUPPORT_STATIC_ALLOCATION == 1 ) */ /** * task.h @@ -1970,8 +2034,22 @@ BaseType_t xTaskCallApplicationTaskHook( TaskHandle_t xTask, * * Simply returns the handle of the idle task. It is not valid to call * xTaskGetIdleTaskHandle() before the scheduler has been started. + * + * In the FreeRTOS SMP, there are a total of configNUMBER_OF_CORES idle tasks: + * 1. 1 Active idle task which does all the housekeeping. + * 2. ( configNUMBER_OF_CORES - 1 ) Passive idle tasks which do nothing. + * These idle tasks are created to ensure that each core has an idle task to run when + * no other task is available to run. + * + * Set xCoreID to 0 to get the Active idle task handle. Set xCoreID to + * 1,2 ... ( configNUMBER_OF_CORES - 1 ) to get the Passive idle task + * handles. */ -TaskHandle_t xTaskGetIdleTaskHandle( void ) PRIVILEGED_FUNCTION; +#if ( configNUMBER_OF_CORES == 1 ) + TaskHandle_t xTaskGetIdleTaskHandle( void ) PRIVILEGED_FUNCTION; +#else /* #if ( configNUMBER_OF_CORES == 1 ) */ + TaskHandle_t xTaskGetIdleTaskHandle( BaseType_t xCoreID ) PRIVILEGED_FUNCTION; +#endif /* #if ( configNUMBER_OF_CORES == 1 ) */ /** * configUSE_TRACE_FACILITY must be defined as 1 in FreeRTOSConfig.h for diff --git a/portable/Common/mpu_wrappers_v2.c b/portable/Common/mpu_wrappers_v2.c index 9db5772ad2e..87e849edf1b 100644 --- a/portable/Common/mpu_wrappers_v2.c +++ b/portable/Common/mpu_wrappers_v2.c @@ -112,6 +112,16 @@ */ #define CONVERT_TO_INTERNAL_INDEX( lIndex ) ( ( lIndex ) - INDEX_OFFSET ) +/** + * @brief Max value that fits in a uint32_t type. + */ + #define mpuUINT32_MAX ( ~( ( uint32_t ) 0 ) ) + +/** + * @brief Check if multiplying a and b will result in overflow. + */ + #define mpuMULTIPLY_UINT32_WILL_OVERFLOW( a, b ) ( ( ( a ) > 0 ) && ( ( b ) > ( mpuUINT32_MAX / ( a ) ) ) ) + /** * @brief Get the index of a free slot in the kernel object pool. * @@ -1035,25 +1045,30 @@ UBaseType_t uxArraySize, configRUN_TIME_COUNTER_TYPE * pulTotalRunTime ) /* PRIVILEGED_FUNCTION */ { - UBaseType_t uxReturn = pdFALSE; + UBaseType_t uxReturn = 0; UBaseType_t xIsTaskStatusArrayWriteable = pdFALSE; UBaseType_t xIsTotalRunTimeWriteable = pdFALSE; + uint32_t ulArraySize = ( uint32_t ) uxArraySize; + uint32_t ulTaskStatusSize = ( uint32_t ) sizeof( TaskStatus_t ); - xIsTaskStatusArrayWriteable = xPortIsAuthorizedToAccessBuffer( pxTaskStatusArray, - sizeof( TaskStatus_t ) * uxArraySize, - tskMPU_WRITE_PERMISSION ); - - if( pulTotalRunTime != NULL ) + if( mpuMULTIPLY_UINT32_WILL_OVERFLOW( ulTaskStatusSize, ulArraySize ) == 0 ) { - xIsTotalRunTimeWriteable = xPortIsAuthorizedToAccessBuffer( pulTotalRunTime, - sizeof( configRUN_TIME_COUNTER_TYPE ), - tskMPU_WRITE_PERMISSION ); - } + xIsTaskStatusArrayWriteable = xPortIsAuthorizedToAccessBuffer( pxTaskStatusArray, + ulTaskStatusSize * ulArraySize, + tskMPU_WRITE_PERMISSION ); - if( ( xIsTaskStatusArrayWriteable == pdTRUE ) && - ( ( pulTotalRunTime == NULL ) || ( xIsTotalRunTimeWriteable == pdTRUE ) ) ) - { - uxReturn = uxTaskGetSystemState( pxTaskStatusArray, uxArraySize, pulTotalRunTime ); + if( pulTotalRunTime != NULL ) + { + xIsTotalRunTimeWriteable = xPortIsAuthorizedToAccessBuffer( pulTotalRunTime, + sizeof( configRUN_TIME_COUNTER_TYPE ), + tskMPU_WRITE_PERMISSION ); + } + + if( ( xIsTaskStatusArrayWriteable == pdTRUE ) && + ( ( pulTotalRunTime == NULL ) || ( xIsTotalRunTimeWriteable == pdTRUE ) ) ) + { + uxReturn = uxTaskGetSystemState( pxTaskStatusArray, ( UBaseType_t ) ulArraySize, pulTotalRunTime ); + } } return uxReturn; @@ -1894,6 +1909,72 @@ #endif /* #if ( INCLUDE_uxTaskPriorityGet == 1 ) */ /*-----------------------------------------------------------*/ + #if ( ( INCLUDE_uxTaskPriorityGet == 1 ) && ( configUSE_MUTEXES == 1 ) ) + + UBaseType_t MPU_uxTaskBasePriorityGet( const TaskHandle_t xTask ) /* PRIVILEGED_FUNCTION */ + { + UBaseType_t uxReturn = configMAX_PRIORITIES; + int32_t lIndex; + TaskHandle_t xInternalTaskHandle = NULL; + + if( xTask == NULL ) + { + uxReturn = uxTaskBasePriorityGet( xTask ); + } + else + { + lIndex = ( int32_t ) xTask; + + if( IS_EXTERNAL_INDEX_VALID( lIndex ) != pdFALSE ) + { + xInternalTaskHandle = MPU_GetTaskHandleAtIndex( CONVERT_TO_INTERNAL_INDEX( lIndex ) ); + + if( xInternalTaskHandle != NULL ) + { + uxReturn = uxTaskBasePriorityGet( xInternalTaskHandle ); + } + } + } + + return uxReturn; + } + + #endif /* #if ( ( INCLUDE_uxTaskPriorityGet == 1 ) && ( configUSE_MUTEXES == 1 ) ) */ +/*-----------------------------------------------------------*/ + + #if ( ( INCLUDE_uxTaskPriorityGet == 1 ) && ( configUSE_MUTEXES == 1 ) ) + + UBaseType_t MPU_uxTaskBasePriorityGetFromISR( const TaskHandle_t xTask ) /* PRIVILEGED_FUNCTION */ + { + UBaseType_t uxReturn = configMAX_PRIORITIES; + int32_t lIndex; + TaskHandle_t xInternalTaskHandle = NULL; + + if( xTask == NULL ) + { + uxReturn = uxTaskBasePriorityGetFromISR( xTask ); + } + else + { + lIndex = ( int32_t ) xTask; + + if( IS_EXTERNAL_INDEX_VALID( lIndex ) != pdFALSE ) + { + xInternalTaskHandle = MPU_GetTaskHandleAtIndex( CONVERT_TO_INTERNAL_INDEX( lIndex ) ); + + if( xInternalTaskHandle != NULL ) + { + uxReturn = uxTaskBasePriorityGetFromISR( xInternalTaskHandle ); + } + } + } + + return uxReturn; + } + + #endif /* #if ( ( INCLUDE_uxTaskPriorityGet == 1 ) && ( configUSE_MUTEXES == 1 ) ) */ +/*-----------------------------------------------------------*/ + #if ( ( INCLUDE_xTaskResumeFromISR == 1 ) && ( INCLUDE_vTaskSuspend == 1 ) ) BaseType_t MPU_xTaskResumeFromISR( TaskHandle_t xTaskToResume ) /* PRIVILEGED_FUNCTION */ @@ -2054,7 +2135,7 @@ if( pvItemToQueue != NULL ) { xIsItemToQueueReadable = xPortIsAuthorizedToAccessBuffer( pvItemToQueue, - uxQueueGetQueueItemSize( xInternalQueueHandle ), + uxQueueItemSize, tskMPU_READ_PERMISSION ); } @@ -2167,7 +2248,7 @@ ) { xIsReceiveBufferWritable = xPortIsAuthorizedToAccessBuffer( pvBuffer, - uxQueueGetQueueItemSize( xInternalQueueHandle ), + uxQueueItemSize, tskMPU_WRITE_PERMISSION ); if( xIsReceiveBufferWritable == pdTRUE ) @@ -2219,7 +2300,7 @@ ) { xIsReceiveBufferWritable = xPortIsAuthorizedToAccessBuffer( pvBuffer, - uxQueueGetQueueItemSize( xInternalQueueHandle ), + uxQueueItemSize, tskMPU_WRITE_PERMISSION ); if( xIsReceiveBufferWritable == pdTRUE ) diff --git a/tasks.c b/tasks.c index 48c1960aa7d..e941907cf9c 100644 --- a/tasks.c +++ b/tasks.c @@ -515,15 +515,6 @@ PRIVILEGED_DATA static volatile configRUN_TIME_COUNTER_TYPE ulTotalRunTime[ conf #endif -#if ( configSUPPORT_STATIC_ALLOCATION == 1 ) && ( configNUMBER_OF_CORES > 1 ) - -/* Do not move these variables to function scope as doing so prevents the - * code working with debuggers that need to remove the static qualifier. */ - static StaticTask_t xIdleTCBBuffers[ configNUMBER_OF_CORES - 1 ]; - static StackType_t xIdleTaskStackBuffers[ configNUMBER_OF_CORES - 1 ][ configMINIMAL_STACK_SIZE ]; - -#endif /* #if ( configSUPPORT_STATIC_ALLOCATION == 1 ) && ( configNUMBER_OF_CORES > 1 ) */ - /*lint -restore */ /*-----------------------------------------------------------*/ @@ -583,7 +574,7 @@ 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. * - * In the FreeRTOS SMP, configNUMBER_OF_CORES - 1 minimal idle tasks are also + * In the FreeRTOS SMP, configNUMBER_OF_CORES - 1 passive idle tasks are also * created to ensure that each core has an idle task to run when no other * task is available to run. * @@ -591,12 +582,12 @@ static void prvInitialiseTaskLists( void ) PRIVILEGED_FUNCTION; * language extensions. The equivalent prototype for these functions are: * * void prvIdleTask( void *pvParameters ); - * void prvMinimalIdleTask( void *pvParameters ); + * void prvPassiveIdleTask( void *pvParameters ); * */ static portTASK_FUNCTION_PROTO( prvIdleTask, pvParameters ) PRIVILEGED_FUNCTION; #if ( configNUMBER_OF_CORES > 1 ) - static portTASK_FUNCTION_PROTO( prvMinimalIdleTask, pvParameters ) PRIVILEGED_FUNCTION; + static portTASK_FUNCTION_PROTO( prvPassiveIdleTask, pvParameters ) PRIVILEGED_FUNCTION; #endif /* @@ -715,6 +706,53 @@ static void prvInitialiseNewTask( TaskFunction_t pxTaskCode, */ static void prvAddNewTaskToReadyList( TCB_t * pxNewTCB ) PRIVILEGED_FUNCTION; +/* + * Create a task with static buffer for both TCB and stack. Returns a handle to + * the task if it is created successfully. Otherwise, returns NULL. + */ +#if ( configSUPPORT_STATIC_ALLOCATION == 1 ) + static TCB_t * prvCreateStaticTask( TaskFunction_t pxTaskCode, + const char * const pcName, /*lint !e971 Unqualified char types are allowed for strings and single characters only. */ + const uint32_t ulStackDepth, + void * const pvParameters, + UBaseType_t uxPriority, + StackType_t * const puxStackBuffer, + StaticTask_t * const pxTaskBuffer, + TaskHandle_t * const pxCreatedTask ) PRIVILEGED_FUNCTION; +#endif /* #if ( configSUPPORT_STATIC_ALLOCATION == 1 ) */ + +/* + * Create a restricted task with static buffer for both TCB and stack. Returns + * a handle to the task if it is created successfully. Otherwise, returns NULL. + */ +#if ( ( portUSING_MPU_WRAPPERS == 1 ) && ( configSUPPORT_STATIC_ALLOCATION == 1 ) ) + static TCB_t * prvCreateRestrictedStaticTask( const TaskParameters_t * const pxTaskDefinition, + TaskHandle_t * const pxCreatedTask ) PRIVILEGED_FUNCTION; +#endif /* #if ( ( portUSING_MPU_WRAPPERS == 1 ) && ( configSUPPORT_STATIC_ALLOCATION == 1 ) ) */ + +/* + * Create a restricted task with static buffer for task stack and allocated buffer + * for TCB. Returns a handle to the task if it is created successfully. Otherwise, + * returns NULL. + */ +#if ( ( portUSING_MPU_WRAPPERS == 1 ) && ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) ) + static TCB_t * prvCreateRestrictedTask( const TaskParameters_t * const pxTaskDefinition, + TaskHandle_t * const pxCreatedTask ) PRIVILEGED_FUNCTION; +#endif /* #if ( ( portUSING_MPU_WRAPPERS == 1 ) && ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) ) */ + +/* + * Create a task with allocated buffer for both TCB and stack. Returns a handle to + * the task if it is created successfully. Otherwise, returns NULL. + */ +#if ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) + static TCB_t * prvCreateTask( TaskFunction_t pxTaskCode, + const char * const pcName, /*lint !e971 Unqualified char types are allowed for strings and single characters only. */ + const configSTACK_DEPTH_TYPE usStackDepth, + void * const pvParameters, + UBaseType_t uxPriority, + TaskHandle_t * const pxCreatedTask ) PRIVILEGED_FUNCTION; +#endif /* #if ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) */ + /* * freertos_tasks_c_additions_init() should only be called if the user definable * macro FREERTOS_TASKS_C_ADDITIONS_INIT() is defined, as that is the only macro @@ -726,9 +764,9 @@ static void prvAddNewTaskToReadyList( TCB_t * pxNewTCB ) PRIVILEGED_FUNCTION; #endif -#if ( configUSE_MINIMAL_IDLE_HOOK == 1 ) - extern void vApplicationMinimalIdleHook( void ); -#endif /* #if ( configUSE_MINIMAL_IDLE_HOOK == 1 ) */ +#if ( configUSE_PASSIVE_IDLE_HOOK == 1 ) + extern void vApplicationPassiveIdleHook( void ); +#endif /* #if ( configUSE_PASSIVE_IDLE_HOOK == 1 ) */ #if ( ( configUSE_TRACE_FACILITY == 1 ) && ( configUSE_STATS_FORMATTING_FUNCTIONS > 0 ) ) @@ -1204,32 +1242,16 @@ static void prvAddNewTaskToReadyList( TCB_t * pxNewTCB ) PRIVILEGED_FUNCTION; #if ( configSUPPORT_STATIC_ALLOCATION == 1 ) - TaskHandle_t xTaskCreateStatic( TaskFunction_t pxTaskCode, - const char * const pcName, /*lint !e971 Unqualified char types are allowed for strings and single characters only. */ - const uint32_t ulStackDepth, - void * const pvParameters, - UBaseType_t uxPriority, - StackType_t * const puxStackBuffer, - StaticTask_t * const pxTaskBuffer ) - #if ( ( configNUMBER_OF_CORES > 1 ) && ( configUSE_CORE_AFFINITY == 1 ) ) - { - return xTaskCreateStaticAffinitySet( pxTaskCode, pcName, ulStackDepth, pvParameters, uxPriority, puxStackBuffer, pxTaskBuffer, tskNO_AFFINITY ); - } - - TaskHandle_t xTaskCreateStaticAffinitySet( TaskFunction_t pxTaskCode, - const char * const pcName, /*lint !e971 Unqualified char types are allowed for strings and single characters only. */ - const uint32_t ulStackDepth, - void * const pvParameters, - UBaseType_t uxPriority, - StackType_t * const puxStackBuffer, - StaticTask_t * const pxTaskBuffer, - UBaseType_t uxCoreAffinityMask ) - #endif /* #if ( ( configNUMBER_OF_CORES > 1 ) && ( configUSE_CORE_AFFINITY == 1 ) ) */ + static TCB_t * prvCreateStaticTask( TaskFunction_t pxTaskCode, + const char * const pcName, /*lint !e971 Unqualified char types are allowed for strings and single characters only. */ + const uint32_t ulStackDepth, + void * const pvParameters, + UBaseType_t uxPriority, + StackType_t * const puxStackBuffer, + StaticTask_t * const pxTaskBuffer, + TaskHandle_t * const pxCreatedTask ) { TCB_t * pxNewTCB; - TaskHandle_t xReturn; - - traceENTER_xTaskCreateStatic( pxTaskCode, pcName, ulStackDepth, pvParameters, uxPriority, puxStackBuffer, pxTaskBuffer ); configASSERT( puxStackBuffer != NULL ); configASSERT( pxTaskBuffer != NULL ); @@ -1261,12 +1283,38 @@ static void prvAddNewTaskToReadyList( TCB_t * pxNewTCB ) PRIVILEGED_FUNCTION; } #endif /* tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE */ - prvInitialiseNewTask( pxTaskCode, pcName, ulStackDepth, pvParameters, uxPriority, &xReturn, pxNewTCB, NULL ); + prvInitialiseNewTask( pxTaskCode, pcName, ulStackDepth, pvParameters, uxPriority, pxCreatedTask, pxNewTCB, NULL ); + } + else + { + pxNewTCB = NULL; + } + + return pxNewTCB; + } +/*-----------------------------------------------------------*/ + TaskHandle_t xTaskCreateStatic( TaskFunction_t pxTaskCode, + const char * const pcName, /*lint !e971 Unqualified char types are allowed for strings and single characters only. */ + const uint32_t ulStackDepth, + void * const pvParameters, + UBaseType_t uxPriority, + StackType_t * const puxStackBuffer, + StaticTask_t * const pxTaskBuffer ) + { + TaskHandle_t xReturn = NULL; + TCB_t * pxNewTCB; + + traceENTER_xTaskCreateStatic( pxTaskCode, pcName, ulStackDepth, pvParameters, uxPriority, puxStackBuffer, pxTaskBuffer ); + + pxNewTCB = prvCreateStaticTask( pxTaskCode, pcName, ulStackDepth, pvParameters, uxPriority, puxStackBuffer, pxTaskBuffer, &xReturn ); + + if( pxNewTCB != NULL ) + { #if ( ( configNUMBER_OF_CORES > 1 ) && ( configUSE_CORE_AFFINITY == 1 ) ) { /* Set the task's affinity before scheduling it. */ - pxNewTCB->uxCoreAffinityMask = uxCoreAffinityMask; + pxNewTCB->uxCoreAffinityMask = tskNO_AFFINITY; } #endif @@ -1274,35 +1322,58 @@ static void prvAddNewTaskToReadyList( TCB_t * pxNewTCB ) PRIVILEGED_FUNCTION; } else { - xReturn = NULL; + mtCOVERAGE_TEST_MARKER(); } traceRETURN_xTaskCreateStatic( xReturn ); return xReturn; } - -#endif /* SUPPORT_STATIC_ALLOCATION */ /*-----------------------------------------------------------*/ -#if ( ( portUSING_MPU_WRAPPERS == 1 ) && ( configSUPPORT_STATIC_ALLOCATION == 1 ) ) - - BaseType_t xTaskCreateRestrictedStatic( const TaskParameters_t * const pxTaskDefinition, - TaskHandle_t * pxCreatedTask ) #if ( ( configNUMBER_OF_CORES > 1 ) && ( configUSE_CORE_AFFINITY == 1 ) ) - { - return xTaskCreateRestrictedStaticAffinitySet( pxTaskDefinition, tskNO_AFFINITY, pxCreatedTask ); - } + TaskHandle_t xTaskCreateStaticAffinitySet( TaskFunction_t pxTaskCode, + const char * const pcName, /*lint !e971 Unqualified char types are allowed for strings and single characters only. */ + const uint32_t ulStackDepth, + void * const pvParameters, + UBaseType_t uxPriority, + StackType_t * const puxStackBuffer, + StaticTask_t * const pxTaskBuffer, + UBaseType_t uxCoreAffinityMask ) + { + TaskHandle_t xReturn = NULL; + TCB_t * pxNewTCB; + + traceENTER_xTaskCreateStaticAffinitySet( pxTaskCode, pcName, ulStackDepth, pvParameters, uxPriority, puxStackBuffer, pxTaskBuffer, uxCoreAffinityMask ); + + pxNewTCB = prvCreateStaticTask( pxTaskCode, pcName, ulStackDepth, pvParameters, uxPriority, puxStackBuffer, pxTaskBuffer, &xReturn ); + + if( pxNewTCB != NULL ) + { + /* Set the task's affinity before scheduling it. */ + pxNewTCB->uxCoreAffinityMask = uxCoreAffinityMask; - BaseType_t xTaskCreateRestrictedStaticAffinitySet( const TaskParameters_t * const pxTaskDefinition, - UBaseType_t uxCoreAffinityMask, - TaskHandle_t * pxCreatedTask ) + prvAddNewTaskToReadyList( pxNewTCB ); + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + + traceRETURN_xTaskCreateStaticAffinitySet( xReturn ); + + return xReturn; + } #endif /* #if ( ( configNUMBER_OF_CORES > 1 ) && ( configUSE_CORE_AFFINITY == 1 ) ) */ + +#endif /* SUPPORT_STATIC_ALLOCATION */ +/*-----------------------------------------------------------*/ + +#if ( ( portUSING_MPU_WRAPPERS == 1 ) && ( configSUPPORT_STATIC_ALLOCATION == 1 ) ) + static TCB_t * prvCreateRestrictedStaticTask( const TaskParameters_t * const pxTaskDefinition, + TaskHandle_t * const pxCreatedTask ) { TCB_t * pxNewTCB; - BaseType_t xReturn = errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY; - - traceENTER_xTaskCreateRestrictedStatic( pxTaskDefinition, pxCreatedTask ); configASSERT( pxTaskDefinition->puxStackBuffer != NULL ); configASSERT( pxTaskDefinition->pxTaskBuffer != NULL ); @@ -1333,44 +1404,92 @@ static void prvAddNewTaskToReadyList( TCB_t * pxNewTCB ) PRIVILEGED_FUNCTION; pxTaskDefinition->uxPriority, pxCreatedTask, pxNewTCB, pxTaskDefinition->xRegions ); + } + else + { + pxNewTCB = NULL; + } + + return pxNewTCB; + } +/*-----------------------------------------------------------*/ + + BaseType_t xTaskCreateRestrictedStatic( const TaskParameters_t * const pxTaskDefinition, + TaskHandle_t * pxCreatedTask ) + { + TCB_t * pxNewTCB; + BaseType_t xReturn; + traceENTER_xTaskCreateRestrictedStatic( pxTaskDefinition, pxCreatedTask ); + + configASSERT( pxTaskDefinition != NULL ); + + pxNewTCB = prvCreateRestrictedStaticTask( pxTaskDefinition, pxCreatedTask ); + + if( pxNewTCB != NULL ) + { #if ( ( configNUMBER_OF_CORES > 1 ) && ( configUSE_CORE_AFFINITY == 1 ) ) { /* Set the task's affinity before scheduling it. */ - pxNewTCB->uxCoreAffinityMask = uxCoreAffinityMask; + pxNewTCB->uxCoreAffinityMask = tskNO_AFFINITY; } #endif prvAddNewTaskToReadyList( pxNewTCB ); xReturn = pdPASS; } + else + { + xReturn = errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY; + } traceRETURN_xTaskCreateRestrictedStatic( xReturn ); return xReturn; } - -#endif /* ( portUSING_MPU_WRAPPERS == 1 ) && ( configSUPPORT_STATIC_ALLOCATION == 1 ) */ /*-----------------------------------------------------------*/ -#if ( ( portUSING_MPU_WRAPPERS == 1 ) && ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) ) - - BaseType_t xTaskCreateRestricted( const TaskParameters_t * const pxTaskDefinition, - TaskHandle_t * pxCreatedTask ) #if ( ( configNUMBER_OF_CORES > 1 ) && ( configUSE_CORE_AFFINITY == 1 ) ) - { - return xTaskCreateRestrictedAffinitySet( pxTaskDefinition, tskNO_AFFINITY, pxCreatedTask ); - } + BaseType_t xTaskCreateRestrictedStaticAffinitySet( const TaskParameters_t * const pxTaskDefinition, + UBaseType_t uxCoreAffinityMask, + TaskHandle_t * pxCreatedTask ) + { + TCB_t * pxNewTCB; + BaseType_t xReturn; + + traceENTER_xTaskCreateRestrictedStaticAffinitySet( pxTaskDefinition, uxCoreAffinityMask, pxCreatedTask ); + + configASSERT( pxTaskDefinition != NULL ); + + pxNewTCB = prvCreateRestrictedStaticTask( pxTaskDefinition, pxCreatedTask ); + + if( pxNewTCB != NULL ) + { + /* Set the task's affinity before scheduling it. */ + pxNewTCB->uxCoreAffinityMask = uxCoreAffinityMask; + + prvAddNewTaskToReadyList( pxNewTCB ); + xReturn = pdPASS; + } + else + { + xReturn = errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY; + } + + traceRETURN_xTaskCreateRestrictedStaticAffinitySet( xReturn ); - BaseType_t xTaskCreateRestrictedAffinitySet( const TaskParameters_t * const pxTaskDefinition, - UBaseType_t uxCoreAffinityMask, - TaskHandle_t * pxCreatedTask ) + return xReturn; + } #endif /* #if ( ( configNUMBER_OF_CORES > 1 ) && ( configUSE_CORE_AFFINITY == 1 ) ) */ + +#endif /* ( portUSING_MPU_WRAPPERS == 1 ) && ( configSUPPORT_STATIC_ALLOCATION == 1 ) */ +/*-----------------------------------------------------------*/ + +#if ( ( portUSING_MPU_WRAPPERS == 1 ) && ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) ) + static TCB_t * prvCreateRestrictedTask( const TaskParameters_t * const pxTaskDefinition, + TaskHandle_t * const pxCreatedTask ) { TCB_t * pxNewTCB; - BaseType_t xReturn = errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY; - - traceENTER_xTaskCreateRestricted( pxTaskDefinition, pxCreatedTask ); configASSERT( pxTaskDefinition->puxStackBuffer ); @@ -1401,53 +1520,96 @@ static void prvAddNewTaskToReadyList( TCB_t * pxNewTCB ) PRIVILEGED_FUNCTION; pxTaskDefinition->uxPriority, pxCreatedTask, pxNewTCB, pxTaskDefinition->xRegions ); + } + } + else + { + pxNewTCB = NULL; + } - #if ( ( configNUMBER_OF_CORES > 1 ) && ( configUSE_CORE_AFFINITY == 1 ) ) - { - /* Set the task's affinity before scheduling it. */ - pxNewTCB->uxCoreAffinityMask = uxCoreAffinityMask; - } - #endif + return pxNewTCB; + } +/*-----------------------------------------------------------*/ - prvAddNewTaskToReadyList( pxNewTCB ); - xReturn = pdPASS; + BaseType_t xTaskCreateRestricted( const TaskParameters_t * const pxTaskDefinition, + TaskHandle_t * pxCreatedTask ) + { + TCB_t * pxNewTCB; + BaseType_t xReturn; + + traceENTER_xTaskCreateRestricted( pxTaskDefinition, pxCreatedTask ); + + pxNewTCB = prvCreateRestrictedTask( pxTaskDefinition, pxCreatedTask ); + + if( pxNewTCB != NULL ) + { + #if ( ( configNUMBER_OF_CORES > 1 ) && ( configUSE_CORE_AFFINITY == 1 ) ) + { + /* Set the task's affinity before scheduling it. */ + pxNewTCB->uxCoreAffinityMask = tskNO_AFFINITY; } + #endif /* #if ( ( configNUMBER_OF_CORES > 1 ) && ( configUSE_CORE_AFFINITY == 1 ) ) */ + + prvAddNewTaskToReadyList( pxNewTCB ); + + xReturn = pdPASS; + } + else + { + xReturn = errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY; } traceRETURN_xTaskCreateRestricted( xReturn ); return xReturn; } - -#endif /* portUSING_MPU_WRAPPERS */ /*-----------------------------------------------------------*/ -#if ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) - - BaseType_t xTaskCreate( TaskFunction_t pxTaskCode, - const char * const pcName, /*lint !e971 Unqualified char types are allowed for strings and single characters only. */ - const configSTACK_DEPTH_TYPE usStackDepth, - void * const pvParameters, - UBaseType_t uxPriority, - TaskHandle_t * const pxCreatedTask ) #if ( ( configNUMBER_OF_CORES > 1 ) && ( configUSE_CORE_AFFINITY == 1 ) ) - { - return xTaskCreateAffinitySet( pxTaskCode, pcName, usStackDepth, pvParameters, uxPriority, tskNO_AFFINITY, pxCreatedTask ); - } + BaseType_t xTaskCreateRestrictedAffinitySet( const TaskParameters_t * const pxTaskDefinition, + UBaseType_t uxCoreAffinityMask, + TaskHandle_t * pxCreatedTask ) + { + TCB_t * pxNewTCB; + BaseType_t xReturn; + + traceENTER_xTaskCreateRestrictedAffinitySet( pxTaskDefinition, uxCoreAffinityMask, pxCreatedTask ); - BaseType_t xTaskCreateAffinitySet( TaskFunction_t pxTaskCode, - const char * const pcName, /*lint !e971 Unqualified char types are allowed for strings and single characters only. */ - const configSTACK_DEPTH_TYPE usStackDepth, - void * const pvParameters, - UBaseType_t uxPriority, - UBaseType_t uxCoreAffinityMask, - TaskHandle_t * const pxCreatedTask ) + pxNewTCB = prvCreateRestrictedTask( pxTaskDefinition, pxCreatedTask ); + + if( pxNewTCB != NULL ) + { + /* Set the task's affinity before scheduling it. */ + pxNewTCB->uxCoreAffinityMask = uxCoreAffinityMask; + + prvAddNewTaskToReadyList( pxNewTCB ); + + xReturn = pdPASS; + } + else + { + xReturn = errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY; + } + + traceRETURN_xTaskCreateRestrictedAffinitySet( xReturn ); + + return xReturn; + } #endif /* #if ( ( configNUMBER_OF_CORES > 1 ) && ( configUSE_CORE_AFFINITY == 1 ) ) */ + + +#endif /* portUSING_MPU_WRAPPERS */ +/*-----------------------------------------------------------*/ + +#if ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) + static TCB_t * prvCreateTask( TaskFunction_t pxTaskCode, + const char * const pcName, /*lint !e971 Unqualified char types are allowed for strings and single characters only. */ + const configSTACK_DEPTH_TYPE usStackDepth, + void * const pvParameters, + UBaseType_t uxPriority, + TaskHandle_t * const pxCreatedTask ) { TCB_t * pxNewTCB; - BaseType_t xReturn; - - traceENTER_xTaskCreate( pxTaskCode, pcName, usStackDepth, pvParameters, uxPriority, pxCreatedTask ); /* If the stack grows down then allocate the stack then the TCB so the stack * does not grow into the TCB. Likewise if the stack grows up then allocate @@ -1520,11 +1682,32 @@ static void prvAddNewTaskToReadyList( TCB_t * pxNewTCB ) PRIVILEGED_FUNCTION; #endif /* tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE */ prvInitialiseNewTask( pxTaskCode, pcName, ( uint32_t ) usStackDepth, pvParameters, uxPriority, pxCreatedTask, pxNewTCB, NULL ); + } + + return pxNewTCB; + } +/*-----------------------------------------------------------*/ + BaseType_t xTaskCreate( TaskFunction_t pxTaskCode, + const char * const pcName, /*lint !e971 Unqualified char types are allowed for strings and single characters only. */ + const configSTACK_DEPTH_TYPE usStackDepth, + void * const pvParameters, + UBaseType_t uxPriority, + TaskHandle_t * const pxCreatedTask ) + { + TCB_t * pxNewTCB; + BaseType_t xReturn; + + traceENTER_xTaskCreate( pxTaskCode, pcName, usStackDepth, pvParameters, uxPriority, pxCreatedTask ); + + pxNewTCB = prvCreateTask( pxTaskCode, pcName, usStackDepth, pvParameters, uxPriority, pxCreatedTask ); + + if( pxNewTCB != NULL ) + { #if ( ( configNUMBER_OF_CORES > 1 ) && ( configUSE_CORE_AFFINITY == 1 ) ) { /* Set the task's affinity before scheduling it. */ - pxNewTCB->uxCoreAffinityMask = uxCoreAffinityMask; + pxNewTCB->uxCoreAffinityMask = tskNO_AFFINITY; } #endif @@ -1540,6 +1723,42 @@ static void prvAddNewTaskToReadyList( TCB_t * pxNewTCB ) PRIVILEGED_FUNCTION; return xReturn; } +/*-----------------------------------------------------------*/ + + #if ( ( configNUMBER_OF_CORES > 1 ) && ( configUSE_CORE_AFFINITY == 1 ) ) + BaseType_t xTaskCreateAffinitySet( TaskFunction_t pxTaskCode, + const char * const pcName, /*lint !e971 Unqualified char types are allowed for strings and single characters only. */ + const configSTACK_DEPTH_TYPE usStackDepth, + void * const pvParameters, + UBaseType_t uxPriority, + UBaseType_t uxCoreAffinityMask, + TaskHandle_t * const pxCreatedTask ) + { + TCB_t * pxNewTCB; + BaseType_t xReturn; + + traceENTER_xTaskCreateAffinitySet( pxTaskCode, pcName, usStackDepth, pvParameters, uxPriority, uxCoreAffinityMask, pxCreatedTask ); + + pxNewTCB = prvCreateTask( pxTaskCode, pcName, usStackDepth, pvParameters, uxPriority, pxCreatedTask ); + + if( pxNewTCB != NULL ) + { + /* Set the task's affinity before scheduling it. */ + pxNewTCB->uxCoreAffinityMask = uxCoreAffinityMask; + + prvAddNewTaskToReadyList( pxNewTCB ); + xReturn = pdPASS; + } + else + { + xReturn = errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY; + } + + traceRETURN_xTaskCreateAffinitySet( xReturn ); + + return xReturn; + } + #endif /* #if ( ( configNUMBER_OF_CORES > 1 ) && ( configUSE_CORE_AFFINITY == 1 ) ) */ #endif /* configSUPPORT_DYNAMIC_ALLOCATION */ /*-----------------------------------------------------------*/ @@ -1690,18 +1909,6 @@ static void prvInitialiseNewTask( TaskFunction_t pxTaskCode, } #endif - #if ( ( configNUMBER_OF_CORES > 1 ) && ( configUSE_CORE_AFFINITY == 1 ) ) - { - pxNewTCB->uxCoreAffinityMask = tskNO_AFFINITY; - } - #endif - - #if ( configUSE_TASK_PREEMPTION_DISABLE == 1 ) - { - pxNewTCB->xPreemptionDisable = 0; - } - #endif - /* Initialize the TCB stack to look as if the task was already running, * but had been interrupted by the scheduler. The return address is set * to the start of the task function. Once the stack has been initialised @@ -1760,7 +1967,7 @@ static void prvInitialiseNewTask( TaskFunction_t pxTaskCode, pxNewTCB->xTaskRunState = taskTASK_NOT_RUNNING; /* Is this an idle task? */ - if( ( ( TaskFunction_t ) pxTaskCode == ( TaskFunction_t ) prvIdleTask ) || ( ( TaskFunction_t ) pxTaskCode == ( TaskFunction_t ) prvMinimalIdleTask ) ) + if( ( ( TaskFunction_t ) pxTaskCode == ( TaskFunction_t ) prvIdleTask ) || ( ( TaskFunction_t ) pxTaskCode == ( TaskFunction_t ) prvPassiveIdleTask ) ) { pxNewTCB->uxTaskAttributes |= taskATTRIBUTE_IS_IDLE; } @@ -2462,6 +2669,77 @@ static void prvInitialiseNewTask( TaskFunction_t pxTaskCode, #endif /* INCLUDE_uxTaskPriorityGet */ /*-----------------------------------------------------------*/ +#if ( ( INCLUDE_uxTaskPriorityGet == 1 ) && ( configUSE_MUTEXES == 1 ) ) + + UBaseType_t uxTaskBasePriorityGet( const TaskHandle_t xTask ) + { + TCB_t const * pxTCB; + UBaseType_t uxReturn; + + traceENTER_uxTaskBasePriorityGet( xTask ); + + taskENTER_CRITICAL(); + { + /* If null is passed in here then it is the base priority of the task + * that called uxTaskBasePriorityGet() that is being queried. */ + pxTCB = prvGetTCBFromHandle( xTask ); + uxReturn = pxTCB->uxBasePriority; + } + taskEXIT_CRITICAL(); + + traceRETURN_uxTaskBasePriorityGet( uxReturn ); + + return uxReturn; + } + +#endif /* #if ( ( INCLUDE_uxTaskPriorityGet == 1 ) && ( configUSE_MUTEXES == 1 ) ) */ +/*-----------------------------------------------------------*/ + +#if ( ( INCLUDE_uxTaskPriorityGet == 1 ) && ( configUSE_MUTEXES == 1 ) ) + + UBaseType_t uxTaskBasePriorityGetFromISR( const TaskHandle_t xTask ) + { + TCB_t const * pxTCB; + UBaseType_t uxReturn; + UBaseType_t uxSavedInterruptStatus; + + traceENTER_uxTaskBasePriorityGetFromISR( xTask ); + + /* RTOS ports that support interrupt nesting have the concept of a + * maximum system call (or maximum API call) interrupt priority. + * Interrupts that are above the maximum system call priority are keep + * permanently enabled, even when the RTOS kernel is in a critical section, + * but cannot make any calls to FreeRTOS API functions. If configASSERT() + * is defined in FreeRTOSConfig.h then + * portASSERT_IF_INTERRUPT_PRIORITY_INVALID() will result in an assertion + * failure if a FreeRTOS API function is called from an interrupt that has + * been assigned a priority above the configured maximum system call + * priority. Only FreeRTOS functions that end in FromISR can be called + * from interrupts that have been assigned a priority at or (logically) + * below the maximum system call interrupt priority. FreeRTOS maintains a + * separate interrupt safe API to ensure interrupt entry is as fast and as + * simple as possible. More information (albeit Cortex-M specific) is + * provided on the following link: + * https://www.FreeRTOS.org/RTOS-Cortex-M3-M4.html */ + portASSERT_IF_INTERRUPT_PRIORITY_INVALID(); + + uxSavedInterruptStatus = taskENTER_CRITICAL_FROM_ISR(); + { + /* If null is passed in here then it is the base priority of the calling + * task that is being queried. */ + pxTCB = prvGetTCBFromHandle( xTask ); + uxReturn = pxTCB->uxBasePriority; + } + taskEXIT_CRITICAL_FROM_ISR( uxSavedInterruptStatus ); + + traceRETURN_uxTaskBasePriorityGetFromISR( uxReturn ); + + return uxReturn; + } + +#endif /* #if ( ( INCLUDE_uxTaskPriorityGet == 1 ) && ( configUSE_MUTEXES == 1 ) ) */ +/*-----------------------------------------------------------*/ + #if ( INCLUDE_vTaskPrioritySet == 1 ) void vTaskPrioritySet( TaskHandle_t xTask, @@ -3192,94 +3470,65 @@ static void prvInitialiseNewTask( TaskFunction_t pxTaskCode, static BaseType_t prvCreateIdleTasks( void ) { BaseType_t xReturn = pdPASS; + BaseType_t xCoreID; + char cIdleName[ configMAX_TASK_NAME_LEN ]; + TaskFunction_t pxIdleTaskFunction = NULL; + BaseType_t xIdleTaskNameIndex; - #if ( configNUMBER_OF_CORES == 1 ) + for( xIdleTaskNameIndex = ( BaseType_t ) 0; xIdleTaskNameIndex < ( BaseType_t ) configMAX_TASK_NAME_LEN; xIdleTaskNameIndex++ ) { - /* Add the idle task at the lowest priority. */ - #if ( configSUPPORT_STATIC_ALLOCATION == 1 ) - { - 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 ); - xIdleTaskHandles[ 0 ] = xTaskCreateStatic( prvIdleTask, - configIDLE_TASK_NAME, - 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. */ + cIdleName[ xIdleTaskNameIndex ] = configIDLE_TASK_NAME[ xIdleTaskNameIndex ]; - if( xIdleTaskHandles[ 0 ] != NULL ) - { - xReturn = pdPASS; - } - else - { - xReturn = pdFAIL; - } + /* Don't copy all configMAX_TASK_NAME_LEN if the string is shorter than + * configMAX_TASK_NAME_LEN characters just in case the memory after the + * string is not accessible (extremely unlikely). */ + if( cIdleName[ xIdleTaskNameIndex ] == ( char ) 0x00 ) + { + break; } - #else /* if ( configSUPPORT_STATIC_ALLOCATION == 1 ) */ + else { - /* The Idle task is being created using dynamically allocated RAM. */ - xReturn = xTaskCreate( prvIdleTask, - configIDLE_TASK_NAME, - configMINIMAL_STACK_SIZE, - ( void * ) NULL, - portPRIVILEGE_BIT, /* In effect ( tskIDLE_PRIORITY | portPRIVILEGE_BIT ), but tskIDLE_PRIORITY is zero. */ - &xIdleTaskHandles[ 0 ] ); /*lint !e961 MISRA exception, justified as it is not a redundant explicit cast to all supported compilers. */ + mtCOVERAGE_TEST_MARKER(); } - #endif /* configSUPPORT_STATIC_ALLOCATION */ } - #else /* #if ( configNUMBER_OF_CORES == 1 ) */ - { - BaseType_t xCoreID; - char cIdleName[ configMAX_TASK_NAME_LEN ]; - /* Add each idle task at the lowest priority. */ - for( xCoreID = ( BaseType_t ) 0; xCoreID < ( BaseType_t ) configNUMBER_OF_CORES; xCoreID++ ) + /* Add each idle task at the lowest priority. */ + for( xCoreID = ( BaseType_t ) 0; xCoreID < ( BaseType_t ) configNUMBER_OF_CORES; xCoreID++ ) + { + #if ( configNUMBER_OF_CORES == 1 ) { - BaseType_t x; - - if( xReturn == pdFAIL ) + pxIdleTaskFunction = prvIdleTask; + } + #else /* #if ( configNUMBER_OF_CORES == 1 ) */ + { + /* In the FreeRTOS SMP, configNUMBER_OF_CORES - 1 passive idle tasks + * are also created to ensure that each core has an idle task to + * run when no other task is available to run. */ + if( xCoreID == 0 ) { - break; + pxIdleTaskFunction = prvIdleTask; } else { - mtCOVERAGE_TEST_MARKER(); - } - - for( x = ( BaseType_t ) 0; x < ( BaseType_t ) configMAX_TASK_NAME_LEN; x++ ) - { - cIdleName[ x ] = configIDLE_TASK_NAME[ x ]; - - /* Don't copy all configMAX_TASK_NAME_LEN if the string is shorter than - * configMAX_TASK_NAME_LEN characters just in case the memory after the - * string is not accessible (extremely unlikely). */ - if( cIdleName[ x ] == ( char ) 0x00 ) - { - break; - } - else - { - mtCOVERAGE_TEST_MARKER(); - } + pxIdleTaskFunction = prvPassiveIdleTask; } + } + #endif /* #if ( configNUMBER_OF_CORES == 1 ) */ + /* Update the idle task name with suffix to differentiate the idle tasks. + * This function is not required in single core FreeRTOS since there is + * only one idle task. */ + #if ( configNUMBER_OF_CORES > 1 ) + { /* Append the idle task number to the end of the name if there is space. */ - if( x < ( BaseType_t ) configMAX_TASK_NAME_LEN ) + if( xIdleTaskNameIndex < ( BaseType_t ) configMAX_TASK_NAME_LEN ) { - cIdleName[ x ] = ( char ) ( xCoreID + '0' ); - x++; + cIdleName[ xIdleTaskNameIndex ] = ( char ) ( xCoreID + '0' ); /* And append a null character if there is space. */ - if( x < ( BaseType_t ) configMAX_TASK_NAME_LEN ) + if( ( xIdleTaskNameIndex + 1 ) < ( BaseType_t ) configMAX_TASK_NAME_LEN ) { - cIdleName[ x ] = '\0'; + cIdleName[ xIdleTaskNameIndex + 1 ] = '\0'; } else { @@ -3290,72 +3539,61 @@ static BaseType_t prvCreateIdleTasks( void ) { mtCOVERAGE_TEST_MARKER(); } + } + #endif /* if ( configNUMBER_OF_CORES > 1 ) */ - #if ( configSUPPORT_STATIC_ALLOCATION == 1 ) - { - if( xCoreID == 0 ) - { - StaticTask_t * pxIdleTaskTCBBuffer = NULL; - StackType_t * pxIdleTaskStackBuffer = NULL; - uint32_t ulIdleTaskStackSize; + #if ( configSUPPORT_STATIC_ALLOCATION == 1 ) + { + 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 ); - xIdleTaskHandles[ 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. */ - } - else - { - xIdleTaskHandles[ 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. */ - xIdleTaskStackBuffers[ xCoreID - 1 ], - &xIdleTCBBuffers[ xCoreID - 1 ] ); /*lint !e961 MISRA exception, justified as it is not a redundant explicit cast to all supported compilers. */ - } + /* The Idle task is created using user provided RAM - obtain the + * address of the RAM then create the idle task. */ + #if ( configNUMBER_OF_CORES == 1 ) + vApplicationGetIdleTaskMemory( &pxIdleTaskTCBBuffer, &pxIdleTaskStackBuffer, &ulIdleTaskStackSize ); + #else + vApplicationGetIdleTaskMemory( &pxIdleTaskTCBBuffer, &pxIdleTaskStackBuffer, &ulIdleTaskStackSize, xCoreID ); + #endif + xIdleTaskHandles[ xCoreID ] = xTaskCreateStatic( pxIdleTaskFunction, + 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( xIdleTaskHandles[ xCoreID ] != NULL ) - { - xReturn = pdPASS; - } - else - { - xReturn = pdFAIL; - } + if( xIdleTaskHandles[ xCoreID ] != NULL ) + { + xReturn = pdPASS; } - #else /* if ( configSUPPORT_STATIC_ALLOCATION == 1 ) */ + else { - if( xCoreID == 0 ) - { - /* The Idle task is being created using dynamically allocated RAM. */ - xReturn = xTaskCreate( prvIdleTask, - cIdleName, - configMINIMAL_STACK_SIZE, - ( void * ) NULL, - portPRIVILEGE_BIT, /* In effect ( tskIDLE_PRIORITY | portPRIVILEGE_BIT ), but tskIDLE_PRIORITY is zero. */ - &xIdleTaskHandles[ xCoreID ] ); /*lint !e961 MISRA exception, justified as it is not a redundant explicit cast to all supported compilers. */ - } - else - { - xReturn = xTaskCreate( prvMinimalIdleTask, - cIdleName, - configMINIMAL_STACK_SIZE, - ( void * ) NULL, - portPRIVILEGE_BIT, /* In effect ( tskIDLE_PRIORITY | portPRIVILEGE_BIT ), but tskIDLE_PRIORITY is zero. */ - &xIdleTaskHandles[ xCoreID ] ); /*lint !e961 MISRA exception, justified as it is not a redundant explicit cast to all supported compilers. */ - } + xReturn = pdFAIL; } - #endif /* configSUPPORT_STATIC_ALLOCATION */ + } + #else /* if ( configSUPPORT_STATIC_ALLOCATION == 1 ) */ + { + /* The Idle task is being created using dynamically allocated RAM. */ + xReturn = xTaskCreate( pxIdleTaskFunction, + cIdleName, + configMINIMAL_STACK_SIZE, + ( void * ) NULL, + portPRIVILEGE_BIT, /* In effect ( tskIDLE_PRIORITY | portPRIVILEGE_BIT ), but tskIDLE_PRIORITY is zero. */ + &xIdleTaskHandles[ xCoreID ] ); /*lint !e961 MISRA exception, justified as it is not a redundant explicit cast to all supported compilers. */ + } + #endif /* configSUPPORT_STATIC_ALLOCATION */ + + /* Break the loop if any of the idle task is failed to be created. */ + if( xReturn == pdFAIL ) + { + break; + } + else + { + mtCOVERAGE_TEST_MARKER(); } } - #endif /* #if ( configNUMBER_OF_CORES == 1 ) */ return xReturn; } @@ -4192,20 +4430,40 @@ char * pcTaskGetName( TaskHandle_t xTaskToQuery ) /*lint !e971 Unqualified char #if ( INCLUDE_xTaskGetIdleTaskHandle == 1 ) -/* SMP_TODO : This function returns only idle task handle for core 0. - * Consider to add another function to return the idle task handles. */ - TaskHandle_t xTaskGetIdleTaskHandle( void ) - { - traceENTER_xTaskGetIdleTaskHandle(); + #if ( configNUMBER_OF_CORES == 1 ) + + TaskHandle_t xTaskGetIdleTaskHandle( void ) + { + traceENTER_xTaskGetIdleTaskHandle(); - /* If xTaskGetIdleTaskHandle() is called before the scheduler has been - * started, then xIdleTaskHandles will be NULL. */ - configASSERT( ( xIdleTaskHandles[ 0 ] != NULL ) ); + /* If xTaskGetIdleTaskHandle() is called before the scheduler has been + * started, then xIdleTaskHandles will be NULL. */ + configASSERT( ( xIdleTaskHandles[ 0 ] != NULL ) ); - traceRETURN_xTaskGetIdleTaskHandle( xIdleTaskHandles[ 0 ] ); + traceRETURN_xTaskGetIdleTaskHandle( xIdleTaskHandles[ 0 ] ); - return xIdleTaskHandles[ 0 ]; - } + return xIdleTaskHandles[ 0 ]; + } + + #else /* if ( configNUMBER_OF_CORES == 1 ) */ + + TaskHandle_t xTaskGetIdleTaskHandle( BaseType_t xCoreID ) + { + traceENTER_xTaskGetIdleTaskHandle( xCoreID ); + + /* Ensure the core ID is valid. */ + configASSERT( taskVALID_CORE_ID( xCoreID ) == pdTRUE ); + + /* If xTaskGetIdleTaskHandle() is called before the scheduler has been + * started, then xIdleTaskHandles will be NULL. */ + configASSERT( ( xIdleTaskHandles[ xCoreID ] != NULL ) ); + + traceRETURN_xTaskGetIdleTaskHandle( xIdleTaskHandles[ xCoreID ] ); + + return xIdleTaskHandles[ xCoreID ]; + } + + #endif /* if ( configNUMBER_OF_CORES == 1 ) */ #endif /* INCLUDE_xTaskGetIdleTaskHandle */ /*----------------------------------------------------------*/ @@ -4940,7 +5198,7 @@ void vTaskPlaceOnEventList( List_t * const pxEventList, configASSERT( pxEventList ); - /* THIS FUNCTION MUST BE CALLED WITH EITHER INTERRUPTS DISABLED OR THE + /* THIS FUNCTION MUST BE CALLED WITH THE * SCHEDULER SUSPENDED AND THE QUEUE BEING ACCESSED LOCKED. */ /* Place the event list item of the TCB in the appropriate event list. @@ -5348,21 +5606,21 @@ void vTaskMissedYield( void ) /* * ----------------------------------------------------------- - * The MinimalIdle task. + * The passive idle task. * ---------------------------------------------------------- * - * 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. + * The passive idle task is used for all the additional cores in a SMP + * system. There must be only 1 active idle task and the rest are passive + * idle tasks. * * The portTASK_FUNCTION() macro is used to allow port/compiler specific * language extensions. The equivalent prototype for this function is: * - * void prvMinimalIdleTask( void *pvParameters ); + * void prvPassiveIdleTask( void *pvParameters ); */ #if ( configNUMBER_OF_CORES > 1 ) - static portTASK_FUNCTION( prvMinimalIdleTask, pvParameters ) + static portTASK_FUNCTION( prvPassiveIdleTask, pvParameters ) { ( void ) pvParameters; @@ -5403,7 +5661,7 @@ void vTaskMissedYield( void ) } #endif /* ( ( configUSE_PREEMPTION == 1 ) && ( configIDLE_SHOULD_YIELD == 1 ) ) */ - #if ( configUSE_MINIMAL_IDLE_HOOK == 1 ) + #if ( configUSE_PASSIVE_IDLE_HOOK == 1 ) { /* Call the user defined function from within the idle task. This * allows the application designer to add background functionality @@ -5411,18 +5669,18 @@ void vTaskMissedYield( void ) * * This hook is intended to manage core activity such as disabling cores that go idle. * - * NOTE: vApplicationMinimalIdleHook() MUST NOT, UNDER ANY CIRCUMSTANCES, + * NOTE: vApplicationPassiveIdleHook() MUST NOT, UNDER ANY CIRCUMSTANCES, * CALL A FUNCTION THAT MIGHT BLOCK. */ - vApplicationMinimalIdleHook(); + vApplicationPassiveIdleHook(); } - #endif /* configUSE_MINIMAL_IDLE_HOOK */ + #endif /* configUSE_PASSIVE_IDLE_HOOK */ } } #endif /* #if ( configNUMBER_OF_CORES > 1 ) */ /* * ----------------------------------------------------------- - * The Idle task. + * The idle task. * ---------------------------------------------------------- * * The portTASK_FUNCTION() macro is used to allow port/compiler specific @@ -5549,7 +5807,7 @@ static portTASK_FUNCTION( prvIdleTask, pvParameters ) } #endif /* configUSE_TICKLESS_IDLE */ - #if ( ( configNUMBER_OF_CORES > 1 ) && ( configUSE_MINIMAL_IDLE_HOOK == 1 ) ) + #if ( ( configNUMBER_OF_CORES > 1 ) && ( configUSE_PASSIVE_IDLE_HOOK == 1 ) ) { /* Call the user defined function from within the idle task. This * allows the application designer to add background functionality @@ -5557,11 +5815,11 @@ static portTASK_FUNCTION( prvIdleTask, pvParameters ) * * This hook is intended to manage core activity such as disabling cores that go idle. * - * NOTE: vApplicationMinimalIdleHook() MUST NOT, UNDER ANY CIRCUMSTANCES, + * NOTE: vApplicationPassiveIdleHook() MUST NOT, UNDER ANY CIRCUMSTANCES, * CALL A FUNCTION THAT MIGHT BLOCK. */ - vApplicationMinimalIdleHook(); + vApplicationPassiveIdleHook(); } - #endif /* #if ( ( configNUMBER_OF_CORES > 1 ) && ( configUSE_MINIMAL_IDLE_HOOK == 1 ) ) */ + #endif /* #if ( ( configNUMBER_OF_CORES > 1 ) && ( configUSE_PASSIVE_IDLE_HOOK == 1 ) ) */ } } /*-----------------------------------------------------------*/ @@ -7222,28 +7480,68 @@ TickType_t uxTaskResetEventItemValue( void ) TickType_t xTicksToWait ) { uint32_t ulReturn; + BaseType_t xAlreadyYielded; traceENTER_ulTaskGenericNotifyTake( uxIndexToWaitOn, xClearCountOnExit, xTicksToWait ); configASSERT( uxIndexToWaitOn < configTASK_NOTIFICATION_ARRAY_ENTRIES ); taskENTER_CRITICAL(); + + /* Only block if the notification count is not already non-zero. */ + if( pxCurrentTCB->ulNotifiedValue[ uxIndexToWaitOn ] == 0UL ) { - /* Only block if the notification count is not already non-zero. */ - if( pxCurrentTCB->ulNotifiedValue[ uxIndexToWaitOn ] == 0UL ) + /* Mark this task as waiting for a notification. */ + pxCurrentTCB->ucNotifyState[ uxIndexToWaitOn ] = taskWAITING_NOTIFICATION; + + if( xTicksToWait > ( TickType_t ) 0 ) { - /* Mark this task as waiting for a notification. */ - pxCurrentTCB->ucNotifyState[ uxIndexToWaitOn ] = taskWAITING_NOTIFICATION; + traceTASK_NOTIFY_TAKE_BLOCK( uxIndexToWaitOn ); - if( xTicksToWait > ( TickType_t ) 0 ) + /* We MUST suspend the scheduler before exiting the critical + * section (i.e. before enabling interrupts). + * + * If we do not do so, a notification sent from an ISR, which + * happens after exiting the critical section and before + * suspending the scheduler, will get lost. The sequence of + * events will be: + * 1. Exit critical section. + * 2. Interrupt - ISR calls xTaskNotifyFromISR which adds the + * task to the Ready list. + * 3. Suspend scheduler. + * 4. prvAddCurrentTaskToDelayedList moves the task to the + * delayed or suspended list. + * 5. Resume scheduler does not touch the task (because it is + * not on the pendingReady list), effectively losing the + * notification from the ISR. + * + * The same does not happen when we suspend the scheduler before + * exiting the critical section. The sequence of events in this + * case will be: + * 1. Suspend scheduler. + * 2. Exit critical section. + * 3. Interrupt - ISR calls xTaskNotifyFromISR which adds the + * task to the pendingReady list as the scheduler is + * suspended. + * 4. prvAddCurrentTaskToDelayedList adds the task to delayed or + * suspended list. Note that this operation does not nullify + * the add to pendingReady list done in the above step because + * a different list item, namely xEventListItem, is used for + * adding the task to the pendingReady list. In other words, + * the task still remains on the pendingReady list. + * 5. Resume scheduler moves the task from pendingReady list to + * the Ready list. + */ + vTaskSuspendAll(); { + taskEXIT_CRITICAL(); + prvAddCurrentTaskToDelayedList( xTicksToWait, pdTRUE ); - traceTASK_NOTIFY_TAKE_BLOCK( uxIndexToWaitOn ); + } + xAlreadyYielded = xTaskResumeAll(); - /* All ports are written to allow a yield in a critical - * section (some will yield immediately, others wait until the - * critical section exits) - but it is not something that - * application code should ever do. */ + if( xAlreadyYielded == pdFALSE ) + { taskYIELD_WITHIN_API(); } else @@ -7253,10 +7551,13 @@ TickType_t uxTaskResetEventItemValue( void ) } else { - mtCOVERAGE_TEST_MARKER(); + taskEXIT_CRITICAL(); } } - taskEXIT_CRITICAL(); + else + { + taskEXIT_CRITICAL(); + } taskENTER_CRITICAL(); { @@ -7299,34 +7600,73 @@ TickType_t uxTaskResetEventItemValue( void ) uint32_t * pulNotificationValue, TickType_t xTicksToWait ) { - BaseType_t xReturn; + BaseType_t xReturn, xAlreadyYielded; traceENTER_xTaskGenericNotifyWait( uxIndexToWaitOn, ulBitsToClearOnEntry, ulBitsToClearOnExit, pulNotificationValue, xTicksToWait ); configASSERT( uxIndexToWaitOn < configTASK_NOTIFICATION_ARRAY_ENTRIES ); taskENTER_CRITICAL(); + + /* Only block if a notification is not already pending. */ + if( pxCurrentTCB->ucNotifyState[ uxIndexToWaitOn ] != taskNOTIFICATION_RECEIVED ) { - /* Only block if a notification is not already pending. */ - if( pxCurrentTCB->ucNotifyState[ uxIndexToWaitOn ] != taskNOTIFICATION_RECEIVED ) - { - /* Clear bits in the task's notification value as bits may get - * set by the notifying task or interrupt. This can be used to - * clear the value to zero. */ - pxCurrentTCB->ulNotifiedValue[ uxIndexToWaitOn ] &= ~ulBitsToClearOnEntry; + /* Clear bits in the task's notification value as bits may get + * set by the notifying task or interrupt. This can be used to + * clear the value to zero. */ + pxCurrentTCB->ulNotifiedValue[ uxIndexToWaitOn ] &= ~ulBitsToClearOnEntry; - /* Mark this task as waiting for a notification. */ - pxCurrentTCB->ucNotifyState[ uxIndexToWaitOn ] = taskWAITING_NOTIFICATION; + /* Mark this task as waiting for a notification. */ + pxCurrentTCB->ucNotifyState[ uxIndexToWaitOn ] = taskWAITING_NOTIFICATION; + + if( xTicksToWait > ( TickType_t ) 0 ) + { + traceTASK_NOTIFY_WAIT_BLOCK( uxIndexToWaitOn ); - if( xTicksToWait > ( TickType_t ) 0 ) + /* We MUST suspend the scheduler before exiting the critical + * section (i.e. before enabling interrupts). + * + * If we do not do so, a notification sent from an ISR, which + * happens after exiting the critical section and before + * suspending the scheduler, will get lost. The sequence of + * events will be: + * 1. Exit critical section. + * 2. Interrupt - ISR calls xTaskNotifyFromISR which adds the + * task to the Ready list. + * 3. Suspend scheduler. + * 4. prvAddCurrentTaskToDelayedList moves the task to the + * delayed or suspended list. + * 5. Resume scheduler does not touch the task (because it is + * not on the pendingReady list), effectively losing the + * notification from the ISR. + * + * The same does not happen when we suspend the scheduler before + * exiting the critical section. The sequence of events in this + * case will be: + * 1. Suspend scheduler. + * 2. Exit critical section. + * 3. Interrupt - ISR calls xTaskNotifyFromISR which adds the + * task to the pendingReady list as the scheduler is + * suspended. + * 4. prvAddCurrentTaskToDelayedList adds the task to delayed or + * suspended list. Note that this operation does not nullify + * the add to pendingReady list done in the above step because + * a different list item, namely xEventListItem, is used for + * adding the task to the pendingReady list. In other words, + * the task still remains on the pendingReady list. + * 5. Resume scheduler moves the task from pendingReady list to + * the Ready list. + */ + vTaskSuspendAll(); { + taskEXIT_CRITICAL(); + prvAddCurrentTaskToDelayedList( xTicksToWait, pdTRUE ); - traceTASK_NOTIFY_WAIT_BLOCK( uxIndexToWaitOn ); + } + xAlreadyYielded = xTaskResumeAll(); - /* All ports are written to allow a yield in a critical - * section (some will yield immediately, others wait until the - * critical section exits) - but it is not something that - * application code should ever do. */ + if( xAlreadyYielded == pdFALSE ) + { taskYIELD_WITHIN_API(); } else @@ -7336,10 +7676,13 @@ TickType_t uxTaskResetEventItemValue( void ) } else { - mtCOVERAGE_TEST_MARKER(); + taskEXIT_CRITICAL(); } } - taskEXIT_CRITICAL(); + else + { + taskEXIT_CRITICAL(); + } taskENTER_CRITICAL(); { @@ -8127,17 +8470,36 @@ static void prvAddCurrentTaskToDelayedList( TickType_t xTicksToWait, * it's own implementation of vApplicationGetIdleTaskMemory by setting * configKERNEL_PROVIDED_STATIC_MEMORY to 0 or leaving it undefined. */ - void vApplicationGetIdleTaskMemory( StaticTask_t ** ppxIdleTaskTCBBuffer, - StackType_t ** ppxIdleTaskStackBuffer, - uint32_t * pulIdleTaskStackSize ) - { - static StaticTask_t xIdleTaskTCB; - static StackType_t uxIdleTaskStack[ configMINIMAL_STACK_SIZE ]; + #if ( configNUMBER_OF_CORES == 1 ) - *ppxIdleTaskTCBBuffer = &( xIdleTaskTCB ); - *ppxIdleTaskStackBuffer = &( uxIdleTaskStack[ 0 ] ); - *pulIdleTaskStackSize = configMINIMAL_STACK_SIZE; - } + void vApplicationGetIdleTaskMemory( StaticTask_t ** ppxIdleTaskTCBBuffer, + StackType_t ** ppxIdleTaskStackBuffer, + uint32_t * pulIdleTaskStackSize ) + { + static StaticTask_t xIdleTaskTCB; + static StackType_t uxIdleTaskStack[ configMINIMAL_STACK_SIZE ]; + + *ppxIdleTaskTCBBuffer = &( xIdleTaskTCB ); + *ppxIdleTaskStackBuffer = &( uxIdleTaskStack[ 0 ] ); + *pulIdleTaskStackSize = configMINIMAL_STACK_SIZE; + } + + #else /* #if ( configNUMBER_OF_CORES == 1 ) */ + + void vApplicationGetIdleTaskMemory( StaticTask_t ** ppxIdleTaskTCBBuffer, + StackType_t ** ppxIdleTaskStackBuffer, + uint32_t * pulIdleTaskStackSize, + BaseType_t xCoreId ) + { + static StaticTask_t xIdleTaskTCBs[ configNUMBER_OF_CORES ]; + static StackType_t uxIdleTaskStacks[ configNUMBER_OF_CORES ][ configMINIMAL_STACK_SIZE ]; + + *ppxIdleTaskTCBBuffer = &( xIdleTaskTCBs[ xCoreId ] ); + *ppxIdleTaskStackBuffer = &( uxIdleTaskStacks[ xCoreId ][ 0 ] ); + *pulIdleTaskStackSize = configMINIMAL_STACK_SIZE; + } + + #endif /* #if ( configNUMBER_OF_CORES == 1 ) */ #endif /* #if ( ( configSUPPORT_STATIC_ALLOCATION == 1 ) && ( configKERNEL_PROVIDED_STATIC_MEMORY == 1 ) && ( portUSING_MPU_WRAPPERS == 0 ) ) */ /*-----------------------------------------------------------*/ diff --git a/timers.c b/timers.c index e2f3f98091f..bff14ea7ecb 100644 --- a/timers.c +++ b/timers.c @@ -60,12 +60,21 @@ #define tmrNO_DELAY ( ( TickType_t ) 0U ) #define tmrMAX_TIME_BEFORE_OVERFLOW ( ( TickType_t ) -1 ) -/* The name assigned to the timer service task. This can be overridden by - * defining trmTIMER_SERVICE_TASK_NAME in FreeRTOSConfig.h. */ +/* The name assigned to the timer service task. This can be overridden by + * defining configTIMER_SERVICE_TASK_NAME in FreeRTOSConfig.h. */ #ifndef configTIMER_SERVICE_TASK_NAME #define configTIMER_SERVICE_TASK_NAME "Tmr Svc" #endif + #if ( ( configNUMBER_OF_CORES > 1 ) && ( configUSE_CORE_AFFINITY == 1 ) ) + +/* The core affinity assigned to the timer service task on SMP systems. + * This can be overridden by defining configTIMER_SERVICE_TASK_CORE_AFFINITY in FreeRTOSConfig.h. */ + #ifndef configTIMER_SERVICE_TASK_CORE_AFFINITY + #define configTIMER_SERVICE_TASK_CORE_AFFINITY tskNO_AFFINITY + #endif + #endif /* #if ( ( configNUMBER_OF_CORES > 1 ) && ( configUSE_CORE_AFFINITY == 1 ) ) */ + /* Bit definitions used in the ucStatus member of a timer structure. */ #define tmrSTATUS_IS_ACTIVE ( 0x01U ) #define tmrSTATUS_IS_STATICALLY_ALLOCATED ( 0x02U ) @@ -245,36 +254,75 @@ if( xTimerQueue != NULL ) { - #if ( configSUPPORT_STATIC_ALLOCATION == 1 ) + #if ( ( configNUMBER_OF_CORES > 1 ) && ( configUSE_CORE_AFFINITY == 1 ) ) { - StaticTask_t * pxTimerTaskTCBBuffer = NULL; - StackType_t * pxTimerTaskStackBuffer = NULL; - uint32_t ulTimerTaskStackSize; - - vApplicationGetTimerTaskMemory( &pxTimerTaskTCBBuffer, &pxTimerTaskStackBuffer, &ulTimerTaskStackSize ); - xTimerTaskHandle = xTaskCreateStatic( prvTimerTask, + #if ( configSUPPORT_STATIC_ALLOCATION == 1 ) + { + StaticTask_t * pxTimerTaskTCBBuffer = NULL; + StackType_t * pxTimerTaskStackBuffer = NULL; + uint32_t ulTimerTaskStackSize; + + vApplicationGetTimerTaskMemory( &pxTimerTaskTCBBuffer, &pxTimerTaskStackBuffer, &ulTimerTaskStackSize ); + xTimerTaskHandle = xTaskCreateStaticAffinitySet( prvTimerTask, + configTIMER_SERVICE_TASK_NAME, + ulTimerTaskStackSize, + NULL, + ( ( UBaseType_t ) configTIMER_TASK_PRIORITY ) | portPRIVILEGE_BIT, + pxTimerTaskStackBuffer, + pxTimerTaskTCBBuffer, + configTIMER_SERVICE_TASK_CORE_AFFINITY ); + + if( xTimerTaskHandle != NULL ) + { + xReturn = pdPASS; + } + } + #else /* if ( configSUPPORT_STATIC_ALLOCATION == 1 ) */ + { + xReturn = xTaskCreateAffinitySet( prvTimerTask, configTIMER_SERVICE_TASK_NAME, - ulTimerTaskStackSize, + configTIMER_TASK_STACK_DEPTH, NULL, ( ( UBaseType_t ) configTIMER_TASK_PRIORITY ) | portPRIVILEGE_BIT, - pxTimerTaskStackBuffer, - pxTimerTaskTCBBuffer ); - - if( xTimerTaskHandle != NULL ) - { - xReturn = pdPASS; + configTIMER_SERVICE_TASK_CORE_AFFINITY, + &xTimerTaskHandle ); } + #endif /* configSUPPORT_STATIC_ALLOCATION */ } - #else /* if ( configSUPPORT_STATIC_ALLOCATION == 1 ) */ + #else /* #if ( ( configNUMBER_OF_CORES > 1 ) && ( configUSE_CORE_AFFINITY == 1 ) ) */ { - xReturn = xTaskCreate( prvTimerTask, - configTIMER_SERVICE_TASK_NAME, - configTIMER_TASK_STACK_DEPTH, - NULL, - ( ( UBaseType_t ) configTIMER_TASK_PRIORITY ) | portPRIVILEGE_BIT, - &xTimerTaskHandle ); + #if ( configSUPPORT_STATIC_ALLOCATION == 1 ) + { + StaticTask_t * pxTimerTaskTCBBuffer = NULL; + StackType_t * pxTimerTaskStackBuffer = NULL; + uint32_t ulTimerTaskStackSize; + + vApplicationGetTimerTaskMemory( &pxTimerTaskTCBBuffer, &pxTimerTaskStackBuffer, &ulTimerTaskStackSize ); + xTimerTaskHandle = xTaskCreateStatic( prvTimerTask, + configTIMER_SERVICE_TASK_NAME, + ulTimerTaskStackSize, + NULL, + ( ( UBaseType_t ) configTIMER_TASK_PRIORITY ) | portPRIVILEGE_BIT, + pxTimerTaskStackBuffer, + pxTimerTaskTCBBuffer ); + + if( xTimerTaskHandle != NULL ) + { + xReturn = pdPASS; + } + } + #else /* if ( configSUPPORT_STATIC_ALLOCATION == 1 ) */ + { + xReturn = xTaskCreate( prvTimerTask, + configTIMER_SERVICE_TASK_NAME, + configTIMER_TASK_STACK_DEPTH, + NULL, + ( ( UBaseType_t ) configTIMER_TASK_PRIORITY ) | portPRIVILEGE_BIT, + &xTimerTaskHandle ); + } + #endif /* configSUPPORT_STATIC_ALLOCATION */ } - #endif /* configSUPPORT_STATIC_ALLOCATION */ + #endif /* #if ( ( configNUMBER_OF_CORES > 1 ) && ( configUSE_CORE_AFFINITY == 1 ) ) */ } else {