Merge branch 'bugfix/clobbering_freertos_base_priority_v4.3' into 'release/v4.3'

spi_flash: fix issue linked with raising of task priority while priority is already raised (v4.3)

See merge request espressif/esp-idf!20546
This commit is contained in:
Zim Kalinowski 2022-10-19 18:02:30 +08:00
commit 96ef8f42be
9 changed files with 319 additions and 6 deletions

View File

@ -18,6 +18,7 @@ if(NOT "${target}" STREQUAL "esp32c3") # should test arch here not target, TODO
set(include_dirs
include
include/esp_additions
port/xtensa/include)
set(private_include_dirs
@ -34,6 +35,7 @@ else() # RISC-V
set(include_dirs
include
include/esp_additions
port/riscv/include)
set(private_include_dirs
@ -57,6 +59,8 @@ list(APPEND srcs
"FreeRTOS-openocd.c"
"freertos_v8_compat.c")
list(APPEND private_include_dirs "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")
endif()

View File

@ -6,9 +6,9 @@ ifdef CONFIG_FREERTOS_DEBUG_OCDAWARE
COMPONENT_ADD_LDFLAGS += -Wl,--undefined=uxTopUsedPriority
endif
COMPONENT_ADD_INCLUDEDIRS := include port/xtensa/include
COMPONENT_PRIV_INCLUDEDIRS := include/freertos port/xtensa/include/freertos port/xtensa .
COMPONENT_SRCDIRS += port port/xtensa
COMPONENT_ADD_INCLUDEDIRS := include include/esp_additions port/xtensa/include
COMPONENT_PRIV_INCLUDEDIRS := esp_additions/private_include include/esp_additions include/freertos port/xtensa/include/freertos port/xtensa .
COMPONENT_SRCDIRS += port port/xtensa esp_additions/
ifndef CONFIG_ESP32_IRAM_AS_8BIT_ACCESSIBLE_MEMORY
COMPONENT_OBJEXCLUDE := xtensa/xtensa_loadstore_handler.o

View File

@ -0,0 +1,211 @@
// 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 "freertos/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 ( 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( &xTaskQueueMutex );
{
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( &xTaskQueueMutex );
}
void prvTaskPriorityRestore( prvTaskSavedPriority_t * pxSavedPriority )
{
TCB_t * pxTCB;
UBaseType_t uxNewPriority;
UBaseType_t uxPriorityUsedOnEntry;
UBaseType_t uxBasePriorityUsedOnEntry;
BaseType_t xYieldRequired = pdFALSE;
taskENTER_CRITICAL( &xTaskQueueMutex );
{
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( &xTaskQueueMutex );
}
#endif // ( INCLUDE_vTaskPrioritySet == 1 )

View File

@ -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)

View File

@ -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_

View File

@ -31,6 +31,8 @@ entries:
tasks: xTaskRemoveFromUnorderedEventList (default)
tasks: uxTaskPriorityGet (default)
tasks: vTaskPrioritySet (default)
tasks: prvTaskPriorityRaise (default)
tasks: prvTaskPriorityRestore (default)
tasks: vTaskSetThreadLocalStoragePointerAndDelCallback (default)
tasks: pvTaskGetThreadLocalStoragePointer (default)
tasks: xTaskGetCurrentTaskHandleForCPU (default)

View File

@ -302,4 +302,6 @@ extern int xPortSwitchFlag;
#endif
#endif
#define configINCLUDE_FREERTOS_TASK_C_ADDITIONS_H 1
#endif // FREERTOS_CONFIG_RISCV_H

View File

@ -360,4 +360,6 @@ extern uint32_t port_switch_flag[];
#endif
#endif
#define configINCLUDE_FREERTOS_TASK_C_ADDITIONS_H 1
#endif // FREERTOS_CONFIG_XTENSA_H

View File

@ -11,6 +11,7 @@
#include <freertos/FreeRTOS.h>
#include <freertos/task.h>
#include <freertos/idf_additions.h>
#include <freertos/semphr.h>
#if CONFIG_IDF_TARGET_ESP32
#include "soc/dport_reg.h"
@ -150,8 +151,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;
@ -164,7 +166,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 <cpuid> because the other CPU is now
// occupied by highest priority task
assert(xPortGetCoreID() == cpuid);