From 1b2b0904cebfde89ac70446d4c16ac2d14a4d0b6 Mon Sep 17 00:00:00 2001 From: Joseph Julicher Date: Sat, 14 Oct 2023 08:00:25 -0700 Subject: [PATCH 1/4] Added the minimal example (#823) * re-adding main.c to the minimal example * Uncrustify: triggered by comment. * Update minimal_freertos_example/main.c Co-authored-by: Soren Ptak * Add in the deleted cmake list * Added a single newline at the end of the cmake * Cleanup the CMakelists * updates the main & Cmake * Formatting --------- Co-authored-by: GitHub Action Co-authored-by: Soren Ptak --- cmake_example/CMakeLists.txt | 28 ++++++++++ cmake_example/main.c | 105 +++++++++++++++++++++++++++++++++++ 2 files changed, 133 insertions(+) create mode 100644 cmake_example/CMakeLists.txt create mode 100644 cmake_example/main.c 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..f0eaf1cf1ba --- /dev/null +++ b/cmake_example/main.c @@ -0,0 +1,105 @@ +/* + * 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 ) +{ + for( ; ; ) + { + /* Example Task Code */ + vTaskDelay( 100 ); /* delay 100 ticks */ + } +} + +int main( void ) +{ + printf( "Example FreeRTOS Project\n" ); + + xTaskCreateStatic( exampleTask, + "example", + configMINIMAL_STACK_SIZE, + NULL, + configMAX_PRIORITIES - 1, + exampleTaskStack, + &exampleTaskTCB ); + + vTaskStartScheduler(); + + /* should never get here. */ + for( ; ; ) + { + } + + return 0; +} + +void vApplicationStackOverflowHook( TaskHandle_t xTask, + char * 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; +} From 631ae9e6e4828cf5c7d58bb7ac78a64fc309bcb7 Mon Sep 17 00:00:00 2001 From: Sudeep Mohanty <91244425+sudeep-mohanty@users.noreply.github.com> Date: Mon, 16 Oct 2023 09:08:55 +0200 Subject: [PATCH 2/4] Add option to set the core affinity for the Timer Svc Task on SMP systems (#805) This PR introduces the configTIMER_SERVICE_TASK_CORE_AFFINITY option which allows the system to configure the core affinity of the Timer Service Task on an SMP system. The default affinity of the Timer Service Task is set to tskNO_AFFINITY which is the current behavior on SMP systems. Signed-off-by: Sudeep Mohanty Co-authored-by: Gaurav-Aggarwal-AWS <33462878+aggarg@users.noreply.github.com> --- timers.c | 96 ++++++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 72 insertions(+), 24 deletions(-) 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 { From 7ffc6a74655ec8a53fdc28fa1cccc74c1c747ecd Mon Sep 17 00:00:00 2001 From: chinglee-iot <61685396+chinglee-iot@users.noreply.github.com> Date: Tue, 17 Oct 2023 12:19:17 +0800 Subject: [PATCH 3/4] Add base priority get APIs (#818) * Add base priority get APIs * Add MPU changes --------- Signed-off-by: Gaurav Aggarwal Co-authored-by: kar-rahul-aws <118818625+kar-rahul-aws@users.noreply.github.com> Co-authored-by: Gaurav Aggarwal --- include/FreeRTOS.h | 16 +++++++ include/mpu_prototypes.h | 2 + include/mpu_wrappers.h | 2 + include/task.h | 31 ++++++++++++++ portable/Common/mpu_wrappers_v2.c | 66 ++++++++++++++++++++++++++++ tasks.c | 71 +++++++++++++++++++++++++++++++ 6 files changed, 188 insertions(+) diff --git a/include/FreeRTOS.h b/include/FreeRTOS.h index c15eb6d39c8..ba7d083a625 100644 --- a/include/FreeRTOS.h +++ b/include/FreeRTOS.h @@ -1714,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 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 de3ab5531f0..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} diff --git a/portable/Common/mpu_wrappers_v2.c b/portable/Common/mpu_wrappers_v2.c index 9db5772ad2e..0f2dc654b31 100644 --- a/portable/Common/mpu_wrappers_v2.c +++ b/portable/Common/mpu_wrappers_v2.c @@ -1894,6 +1894,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 */ diff --git a/tasks.c b/tasks.c index 2cd130a8297..6edf36ff32c 100644 --- a/tasks.c +++ b/tasks.c @@ -2669,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, From 30283b57dfd23f017389f0cfaf9318f7f2469027 Mon Sep 17 00:00:00 2001 From: Rahul Kar <118818625+kar-rahul-aws@users.noreply.github.com> Date: Tue, 17 Oct 2023 15:05:18 +0530 Subject: [PATCH 4/4] Fix xTaskNotifyWait & ulTaskNotifyTake determinism. (#833) This PR fixes the bug described in the following issue: https://github.com/FreeRTOS/FreeRTOS-Kernel/issues/612. This was originally contributed in the following PR: https://github.com/FreeRTOS/FreeRTOS-Kernel/pull/625. The implementation suspends 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. ------------ Co-authored-by: Jacob Carver --- tasks.c | 147 ++++++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 116 insertions(+), 31 deletions(-) diff --git a/tasks.c b/tasks.c index 6edf36ff32c..e941907cf9c 100644 --- a/tasks.c +++ b/tasks.c @@ -5198,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. @@ -7480,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 @@ -7511,10 +7551,13 @@ TickType_t uxTaskResetEventItemValue( void ) } else { - mtCOVERAGE_TEST_MARKER(); + taskEXIT_CRITICAL(); } } - taskEXIT_CRITICAL(); + else + { + taskEXIT_CRITICAL(); + } taskENTER_CRITICAL(); { @@ -7557,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 ) + if( xTicksToWait > ( TickType_t ) 0 ) + { + traceTASK_NOTIFY_WAIT_BLOCK( uxIndexToWaitOn ); + + /* 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 @@ -7594,10 +7676,13 @@ TickType_t uxTaskResetEventItemValue( void ) } else { - mtCOVERAGE_TEST_MARKER(); + taskEXIT_CRITICAL(); } } - taskEXIT_CRITICAL(); + else + { + taskEXIT_CRITICAL(); + } taskENTER_CRITICAL(); {