mirror of
				https://github.com/espressif/esp-idf.git
				synced 2025-10-29 20:34:36 +00:00 
			
		
		
		
	 3d2e674326
			
		
	
	3d2e674326
	
	
	
		
			
			Previously, some IDF FreeRTOS API additions that were meant to be private were exposed through the same "idf_additions.h" header. This commit moves those functions to a separate header included via "esp_private/freertos_idf_additions_priv.h" so that they are not mistaken as public API by users. This commit also fixes some missing include and C++ guards in idf_additions.h
		
			
				
	
	
		
			598 lines
		
	
	
		
			24 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			598 lines
		
	
	
		
			24 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /*
 | |
|  * SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD
 | |
|  *
 | |
|  * SPDX-License-Identifier: Apache-2.0
 | |
|  */
 | |
| 
 | |
| #pragma once
 | |
| 
 | |
| #include "sdkconfig.h"
 | |
| #include "idf_additions.h"
 | |
| #include "esp_private/freertos_idf_additions_priv.h"
 | |
| 
 | |
| /**
 | |
|  * This file will be included in `tasks.c` file, thus, it is treated as a source
 | |
|  * file instead of a header file, and must NOT be included by any (other) file.
 | |
|  * This file is used to add additional functions to `tasks.c`. See the
 | |
|  * `esp_additions/include` directory of the headers that expose these `tasks.c`
 | |
|  * additional API.
 | |
|  */
 | |
| 
 | |
| /* ----------------------------------------------------- Newlib --------------------------------------------------------
 | |
|  *
 | |
|  * ------------------------------------------------------------------------------------------------------------------ */
 | |
| 
 | |
| #if ( configUSE_NEWLIB_REENTRANT == 1 )
 | |
| /**
 | |
|  * @brief Get reentrancy structure of the current task
 | |
|  *
 | |
|  * - This funciton is required by newlib (when __DYNAMIC_REENT__ is enabled)
 | |
|  * - It will return a pointer to the current task's reent struct
 | |
|  * - If FreeRTOS is not running, it will return the global reent struct
 | |
|  *
 | |
|  * @return Pointer to a the (current taks's)/(globa) reent struct
 | |
|  */
 | |
| struct _reent *__getreent(void)
 | |
| {
 | |
|     // No lock needed because if this changes, we won't be running anymore.
 | |
|     TCB_t *pxCurTask = xTaskGetCurrentTaskHandle();
 | |
|     struct _reent *ret;
 | |
|     if (pxCurTask == NULL) {
 | |
|         // No task running. Return global struct.
 | |
|         ret = _GLOBAL_REENT;
 | |
|     } else {
 | |
|         // We have a task; return its reentrant struct.
 | |
|         ret = &pxCurTask->xNewLib_reent;
 | |
|     }
 | |
|     return ret;
 | |
| }
 | |
| #endif // configUSE_NEWLIB_REENTRANT == 1
 | |
| 
 | |
| /* -------------------------------------------------- Task Snapshot ----------------------------------------------------
 | |
|  *
 | |
|  * ------------------------------------------------------------------------------------------------------------------ */
 | |
| 
 | |
| #if CONFIG_FREERTOS_ENABLE_TASK_SNAPSHOT
 | |
| 
 | |
| #include "task_snapshot.h"
 | |
| 
 | |
| /**
 | |
|  * @brief List of all task lists in FreeRTOS
 | |
|  *
 | |
|  * @note There are currently differing number of task list between SMP FreeRTOS and ESP-IDF FreeRTOS
 | |
|  */
 | |
| static List_t *non_ready_task_lists[] = {
 | |
|     #ifdef CONFIG_FREERTOS_SMP
 | |
|         &xPendingReadyList,
 | |
|     #else
 | |
|         &xPendingReadyList[0],
 | |
|         #ifndef CONFIG_FREERTOS_UNICORE
 | |
|             &xPendingReadyList[1],
 | |
|         #endif // CONFIG_FREERTOS_UNICORE
 | |
|     #endif //CONFIG_FREERTOS_SMP
 | |
|     &xDelayedTaskList1,
 | |
|     &xDelayedTaskList2,
 | |
|     #if( INCLUDE_vTaskDelete == 1 )
 | |
|         &xTasksWaitingTermination,
 | |
|     #endif
 | |
|     #if( INCLUDE_vTaskSuspend == 1 )
 | |
|         &xSuspendedTaskList,
 | |
|     #endif
 | |
| };
 | |
| 
 | |
| /**
 | |
|  * @brief Get the next task list to traverse
 | |
|  *
 | |
|  * - Given a particular task list, this function returns the next task to traverse.
 | |
|  * - The task lists are returned in the following precedence
 | |
|  *      - Ready lists (highest to lowers priority)
 | |
|  *      - Pending ready list(s)
 | |
|  *      - Delayed list 1
 | |
|  *      - Delayed list 2
 | |
|  *      - Waiting termination list
 | |
|  *      - Suspended list
 | |
|  *
 | |
|  * @param pxCurTaskList Previously traversed task list (or NULL if obtaining the first task list)
 | |
|  * @return List_t* The next task list to traverse (or NULL of all task lists have been traversed)
 | |
|  */
 | |
| static List_t *pxGetNextTaskList(List_t *pxCurTaskList)
 | |
| {
 | |
|     List_t *pxNextTaskList = NULL;
 | |
| 
 | |
|     // No Current List. Start from the highest priority ready task list
 | |
|     if (pxCurTaskList == NULL)
 | |
|     {
 | |
|         pxNextTaskList = &pxReadyTasksLists[configMAX_PRIORITIES - 1];
 | |
|     }
 | |
|     // Current list is one of the ready task lists. Find the current priority, and return the next lower priority ready task list
 | |
|     else if (pxCurTaskList >= &pxReadyTasksLists[0] && pxCurTaskList <= &pxReadyTasksLists[configMAX_PRIORITIES - 1] )
 | |
|     {
 | |
|         // Find the current priority
 | |
|         int cur_priority;
 | |
|         for (cur_priority = configMAX_PRIORITIES - 1; cur_priority >= 0; cur_priority--) {
 | |
|             if (pxCurTaskList == &pxReadyTasksLists[cur_priority]) {
 | |
|                 break;
 | |
|             }
 | |
|         }
 | |
|         // Return the ready task list at (cur_priority - 1), or the pending ready task list
 | |
|         if (cur_priority > 0)
 | |
|         {
 | |
|             pxNextTaskList = &pxReadyTasksLists[cur_priority - 1];
 | |
|         }
 | |
|         // We've reached the end of the Ready Task Lists.  We get the next list from the non-ready task lists
 | |
|         else if (cur_priority == 0)
 | |
|         {
 | |
|             pxNextTaskList = non_ready_task_lists[0];
 | |
|         }
 | |
|         else
 | |
|         {
 | |
|             abort();    // This should never occur
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     // Current list is one of the non-ready task lists. Fetch the next non-ready task list
 | |
|     if (pxNextTaskList == NULL) {
 | |
|         int cur_list_idx;
 | |
|         const int num_non_ready_task_lists = (sizeof(non_ready_task_lists) / sizeof(List_t *));
 | |
|         // Note: - 1 so that if the current list is the last on non_ready_task_lists[], the next list will return NULL
 | |
|         for (cur_list_idx = 0; cur_list_idx < num_non_ready_task_lists - 1; cur_list_idx++) {
 | |
|             if (pxCurTaskList == non_ready_task_lists[cur_list_idx]) {
 | |
|                 pxNextTaskList = non_ready_task_lists[cur_list_idx + 1];
 | |
|                 break;
 | |
|             }
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     return pxNextTaskList;
 | |
| }
 | |
| 
 | |
| TaskHandle_t pxTaskGetNext( TaskHandle_t pxTask )
 | |
| {
 | |
|     TCB_t *pxTCB = (TCB_t *)pxTask;
 | |
|     // Check current task is valid
 | |
|     if (pxTCB != NULL && !portVALID_TCB_MEM(pxTCB)) {
 | |
|         return NULL;
 | |
|     }
 | |
| 
 | |
|     List_t *pxCurTaskList;
 | |
|     const ListItem_t *pxCurListItem;
 | |
|     if (pxTCB == NULL) {
 | |
|         // Starting traversal for the first time
 | |
|         pxCurTaskList = pxGetNextTaskList(NULL);
 | |
|         pxCurListItem = listGET_END_MARKER(pxCurTaskList);
 | |
|     } else {
 | |
|         // Continuing traversal
 | |
|         pxCurTaskList = listLIST_ITEM_CONTAINER(&pxTCB->xStateListItem);
 | |
|         pxCurListItem = &pxTCB->xStateListItem;
 | |
|     }
 | |
| 
 | |
|     ListItem_t *pxNextListItem = NULL;
 | |
|     if (pxCurListItem->pxNext == listGET_END_MARKER(pxCurTaskList)) {
 | |
|         List_t *pxNextTaskList = pxGetNextTaskList(pxCurTaskList);
 | |
|         while (pxNextTaskList != NULL) {
 | |
|             if (!listLIST_IS_EMPTY(pxNextTaskList)) {
 | |
|                 // Get the first item in the next task list
 | |
|                 pxNextListItem = listGET_HEAD_ENTRY(pxNextTaskList);
 | |
|                 break;
 | |
|             }
 | |
|             // Task list is empty. Get the next task list
 | |
|             pxNextTaskList = pxGetNextTaskList(pxNextTaskList);
 | |
|         }
 | |
|     } else {
 | |
|         //There are still more items in the current task list. Get the next item
 | |
|         pxNextListItem = listGET_NEXT(pxCurListItem);
 | |
|     }
 | |
| 
 | |
|     TCB_t *pxNextTCB;
 | |
|     if (pxNextListItem == NULL) {
 | |
|         pxNextTCB = NULL;
 | |
|     } else {
 | |
|         pxNextTCB = (TCB_t *)listGET_LIST_ITEM_OWNER(pxNextListItem);
 | |
|     }
 | |
| 
 | |
|     return pxNextTCB;
 | |
| }
 | |
| 
 | |
| BaseType_t vTaskGetSnapshot( TaskHandle_t pxTask, TaskSnapshot_t *pxTaskSnapshot )
 | |
| {
 | |
|     if (portVALID_TCB_MEM(pxTask) == false || pxTaskSnapshot == NULL) {
 | |
|         return pdFALSE;
 | |
|     }
 | |
| 
 | |
|     TCB_t *pxTCB = (TCB_t *)pxTask;
 | |
|     pxTaskSnapshot->pxTCB = pxTCB;
 | |
|     pxTaskSnapshot->pxTopOfStack = (StackType_t *)pxTCB->pxTopOfStack;
 | |
|     pxTaskSnapshot->pxEndOfStack = (StackType_t *)pxTCB->pxEndOfStack;
 | |
|     return pdTRUE;
 | |
| }
 | |
| 
 | |
| UBaseType_t uxTaskGetSnapshotAll( TaskSnapshot_t * const pxTaskSnapshotArray, const UBaseType_t uxArrayLength, UBaseType_t * const pxTCBSize )
 | |
| {
 | |
|     UBaseType_t uxArrayNumFilled = 0;
 | |
| 
 | |
|     //Traverse all of the tasks lists
 | |
|     List_t *pxCurTaskList = pxGetNextTaskList(NULL);    //Get the first task list
 | |
|     while (pxCurTaskList != NULL && uxArrayNumFilled < uxArrayLength) {
 | |
|         if (!listLIST_IS_EMPTY(pxCurTaskList)) {
 | |
|             const ListItem_t *pxCurListItem;
 | |
|             //Walk each task on the current task list
 | |
|             pxCurListItem = listGET_HEAD_ENTRY(pxCurTaskList);
 | |
|             while (pxCurListItem != listGET_END_MARKER(pxCurTaskList)) {
 | |
|                 TCB_t *pxTCB = (TCB_t *)listGET_LIST_ITEM_OWNER(pxCurListItem);
 | |
|                 vTaskGetSnapshot((TaskHandle_t)pxTCB, &pxTaskSnapshotArray[uxArrayNumFilled]);
 | |
|                 uxArrayNumFilled++;
 | |
|                 if (!(uxArrayNumFilled < uxArrayLength)) {
 | |
|                     break;
 | |
|                 }
 | |
|                 pxCurListItem = listGET_NEXT(pxCurListItem);
 | |
|             }
 | |
|         }
 | |
|         //Get the next task list
 | |
|         pxCurTaskList = pxGetNextTaskList(pxCurTaskList);
 | |
|     }
 | |
| 
 | |
|     *pxTCBSize = sizeof(TCB_t);
 | |
|     return uxArrayNumFilled;
 | |
| }
 | |
| #endif // CONFIG_FREERTOS_ENABLE_TASK_SNAPSHOT
 | |
| 
 | |
| /* ----------------------------------------------------- OpenOCD -------------------------------------------------------
 | |
|  *
 | |
|  * ------------------------------------------------------------------------------------------------------------------ */
 | |
| 
 | |
| #if ( configENABLE_FREERTOS_DEBUG_OCDAWARE == 1 )
 | |
| 
 | |
| /**
 | |
|  * Debug param indexes. DO NOT change the order. OpenOCD uses the same indexes
 | |
|  * Entries in FreeRTOS_openocd_params must match the order of these indexes
 | |
|  */
 | |
| enum {
 | |
|     ESP_FREERTOS_DEBUG_TABLE_SIZE = 0,
 | |
|     ESP_FREERTOS_DEBUG_TABLE_VERSION,
 | |
|     ESP_FREERTOS_DEBUG_KERNEL_VER_MAJOR,
 | |
|     ESP_FREERTOS_DEBUG_KERNEL_VER_MINOR,
 | |
|     ESP_FREERTOS_DEBUG_KERNEL_VER_BUILD,
 | |
|     ESP_FREERTOS_DEBUG_UX_TOP_USED_PIORITY,
 | |
|     ESP_FREERTOS_DEBUG_PX_TOP_OF_STACK,
 | |
|     ESP_FREERTOS_DEBUG_PC_TASK_NAME,
 | |
|     /* New entries must be inserted here */
 | |
|     ESP_FREERTOS_DEBUG_TABLE_END,
 | |
| };
 | |
| 
 | |
| const DRAM_ATTR uint8_t FreeRTOS_openocd_params[ESP_FREERTOS_DEBUG_TABLE_END]  = {
 | |
|     ESP_FREERTOS_DEBUG_TABLE_END,       /* table size */
 | |
|     1,                                  /* table version */
 | |
|     tskKERNEL_VERSION_MAJOR,
 | |
|     tskKERNEL_VERSION_MINOR,
 | |
|     tskKERNEL_VERSION_BUILD,
 | |
|     configMAX_PRIORITIES - 1,           /* uxTopUsedPriority */
 | |
|     offsetof(TCB_t, pxTopOfStack),      /* thread_stack_offset; */
 | |
|     offsetof(TCB_t, pcTaskName),        /* thread_name_offset; */
 | |
| };
 | |
| 
 | |
| #endif // configENABLE_FREERTOS_DEBUG_OCDAWARE == 1
 | |
| 
 | |
| /* -------------------------------------------- FreeRTOS IDF API Additions ---------------------------------------------
 | |
|  * FreeRTOS related API that were added by IDF
 | |
|  * ------------------------------------------------------------------------------------------------------------------ */
 | |
| 
 | |
| #if CONFIG_FREERTOS_SMP
 | |
| _Static_assert(tskNO_AFFINITY == CONFIG_FREERTOS_NO_AFFINITY, "CONFIG_FREERTOS_NO_AFFINITY must be the same as tskNO_AFFINITY");
 | |
| 
 | |
| BaseType_t xTaskCreatePinnedToCore( TaskFunction_t pxTaskCode,
 | |
|                                     const char * const pcName,
 | |
|                                     const uint32_t usStackDepth,
 | |
|                                     void * const pvParameters,
 | |
|                                     UBaseType_t uxPriority,
 | |
|                                     TaskHandle_t * const pxCreatedTask,
 | |
|                                     const BaseType_t xCoreID)
 | |
| {
 | |
|     BaseType_t ret;
 | |
|     #if ( ( configUSE_CORE_AFFINITY == 1 ) && ( configNUM_CORES > 1 ) )
 | |
|         {
 | |
|             // Convert xCoreID into an affinity mask
 | |
|             UBaseType_t uxCoreAffinityMask;
 | |
|             if (xCoreID == tskNO_AFFINITY) {
 | |
|                 uxCoreAffinityMask = tskNO_AFFINITY;
 | |
|             } else {
 | |
|                 uxCoreAffinityMask = (1 << xCoreID);
 | |
|             }
 | |
|             ret = xTaskCreateAffinitySet(pxTaskCode, pcName, usStackDepth, pvParameters, uxPriority, uxCoreAffinityMask, pxCreatedTask);
 | |
|         }
 | |
|     #else /* ( ( configUSE_CORE_AFFINITY == 1 ) && ( configNUM_CORES > 1 ) ) */
 | |
|         {
 | |
|             ret = xTaskCreate(pxTaskCode, pcName, usStackDepth, pvParameters, uxPriority, pxCreatedTask);
 | |
|         }
 | |
|     #endif /* ( ( configUSE_CORE_AFFINITY == 1 ) && ( configNUM_CORES > 1 ) ) */
 | |
|     return ret;
 | |
| }
 | |
| 
 | |
| #if ( configSUPPORT_STATIC_ALLOCATION == 1 )
 | |
| TaskHandle_t xTaskCreateStaticPinnedToCore( TaskFunction_t pxTaskCode,
 | |
|                                             const char * const pcName,
 | |
|                                             const uint32_t ulStackDepth,
 | |
|                                             void * const pvParameters,
 | |
|                                             UBaseType_t uxPriority,
 | |
|                                             StackType_t * const puxStackBuffer,
 | |
|                                             StaticTask_t * const pxTaskBuffer,
 | |
|                                             const BaseType_t xCoreID)
 | |
| {
 | |
|     TaskHandle_t ret;
 | |
|     #if ( ( configUSE_CORE_AFFINITY == 1 ) && ( configNUM_CORES > 1 ) )
 | |
|         {
 | |
|             // Convert xCoreID into an affinity mask
 | |
|             UBaseType_t uxCoreAffinityMask;
 | |
|             if (xCoreID == tskNO_AFFINITY) {
 | |
|                 uxCoreAffinityMask = tskNO_AFFINITY;
 | |
|             } else {
 | |
|                 uxCoreAffinityMask = (1 << xCoreID);
 | |
|             }
 | |
|             ret = xTaskCreateStaticAffinitySet(pxTaskCode, pcName, ulStackDepth, pvParameters, uxPriority, puxStackBuffer, pxTaskBuffer, uxCoreAffinityMask);
 | |
|         }
 | |
|     #else /* ( ( configUSE_CORE_AFFINITY == 1 ) && ( configNUM_CORES > 1 ) ) */
 | |
|         {
 | |
|             ret = xTaskCreateStatic(pxTaskCode, pcName, ulStackDepth, pvParameters, uxPriority, puxStackBuffer, pxTaskBuffer);
 | |
|         }
 | |
|     #endif /* ( ( configUSE_CORE_AFFINITY == 1 ) && ( configNUM_CORES > 1 ) ) */
 | |
|     return ret;
 | |
| }
 | |
| #endif /* configSUPPORT_STATIC_ALLOCATION */
 | |
| 
 | |
| TaskHandle_t xTaskGetCurrentTaskHandleForCPU( BaseType_t xCoreID )
 | |
| {
 | |
|     TaskHandle_t xTaskHandleTemp;
 | |
|     assert(xCoreID >= 0 && xCoreID < configNUM_CORES);
 | |
|     taskENTER_CRITICAL();
 | |
|     xTaskHandleTemp = (TaskHandle_t) pxCurrentTCBs[xCoreID];
 | |
|     taskEXIT_CRITICAL();
 | |
|     return xTaskHandleTemp;
 | |
| }
 | |
| 
 | |
| TaskHandle_t xTaskGetIdleTaskHandleForCPU( BaseType_t xCoreID )
 | |
| {
 | |
|     assert(xCoreID >= 0 && xCoreID < configNUM_CORES);
 | |
|     return (TaskHandle_t) xIdleTaskHandle[xCoreID];
 | |
| }
 | |
| 
 | |
| BaseType_t xTaskGetAffinity( TaskHandle_t xTask )
 | |
| {
 | |
|     taskENTER_CRITICAL();
 | |
|     UBaseType_t uxCoreAffinityMask;
 | |
| #if ( configUSE_CORE_AFFINITY == 1 && configNUM_CORES > 1 )
 | |
|     TCB_t *pxTCB = prvGetTCBFromHandle( xTask );
 | |
|     uxCoreAffinityMask = pxTCB->uxCoreAffinityMask;
 | |
| #else
 | |
|     uxCoreAffinityMask = tskNO_AFFINITY;
 | |
| #endif
 | |
|     taskEXIT_CRITICAL();
 | |
|     BaseType_t ret;
 | |
|     // If the task is not pinned to a particular core, treat it as tskNO_AFFINITY
 | |
|     if (uxCoreAffinityMask & (uxCoreAffinityMask - 1)) {    // If more than one bit set
 | |
|         ret = tskNO_AFFINITY;
 | |
|     } else {
 | |
|         int index_plus_one = __builtin_ffs(uxCoreAffinityMask);
 | |
|         assert(index_plus_one >= 1);
 | |
|         ret = index_plus_one - 1;
 | |
|     }
 | |
|     return ret;
 | |
| }
 | |
| 
 | |
| #if ( CONFIG_FREERTOS_TLSP_DELETION_CALLBACKS )
 | |
| void vTaskSetThreadLocalStoragePointerAndDelCallback( TaskHandle_t xTaskToSet, BaseType_t xIndex, void *pvValue, TlsDeleteCallbackFunction_t pvDelCallback)
 | |
|     {
 | |
|         // Verify that the offsets of pvThreadLocalStoragePointers and pvDummy15 match.
 | |
|         // pvDummy15 is part of the StaticTask_t struct and is used to access the TLSPs
 | |
|         // while deletion.
 | |
|         _Static_assert(offsetof( StaticTask_t, pvDummy15 ) == offsetof( TCB_t, pvThreadLocalStoragePointers ), "Offset of pvDummy15 must match the offset of pvThreadLocalStoragePointers");
 | |
| 
 | |
|         //Set the local storage pointer first
 | |
|         vTaskSetThreadLocalStoragePointer( xTaskToSet, xIndex, pvValue );
 | |
| 
 | |
|         //Set the deletion callback at an offset of configNUM_THREAD_LOCAL_STORAGE_POINTERS/2
 | |
|         vTaskSetThreadLocalStoragePointer( xTaskToSet, ( xIndex + ( configNUM_THREAD_LOCAL_STORAGE_POINTERS / 2 ) ), pvDelCallback );
 | |
|     }
 | |
| #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;
 | |
|     }
 | |
| 
 | |
| #if CONFIG_FREERTOS_SMP
 | |
|     taskENTER_CRITICAL();
 | |
| #else
 | |
|     taskENTER_CRITICAL( &xKernelLock );
 | |
| #endif
 | |
|     {
 | |
|         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
 | |
|     }
 | |
| #if CONFIG_FREERTOS_SMP
 | |
|     taskEXIT_CRITICAL();
 | |
| #else
 | |
|     taskEXIT_CRITICAL( &xKernelLock );
 | |
| #endif
 | |
| }
 | |
| 
 | |
| void prvTaskPriorityRestore( prvTaskSavedPriority_t * pxSavedPriority )
 | |
| {
 | |
|     TCB_t * pxTCB;
 | |
|     UBaseType_t uxNewPriority;
 | |
|     UBaseType_t uxPriorityUsedOnEntry;
 | |
|     UBaseType_t uxBasePriorityUsedOnEntry;
 | |
|     BaseType_t xYieldRequired = pdFALSE;
 | |
| 
 | |
| #if CONFIG_FREERTOS_SMP
 | |
|     taskENTER_CRITICAL();
 | |
| #else
 | |
|     taskENTER_CRITICAL( &xKernelLock );
 | |
| #endif
 | |
|     {
 | |
|         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
 | |
|     }
 | |
| #if CONFIG_FREERTOS_SMP
 | |
|     taskEXIT_CRITICAL();
 | |
| #else
 | |
|     taskEXIT_CRITICAL( &xKernelLock );
 | |
| #endif
 | |
| }
 | |
| 
 | |
| #endif // ( INCLUDE_vTaskPrioritySet == 1 )
 |