From 1167a5c2f903e5f3d8517e8fd8ca1bafa7d07022 Mon Sep 17 00:00:00 2001 From: Darian Leung Date: Tue, 14 Jan 2020 04:39:33 +0800 Subject: [PATCH] Add vTaskPrioritySetCurrent() --- components/freertos/include/freertos/task.h | 13 ++ components/freertos/tasks.c | 135 ++++++++++++++++++++ components/spi_flash/cache_utils.c | 4 +- 3 files changed, 150 insertions(+), 2 deletions(-) diff --git a/components/freertos/include/freertos/task.h b/components/freertos/include/freertos/task.h index adefb3a854..81f51e55b0 100644 --- a/components/freertos/include/freertos/task.h +++ b/components/freertos/include/freertos/task.h @@ -974,6 +974,19 @@ eTaskState eTaskGetState( TaskHandle_t xTask ) PRIVILEGED_FUNCTION; */ void vTaskPrioritySet( TaskHandle_t xTask, UBaseType_t uxNewPriority ) PRIVILEGED_FUNCTION; +/** + * Set the current priority of any task. + * + * This function sets the current priority of a task, and does not modify the + * base priority at all. + * + * @param xTask Handle to the task for which the priority is being set. + * Passing a NULL handle results in the priority of the calling task being set. + * + * @param uxNewPriority The priority to which the task will be set. + */ +void vTaskPrioritySetCurrent( TaskHandle_t xTask, UBaseType_t uxNewPriority ) + /** * Suspend a task. * diff --git a/components/freertos/tasks.c b/components/freertos/tasks.c index 76f093bed3..9a01b8842c 100644 --- a/components/freertos/tasks.c +++ b/components/freertos/tasks.c @@ -1770,6 +1770,141 @@ static void prvAddNewTaskToReadyList( TCB_t *pxNewTCB, TaskFunction_t pxTaskCode taskEXIT_CRITICAL(&xTaskQueueMutex); } + void vTaskPrioritySetCurrent( TaskHandle_t xTask, UBaseType_t uxNewPriority ) + { + TCB_t *pxTCB; + UBaseType_t uxCurrentPriority, uxPriorityUsedOnEntry; + BaseType_t xYieldRequired = pdFALSE; + + configASSERT( ( uxNewPriority < configMAX_PRIORITIES ) ); + + /* Ensure the new priority is valid. */ + if( uxNewPriority >= ( UBaseType_t ) configMAX_PRIORITIES ) + { + uxNewPriority = ( UBaseType_t ) configMAX_PRIORITIES - ( UBaseType_t ) 1U; + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + + taskENTER_CRITICAL(&xTaskQueueMutex); + { + /* If null is passed in here then it is the priority of the calling + task that is being changed. */ + pxTCB = prvGetTCBFromHandle( xTask ); + + traceTASK_PRIORITY_SET( pxTCB, uxNewPriority ); + + uxCurrentPriority = pxTCB->uxPriority; + + if( uxCurrentPriority != uxNewPriority ) + { + /* The priority change may have readied a task of higher + priority than the calling task. */ + if( uxNewPriority > uxCurrentPriority ) + { + if( pxTCB != pxCurrentTCB[ xPortGetCoreID() ] ) + { + /* The priority of a task other than the currently + running task is being raised. Is the priority being + raised above that of the running task? */ + if ( tskCAN_RUN_HERE(pxTCB->xCoreID) && uxNewPriority >= pxCurrentTCB[ xPortGetCoreID() ]->uxPriority ) + { + xYieldRequired = pdTRUE; + } + else if ( pxTCB->xCoreID != xPortGetCoreID() ) + { + taskYIELD_OTHER_CORE( pxTCB->xCoreID, uxNewPriority ); + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + } + else + { + /* The priority of the running task is being raised, + but the running task must already be the highest + priority task able to run so no yield is required. */ + } + } + else if( pxTCB == pxCurrentTCB[ xPortGetCoreID() ] ) + { + /* 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; + } + else + { + /* Setting the priority of any other task down does not + require a yield as the running task must be above the + new priority of the task being modified. */ + } + + /* Remember the ready list the task might be referenced from + before its uxPriority member is changed so the + taskRESET_READY_PRIORITY() macro can function correctly. */ + uxPriorityUsedOnEntry = 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. */ + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + + /* If the task is in the blocked or suspended list we need do + nothing more than change it's 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->xGenericListItem ) ) != pdFALSE ) + { + /* The task is currently in its ready list - remove before adding + it to it's new ready list. As we are in a critical section we + can do this even if the scheduler is suspended. */ + if( uxListRemove( &( pxTCB->xGenericListItem ) ) == ( 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 ); + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + prvReaddTaskToReadyList( pxTCB ); + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + + if( xYieldRequired == pdTRUE ) + { + taskYIELD_IF_USING_PREEMPTION(); + } + else + { + mtCOVERAGE_TEST_MARKER(); + } + + /* Remove compiler warning about unused variables when the port + optimised task selection is not being used. */ + ( void ) uxPriorityUsedOnEntry; + } + } + taskEXIT_CRITICAL(&xTaskQueueMutex); + } + #endif /* INCLUDE_vTaskPrioritySet */ /*-----------------------------------------------------------*/ diff --git a/components/spi_flash/cache_utils.c b/components/spi_flash/cache_utils.c index 56038de379..a6b585478f 100644 --- a/components/spi_flash/cache_utils.c +++ b/components/spi_flash/cache_utils.c @@ -113,7 +113,7 @@ void IRAM_ATTR spi_flash_disable_interrupts_caches_and_other_cpu() // 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); + vTaskPrioritySetCurrent(NULL, 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; @@ -126,7 +126,7 @@ void IRAM_ATTR spi_flash_disable_interrupts_caches_and_other_cpu() // Disable scheduler on the current CPU vTaskSuspendAll(); // Can now set the priority back to the normal one - vTaskPrioritySet(NULL, old_prio); + vTaskPrioritySetCurrent(NULL, old_prio); // This is guaranteed to run on CPU because the other CPU is now // occupied by highest priority task assert(xPortGetCoreID() == cpuid);