mirror of
https://github.com/espressif/esp-idf.git
synced 2024-10-05 20:47:46 -04:00
freertos: Adds new APIs to set/get and restore base priority
Closes https://github.com/espressif/esp-idf/issues/7580
This commit is contained in:
parent
4532e6e0b2
commit
0147bd6b0d
@ -7,6 +7,7 @@
|
||||
#include "sdkconfig.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "idf_additions_inc.h"
|
||||
|
||||
#if CONFIG_FREERTOS_SMP || __DOXYGEN__
|
||||
|
||||
@ -141,3 +142,50 @@ BaseType_t xTaskGetAffinity( TaskHandle_t xTask );
|
||||
#endif // CONFIG_FREERTOS_TLSP_DELETION_CALLBACKS
|
||||
|
||||
#endif // CONFIG_FREERTOS_SMP || __DOXYGEN__
|
||||
|
||||
#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)
|
||||
|
@ -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_
|
@ -7,6 +7,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "sdkconfig.h"
|
||||
#include "idf_additions_inc.h"
|
||||
|
||||
/**
|
||||
* This file will be included in `tasks.c` file, thus, it must NOT be included
|
||||
@ -393,3 +394,188 @@ void vTaskSetThreadLocalStoragePointerAndDelCallback( TaskHandle_t xTaskToSet, B
|
||||
#endif // CONFIG_FREERTOS_TLSP_DELETION_CALLBACKS
|
||||
|
||||
#endif // CONFIG_FREERTOS_SMP
|
||||
|
||||
#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 )
|
||||
|
@ -34,6 +34,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)
|
||||
|
@ -76,6 +76,8 @@ entries:
|
||||
tasks: eTaskGetState (default)
|
||||
tasks: uxTaskPriorityGet (default)
|
||||
tasks: vTaskPrioritySet (default)
|
||||
tasks: prvTaskPriorityRaise (default)
|
||||
tasks: prvTaskPriorityRestore (default)
|
||||
tasks: vTaskSuspend (default)
|
||||
tasks: vTaskResume (default)
|
||||
tasks: prvCreateIdleTasks (default)
|
||||
|
@ -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"
|
||||
@ -170,8 +171,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;
|
||||
@ -189,7 +191,7 @@ void IRAM_ATTR spi_flash_disable_interrupts_caches_and_other_cpu(void)
|
||||
vTaskSuspendAll();
|
||||
#endif // CONFIG_FREERTOS_SMP
|
||||
// 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);
|
||||
|
Loading…
Reference in New Issue
Block a user