From 9c830297b940715da86c886e91f116ed6f259fd9 Mon Sep 17 00:00:00 2001 From: KonstantinKondrashov Date: Thu, 14 Jul 2022 00:28:59 +0800 Subject: [PATCH] freertos: Adds new APIs to set/get and restore base priority Closes https://github.com/espressif/esp-idf/issues/7580 --- components/freertos/CMakeLists.txt | 3 +- components/freertos/component.mk | 2 +- .../freertos_tasks_c_additions.h | 267 ++++++++++++++++++ .../esp_additions/freertos/idf_additions.h | 57 ++++ .../freertos/idf_additions_inc.h | 33 +++ .../freertos_tasks_c_additions.h | 80 ------ components/freertos/linker.lf | 2 + components/spi_flash/cache_utils.c | 8 +- 8 files changed, 367 insertions(+), 85 deletions(-) create mode 100644 components/freertos/esp_additions/private_include/freertos_tasks_c_additions.h create mode 100644 components/freertos/include/esp_additions/freertos/idf_additions.h create mode 100644 components/freertos/include/esp_additions/freertos/idf_additions_inc.h delete mode 100644 components/freertos/include/esp_additions/freertos_tasks_c_additions.h diff --git a/components/freertos/CMakeLists.txt b/components/freertos/CMakeLists.txt index bd5acf5a2f..36e8825acc 100644 --- a/components/freertos/CMakeLists.txt +++ b/components/freertos/CMakeLists.txt @@ -62,7 +62,8 @@ list(APPEND srcs "freertos_v8_compat.c") list(APPEND private_include_dirs - "include/freertos") + "include/freertos" + "esp_additions/private_include") # For include "freertos_tasks_c_additions.h" if(CONFIG_ESP32_IRAM_AS_8BIT_ACCESSIBLE_MEMORY) list(APPEND srcs "port/xtensa/xtensa_loadstore_handler.S") diff --git a/components/freertos/component.mk b/components/freertos/component.mk index 2fd40c90ac..a00180f8e7 100644 --- a/components/freertos/component.mk +++ b/components/freertos/component.mk @@ -7,7 +7,7 @@ ifdef CONFIG_FREERTOS_DEBUG_OCDAWARE endif COMPONENT_ADD_INCLUDEDIRS := include include/esp_additions include/esp_additions/freertos port/xtensa/include -COMPONENT_PRIV_INCLUDEDIRS := include/esp_additions include/esp_additions/freertos include/freertos port/xtensa/include/freertos port/xtensa port/priv_include . +COMPONENT_PRIV_INCLUDEDIRS := esp_additions/private_include include/esp_additions include/esp_additions/freertos include/freertos port/xtensa/include/freertos port/xtensa port/priv_include . COMPONENT_SRCDIRS += port port/xtensa esp_additions/ ifndef CONFIG_ESP32_IRAM_AS_8BIT_ACCESSIBLE_MEMORY diff --git a/components/freertos/esp_additions/private_include/freertos_tasks_c_additions.h b/components/freertos/esp_additions/private_include/freertos_tasks_c_additions.h new file mode 100644 index 0000000000..9b55802811 --- /dev/null +++ b/components/freertos/esp_additions/private_include/freertos_tasks_c_additions.h @@ -0,0 +1,267 @@ +// Copyright 2015-2021 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once + +#include "idf_additions_inc.h" + +/** + * This file will be included in `tasks.c` file, thus, it must NOT be included + * by any (other) file. + * The functions below only consist in getters for the static variables in + * `tasks.c` file. + * The only source files that should call these functions are the ones in + * `/additions` directory. + */ + +#if ( configENABLE_TASK_SNAPSHOT == 1 ) + + UBaseType_t pxTCBGetSize ( void ) + { + return sizeof(TCB_t); + } + + ListItem_t* pxTCBGetStateListItem ( void *pxTCB ) + { + return &(((TCB_t*)pxTCB)->xStateListItem); + } + + StackType_t* pxTCBGetStartOfStack ( void *pxTCB ) + { + return (StackType_t*) ((TCB_t*)pxTCB)->pxStack; + } + + StackType_t* pxTCBGetTopOfStack ( void *pxTCB ) + { + return (StackType_t*) ((TCB_t*)pxTCB)->pxTopOfStack; + } + + StackType_t* pxTCBGetEndOfStack ( void *pxTCB ) + { + return (StackType_t*) ((TCB_t*)pxTCB)->pxEndOfStack; + } + + + List_t* pxListGetReadyTask ( UBaseType_t idx ) + { + return &( pxReadyTasksLists[idx] ); + } + + List_t* pxListGetReadyPendingTask ( UBaseType_t idx ) + { + return &( xPendingReadyList[idx] ); + } + + List_t* pxGetDelayedTaskList ( void ) { + return pxDelayedTaskList; + } + + List_t* pxGetOverflowDelayedTaskList ( void ) { + return pxOverflowDelayedTaskList; + } + + List_t* pxGetTasksWaitingTermination ( void ) { + return &xTasksWaitingTermination; + } + + List_t* pxGetSuspendedTaskList ( void ) { + return &xSuspendedTaskList; + } + +#endif + +#if ( INCLUDE_vTaskPrioritySet == 1 ) + +void prvTaskPriorityRaise( prvTaskSavedPriority_t * pxSavedPriority, UBaseType_t uxNewPriority ) +{ + TCB_t * pxTCB; + UBaseType_t uxPriorityUsedOnEntry; + + configASSERT( ( uxNewPriority < configMAX_PRIORITIES ) ); + + /* Ensure the new priority is valid. */ + if( uxNewPriority >= ( UBaseType_t ) configMAX_PRIORITIES ) + { + uxNewPriority = ( UBaseType_t ) configMAX_PRIORITIES - ( UBaseType_t ) 1U; + } + + taskENTER_CRITICAL(); + { + pxTCB = prvGetTCBFromHandle( NULL ); + + #if ( configUSE_MUTEXES == 1 ) + { + pxSavedPriority->uxPriority = pxTCB->uxPriority; + pxSavedPriority->uxBasePriority = pxTCB->uxBasePriority; + + /* If uxNewPriority < uxBasePriority, then there is nothing else to + * do, as uxBasePriority is always <= uxPriority. */ + if( uxNewPriority > pxTCB->uxBasePriority ) + { + pxTCB->uxBasePriority = uxNewPriority; + + /* Remember the task's current priority before attempting to + * change it. If the task's current priority is changed, it must + * be done so before moving the task between task lists) in order + * for the taskRESET_READY_PRIORITY() macro to function correctly. */ + uxPriorityUsedOnEntry = pxTCB->uxPriority; + + if( uxNewPriority > pxTCB->uxPriority ) + { + pxTCB->uxPriority = uxNewPriority; + + /* Only reset the event list item value if the value is not + * being used for anything else. */ + if( ( listGET_LIST_ITEM_VALUE( &( pxTCB->xEventListItem ) ) & taskEVENT_LIST_ITEM_VALUE_IN_USE ) == 0UL ) + { + listSET_LIST_ITEM_VALUE( &( pxTCB->xEventListItem ), ( ( TickType_t ) configMAX_PRIORITIES - ( TickType_t ) uxNewPriority ) ); /*lint !e961 MISRA exception as the casts are only redundant for some ports. */ + } + + /* If the task is in the blocked or suspended list we need do + * nothing more than change its priority variable. However, if + * the task is in a ready list it needs to be removed and placed + * in the list appropriate to its new priority. */ + if( listIS_CONTAINED_WITHIN( &( pxReadyTasksLists[ uxPriorityUsedOnEntry ] ), &( pxTCB->xStateListItem ) ) != pdFALSE ) + { + /* The task is currently in its ready list - remove before + * adding it to its new ready list. As we are in a critical + * section we can do this even if the scheduler is suspended. */ + if( uxListRemove( &( pxTCB->xStateListItem ) ) == ( UBaseType_t ) 0 ) + { + /* It is known that the task is in its ready list so + * there is no need to check again and the port level + * reset macro can be called directly. */ + portRESET_READY_PRIORITY( uxPriorityUsedOnEntry, uxTopReadyPriority ); + } + prvAddTaskToReadyList( pxTCB ); + } + } + } + } + #else /* if ( configUSE_MUTEXES == 1 ) */ + { + pxSavedPriority->uxPriority = pxTCB->uxPriority; + if ( uxNewPriority > pxTCB->uxPriority) + { + vTaskPrioritySet( NULL, uxNewPriority ); + } + } + #endif + } + taskEXIT_CRITICAL(); +} + +void prvTaskPriorityRestore( prvTaskSavedPriority_t * pxSavedPriority ) +{ + TCB_t * pxTCB; + UBaseType_t uxNewPriority; + UBaseType_t uxPriorityUsedOnEntry; + UBaseType_t uxBasePriorityUsedOnEntry; + BaseType_t xYieldRequired = pdFALSE; + + taskENTER_CRITICAL(); + { + pxTCB = prvGetTCBFromHandle( NULL ); + + #if ( configUSE_MUTEXES == 1 ) + { + /* If the saved uxBasePriority == the task's uxBasePriority, it means + * that prvTaskPriorityRaise() never raised the task's uxBasePriority. + * In that case, there is nothing else to do. */ + if( pxSavedPriority->uxBasePriority != pxTCB->uxBasePriority ) + { + uxBasePriorityUsedOnEntry = pxTCB->uxBasePriority; + pxTCB->uxBasePriority = pxSavedPriority->uxBasePriority; + + /* Remember the task's current priority before attempting to + * change it. If the task's current priority is changed, it must + * be done so before moving the task between task lists in order + * for the taskRESET_READY_PRIORITY() macro to function correctly. */ + uxPriorityUsedOnEntry = pxTCB->uxPriority; + + /* Check if the task inherited a priority after prvTaskPriorityRaise(). + * If this is the case, there is nothing else to do. The priority + * will be restored when the task disinherits its priority. */ + if( pxTCB->uxPriority == uxBasePriorityUsedOnEntry ) + { + if( pxTCB->uxMutexesHeld == 0 ) + { + /* The task may have inherited a priority before prvTaskPriorityRaise() + * then disinherited a priority after prvTaskPriorityRaise(). + * Thus we need set the uxPriority to the saved base priority + * so that the task's priority gets restored to the priority + * before any inheritance or raising. */ + pxTCB->uxPriority = pxSavedPriority->uxBasePriority; + } + else + { + /* The task may have inherited a priority before prvTaskPriorityRaise() + * was called. Thus, we need to restore uxPriority to the + * "saved uxPriority" so that the task still retains that + * inherited priority. */ + pxTCB->uxPriority = pxSavedPriority->uxPriority; + } + uxNewPriority = pxTCB->uxPriority; + + if( uxNewPriority < uxPriorityUsedOnEntry ) + { + /* Setting the priority of the running task down means + * there may now be another task of higher priority that + * is ready to execute. */ + xYieldRequired = pdTRUE; + } + + /* Only reset the event list item value if the value is not + * being used for anything else. */ + if( ( listGET_LIST_ITEM_VALUE( &( pxTCB->xEventListItem ) ) & taskEVENT_LIST_ITEM_VALUE_IN_USE ) == 0UL ) + { + listSET_LIST_ITEM_VALUE( &( pxTCB->xEventListItem ), ( ( TickType_t ) configMAX_PRIORITIES - ( TickType_t ) uxNewPriority ) ); /*lint !e961 MISRA exception as the casts are only redundant for some ports. */ + } + + /* If the task is in the blocked or suspended list we need do + * nothing more than change its priority variable. However, if + * the task is in a ready list it needs to be removed and placed + * in the list appropriate to its new priority. */ + if( listIS_CONTAINED_WITHIN( &( pxReadyTasksLists[ uxPriorityUsedOnEntry ] ), &( pxTCB->xStateListItem ) ) != pdFALSE ) + { + /* The task is currently in its ready list - remove before + * adding it to its new ready list. As we are in a critical + * section we can do this even if the scheduler is suspended. */ + if( uxListRemove( &( pxTCB->xStateListItem ) ) == ( UBaseType_t ) 0 ) + { + /* It is known that the task is in its ready list so + * there is no need to check again and the port level + * reset macro can be called directly. */ + portRESET_READY_PRIORITY( uxPriorityUsedOnEntry, uxTopReadyPriority ); + } + prvAddTaskToReadyList( pxTCB ); + } + + if( xYieldRequired != pdFALSE ) + { + taskYIELD_IF_USING_PREEMPTION(); + } + } + } + } + #else /* if ( configUSE_MUTEXES == 1 ) */ + { + vTaskPrioritySet( NULL, pxSavedPriority->uxPriority ); + } + #endif + } + taskEXIT_CRITICAL(); +} + +#endif // ( INCLUDE_vTaskPrioritySet == 1 ) diff --git a/components/freertos/include/esp_additions/freertos/idf_additions.h b/components/freertos/include/esp_additions/freertos/idf_additions.h new file mode 100644 index 0000000000..bd1d0bd238 --- /dev/null +++ b/components/freertos/include/esp_additions/freertos/idf_additions.h @@ -0,0 +1,57 @@ +/* + * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "sdkconfig.h" +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "idf_additions_inc.h" + +#if ( INCLUDE_vTaskPrioritySet == 1 ) + +/** + * INCLUDE_vTaskPrioritySet must be defined as 1 for this function to be available. + * See the configuration section for more information. + * + * Saves the current priority and current base priority of a task, then raises the tasks + * current and base priority to uxNewPriority if uxNewPriority is of a higher priority. + * Once a task's priority has been raised with this function, the priority can be restored + * by calling prvTaskPriorityRestore() + * - Note that this function differs from vTaskPrioritySet() as the task's current priority + * will be modified even if the task has already inherited a priority. + * - This function is intended for special circumstance where a task must be forced immediately + * to a higher priority. + * + * For configUSE_MUTEXES == 0: A context switch will occur before the function returns if the priority + * being set is higher than the currently executing task. + * + * @note This functions is private is only be called internally within various IDF components. + * Users should never call this function from their application. + * + * @note vTaskPrioritySet() should not be called while a task's priority is already raised via this function + * + * @param pxSavedPriority returns base and current priorities + * + * @param uxNewPriority The priority to which the task will be set. + */ +void prvTaskPriorityRaise( prvTaskSavedPriority_t * pxSavedPriority, UBaseType_t uxNewPriority ); + +/** + * INCLUDE_vTaskPrioritySet must be defined as 1 for this function to be available. + * See the configuration section for more information. + * + * Restore a task's priority that was previously raised by prvTaskPriorityRaise(). + * + * For configUSE_MUTEXES == 0: A context switch will occur before the function returns if the priority + * being set is higher than the currently executing task. + * + * @note This functions is private is only be called internally within various IDF components. + * Users should never call this function from their application. + * + * @param pxSavedPriority previously saved base and current priorities that need to be restored + */ +void prvTaskPriorityRestore( prvTaskSavedPriority_t * pxSavedPriority ); + +#endif // ( INCLUDE_vTaskPrioritySet == 1) diff --git a/components/freertos/include/esp_additions/freertos/idf_additions_inc.h b/components/freertos/include/esp_additions/freertos/idf_additions_inc.h new file mode 100644 index 0000000000..25b0b6d9a4 --- /dev/null +++ b/components/freertos/include/esp_additions/freertos/idf_additions_inc.h @@ -0,0 +1,33 @@ +/* + * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + + +#ifndef FREERTOS_ADDITITIONS_INC_H_ +#define FREERTOS_ADDITITIONS_INC_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "sdkconfig.h" +#include "freertos/FreeRTOS.h" + +#if ( INCLUDE_vTaskPrioritySet == 1 ) + +typedef struct { + UBaseType_t uxPriority; +#if ( configUSE_MUTEXES == 1 ) + UBaseType_t uxBasePriority; +#endif +} prvTaskSavedPriority_t; + +#endif // ( INCLUDE_vTaskPrioritySet == 1) + +#ifdef __cplusplus +} +#endif + +#endif //FREERTOS_ADDITITIONS_INC_H_ diff --git a/components/freertos/include/esp_additions/freertos_tasks_c_additions.h b/components/freertos/include/esp_additions/freertos_tasks_c_additions.h deleted file mode 100644 index 464c0b3ffb..0000000000 --- a/components/freertos/include/esp_additions/freertos_tasks_c_additions.h +++ /dev/null @@ -1,80 +0,0 @@ -// Copyright 2015-2021 Espressif Systems (Shanghai) PTE LTD -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -#pragma once - -/** - * This file will be included in `tasks.c` file, thus, it must NOT be included - * by any (other) file. - * The functions below only consist in getters for the static variables in - * `tasks.c` file. - * The only source files that should call these functions are the ones in - * `/additions` directory. - */ - -#if ( configENABLE_TASK_SNAPSHOT == 1 ) - - UBaseType_t pxTCBGetSize ( void ) - { - return sizeof(TCB_t); - } - - ListItem_t* pxTCBGetStateListItem ( void *pxTCB ) - { - return &(((TCB_t*)pxTCB)->xStateListItem); - } - - StackType_t* pxTCBGetStartOfStack ( void *pxTCB ) - { - return (StackType_t*) ((TCB_t*)pxTCB)->pxStack; - } - - StackType_t* pxTCBGetTopOfStack ( void *pxTCB ) - { - return (StackType_t*) ((TCB_t*)pxTCB)->pxTopOfStack; - } - - StackType_t* pxTCBGetEndOfStack ( void *pxTCB ) - { - return (StackType_t*) ((TCB_t*)pxTCB)->pxEndOfStack; - } - - - List_t* pxListGetReadyTask ( UBaseType_t idx ) - { - return &( pxReadyTasksLists[idx] ); - } - - List_t* pxListGetReadyPendingTask ( UBaseType_t idx ) - { - return &( xPendingReadyList[idx] ); - } - - List_t* pxGetDelayedTaskList ( void ) { - return pxDelayedTaskList; - } - - List_t* pxGetOverflowDelayedTaskList ( void ) { - return pxOverflowDelayedTaskList; - } - - List_t* pxGetTasksWaitingTermination ( void ) { - return &xTasksWaitingTermination; - } - - List_t* pxGetSuspendedTaskList ( void ) { - return &xSuspendedTaskList; - } - -#endif diff --git a/components/freertos/linker.lf b/components/freertos/linker.lf index 8473d52605..ecafb1d4ec 100644 --- a/components/freertos/linker.lf +++ b/components/freertos/linker.lf @@ -29,6 +29,8 @@ entries: tasks: vTaskRemoveFromUnorderedEventList (default) tasks: uxTaskPriorityGet (default) tasks: vTaskPrioritySet (default) + tasks: prvTaskPriorityRaise (default) + tasks: prvTaskPriorityRestore (default) tasks: vTaskSetThreadLocalStoragePointerAndDelCallback (default) tasks: pvTaskGetThreadLocalStoragePointer (default) tasks: xTaskGetCurrentTaskHandleForCPU (default) diff --git a/components/spi_flash/cache_utils.c b/components/spi_flash/cache_utils.c index 7715900055..d235972f0c 100644 --- a/components/spi_flash/cache_utils.c +++ b/components/spi_flash/cache_utils.c @@ -11,6 +11,7 @@ #include #include +#include #include #if CONFIG_IDF_TARGET_ESP32 #include "soc/dport_reg.h" @@ -155,8 +156,9 @@ void IRAM_ATTR spi_flash_disable_interrupts_caches_and_other_cpu(void) } else { // Temporarily raise current task priority to prevent a deadlock while // waiting for IPC task to start on the other CPU - int old_prio = uxTaskPriorityGet(NULL); - vTaskPrioritySet(NULL, configMAX_PRIORITIES - 1); + prvTaskSavedPriority_t SavedPriority; + prvTaskPriorityRaise(&SavedPriority, configMAX_PRIORITIES - 1); + // Signal to the spi_flash_op_block_task on the other CPU that we need it to // disable cache there and block other tasks from executing. s_flash_op_can_start = false; @@ -169,7 +171,7 @@ void IRAM_ATTR spi_flash_disable_interrupts_caches_and_other_cpu(void) // Disable scheduler on the current CPU vTaskSuspendAll(); // Can now set the priority back to the normal one - vTaskPrioritySet(NULL, old_prio); + prvTaskPriorityRestore(&SavedPriority); // This is guaranteed to run on CPU because the other CPU is now // occupied by highest priority task assert(xPortGetCoreID() == cpuid);