2023-05-10 04:22:41 -04:00
/*
2023-05-10 04:51:13 -04:00
* FreeRTOS Kernel V10 .5 .1 ( ESP - IDF SMP modified )
2023-05-10 04:22:41 -04:00
* Copyright ( C ) 2021 Amazon . com , Inc . or its affiliates . All Rights Reserved .
*
* SPDX - FileCopyrightText : 2021 Amazon . com , Inc . or its affiliates
*
* SPDX - License - Identifier : MIT
*
2024-01-02 11:14:02 -05:00
* SPDX - FileContributor : 2023 - 2024 Espressif Systems ( Shanghai ) CO LTD
2023-05-10 04:22:41 -04:00
*
* Permission is hereby granted , free of charge , to any person obtaining a copy of
* this software and associated documentation files ( the " Software " ) , to deal in
* the Software without restriction , including without limitation the rights to
* use , copy , modify , merge , publish , distribute , sublicense , and / or sell copies of
* the Software , and to permit persons to whom the Software is furnished to do so ,
* subject to the following conditions :
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software .
*
* THE SOFTWARE IS PROVIDED " AS IS " , WITHOUT WARRANTY OF ANY KIND , EXPRESS OR
* IMPLIED , INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY , FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT . IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM , DAMAGES OR OTHER LIABILITY , WHETHER
* IN AN ACTION OF CONTRACT , TORT OR OTHERWISE , ARISING FROM , OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE .
*
* https : //www.FreeRTOS.org
* https : //github.com/FreeRTOS
*
*/
/* Standard includes. */
# include <stdlib.h>
# include <string.h>
/* Defining MPU_WRAPPERS_INCLUDED_FROM_API_FILE prevents task.h from redefining
* all the API functions to use the MPU wrappers . That should only be done when
* task . h is included from an application file . */
# define MPU_WRAPPERS_INCLUDED_FROM_API_FILE
/* FreeRTOS includes. */
# include "FreeRTOS.h"
# include "task.h"
# include "timers.h"
# include "stack_macros.h"
2023-09-07 12:29:57 -04:00
/* Include private IDF API additions for critical thread safety macros */
# include "esp_private/freertos_idf_additions_priv.h"
2023-09-14 12:35:31 -04:00
# include "freertos/idf_additions.h"
2023-05-10 04:22:41 -04:00
/* Lint e9021, e961 and e750 are suppressed as a MISRA exception justified
* because the MPU ports require MPU_WRAPPERS_INCLUDED_FROM_API_FILE to be defined
* for the header files above , but not in this file , in order to generate the
* correct privileged Vs unprivileged linkage and placement . */
# undef MPU_WRAPPERS_INCLUDED_FROM_API_FILE /*lint !e961 !e750 !e9021. */
/* Set configUSE_STATS_FORMATTING_FUNCTIONS to 2 to include the stats formatting
* functions but without including stdio . h here . */
# if ( configUSE_STATS_FORMATTING_FUNCTIONS == 1 )
/* At the bottom of this file are two optional functions that can be used
* to generate human readable text from the raw data generated by the
* uxTaskGetSystemState ( ) function . Note the formatting functions are provided
* for convenience only , and are NOT considered part of the kernel . */
# include <stdio.h>
# endif /* configUSE_STATS_FORMATTING_FUNCTIONS == 1 ) */
# if ( configUSE_PREEMPTION == 0 )
/* If the cooperative scheduler is being used then a yield should not be
* performed just because a higher priority task has been woken . */
# define taskYIELD_IF_USING_PREEMPTION()
# else
# define taskYIELD_IF_USING_PREEMPTION() portYIELD_WITHIN_API()
# endif
2023-09-14 12:35:31 -04:00
# if ( configNUMBER_OF_CORES > 1 )
# define taskYIELD_CORE( xCoreID ) portYIELD_CORE( xCoreID )
# endif /* configNUMBER_OF_CORES > 1 */
2023-05-10 04:22:41 -04:00
/* Values that can be assigned to the ucNotifyState member of the TCB. */
# define taskNOT_WAITING_NOTIFICATION ( ( uint8_t ) 0 ) /* Must be zero as it is the initialised value. */
# define taskWAITING_NOTIFICATION ( ( uint8_t ) 1 )
# define taskNOTIFICATION_RECEIVED ( ( uint8_t ) 2 )
/*
* The value used to fill the stack of a task when the task is created . This
* is used purely for checking the high water mark for tasks .
*/
# define tskSTACK_FILL_BYTE ( 0xa5U )
/* Bits used to record how a task's stack and TCB were allocated. */
# define tskDYNAMICALLY_ALLOCATED_STACK_AND_TCB ( ( uint8_t ) 0 )
# define tskSTATICALLY_ALLOCATED_STACK_ONLY ( ( uint8_t ) 1 )
# define tskSTATICALLY_ALLOCATED_STACK_AND_TCB ( ( uint8_t ) 2 )
/* If any of the following are set then task stacks are filled with a known
* value so the high water mark can be determined . If none of the following are
* set then don ' t fill the stack so there is no unnecessary dependency on memset . */
# if ( ( configCHECK_FOR_STACK_OVERFLOW > 1 ) || ( configUSE_TRACE_FACILITY == 1 ) || ( INCLUDE_uxTaskGetStackHighWaterMark == 1 ) || ( INCLUDE_uxTaskGetStackHighWaterMark2 == 1 ) )
# define tskSET_NEW_STACKS_TO_KNOWN_VALUE 1
# else
# define tskSET_NEW_STACKS_TO_KNOWN_VALUE 0
# endif
/*
* Macros used by vListTask to indicate which state a task is in .
*/
# define tskRUNNING_CHAR ( 'X' )
# define tskBLOCKED_CHAR ( 'B' )
# define tskREADY_CHAR ( 'R' )
# define tskDELETED_CHAR ( 'D' )
# define tskSUSPENDED_CHAR ( 'S' )
/*
* Some kernel aware debuggers require the data the debugger needs access to to
* be global , rather than file scope .
*/
# ifdef portREMOVE_STATIC_QUALIFIER
# define static
# endif
/* The name allocated to the Idle task. This can be overridden by defining
* configIDLE_TASK_NAME in FreeRTOSConfig . h . */
# ifndef configIDLE_TASK_NAME
# define configIDLE_TASK_NAME "IDLE"
# endif
2023-09-14 12:35:31 -04:00
/*-----------------------------------------------------------*/
/* Macros to check if an unblocked task causes a yield on the current core.
* - pxTCB is the TCB of the task to check
* - uxTaskPriority is the task ' s priority
2023-11-16 06:18:17 -05:00
* - xYieldEqualPriority if the task having equal priority as the currently
* executing task should cause a yield .
*
* In single - core , this macro simply checks the unblocked task has a high enough
* priority to preempt the current task , and returns pdTRUE if so .
*
* In SMP , this macro checks if the unblocked task can preempt either core :
* - If a yield is required on the current core , this macro return pdTRUE
* - if a yield is required on the other core , this macro will internally
* trigger it .
2024-05-14 11:01:50 -04:00
*
* - In SMP , these macros must be called from a critical section ( where the
* kernel locks are taken ) .
* - In single - core , these macros must be called from a critical section or when
* the scheduler is suspended .
2023-11-16 06:18:17 -05:00
*/
2023-09-14 12:35:31 -04:00
# if ( configNUMBER_OF_CORES > 1 )
2023-11-16 06:18:17 -05:00
# define taskIS_YIELD_REQUIRED( pxTCB, xYieldEqualPriority ) prvIsYieldRequiredSMP( ( pxTCB ), ( pxTCB )->uxPriority, xYieldEqualPriority )
# define taskIS_YIELD_REQUIRED_USING_PRIORITY( pxTCB, uxTaskPriority, xYieldEqualPriority ) prvIsYieldRequiredSMP( ( pxTCB ), uxTaskPriority, xYieldEqualPriority )
2023-09-14 12:35:31 -04:00
# else
2023-11-16 06:18:17 -05:00
# define taskIS_YIELD_REQUIRED( pxTCB, xYieldEqualPriority ) \
2023-10-07 01:58:07 -04:00
( { \
( ( ( pxTCB ) - > uxPriority + ( ( xYieldEqualPriority = = pdTRUE ) ? 1 : 0 ) ) > pxCurrentTCBs [ 0 ] - > uxPriority ) ? pdTRUE : pdFALSE ; \
} )
2023-11-16 06:18:17 -05:00
# define taskIS_YIELD_REQUIRED_USING_PRIORITY( pxTCB, uxTaskPriority, xYieldEqualPriority ) \
2023-10-07 01:58:07 -04:00
( { \
2023-11-16 06:18:17 -05:00
( void ) pxTCB ; \
2023-10-07 01:58:07 -04:00
( ( uxTaskPriority + ( ( xYieldEqualPriority = = pdTRUE ) ? 1 : 0 ) ) > = pxCurrentTCBs [ 0 ] - > uxPriority ) ? pdTRUE : pdFALSE ; \
} )
2023-09-14 12:35:31 -04:00
# endif /* configNUMBER_OF_CORES > 1 */
/*-----------------------------------------------------------*/
/* Macros to check if a task has a compatible affinity with a particular core.
* - xCore is the target core
2023-11-16 06:18:17 -05:00
* - pxTCB is the task to check
2023-09-14 12:35:31 -04:00
*
* This macro will always return true on single core as the concept of core
* affinity doesn ' t exist . */
# if ( configNUMBER_OF_CORES > 1 )
2023-11-16 06:18:17 -05:00
# define taskIS_AFFINITY_COMPATIBLE( xCore, pxTCB ) ( ( ( ( pxTCB )->xCoreID == xCore ) || ( ( pxTCB )->xCoreID == tskNO_AFFINITY ) ) ? pdTRUE : pdFALSE )
2023-09-14 12:35:31 -04:00
# else
2023-11-16 06:18:17 -05:00
# define taskIS_AFFINITY_COMPATIBLE( xCore, pxTCB ) \
( { \
/* xCore and pxTCB are unused */ \
( void ) xCore ; \
( void ) pxTCB ; \
pdTRUE ; \
2023-10-07 01:58:07 -04:00
} )
2023-09-14 12:35:31 -04:00
# endif /* configNUMBER_OF_CORES > 1 */
/*-----------------------------------------------------------*/
2024-05-14 11:01:50 -04:00
/* Macros to check if a particular task is a currently running.
*
* - In SMP , these macros must be called from a critical section ( where the
* kernel lock is taken ) .
* - In single - core , these macros must be called from a critical section or when
* the scheduler is suspended */
2023-09-14 12:35:31 -04:00
# if ( configNUMBER_OF_CORES > 1 )
# define taskIS_CURRENTLY_RUNNING( pxTCB ) ( ( ( ( pxTCB ) == pxCurrentTCBs[ 0 ] ) || ( ( pxTCB ) == pxCurrentTCBs[ 1 ] ) ) ? pdTRUE : pdFALSE )
# define taskIS_CURRENTLY_RUNNING_ON_CORE( pxTCB, xCoreID ) ( ( ( pxTCB ) == pxCurrentTCBs[ ( xCoreID ) ] ) ? pdTRUE : pdFALSE )
# else
# define taskIS_CURRENTLY_RUNNING( pxTCB ) ( ( ( pxTCB ) == pxCurrentTCBs[ 0 ] ) ? pdTRUE : pdFALSE )
2023-10-07 01:58:07 -04:00
# define taskIS_CURRENTLY_RUNNING_ON_CORE( pxTCB, xCoreID ) \
( { \
/* xCoreID is unused */ \
( void ) xCoreID ; \
taskIS_CURRENTLY_RUNNING ( pxTCB ) ; \
} )
2023-09-14 12:35:31 -04:00
# endif /* configNUMBER_OF_CORES > 1 */
/*-----------------------------------------------------------*/
/* Macro to check if a particular task can currently be scheduled (i.e., is
2024-05-14 11:01:50 -04:00
* the scheduler suspended ) .
*
* - In SMP , these macros must be called from a critical section ( where the
* kernel lock is taken ) .
* - In single - core , these macros must be called from a critical section or when
* the scheduler is suspended */
2023-09-14 12:35:31 -04:00
# if ( configNUMBER_OF_CORES > 1 )
# define taskCAN_BE_SCHEDULED( pxTCB ) prvCheckTaskCanBeScheduledSMP( pxTCB )
# else
2023-10-07 01:58:07 -04:00
# define taskCAN_BE_SCHEDULED( pxTCB ) \
( { \
/* pxTCB is unused */ \
( void ) pxTCB ; \
( ( uxSchedulerSuspended [ 0 ] = = ( UBaseType_t ) 0U ) ) ? pdTRUE : pdFALSE ; \
} )
2023-09-14 12:35:31 -04:00
# endif /* configNUMBER_OF_CORES > 1 */
/*-----------------------------------------------------------*/
/* Macro to check if the scheduler is suspended (on the current core)
*
* There are various blocking tasks . c APIs that call configASSERT ( ) to check if
* the API is being called while the scheduler is suspended . However , these
* asserts are done outside a critical section or interrupt disabled block .
* Directly checking uxSchedulerSuspended [ portGET_CORE_ID ( ) ] outside a
* critical section can lead to false positives in SMP . Thus for SMP , we call
* xTaskGetSchedulerState ( ) instead .
*
* Take the following example of an unpinned Task A in SMP calling
* uxSchedulerSuspended [ portGET_CORE_ID ( ) ] :
* - Task A calls portGET_CORE_ID ( ) which is 0
* - Task A gets preempted by Task B , Task A switches to core 1
* - Task B on core 0 calls vTaskSuspendAll ( )
* - Task A checks uxSchedulerSuspended [ 0 ] leading to a false positive
*/
# if ( configNUMBER_OF_CORES > 1 )
# define taskIS_SCHEDULER_SUSPENDED() ( ( xTaskGetSchedulerState() == taskSCHEDULER_SUSPENDED ) ? pdTRUE : pdFALSE )
# else
# define taskIS_SCHEDULER_SUSPENDED() ( ( ( uxSchedulerSuspended[ 0 ] != ( UBaseType_t ) 0U ) ) ? pdTRUE : pdFALSE )
# endif /* configNUMBER_OF_CORES > 1 */
/*-----------------------------------------------------------*/
2023-05-10 04:22:41 -04:00
# if ( configUSE_PORT_OPTIMISED_TASK_SELECTION == 0 )
/* If configUSE_PORT_OPTIMISED_TASK_SELECTION is 0 then task selection is
* performed in a generic way that is not optimised to any particular
* microcontroller architecture . */
/* uxTopReadyPriority holds the priority of the highest priority ready
* state task . */
# define taskRECORD_READY_PRIORITY( uxPriority ) \
{ \
if ( ( uxPriority ) > uxTopReadyPriority ) \
{ \
uxTopReadyPriority = ( uxPriority ) ; \
} \
} /* taskRECORD_READY_PRIORITY */
/*-----------------------------------------------------------*/
2023-09-14 12:35:31 -04:00
# if ( configNUMBER_OF_CORES > 1 )
# define taskSELECT_HIGHEST_PRIORITY_TASK() prvSelectHighestPriorityTaskSMP()
# else /* if ( configNUMBER_OF_CORES > 1 ) */
# define taskSELECT_HIGHEST_PRIORITY_TASK() \
2023-05-10 04:22:41 -04:00
{ \
UBaseType_t uxTopPriority = uxTopReadyPriority ; \
\
/* Find the highest priority queue that contains ready tasks. */ \
while ( listLIST_IS_EMPTY ( & ( pxReadyTasksLists [ uxTopPriority ] ) ) ) \
{ \
configASSERT ( uxTopPriority ) ; \
- - uxTopPriority ; \
} \
\
/* listGET_OWNER_OF_NEXT_ENTRY indexes through the list, so the tasks of \
2023-09-14 12:35:31 -04:00
* the same priority get an equal share of the processor time . */ \
listGET_OWNER_OF_NEXT_ENTRY ( pxCurrentTCBs [ 0 ] , & ( pxReadyTasksLists [ uxTopPriority ] ) ) ; \
uxTopReadyPriority = uxTopPriority ; \
2023-05-10 04:22:41 -04:00
} /* taskSELECT_HIGHEST_PRIORITY_TASK */
2023-09-14 12:35:31 -04:00
# endif /* if ( configNUMBER_OF_CORES > 1 ) */
2023-05-10 04:22:41 -04:00
/*-----------------------------------------------------------*/
/* Define away taskRESET_READY_PRIORITY() and portRESET_READY_PRIORITY() as
* they are only required when a port optimised method of task selection is
* being used . */
# define taskRESET_READY_PRIORITY( uxPriority )
# define portRESET_READY_PRIORITY( uxPriority, uxTopReadyPriority )
# else /* configUSE_PORT_OPTIMISED_TASK_SELECTION */
/* If configUSE_PORT_OPTIMISED_TASK_SELECTION is 1 then task selection is
* performed in a way that is tailored to the particular microcontroller
* architecture being used . */
/* A port optimised version is provided. Call the port defined macros. */
# define taskRECORD_READY_PRIORITY( uxPriority ) portRECORD_READY_PRIORITY( ( uxPriority ), uxTopReadyPriority )
/*-----------------------------------------------------------*/
2023-09-14 12:35:31 -04:00
# define taskSELECT_HIGHEST_PRIORITY_TASK() \
{ \
UBaseType_t uxTopPriority ; \
\
/* Find the highest priority list that contains ready tasks. */ \
portGET_HIGHEST_PRIORITY ( uxTopPriority , uxTopReadyPriority ) ; \
configASSERT ( listCURRENT_LIST_LENGTH ( & ( pxReadyTasksLists [ uxTopPriority ] ) ) > 0 ) ; \
listGET_OWNER_OF_NEXT_ENTRY ( pxCurrentTCBs [ 0 ] , & ( pxReadyTasksLists [ uxTopPriority ] ) ) ; \
2023-05-10 04:22:41 -04:00
} /* taskSELECT_HIGHEST_PRIORITY_TASK() */
/*-----------------------------------------------------------*/
/* A port optimised version is provided, call it only if the TCB being reset
* is being referenced from a ready list . If it is referenced from a delayed
* or suspended list then it won ' t be in a ready list . */
# define taskRESET_READY_PRIORITY( uxPriority ) \
{ \
if ( listCURRENT_LIST_LENGTH ( & ( pxReadyTasksLists [ ( uxPriority ) ] ) ) = = ( UBaseType_t ) 0 ) \
{ \
portRESET_READY_PRIORITY ( ( uxPriority ) , ( uxTopReadyPriority ) ) ; \
} \
}
# endif /* configUSE_PORT_OPTIMISED_TASK_SELECTION */
/*-----------------------------------------------------------*/
/* pxDelayedTaskList and pxOverflowDelayedTaskList are switched when the tick
* count overflows . */
# define taskSWITCH_DELAYED_LISTS() \
{ \
List_t * pxTemp ; \
\
/* The delayed tasks list should be empty when the lists are switched. */ \
configASSERT ( ( listLIST_IS_EMPTY ( pxDelayedTaskList ) ) ) ; \
\
pxTemp = pxDelayedTaskList ; \
pxDelayedTaskList = pxOverflowDelayedTaskList ; \
pxOverflowDelayedTaskList = pxTemp ; \
xNumOfOverflows + + ; \
prvResetNextTaskUnblockTime ( ) ; \
}
/*-----------------------------------------------------------*/
/*
* Place the task represented by pxTCB into the appropriate ready list for
* the task . It is inserted at the end of the list .
*/
# define prvAddTaskToReadyList( pxTCB ) \
traceMOVED_TASK_TO_READY_STATE ( pxTCB ) ; \
taskRECORD_READY_PRIORITY ( ( pxTCB ) - > uxPriority ) ; \
listINSERT_END ( & ( pxReadyTasksLists [ ( pxTCB ) - > uxPriority ] ) , & ( ( pxTCB ) - > xStateListItem ) ) ; \
tracePOST_MOVED_TASK_TO_READY_STATE ( pxTCB )
/*-----------------------------------------------------------*/
/*
* Several functions take a TaskHandle_t parameter that can optionally be NULL ,
* where NULL is used to indicate that the handle of the currently executing
* task should be used in place of the parameter . This macro simply checks to
* see if the parameter is NULL and returns a pointer to the appropriate TCB .
2023-09-14 12:35:31 -04:00
*
* In SMP , calling xTaskGetCurrentTaskHandle ( ) ensures atomic access to pxCurrentTCBs
2023-05-10 04:22:41 -04:00
*/
2023-09-14 12:35:31 -04:00
# if ( configNUMBER_OF_CORES > 1 )
# define prvGetTCBFromHandle( pxHandle ) ( ( ( pxHandle ) == NULL ) ? xTaskGetCurrentTaskHandle() : ( pxHandle ) )
# else
# define prvGetTCBFromHandle( pxHandle ) ( ( ( pxHandle ) == NULL ) ? pxCurrentTCBs[ 0 ] : ( pxHandle ) )
# endif
2023-05-10 04:22:41 -04:00
/* The item value of the event list item is normally used to hold the priority
* of the task to which it belongs ( coded to allow it to be held in reverse
* priority order ) . However , it is occasionally borrowed for other purposes . It
* is important its value is not updated due to a task priority change while it is
* being used for another purpose . The following bit definition is used to inform
* the scheduler that the value should not be changed - in which case it is the
* responsibility of whichever module is using the value to ensure it gets set back
* to its original value when it is released . */
# if ( configUSE_16_BIT_TICKS == 1 )
# define taskEVENT_LIST_ITEM_VALUE_IN_USE 0x8000U
# else
# define taskEVENT_LIST_ITEM_VALUE_IN_USE 0x80000000UL
# endif
/*
* Task control block . A task control block ( TCB ) is allocated for each task ,
* and stores task state information , including a pointer to the task ' s context
* ( the task ' s run time environment , including register values )
*/
typedef struct tskTaskControlBlock /* The old naming convention is used to prevent breaking kernel aware debuggers. */
{
volatile StackType_t * pxTopOfStack ; /*< Points to the location of the last item placed on the tasks stack. THIS MUST BE THE FIRST MEMBER OF THE TCB STRUCT. */
# if ( portUSING_MPU_WRAPPERS == 1 )
xMPU_SETTINGS xMPUSettings ; /*< The MPU settings are defined as part of the port layer. THIS MUST BE THE SECOND MEMBER OF THE TCB STRUCT. */
# endif
ListItem_t xStateListItem ; /*< The list that the state list item of a task is reference from denotes the state of that task (Ready, Blocked, Suspended ). */
ListItem_t xEventListItem ; /*< Used to reference a task from an event list. */
UBaseType_t uxPriority ; /*< The priority of the task. 0 is the lowest priority. */
StackType_t * pxStack ; /*< Points to the start of the stack. */
char pcTaskName [ configMAX_TASK_NAME_LEN ] ; /*< Descriptive name given to the task when created. Facilitates debugging only. */ /*lint !e971 Unqualified char types are allowed for strings and single characters only. */
2023-11-16 06:41:24 -05:00
# if ( configNUMBER_OF_CORES > 1 )
BaseType_t xCoreID ; /*< The core that this task is pinned to */
# endif /* configNUMBER_OF_CORES > 1 */
2023-09-14 12:35:31 -04:00
2023-05-10 04:22:41 -04:00
# if ( ( portSTACK_GROWTH > 0 ) || ( configRECORD_STACK_HIGH_ADDRESS == 1 ) )
StackType_t * pxEndOfStack ; /*< Points to the highest valid address for the stack. */
# endif
# if ( portCRITICAL_NESTING_IN_TCB == 1 )
UBaseType_t uxCriticalNesting ; /*< Holds the critical section nesting depth for ports that do not maintain their own count in the port layer. */
# endif
# if ( configUSE_TRACE_FACILITY == 1 )
UBaseType_t uxTCBNumber ; /*< Stores a number that increments each time a TCB is created. It allows debuggers to determine when a task has been deleted and then recreated. */
UBaseType_t uxTaskNumber ; /*< Stores a number specifically for use by third party trace code. */
# endif
# if ( configUSE_MUTEXES == 1 )
UBaseType_t uxBasePriority ; /*< The priority last assigned to the task - used by the priority inheritance mechanism. */
UBaseType_t uxMutexesHeld ;
# endif
# if ( configUSE_APPLICATION_TASK_TAG == 1 )
TaskHookFunction_t pxTaskTag ;
# endif
# if ( configNUM_THREAD_LOCAL_STORAGE_POINTERS > 0 )
void * pvThreadLocalStoragePointers [ configNUM_THREAD_LOCAL_STORAGE_POINTERS ] ;
# endif
# if ( configGENERATE_RUN_TIME_STATS == 1 )
configRUN_TIME_COUNTER_TYPE ulRunTimeCounter ; /*< Stores the amount of time the task has spent in the Running state. */
# endif
# if ( ( configUSE_NEWLIB_REENTRANT == 1 ) || ( configUSE_C_RUNTIME_TLS_SUPPORT == 1 ) )
configTLS_BLOCK_TYPE xTLSBlock ; /*< Memory block used as Thread Local Storage (TLS) Block for the task. */
# endif
# if ( configUSE_TASK_NOTIFICATIONS == 1 )
volatile uint32_t ulNotifiedValue [ configTASK_NOTIFICATION_ARRAY_ENTRIES ] ;
volatile uint8_t ucNotifyState [ configTASK_NOTIFICATION_ARRAY_ENTRIES ] ;
# endif
/* See the comments in FreeRTOS.h with the definition of
* tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE . */
# if ( tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE != 0 ) /*lint !e731 !e9029 Macro has been consolidated for readability reasons. */
uint8_t ucStaticallyAllocated ; /*< Set to pdTRUE if the task is a statically allocated to ensure no attempt is made to free the memory. */
# endif
# if ( INCLUDE_xTaskAbortDelay == 1 )
uint8_t ucDelayAborted ;
# endif
# if ( configUSE_POSIX_ERRNO == 1 )
int iTaskErrno ;
# endif
} tskTCB ;
/* The old tskTCB name is maintained above then typedefed to the new TCB_t name
* below to enable the use of older kernel aware debuggers . */
typedef tskTCB TCB_t ;
/*lint -save -e956 A manual analysis and inspection has been used to determine
* which static variables must be declared volatile . */
2023-09-14 12:35:31 -04:00
portDONT_DISCARD PRIVILEGED_DATA TCB_t * volatile pxCurrentTCBs [ configNUMBER_OF_CORES ] = { NULL } ;
2023-05-10 04:22:41 -04:00
/* Lists for ready and blocked tasks. --------------------
* xDelayedTaskList1 and xDelayedTaskList2 could be moved to function scope but
* doing so breaks some kernel aware debuggers and debuggers that rely on removing
* the static qualifier . */
2023-09-14 12:35:31 -04:00
PRIVILEGED_DATA static List_t pxReadyTasksLists [ configMAX_PRIORITIES ] ; /*< Prioritised ready tasks. */
PRIVILEGED_DATA static List_t xDelayedTaskList1 ; /*< Delayed tasks. */
PRIVILEGED_DATA static List_t xDelayedTaskList2 ; /*< Delayed tasks (two lists are used - one for delays that have overflowed the current tick count. */
PRIVILEGED_DATA static List_t * volatile pxDelayedTaskList ; /*< Points to the delayed task list currently being used. */
PRIVILEGED_DATA static List_t * volatile pxOverflowDelayedTaskList ; /*< Points to the delayed task list currently being used to hold tasks that have overflowed the current tick count. */
PRIVILEGED_DATA static List_t xPendingReadyList [ configNUMBER_OF_CORES ] ; /*< Tasks that have been readied while the scheduler was suspended. They will be moved to the ready list when the scheduler is resumed. */
2023-05-10 04:22:41 -04:00
# if ( INCLUDE_vTaskDelete == 1 )
PRIVILEGED_DATA static List_t xTasksWaitingTermination ; /*< Tasks that have been deleted - but their memory not yet freed. */
PRIVILEGED_DATA static volatile UBaseType_t uxDeletedTasksWaitingCleanUp = ( UBaseType_t ) 0U ;
# endif
# if ( INCLUDE_vTaskSuspend == 1 )
PRIVILEGED_DATA static List_t xSuspendedTaskList ; /*< Tasks that are currently suspended. */
# endif
/* Global POSIX errno. Its value is changed upon context switching to match
* the errno of the currently running task . */
# if ( configUSE_POSIX_ERRNO == 1 )
int FreeRTOS_errno = 0 ;
# endif
/* Other file private variables. --------------------------------*/
PRIVILEGED_DATA static volatile UBaseType_t uxCurrentNumberOfTasks = ( UBaseType_t ) 0U ;
PRIVILEGED_DATA static volatile TickType_t xTickCount = ( TickType_t ) configINITIAL_TICK_COUNT ;
PRIVILEGED_DATA static volatile UBaseType_t uxTopReadyPriority = tskIDLE_PRIORITY ;
PRIVILEGED_DATA static volatile BaseType_t xSchedulerRunning = pdFALSE ;
PRIVILEGED_DATA static volatile TickType_t xPendedTicks = ( TickType_t ) 0U ;
2023-09-14 12:35:31 -04:00
PRIVILEGED_DATA static volatile BaseType_t xYieldPending [ configNUMBER_OF_CORES ] = { pdFALSE } ;
2023-05-10 04:22:41 -04:00
PRIVILEGED_DATA static volatile BaseType_t xNumOfOverflows = ( BaseType_t ) 0 ;
PRIVILEGED_DATA static UBaseType_t uxTaskNumber = ( UBaseType_t ) 0U ;
2023-09-14 12:35:31 -04:00
PRIVILEGED_DATA static volatile TickType_t xNextTaskUnblockTime = ( TickType_t ) 0U ; /* Initialised to portMAX_DELAY before the scheduler starts. */
PRIVILEGED_DATA static TaskHandle_t xIdleTaskHandle [ configNUMBER_OF_CORES ] = { NULL } ; /*< Holds the handle of the idle task. The idle task is created automatically when the scheduler is started. */
2023-05-10 04:22:41 -04:00
/* Improve support for OpenOCD. The kernel tracks Ready tasks via priority lists.
* For tracking the state of remote threads , OpenOCD uses uxTopUsedPriority
* to determine the number of priority lists to read back from the remote target . */
const volatile UBaseType_t uxTopUsedPriority = configMAX_PRIORITIES - 1U ;
/* Context switches are held pending while the scheduler is suspended. Also,
* interrupts must not manipulate the xStateListItem of a TCB , or any of the
* lists the xStateListItem can be referenced from , if the scheduler is suspended .
* If an interrupt needs to unblock a task while the scheduler is suspended then it
* moves the task ' s event list item into the xPendingReadyList , ready for the
* kernel to move the task from the pending ready list into the real ready list
* when the scheduler is unsuspended . The pending ready list itself can only be
* accessed from a critical section . */
2023-09-14 12:35:31 -04:00
PRIVILEGED_DATA static volatile UBaseType_t uxSchedulerSuspended [ configNUMBER_OF_CORES ] = { ( UBaseType_t ) pdFALSE } ;
2023-05-10 04:22:41 -04:00
# if ( configGENERATE_RUN_TIME_STATS == 1 )
/* Do not move these variables to function scope as doing so prevents the
* code working with debuggers that need to remove the static qualifier . */
2023-09-14 12:35:31 -04:00
PRIVILEGED_DATA static configRUN_TIME_COUNTER_TYPE ulTaskSwitchedInTime [ configNUMBER_OF_CORES ] = { 0UL } ; /*< Holds the value of a timer/counter the last time a task was switched in. */
PRIVILEGED_DATA static volatile configRUN_TIME_COUNTER_TYPE ulTotalRunTime = 0UL ; /*< Holds the total amount of execution time as defined by the run time counter clock. */
2023-05-10 04:22:41 -04:00
# endif
2023-09-07 12:29:57 -04:00
/* Spinlock required for SMP critical sections. This lock protects all of the
* kernel ' s data structures such as various tasks lists , flags , and tick counts . */
PRIVILEGED_DATA static portMUX_TYPE xKernelLock = portMUX_INITIALIZER_UNLOCKED ;
2023-05-10 04:22:41 -04:00
/*lint -restore */
/*-----------------------------------------------------------*/
/* File private functions. --------------------------------*/
2023-09-08 10:13:06 -04:00
/*
* Creates the idle tasks during scheduler start .
*/
static BaseType_t prvCreateIdleTasks ( void ) ;
2023-09-14 12:35:31 -04:00
/**
* Utility function to check whether a yield ( on either core ) is required after
* unblocking ( or changing the priority of ) a particular task .
*
* - This function is the SMP replacement for checking if an unblocked task has
* a higher ( or equal ) priority than the current task .
* - It should be called before calling taskYIELD_IF_USING_PREEMPTION ( ) or
* before setting xYieldRequired
* - If it is the other core that requires a yield , this function will
* internally trigger the other core to yield
*
* Note : In some special instances , a yield is triggered if the unblocked task
* has an equal priority ( such as in xTaskResumeAll ) . Thus the
* xYieldEqualPriority parameter specifies whether to yield if the current
* task has equal priority .
*
* Scheduling Algorithm :
* This function will bias towards yielding the current core .
* - If the unblocked task has a higher ( or equal ) priority than the current
* core , the current core is yielded regardless of the current priority of the
* other core .
* - A core ( current or other ) will only yield if their schedulers are not
* suspended .
*
* Todo : This can be optimized ( IDF - 5772 )
*
* Entry :
* - This function must be called in a critical section
* - A task must just have been unblocked , or its priority raised
* Exit :
* - Returns pdTRUE if the current core requires yielding
* - The other core will be triggered to yield if required
2024-05-14 11:01:50 -04:00
*
* @ note This function must be called from a critical section where the kernel
* lock is taken ) .
2023-09-14 12:35:31 -04:00
*/
# if ( configNUMBER_OF_CORES > 1 )
2023-11-16 06:18:17 -05:00
static BaseType_t prvIsYieldRequiredSMP ( TCB_t * pxTCB ,
UBaseType_t uxTaskPriority ,
BaseType_t xYieldEqualPriority ) PRIVILEGED_FUNCTION ;
2023-09-14 12:35:31 -04:00
# endif /* configNUMBER_OF_CORES > 1 */
/**
* Utility function to check whether a task can currently be scheduled on one
* or more cores . This function is the SMP replacement for checking if
* ` uxSchedulerSuspended = = 0 ` .
*
* - If a task is pinned , check the scheduler suspension state on the task ' s
* pinned core . The task can be scheduled if the scheduler is not suspended on
* the pinned core .
* - If a task is unpinned , check the scheduler suspension state on both cores .
* The task can be scheduled if the scheduler is not suspended on either of
* the cores .
2024-05-14 11:01:50 -04:00
*
* @ note This function must be called from a critical section ( where the kernel
* lock is taken ) .
2023-09-14 12:35:31 -04:00
*/
# if ( configNUMBER_OF_CORES > 1 )
static BaseType_t prvCheckTaskCanBeScheduledSMP ( TCB_t * pxTCB ) PRIVILEGED_FUNCTION ;
# endif /* configNUMBER_OF_CORES > 1 */
/**
* Utility function to select the highest priority and runnable task for the
* current core .
*/
# if ( configNUMBER_OF_CORES > 1 )
static void prvSelectHighestPriorityTaskSMP ( void ) PRIVILEGED_FUNCTION ;
# endif /* configNUMBER_OF_CORES > 1 */
2023-05-10 04:22:41 -04:00
/**
* Utility task that simply returns pdTRUE if the task referenced by xTask is
* currently in the Suspended state , or pdFALSE if the task referenced by xTask
* is in any other state .
*/
# if ( INCLUDE_vTaskSuspend == 1 )
static BaseType_t prvTaskIsTaskSuspended ( const TaskHandle_t xTask ) PRIVILEGED_FUNCTION ;
# endif /* INCLUDE_vTaskSuspend */
/*
* Utility to ready all the lists used by the scheduler . This is called
* automatically upon the creation of the first task .
*/
static void prvInitialiseTaskLists ( void ) PRIVILEGED_FUNCTION ;
/*
* The idle task , which as all tasks is implemented as a never ending loop .
* The idle task is automatically created and added to the ready lists upon
* creation of the first user task .
*
* The portTASK_FUNCTION_PROTO ( ) macro is used to allow port / compiler specific
* language extensions . The equivalent prototype for this function is :
*
* void prvIdleTask ( void * pvParameters ) ;
*
*/
static portTASK_FUNCTION_PROTO ( prvIdleTask , pvParameters ) PRIVILEGED_FUNCTION ;
/*
* Utility to free all memory allocated by the scheduler to hold a TCB ,
* including the stack pointed to by the TCB .
*
* This does not free memory allocated by the task itself ( i . e . memory
* allocated by calls to pvPortMalloc from within the tasks application code ) .
*/
# if ( INCLUDE_vTaskDelete == 1 )
static void prvDeleteTCB ( TCB_t * pxTCB ) PRIVILEGED_FUNCTION ;
# endif
/*
* Used only by the idle task . This checks to see if anything has been placed
* in the list of tasks waiting to be deleted . If so the task is cleaned up
* and its TCB deleted .
*/
static void prvCheckTasksWaitingTermination ( void ) PRIVILEGED_FUNCTION ;
/*
* The currently executing task is entering the Blocked state . Add the task to
* either the current or the overflow delayed task list .
*/
static void prvAddCurrentTaskToDelayedList ( TickType_t xTicksToWait ,
const BaseType_t xCanBlockIndefinitely ) PRIVILEGED_FUNCTION ;
/*
* Fills an TaskStatus_t structure with information on each task that is
* referenced from the pxList list ( which may be a ready list , a delayed list ,
* a suspended list , etc . ) .
*
* THIS FUNCTION IS INTENDED FOR DEBUGGING ONLY , AND SHOULD NOT BE CALLED FROM
* NORMAL APPLICATION CODE .
*/
# if ( configUSE_TRACE_FACILITY == 1 )
static UBaseType_t prvListTasksWithinSingleList ( TaskStatus_t * pxTaskStatusArray ,
List_t * pxList ,
eTaskState eState ) PRIVILEGED_FUNCTION ;
# endif
/*
* Searches pxList for a task with name pcNameToQuery - returning a handle to
* the task if it is found , or NULL if the task is not found .
*/
# if ( INCLUDE_xTaskGetHandle == 1 )
static TCB_t * prvSearchForNameWithinSingleList ( List_t * pxList ,
const char pcNameToQuery [ ] ) PRIVILEGED_FUNCTION ;
# endif
/*
* When a task is created , the stack of the task is filled with a known value .
* This function determines the ' high water mark ' of the task stack by
* determining how much of the stack remains at the original preset value .
*/
# if ( ( configUSE_TRACE_FACILITY == 1 ) || ( INCLUDE_uxTaskGetStackHighWaterMark == 1 ) || ( INCLUDE_uxTaskGetStackHighWaterMark2 == 1 ) )
static configSTACK_DEPTH_TYPE prvTaskCheckFreeStackSpace ( const uint8_t * pucStackByte ) PRIVILEGED_FUNCTION ;
# endif
/*
* Return the amount of time , in ticks , that will pass before the kernel will
* next move a task from the Blocked state to the Running state .
*
* This conditional compilation should use inequality to 0 , not equality to 1.
* This is to ensure portSUPPRESS_TICKS_AND_SLEEP ( ) can be called when user
* defined low power mode implementations require configUSE_TICKLESS_IDLE to be
* set to a value other than 1.
*/
# if ( configUSE_TICKLESS_IDLE != 0 )
static TickType_t prvGetExpectedIdleTime ( void ) PRIVILEGED_FUNCTION ;
# endif
/*
* Set xNextTaskUnblockTime to the time at which the next Blocked state task
* will exit the Blocked state .
*/
static void prvResetNextTaskUnblockTime ( void ) PRIVILEGED_FUNCTION ;
# if ( configUSE_STATS_FORMATTING_FUNCTIONS > 0 )
/*
* Helper function used to pad task names with spaces when printing out
* human readable tables of task information .
*/
static char * prvWriteNameToBuffer ( char * pcBuffer ,
const char * pcTaskName ) PRIVILEGED_FUNCTION ;
# endif
/*
* Called after a Task_t structure has been allocated either statically or
* dynamically to fill in the structure ' s members .
*/
static void prvInitialiseNewTask ( TaskFunction_t pxTaskCode ,
const char * const pcName , /*lint !e971 Unqualified char types are allowed for strings and single characters only. */
const uint32_t ulStackDepth ,
void * const pvParameters ,
UBaseType_t uxPriority ,
TaskHandle_t * const pxCreatedTask ,
TCB_t * pxNewTCB ,
2023-09-14 12:35:31 -04:00
const MemoryRegion_t * const xRegions ,
BaseType_t xCoreID ) PRIVILEGED_FUNCTION ;
2023-05-10 04:22:41 -04:00
/*
* Called after a new task has been created and initialised to place the task
* under the control of the scheduler .
*/
static void prvAddNewTaskToReadyList ( TCB_t * pxNewTCB ) PRIVILEGED_FUNCTION ;
/*
* freertos_tasks_c_additions_init ( ) should only be called if the user definable
* macro FREERTOS_TASKS_C_ADDITIONS_INIT ( ) is defined , as that is the only macro
* called by the function .
*/
# ifdef FREERTOS_TASKS_C_ADDITIONS_INIT
static void freertos_tasks_c_additions_init ( void ) PRIVILEGED_FUNCTION ;
# endif
/*-----------------------------------------------------------*/
2023-09-14 12:35:31 -04:00
# if ( configNUMBER_OF_CORES > 1 )
2023-05-10 04:22:41 -04:00
2023-11-16 06:18:17 -05:00
static BaseType_t prvIsYieldRequiredSMP ( TCB_t * pxTCB ,
UBaseType_t uxTaskPriority ,
BaseType_t xYieldEqualPriority )
2023-05-10 04:22:41 -04:00
{
2024-05-14 11:01:50 -04:00
/* This function must be called from a critical section (where the kernel
* lock is taken ) . */
2023-09-14 12:35:31 -04:00
configASSERT ( uxTaskPriority < configMAX_PRIORITIES ) ;
2023-11-16 06:18:17 -05:00
/* Save core ID as we can no longer be preempted. */
const BaseType_t xCurCoreID = portGET_CORE_ID ( ) ;
2023-09-14 12:35:31 -04:00
if ( xYieldEqualPriority = = pdTRUE )
{
/* Increment the task priority to achieve the same affect as
* if ( uxTaskPriority > = pxCurrentTCBs - > uxPriority ) . */
uxTaskPriority + + ;
}
2023-05-10 04:22:41 -04:00
2023-09-14 12:35:31 -04:00
/* Indicate whether the current core needs to yield */
BaseType_t xYieldRequiredCurrentCore ;
2023-05-10 04:22:41 -04:00
2023-09-14 12:35:31 -04:00
/* If the target task can run on the current core, and has a higher
* priority than the current core , and the core has not suspended
* scheduling , then yield the current core .
* Todo : Make fair scheduling a configurable option ( IDF - 5772 ) . */
2023-11-16 06:18:17 -05:00
if ( ( taskIS_AFFINITY_COMPATIBLE ( xCurCoreID , pxTCB ) = = pdTRUE ) & &
2023-09-14 12:35:31 -04:00
( uxTaskPriority > pxCurrentTCBs [ xCurCoreID ] - > uxPriority ) & &
( uxSchedulerSuspended [ xCurCoreID ] = = ( UBaseType_t ) 0U ) )
2023-05-10 04:22:41 -04:00
{
2023-09-14 12:35:31 -04:00
/* Return true for the caller to yield the current core */
xYieldRequiredCurrentCore = pdTRUE ;
2023-05-10 04:22:41 -04:00
}
2023-09-14 12:35:31 -04:00
/* If the target task can run on the other core, and has a higher
* priority then the other core , and the other core has not suspended
* scheduling , then yield the other core */
2023-11-16 06:18:17 -05:00
else if ( ( taskIS_AFFINITY_COMPATIBLE ( ! xCurCoreID , pxTCB ) = = pdTRUE ) & &
2023-09-14 12:35:31 -04:00
( uxTaskPriority > pxCurrentTCBs [ ! xCurCoreID ] - > uxPriority ) & &
( uxSchedulerSuspended [ ! xCurCoreID ] = = ( UBaseType_t ) 0U ) )
2023-05-10 04:22:41 -04:00
{
2023-09-14 12:35:31 -04:00
/* Signal the other core to yield */
taskYIELD_CORE ( ! xCurCoreID ) ;
xYieldRequiredCurrentCore = pdFALSE ;
}
else
{
xYieldRequiredCurrentCore = pdFALSE ;
}
return xYieldRequiredCurrentCore ;
}
# endif /* configNUMBER_OF_CORES > 1 */
/*-----------------------------------------------------------*/
2023-05-10 04:22:41 -04:00
2023-09-14 12:35:31 -04:00
# if ( configNUMBER_OF_CORES > 1 )
static BaseType_t prvCheckTaskCanBeScheduledSMP ( TCB_t * pxTCB )
{
2024-05-14 11:01:50 -04:00
/* This function must be called from a critical section (where the kernel
* lock is taken ) . */
2023-09-14 12:35:31 -04:00
BaseType_t xReturn ;
if ( pxTCB - > xCoreID = = tskNO_AFFINITY )
{
/* Task is unpinned. As long as one core has not suspended
* scheduling , the task can be scheduled . */
if ( ( uxSchedulerSuspended [ 0 ] = = ( UBaseType_t ) 0U ) | | ( uxSchedulerSuspended [ 1 ] = = ( UBaseType_t ) 0U ) )
2023-05-10 04:22:41 -04:00
{
2023-09-14 12:35:31 -04:00
xReturn = pdTRUE ;
}
else
{
xReturn = pdFALSE ;
2023-05-10 04:22:41 -04:00
}
2023-09-14 12:35:31 -04:00
}
else if ( uxSchedulerSuspended [ pxTCB - > xCoreID ] = = ( UBaseType_t ) 0U )
{
/* The task is pinned to a core. If it's pinned core has not
* suspended scheduling , the task can be scheduled . */
xReturn = pdTRUE ;
2023-05-10 04:22:41 -04:00
}
else
{
2023-09-14 12:35:31 -04:00
xReturn = pdFALSE ;
2023-05-10 04:22:41 -04:00
}
return xReturn ;
}
2023-09-14 12:35:31 -04:00
# endif /* configNUMBER_OF_CORES > 1 */
2023-05-10 04:22:41 -04:00
/*-----------------------------------------------------------*/
# if ( ( portUSING_MPU_WRAPPERS == 1 ) && ( configSUPPORT_STATIC_ALLOCATION == 1 ) )
2023-09-14 12:35:31 -04:00
/* Todo: Add support for task restricted API (IDF-7895) */
2023-05-10 04:22:41 -04:00
BaseType_t xTaskCreateRestrictedStatic ( const TaskParameters_t * const pxTaskDefinition ,
TaskHandle_t * pxCreatedTask )
{
TCB_t * pxNewTCB ;
BaseType_t xReturn = errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY ;
configASSERT ( pxTaskDefinition - > puxStackBuffer ! = NULL ) ;
configASSERT ( pxTaskDefinition - > pxTaskBuffer ! = NULL ) ;
if ( ( pxTaskDefinition - > puxStackBuffer ! = NULL ) & & ( pxTaskDefinition - > pxTaskBuffer ! = NULL ) )
{
/* Allocate space for the TCB. Where the memory comes from depends
* on the implementation of the port malloc function and whether or
* not static allocation is being used . */
pxNewTCB = ( TCB_t * ) pxTaskDefinition - > pxTaskBuffer ;
memset ( ( void * ) pxNewTCB , 0x00 , sizeof ( TCB_t ) ) ;
/* Store the stack location in the TCB. */
pxNewTCB - > pxStack = pxTaskDefinition - > puxStackBuffer ;
# if ( tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE != 0 )
{
/* Tasks can be created statically or dynamically, so note this
* task was created statically in case the task is later deleted . */
pxNewTCB - > ucStaticallyAllocated = tskSTATICALLY_ALLOCATED_STACK_AND_TCB ;
}
# endif /* tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE */
prvInitialiseNewTask ( pxTaskDefinition - > pvTaskCode ,
pxTaskDefinition - > pcName ,
( uint32_t ) pxTaskDefinition - > usStackDepth ,
pxTaskDefinition - > pvParameters ,
pxTaskDefinition - > uxPriority ,
pxCreatedTask , pxNewTCB ,
pxTaskDefinition - > xRegions ) ;
prvAddNewTaskToReadyList ( pxNewTCB ) ;
xReturn = pdPASS ;
}
return xReturn ;
}
# endif /* ( portUSING_MPU_WRAPPERS == 1 ) && ( configSUPPORT_STATIC_ALLOCATION == 1 ) */
/*-----------------------------------------------------------*/
# if ( ( portUSING_MPU_WRAPPERS == 1 ) && ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) )
2023-09-14 12:35:31 -04:00
/* Todo: Add support for task restricted API (IDF-7895) */
2023-05-10 04:22:41 -04:00
BaseType_t xTaskCreateRestricted ( const TaskParameters_t * const pxTaskDefinition ,
TaskHandle_t * pxCreatedTask )
{
TCB_t * pxNewTCB ;
BaseType_t xReturn = errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY ;
configASSERT ( pxTaskDefinition - > puxStackBuffer ) ;
if ( pxTaskDefinition - > puxStackBuffer ! = NULL )
{
/* Allocate space for the TCB. Where the memory comes from depends
* on the implementation of the port malloc function and whether or
* not static allocation is being used . */
pxNewTCB = ( TCB_t * ) pvPortMalloc ( sizeof ( TCB_t ) ) ;
if ( pxNewTCB ! = NULL )
{
memset ( ( void * ) pxNewTCB , 0x00 , sizeof ( TCB_t ) ) ;
/* Store the stack location in the TCB. */
pxNewTCB - > pxStack = pxTaskDefinition - > puxStackBuffer ;
# if ( tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE != 0 )
{
/* Tasks can be created statically or dynamically, so note
* this task had a statically allocated stack in case it is
* later deleted . The TCB was allocated dynamically . */
pxNewTCB - > ucStaticallyAllocated = tskSTATICALLY_ALLOCATED_STACK_ONLY ;
}
# endif /* tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE */
prvInitialiseNewTask ( pxTaskDefinition - > pvTaskCode ,
pxTaskDefinition - > pcName ,
( uint32_t ) pxTaskDefinition - > usStackDepth ,
pxTaskDefinition - > pvParameters ,
pxTaskDefinition - > uxPriority ,
pxCreatedTask , pxNewTCB ,
pxTaskDefinition - > xRegions ) ;
prvAddNewTaskToReadyList ( pxNewTCB ) ;
xReturn = pdPASS ;
}
}
return xReturn ;
}
# endif /* portUSING_MPU_WRAPPERS */
/*-----------------------------------------------------------*/
static void prvInitialiseNewTask ( TaskFunction_t pxTaskCode ,
const char * const pcName , /*lint !e971 Unqualified char types are allowed for strings and single characters only. */
const uint32_t ulStackDepth ,
void * const pvParameters ,
UBaseType_t uxPriority ,
TaskHandle_t * const pxCreatedTask ,
TCB_t * pxNewTCB ,
2023-09-14 12:35:31 -04:00
const MemoryRegion_t * const xRegions ,
BaseType_t xCoreID )
2023-05-10 04:22:41 -04:00
{
StackType_t * pxTopOfStack ;
UBaseType_t x ;
# if ( portUSING_MPU_WRAPPERS == 1 )
/* Should the task be created in privileged mode? */
BaseType_t xRunPrivileged ;
if ( ( uxPriority & portPRIVILEGE_BIT ) ! = 0U )
{
xRunPrivileged = pdTRUE ;
}
else
{
xRunPrivileged = pdFALSE ;
}
uxPriority & = ~ portPRIVILEGE_BIT ;
# endif /* portUSING_MPU_WRAPPERS == 1 */
/* Avoid dependency on memset() if it is not required. */
# if ( tskSET_NEW_STACKS_TO_KNOWN_VALUE == 1 )
{
/* Fill the stack with a known value to assist debugging. */
( void ) memset ( pxNewTCB - > pxStack , ( int ) tskSTACK_FILL_BYTE , ( size_t ) ulStackDepth * sizeof ( StackType_t ) ) ;
}
# endif /* tskSET_NEW_STACKS_TO_KNOWN_VALUE */
/* Calculate the top of stack address. This depends on whether the stack
* grows from high memory to low ( as per the 80 x86 ) or vice versa .
* portSTACK_GROWTH is used to make the result positive or negative as required
* by the port . */
# if ( portSTACK_GROWTH < 0 )
{
pxTopOfStack = & ( pxNewTCB - > pxStack [ ulStackDepth - ( uint32_t ) 1 ] ) ;
pxTopOfStack = ( StackType_t * ) ( ( ( portPOINTER_SIZE_TYPE ) pxTopOfStack ) & ( ~ ( ( portPOINTER_SIZE_TYPE ) portBYTE_ALIGNMENT_MASK ) ) ) ; /*lint !e923 !e9033 !e9078 MISRA exception. Avoiding casts between pointers and integers is not practical. Size differences accounted for using portPOINTER_SIZE_TYPE type. Checked by assert(). */
/* Check the alignment of the calculated top of stack is correct. */
configASSERT ( ( ( ( portPOINTER_SIZE_TYPE ) pxTopOfStack & ( portPOINTER_SIZE_TYPE ) portBYTE_ALIGNMENT_MASK ) = = 0UL ) ) ;
# if ( configRECORD_STACK_HIGH_ADDRESS == 1 )
{
/* Also record the stack's high address, which may assist
* debugging . */
pxNewTCB - > pxEndOfStack = pxTopOfStack ;
}
# endif /* configRECORD_STACK_HIGH_ADDRESS */
}
# else /* portSTACK_GROWTH */
{
pxTopOfStack = pxNewTCB - > pxStack ;
/* Check the alignment of the stack buffer is correct. */
configASSERT ( ( ( ( portPOINTER_SIZE_TYPE ) pxNewTCB - > pxStack & ( portPOINTER_SIZE_TYPE ) portBYTE_ALIGNMENT_MASK ) = = 0UL ) ) ;
/* The other extreme of the stack space is required if stack checking is
* performed . */
pxNewTCB - > pxEndOfStack = pxNewTCB - > pxStack + ( ulStackDepth - ( uint32_t ) 1 ) ;
}
# endif /* portSTACK_GROWTH */
/* Store the task name in the TCB. */
if ( pcName ! = NULL )
{
for ( x = ( UBaseType_t ) 0 ; x < ( UBaseType_t ) configMAX_TASK_NAME_LEN ; x + + )
{
pxNewTCB - > pcTaskName [ x ] = pcName [ x ] ;
/* Don't copy all configMAX_TASK_NAME_LEN if the string is shorter than
* configMAX_TASK_NAME_LEN characters just in case the memory after the
* string is not accessible ( extremely unlikely ) . */
if ( pcName [ x ] = = ( char ) 0x00 )
{
break ;
}
else
{
mtCOVERAGE_TEST_MARKER ( ) ;
}
}
/* Ensure the name string is terminated in the case that the string length
* was greater or equal to configMAX_TASK_NAME_LEN . */
pxNewTCB - > pcTaskName [ configMAX_TASK_NAME_LEN - 1 ] = ' \0 ' ;
}
else
{
mtCOVERAGE_TEST_MARKER ( ) ;
}
/* This is used as an array index so must ensure it's not too large. */
configASSERT ( uxPriority < configMAX_PRIORITIES ) ;
if ( uxPriority > = ( UBaseType_t ) configMAX_PRIORITIES )
{
uxPriority = ( UBaseType_t ) configMAX_PRIORITIES - ( UBaseType_t ) 1U ;
}
else
{
mtCOVERAGE_TEST_MARKER ( ) ;
}
pxNewTCB - > uxPriority = uxPriority ;
2023-11-16 06:41:24 -05:00
# if ( configNUMBER_OF_CORES > 1 )
{
pxNewTCB - > xCoreID = xCoreID ;
}
# else /* configNUMBER_OF_CORES > 1 */
{
/* Avoid compiler warning about unreferenced parameter. */
( void ) xCoreID ;
}
# endif /* configNUMBER_OF_CORES > 1 */
2023-05-10 04:22:41 -04:00
# if ( configUSE_MUTEXES == 1 )
{
pxNewTCB - > uxBasePriority = uxPriority ;
}
# endif /* configUSE_MUTEXES */
vListInitialiseItem ( & ( pxNewTCB - > xStateListItem ) ) ;
vListInitialiseItem ( & ( pxNewTCB - > xEventListItem ) ) ;
/* Set the pxNewTCB as a link back from the ListItem_t. This is so we can get
* back to the containing TCB from a generic item in a list . */
listSET_LIST_ITEM_OWNER ( & ( pxNewTCB - > xStateListItem ) , pxNewTCB ) ;
/* Event lists are always in priority order. */
listSET_LIST_ITEM_VALUE ( & ( pxNewTCB - > xEventListItem ) , ( TickType_t ) configMAX_PRIORITIES - ( TickType_t ) uxPriority ) ; /*lint !e961 MISRA exception as the casts are only redundant for some ports. */
listSET_LIST_ITEM_OWNER ( & ( pxNewTCB - > xEventListItem ) , pxNewTCB ) ;
# if ( portUSING_MPU_WRAPPERS == 1 )
{
vPortStoreTaskMPUSettings ( & ( pxNewTCB - > xMPUSettings ) , xRegions , pxNewTCB - > pxStack , ulStackDepth ) ;
}
# else
{
/* Avoid compiler warning about unreferenced parameter. */
( void ) xRegions ;
}
# endif
# if ( ( configUSE_NEWLIB_REENTRANT == 1 ) || ( configUSE_C_RUNTIME_TLS_SUPPORT == 1 ) )
{
/* Allocate and initialize memory for the task's TLS Block. */
configINIT_TLS_BLOCK ( pxNewTCB - > xTLSBlock ) ;
}
# endif
/* Initialize the TCB stack to look as if the task was already running,
* but had been interrupted by the scheduler . The return address is set
* to the start of the task function . Once the stack has been initialised
* the top of stack variable is updated . */
# if ( portUSING_MPU_WRAPPERS == 1 )
{
/* If the port has capability to detect stack overflow,
* pass the stack end address to the stack initialization
* function as well . */
# if ( portHAS_STACK_OVERFLOW_CHECKING == 1 )
{
# if ( portSTACK_GROWTH < 0 )
{
pxNewTCB - > pxTopOfStack = pxPortInitialiseStack ( pxTopOfStack , pxNewTCB - > pxStack , pxTaskCode , pvParameters , xRunPrivileged ) ;
}
# else /* portSTACK_GROWTH */
{
pxNewTCB - > pxTopOfStack = pxPortInitialiseStack ( pxTopOfStack , pxNewTCB - > pxEndOfStack , pxTaskCode , pvParameters , xRunPrivileged ) ;
}
# endif /* portSTACK_GROWTH */
}
# else /* portHAS_STACK_OVERFLOW_CHECKING */
{
pxNewTCB - > pxTopOfStack = pxPortInitialiseStack ( pxTopOfStack , pxTaskCode , pvParameters , xRunPrivileged ) ;
}
# endif /* portHAS_STACK_OVERFLOW_CHECKING */
}
# else /* portUSING_MPU_WRAPPERS */
{
/* If the port has capability to detect stack overflow,
* pass the stack end address to the stack initialization
* function as well . */
# if ( portHAS_STACK_OVERFLOW_CHECKING == 1 )
{
# if ( portSTACK_GROWTH < 0 )
{
pxNewTCB - > pxTopOfStack = pxPortInitialiseStack ( pxTopOfStack , pxNewTCB - > pxStack , pxTaskCode , pvParameters ) ;
}
# else /* portSTACK_GROWTH */
{
pxNewTCB - > pxTopOfStack = pxPortInitialiseStack ( pxTopOfStack , pxNewTCB - > pxEndOfStack , pxTaskCode , pvParameters ) ;
}
# endif /* portSTACK_GROWTH */
}
# else /* portHAS_STACK_OVERFLOW_CHECKING */
{
pxNewTCB - > pxTopOfStack = pxPortInitialiseStack ( pxTopOfStack , pxTaskCode , pvParameters ) ;
}
# endif /* portHAS_STACK_OVERFLOW_CHECKING */
}
# endif /* portUSING_MPU_WRAPPERS */
if ( pxCreatedTask ! = NULL )
{
/* Pass the handle out in an anonymous way. The handle can be used to
* change the created task ' s priority , delete the created task , etc . */
* pxCreatedTask = ( TaskHandle_t ) pxNewTCB ;
}
else
{
mtCOVERAGE_TEST_MARKER ( ) ;
}
}
/*-----------------------------------------------------------*/
static void prvAddNewTaskToReadyList ( TCB_t * pxNewTCB )
{
/* Ensure interrupts don't access the task lists while the lists are being
* updated . */
2023-09-07 12:29:57 -04:00
taskENTER_CRITICAL ( & xKernelLock ) ;
2023-05-10 04:22:41 -04:00
{
uxCurrentNumberOfTasks + + ;
2023-09-14 12:35:31 -04:00
if ( uxCurrentNumberOfTasks = = ( UBaseType_t ) 1 )
2023-05-10 04:22:41 -04:00
{
2023-09-14 12:35:31 -04:00
/* This is the first task to be created so do the preliminary
* initialisation required . We will not recover if this call
* fails , but we will report the failure . */
prvInitialiseTaskLists ( ) ;
}
else
{
mtCOVERAGE_TEST_MARKER ( ) ;
}
2023-05-10 04:22:41 -04:00
2023-11-16 06:18:17 -05:00
if ( ( pxCurrentTCBs [ 0 ] = = NULL ) & & ( taskIS_AFFINITY_COMPATIBLE ( 0 , pxNewTCB ) = = pdTRUE ) )
2023-09-14 12:35:31 -04:00
{
/* On core 0, there are no other tasks, or all the other tasks
* are in the suspended state - make this the current task . */
pxCurrentTCBs [ 0 ] = pxNewTCB ;
}
# if ( configNUMBER_OF_CORES > 1 )
2023-11-16 06:18:17 -05:00
else if ( ( pxCurrentTCBs [ 1 ] = = NULL ) & & ( taskIS_AFFINITY_COMPATIBLE ( 1 , pxNewTCB ) = = pdTRUE ) )
2023-05-10 04:22:41 -04:00
{
2023-09-14 12:35:31 -04:00
/* On core 1, there are no other tasks, or all the other tasks
* are in the suspended state - make this the current task . */
pxCurrentTCBs [ 1 ] = pxNewTCB ;
2023-05-10 04:22:41 -04:00
}
2023-09-14 12:35:31 -04:00
# endif /* configNUMBER_OF_CORES > 1 */
2023-05-10 04:22:41 -04:00
else
{
/* If the scheduler is not already running, make this task the
* current task if it is the highest priority task to be created
* so far . */
if ( xSchedulerRunning = = pdFALSE )
{
2023-09-14 12:35:31 -04:00
if ( ( pxCurrentTCBs [ 0 ] ! = NULL ) & &
2023-11-16 06:18:17 -05:00
( taskIS_AFFINITY_COMPATIBLE ( 0 , pxNewTCB ) = = pdTRUE ) & &
2023-09-14 12:35:31 -04:00
( pxCurrentTCBs [ 0 ] - > uxPriority < = pxNewTCB - > uxPriority ) )
2023-05-10 04:22:41 -04:00
{
2023-09-14 12:35:31 -04:00
pxCurrentTCBs [ 0 ] = pxNewTCB ;
2023-05-10 04:22:41 -04:00
}
2023-09-14 12:35:31 -04:00
# if ( configNUMBER_OF_CORES > 1 )
else if ( ( pxCurrentTCBs [ 1 ] ! = NULL ) & &
2023-11-16 06:18:17 -05:00
( taskIS_AFFINITY_COMPATIBLE ( 1 , pxNewTCB ) = = pdTRUE ) & &
2023-09-14 12:35:31 -04:00
( pxCurrentTCBs [ 1 ] - > uxPriority < = pxNewTCB - > uxPriority ) )
{
pxCurrentTCBs [ 1 ] = pxNewTCB ;
}
# endif /* configNUMBER_OF_CORES > 1 */
2023-05-10 04:22:41 -04:00
else
{
mtCOVERAGE_TEST_MARKER ( ) ;
}
}
else
{
mtCOVERAGE_TEST_MARKER ( ) ;
}
}
uxTaskNumber + + ;
# if ( configUSE_TRACE_FACILITY == 1 )
{
/* Add a counter into the TCB for tracing only. */
pxNewTCB - > uxTCBNumber = uxTaskNumber ;
}
# endif /* configUSE_TRACE_FACILITY */
traceTASK_CREATE ( pxNewTCB ) ;
prvAddTaskToReadyList ( pxNewTCB ) ;
portSETUP_TCB ( pxNewTCB ) ;
2023-09-07 12:29:57 -04:00
if ( xSchedulerRunning ! = pdFALSE )
2023-05-10 04:22:41 -04:00
{
2023-09-07 12:29:57 -04:00
/* If the created task is of a higher priority than the current task
* then it should run now . */
2023-11-16 06:18:17 -05:00
if ( taskIS_YIELD_REQUIRED ( pxNewTCB , pdTRUE ) = = pdTRUE )
2023-09-07 12:29:57 -04:00
{
taskYIELD_IF_USING_PREEMPTION ( ) ;
}
else
{
mtCOVERAGE_TEST_MARKER ( ) ;
}
2023-05-10 04:22:41 -04:00
}
else
{
mtCOVERAGE_TEST_MARKER ( ) ;
}
}
2023-09-07 12:29:57 -04:00
taskEXIT_CRITICAL ( & xKernelLock ) ;
2023-09-14 12:35:31 -04:00
2023-09-07 12:29:57 -04:00
/* SINGLE-CORE MODIFICATION: Extended critical section so that SMP can check
* for yield inside critical section . */
2023-05-10 04:22:41 -04:00
}
/*-----------------------------------------------------------*/
# if ( INCLUDE_vTaskDelete == 1 )
void vTaskDelete ( TaskHandle_t xTaskToDelete )
{
TCB_t * pxTCB ;
2023-09-14 12:35:31 -04:00
BaseType_t xSelfDelete ;
BaseType_t xIsCurRunning ;
2023-05-10 04:22:41 -04:00
2023-09-07 12:29:57 -04:00
taskENTER_CRITICAL ( & xKernelLock ) ;
2023-05-10 04:22:41 -04:00
{
2023-09-14 12:35:31 -04:00
/* Get current core ID as we can no longer be preempted. */
const BaseType_t xCurCoreID = portGET_CORE_ID ( ) ;
2023-05-10 04:22:41 -04:00
/* If null is passed in here then it is the calling task that is
* being deleted . */
pxTCB = prvGetTCBFromHandle ( xTaskToDelete ) ;
/* Remove task from the ready/delayed list. */
if ( uxListRemove ( & ( pxTCB - > xStateListItem ) ) = = ( UBaseType_t ) 0 )
{
taskRESET_READY_PRIORITY ( pxTCB - > uxPriority ) ;
}
else
{
mtCOVERAGE_TEST_MARKER ( ) ;
}
/* Is the task waiting on an event also? */
if ( listLIST_ITEM_CONTAINER ( & ( pxTCB - > xEventListItem ) ) ! = NULL )
{
( void ) uxListRemove ( & ( pxTCB - > xEventListItem ) ) ;
}
else
{
mtCOVERAGE_TEST_MARKER ( ) ;
}
/* Increment the uxTaskNumber also so kernel aware debuggers can
* detect that the task lists need re - generating . This is done before
* portPRE_TASK_DELETE_HOOK ( ) as in the Windows port that macro will
* not return . */
uxTaskNumber + + ;
2023-09-14 12:35:31 -04:00
/* Check if the task is deleting itself, or is currently running on
* the other core . */
if ( taskIS_CURRENTLY_RUNNING_ON_CORE ( pxTCB , xCurCoreID ) = = pdTRUE )
{
xSelfDelete = pdTRUE ;
xIsCurRunning = pdTRUE ;
}
# if ( configNUMBER_OF_CORES > 1 )
else if ( taskIS_CURRENTLY_RUNNING_ON_CORE ( pxTCB , ! xCurCoreID ) = = pdTRUE )
{
xSelfDelete = pdFALSE ;
xIsCurRunning = pdTRUE ;
}
# endif /* configNUMBER_OF_CORES > 1 */
else
{
xSelfDelete = pdFALSE ;
xIsCurRunning = pdFALSE ;
}
if ( xIsCurRunning = = pdTRUE )
2023-05-10 04:22:41 -04:00
{
2023-09-14 12:35:31 -04:00
/* A task is deleting itself or is currently running. This
* cannot complete within the task itself , as a context switch
* to another task is required . Place the task in the
* termination list . The idle task will check the termination
* list and free up any memory allocated by the scheduler for
* the TCB and stack of the deleted task . */
2023-05-10 04:22:41 -04:00
vListInsertEnd ( & xTasksWaitingTermination , & ( pxTCB - > xStateListItem ) ) ;
/* Increment the ucTasksDeleted variable so the idle task knows
* there is a task that has been deleted and that it should therefore
* check the xTasksWaitingTermination list . */
+ + uxDeletedTasksWaitingCleanUp ;
/* Call the delete hook before portPRE_TASK_DELETE_HOOK() as
* portPRE_TASK_DELETE_HOOK ( ) does not return in the Win32 port . */
traceTASK_DELETE ( pxTCB ) ;
/* The pre-delete hook is primarily for the Windows simulator,
* in which Windows specific clean up operations are performed ,
* after which it is not possible to yield away from this task -
* hence xYieldPending is used to latch that a context switch is
* required . */
2023-09-14 12:35:31 -04:00
portPRE_TASK_DELETE_HOOK ( pxTCB , & xYieldPending [ xCurCoreID ] ) ;
# if ( configNUMBER_OF_CORES > 1 )
if ( xSelfDelete = = pdFALSE )
{
/* The task that is being deleted is currently running
* on the other core . Send a yield request to the other
* core so that the task is swapped out . */
taskYIELD_CORE ( ! xCurCoreID ) ;
}
# else /* configNUMBER_OF_CORES > 1 */
/* xCurCoreID is unused */
( void ) xCurCoreID ;
# endif /* configNUMBER_OF_CORES > 1 */
2023-05-10 04:22:41 -04:00
}
else
{
- - uxCurrentNumberOfTasks ;
traceTASK_DELETE ( pxTCB ) ;
/* Reset the next expected unblock time in case it referred to
* the task that has just been deleted . */
prvResetNextTaskUnblockTime ( ) ;
}
}
2023-09-07 12:29:57 -04:00
taskEXIT_CRITICAL ( & xKernelLock ) ;
2023-05-10 04:22:41 -04:00
2023-09-14 12:35:31 -04:00
/* If the task is currently running, call prvDeleteTCB from outside of
* critical section . If a task is currently running , prvDeleteTCB is
* called from prvCheckTasksWaitingTermination which is called from
* Idle task . */
if ( xIsCurRunning = = pdFALSE )
2023-05-10 04:22:41 -04:00
{
prvDeleteTCB ( pxTCB ) ;
}
2023-09-07 12:29:57 -04:00
/* For SMP, we need to take the kernel lock here as we are about to
* access kernel data structures . */
2023-10-31 12:02:58 -04:00
prvENTER_CRITICAL_SMP_ONLY ( & xKernelLock ) ;
2023-05-10 04:22:41 -04:00
{
2023-09-07 12:29:57 -04:00
/* Force a reschedule if it is the currently running task that has just
* been deleted . */
if ( xSchedulerRunning ! = pdFALSE )
2023-05-10 04:22:41 -04:00
{
2023-09-07 12:29:57 -04:00
if ( xSelfDelete = = pdTRUE )
{
configASSERT ( taskIS_SCHEDULER_SUSPENDED ( ) = = pdFALSE ) ;
portYIELD_WITHIN_API ( ) ;
}
else
{
mtCOVERAGE_TEST_MARKER ( ) ;
}
2023-05-10 04:22:41 -04:00
}
}
2023-09-07 12:29:57 -04:00
/* Release the previously taken kernel lock. */
2023-10-31 12:02:58 -04:00
prvEXIT_CRITICAL_SMP_ONLY ( & xKernelLock ) ;
2023-05-10 04:22:41 -04:00
}
# endif /* INCLUDE_vTaskDelete */
/*-----------------------------------------------------------*/
# if ( INCLUDE_xTaskDelayUntil == 1 )
BaseType_t xTaskDelayUntil ( TickType_t * const pxPreviousWakeTime ,
const TickType_t xTimeIncrement )
{
TickType_t xTimeToWake ;
BaseType_t xAlreadyYielded , xShouldDelay = pdFALSE ;
configASSERT ( pxPreviousWakeTime ) ;
configASSERT ( ( xTimeIncrement > 0U ) ) ;
2023-09-14 12:35:31 -04:00
configASSERT ( taskIS_SCHEDULER_SUSPENDED ( ) = = pdFALSE ) ;
2023-05-10 04:22:41 -04:00
2023-09-07 12:29:57 -04:00
prvENTER_CRITICAL_OR_SUSPEND_ALL ( & xKernelLock ) ;
2023-05-10 04:22:41 -04:00
{
/* Minor optimisation. The tick count cannot change in this
* block . */
const TickType_t xConstTickCount = xTickCount ;
/* Generate the tick time at which the task wants to wake. */
xTimeToWake = * pxPreviousWakeTime + xTimeIncrement ;
if ( xConstTickCount < * pxPreviousWakeTime )
{
/* The tick count has overflowed since this function was
* lasted called . In this case the only time we should ever
* actually delay is if the wake time has also overflowed ,
* and the wake time is greater than the tick time . When this
* is the case it is as if neither time had overflowed . */
if ( ( xTimeToWake < * pxPreviousWakeTime ) & & ( xTimeToWake > xConstTickCount ) )
{
xShouldDelay = pdTRUE ;
}
else
{
mtCOVERAGE_TEST_MARKER ( ) ;
}
}
else
{
/* The tick time has not overflowed. In this case we will
* delay if either the wake time has overflowed , and / or the
* tick time is less than the wake time . */
if ( ( xTimeToWake < * pxPreviousWakeTime ) | | ( xTimeToWake > xConstTickCount ) )
{
xShouldDelay = pdTRUE ;
}
else
{
mtCOVERAGE_TEST_MARKER ( ) ;
}
}
/* Update the wake time ready for the next call. */
* pxPreviousWakeTime = xTimeToWake ;
if ( xShouldDelay ! = pdFALSE )
{
traceTASK_DELAY_UNTIL ( xTimeToWake ) ;
/* prvAddCurrentTaskToDelayedList() needs the block time, not
* the time to wake , so subtract the current tick count . */
prvAddCurrentTaskToDelayedList ( xTimeToWake - xConstTickCount , pdFALSE ) ;
}
else
{
mtCOVERAGE_TEST_MARKER ( ) ;
}
}
2023-09-07 12:29:57 -04:00
xAlreadyYielded = prvEXIT_CRITICAL_OR_RESUME_ALL ( & xKernelLock ) ;
2023-05-10 04:22:41 -04:00
/* Force a reschedule if xTaskResumeAll has not already done so, we may
* have put ourselves to sleep . */
if ( xAlreadyYielded = = pdFALSE )
{
portYIELD_WITHIN_API ( ) ;
}
else
{
mtCOVERAGE_TEST_MARKER ( ) ;
}
return xShouldDelay ;
}
# endif /* INCLUDE_xTaskDelayUntil */
/*-----------------------------------------------------------*/
# if ( INCLUDE_vTaskDelay == 1 )
void vTaskDelay ( const TickType_t xTicksToDelay )
{
BaseType_t xAlreadyYielded = pdFALSE ;
/* A delay time of zero just forces a reschedule. */
if ( xTicksToDelay > ( TickType_t ) 0U )
{
2023-09-14 12:35:31 -04:00
configASSERT ( taskIS_SCHEDULER_SUSPENDED ( ) = = pdFALSE ) ;
2023-09-07 12:29:57 -04:00
prvENTER_CRITICAL_OR_SUSPEND_ALL ( & xKernelLock ) ;
2023-05-10 04:22:41 -04:00
{
traceTASK_DELAY ( ) ;
/* A task that is removed from the event list while the
* scheduler is suspended will not get placed in the ready
* list or removed from the blocked list until the scheduler
* is resumed .
*
* This task cannot be in an event list as it is the currently
* executing task . */
prvAddCurrentTaskToDelayedList ( xTicksToDelay , pdFALSE ) ;
}
2023-09-07 12:29:57 -04:00
xAlreadyYielded = prvEXIT_CRITICAL_OR_RESUME_ALL ( & xKernelLock ) ;
2023-05-10 04:22:41 -04:00
}
else
{
mtCOVERAGE_TEST_MARKER ( ) ;
}
/* Force a reschedule if xTaskResumeAll has not already done so, we may
* have put ourselves to sleep . */
if ( xAlreadyYielded = = pdFALSE )
{
portYIELD_WITHIN_API ( ) ;
}
else
{
mtCOVERAGE_TEST_MARKER ( ) ;
}
}
# endif /* INCLUDE_vTaskDelay */
/*-----------------------------------------------------------*/
# if ( ( INCLUDE_eTaskGetState == 1 ) || ( configUSE_TRACE_FACILITY == 1 ) || ( INCLUDE_xTaskAbortDelay == 1 ) )
eTaskState eTaskGetState ( TaskHandle_t xTask )
{
eTaskState eReturn ;
List_t const * pxStateList ;
List_t const * pxDelayedList ;
List_t const * pxOverflowedDelayedList ;
const TCB_t * const pxTCB = xTask ;
configASSERT ( pxTCB ) ;
2023-09-07 12:29:57 -04:00
taskENTER_CRITICAL ( & xKernelLock ) ;
2023-05-10 04:22:41 -04:00
{
2023-09-14 12:35:31 -04:00
if ( taskIS_CURRENTLY_RUNNING ( pxTCB ) = = pdTRUE )
{
/* The task calling this function is querying its own state. */
eReturn = eRunning ;
}
else
2023-05-10 04:22:41 -04:00
{
pxStateList = listLIST_ITEM_CONTAINER ( & ( pxTCB - > xStateListItem ) ) ;
pxDelayedList = pxDelayedTaskList ;
pxOverflowedDelayedList = pxOverflowDelayedTaskList ;
2023-09-14 12:35:31 -04:00
if ( ( pxStateList = = pxDelayedList ) | | ( pxStateList = = pxOverflowedDelayedList ) )
2023-05-10 04:22:41 -04:00
{
2023-09-14 12:35:31 -04:00
/* The task being queried is referenced from one of the Blocked
* lists . */
eReturn = eBlocked ;
}
# if ( INCLUDE_vTaskSuspend == 1 )
else if ( pxStateList = = & xSuspendedTaskList )
2023-05-10 04:22:41 -04:00
{
2023-09-14 12:35:31 -04:00
/* The task being queried is referenced from the suspended
* list . Is it genuinely suspended or is it blocked
* indefinitely ? */
if ( listLIST_ITEM_CONTAINER ( & ( pxTCB - > xEventListItem ) ) = = NULL )
2023-05-10 04:22:41 -04:00
{
2023-09-14 12:35:31 -04:00
# if ( configUSE_TASK_NOTIFICATIONS == 1 )
{
BaseType_t x ;
2023-05-10 04:22:41 -04:00
2023-09-14 12:35:31 -04:00
/* The task does not appear on the event list item of
* and of the RTOS objects , but could still be in the
* blocked state if it is waiting on its notification
* rather than waiting on an object . If not , is
* suspended . */
eReturn = eSuspended ;
2023-05-10 04:22:41 -04:00
2023-09-14 12:35:31 -04:00
for ( x = 0 ; x < configTASK_NOTIFICATION_ARRAY_ENTRIES ; x + + )
2023-05-10 04:22:41 -04:00
{
2023-09-14 12:35:31 -04:00
if ( pxTCB - > ucNotifyState [ x ] = = taskWAITING_NOTIFICATION )
{
eReturn = eBlocked ;
break ;
}
2023-05-10 04:22:41 -04:00
}
}
2023-09-14 12:35:31 -04:00
# else /* if ( configUSE_TASK_NOTIFICATIONS == 1 ) */
{
eReturn = eSuspended ;
}
# endif /* if ( configUSE_TASK_NOTIFICATIONS == 1 ) */
2023-05-10 04:22:41 -04:00
}
2023-09-14 12:35:31 -04:00
else
2023-05-10 04:22:41 -04:00
{
2023-09-14 12:35:31 -04:00
eReturn = eBlocked ;
2023-05-10 04:22:41 -04:00
}
}
2023-09-14 12:35:31 -04:00
# endif /* if ( INCLUDE_vTaskSuspend == 1 ) */
# if ( INCLUDE_vTaskDelete == 1 )
else if ( ( pxStateList = = & xTasksWaitingTermination ) | | ( pxStateList = = NULL ) )
2023-05-10 04:22:41 -04:00
{
2023-09-14 12:35:31 -04:00
/* The task being queried is referenced from the deleted
* tasks list , or it is not referenced from any lists at
* all . */
eReturn = eDeleted ;
2023-05-10 04:22:41 -04:00
}
2023-09-14 12:35:31 -04:00
# endif
2023-05-10 04:22:41 -04:00
2023-09-14 12:35:31 -04:00
else /*lint !e525 Negative indentation is intended to make use of pre-processor clearer. */
2023-05-10 04:22:41 -04:00
{
2023-09-14 12:35:31 -04:00
/* If the task is not in any other state, it must be in the
* Ready ( including pending ready ) state . */
eReturn = eReady ;
2023-05-10 04:22:41 -04:00
}
}
}
2023-09-07 12:29:57 -04:00
taskEXIT_CRITICAL ( & xKernelLock ) ;
2023-05-10 04:22:41 -04:00
return eReturn ;
} /*lint !e818 xTask cannot be a pointer to const because it is a typedef. */
# endif /* INCLUDE_eTaskGetState */
/*-----------------------------------------------------------*/
# if ( INCLUDE_uxTaskPriorityGet == 1 )
UBaseType_t uxTaskPriorityGet ( const TaskHandle_t xTask )
{
TCB_t const * pxTCB ;
UBaseType_t uxReturn ;
2023-09-07 12:29:57 -04:00
taskENTER_CRITICAL ( & xKernelLock ) ;
2023-05-10 04:22:41 -04:00
{
/* If null is passed in here then it is the priority of the task
* that called uxTaskPriorityGet ( ) that is being queried . */
pxTCB = prvGetTCBFromHandle ( xTask ) ;
uxReturn = pxTCB - > uxPriority ;
}
2023-09-07 12:29:57 -04:00
taskEXIT_CRITICAL ( & xKernelLock ) ;
2023-05-10 04:22:41 -04:00
return uxReturn ;
}
# endif /* INCLUDE_uxTaskPriorityGet */
/*-----------------------------------------------------------*/
# if ( INCLUDE_uxTaskPriorityGet == 1 )
UBaseType_t uxTaskPriorityGetFromISR ( const TaskHandle_t xTask )
{
TCB_t const * pxTCB ;
UBaseType_t uxReturn , uxSavedInterruptState ;
/* RTOS ports that support interrupt nesting have the concept of a
* maximum system call ( or maximum API call ) interrupt priority .
* Interrupts that are above the maximum system call priority are keep
* permanently enabled , even when the RTOS kernel is in a critical section ,
* but cannot make any calls to FreeRTOS API functions . If configASSERT ( )
* is defined in FreeRTOSConfig . h then
* portASSERT_IF_INTERRUPT_PRIORITY_INVALID ( ) will result in an assertion
* failure if a FreeRTOS API function is called from an interrupt that has
* been assigned a priority above the configured maximum system call
* priority . Only FreeRTOS functions that end in FromISR can be called
* from interrupts that have been assigned a priority at or ( logically )
* below the maximum system call interrupt priority . FreeRTOS maintains a
* separate interrupt safe API to ensure interrupt entry is as fast and as
* simple as possible . More information ( albeit Cortex - M specific ) is
* provided on the following link :
* https : //www.FreeRTOS.org/RTOS-Cortex-M3-M4.html */
portASSERT_IF_INTERRUPT_PRIORITY_INVALID ( ) ;
2023-09-07 12:29:57 -04:00
prvENTER_CRITICAL_OR_MASK_ISR ( & xKernelLock , uxSavedInterruptState ) ;
2023-05-10 04:22:41 -04:00
{
/* If null is passed in here then it is the priority of the calling
* task that is being queried . */
pxTCB = prvGetTCBFromHandle ( xTask ) ;
uxReturn = pxTCB - > uxPriority ;
}
2023-09-07 12:29:57 -04:00
prvEXIT_CRITICAL_OR_UNMASK_ISR ( & xKernelLock , uxSavedInterruptState ) ;
2023-05-10 04:22:41 -04:00
return uxReturn ;
}
# endif /* INCLUDE_uxTaskPriorityGet */
/*-----------------------------------------------------------*/
# if ( INCLUDE_vTaskPrioritySet == 1 )
void vTaskPrioritySet ( TaskHandle_t xTask ,
UBaseType_t uxNewPriority )
{
TCB_t * pxTCB ;
UBaseType_t uxCurrentBasePriority , 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 ( ) ;
}
2023-09-07 12:29:57 -04:00
taskENTER_CRITICAL ( & xKernelLock ) ;
2023-05-10 04:22:41 -04:00
{
2023-09-14 12:35:31 -04:00
/* Get current core ID as we can no longer be preempted. */
const BaseType_t xCurCoreID = portGET_CORE_ID ( ) ;
2023-05-10 04:22:41 -04:00
/* 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 ) ;
# if ( configUSE_MUTEXES == 1 )
{
uxCurrentBasePriority = pxTCB - > uxBasePriority ;
}
# else
{
uxCurrentBasePriority = pxTCB - > uxPriority ;
}
# endif
if ( uxCurrentBasePriority ! = uxNewPriority )
{
/* The priority change may have readied a task of higher
* priority than the calling task . */
if ( uxNewPriority > uxCurrentBasePriority )
{
2023-09-14 12:35:31 -04:00
if ( taskIS_CURRENTLY_RUNNING ( pxTCB ) = = pdFALSE )
2023-05-10 04:22:41 -04:00
{
/* 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 ? */
2023-11-16 06:18:17 -05:00
if ( taskIS_YIELD_REQUIRED_USING_PRIORITY ( pxTCB , uxNewPriority , pdTRUE ) = = pdTRUE )
2023-05-10 04:22:41 -04:00
{
xYieldRequired = pdTRUE ;
}
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 . */
}
}
2023-09-14 12:35:31 -04:00
else if ( taskIS_CURRENTLY_RUNNING_ON_CORE ( pxTCB , xCurCoreID ) = = pdTRUE )
2023-05-10 04:22:41 -04:00
{
2023-09-14 12:35:31 -04:00
/* Lowering the priority of task currently running on the
* current core means there may now be another task of
* higher priority that is ready to execute . */
2023-05-10 04:22:41 -04:00
xYieldRequired = pdTRUE ;
}
2023-09-14 12:35:31 -04:00
# if ( configNUMBER_OF_CORES > 1 )
else if ( taskIS_CURRENTLY_RUNNING_ON_CORE ( pxTCB , ! xCurCoreID ) = = pdTRUE )
{
/* Lowering the priority of task currently running on the
* other core also means there may now be another task of
* higher priority that is ready to execute . */
taskYIELD_CORE ( ! xCurCoreID ) ;
}
# endif /* configNUMBER_OF_CORES > 1 */
2023-05-10 04:22:41 -04:00
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 ;
# if ( configUSE_MUTEXES == 1 )
{
/* Only change the priority being used if the task is not
* currently using an inherited priority . */
if ( pxTCB - > uxBasePriority = = pxTCB - > uxPriority )
{
pxTCB - > uxPriority = uxNewPriority ;
}
else
{
mtCOVERAGE_TEST_MARKER ( ) ;
}
/* The base priority gets set whatever. */
pxTCB - > uxBasePriority = uxNewPriority ;
}
# else /* if ( configUSE_MUTEXES == 1 ) */
{
pxTCB - > uxPriority = uxNewPriority ;
}
# endif /* if ( configUSE_MUTEXES == 1 ) */
/* 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 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 ) ;
}
else
{
mtCOVERAGE_TEST_MARKER ( ) ;
}
prvAddTaskToReadyList ( pxTCB ) ;
}
else
{
mtCOVERAGE_TEST_MARKER ( ) ;
}
if ( xYieldRequired ! = pdFALSE )
{
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 ;
}
}
2023-09-07 12:29:57 -04:00
taskEXIT_CRITICAL ( & xKernelLock ) ;
2023-05-10 04:22:41 -04:00
}
# endif /* INCLUDE_vTaskPrioritySet */
/*-----------------------------------------------------------*/
# if ( INCLUDE_vTaskSuspend == 1 )
void vTaskSuspend ( TaskHandle_t xTaskToSuspend )
{
TCB_t * pxTCB ;
2023-09-07 12:29:57 -04:00
taskENTER_CRITICAL ( & xKernelLock ) ;
2023-05-10 04:22:41 -04:00
{
2023-09-14 12:35:31 -04:00
/* Get current core ID as we can no longer be preempted. */
const BaseType_t xCurCoreID = portGET_CORE_ID ( ) ;
2023-05-10 04:22:41 -04:00
/* If null is passed in here then it is the running task that is
* being suspended . */
pxTCB = prvGetTCBFromHandle ( xTaskToSuspend ) ;
traceTASK_SUSPEND ( pxTCB ) ;
/* Remove task from the ready/delayed list and place in the
* suspended list . */
if ( uxListRemove ( & ( pxTCB - > xStateListItem ) ) = = ( UBaseType_t ) 0 )
{
taskRESET_READY_PRIORITY ( pxTCB - > uxPriority ) ;
}
else
{
mtCOVERAGE_TEST_MARKER ( ) ;
}
/* Is the task waiting on an event also? */
if ( listLIST_ITEM_CONTAINER ( & ( pxTCB - > xEventListItem ) ) ! = NULL )
{
( void ) uxListRemove ( & ( pxTCB - > xEventListItem ) ) ;
}
else
{
mtCOVERAGE_TEST_MARKER ( ) ;
}
vListInsertEnd ( & xSuspendedTaskList , & ( pxTCB - > xStateListItem ) ) ;
# if ( configUSE_TASK_NOTIFICATIONS == 1 )
{
BaseType_t x ;
for ( x = 0 ; x < configTASK_NOTIFICATION_ARRAY_ENTRIES ; x + + )
{
if ( pxTCB - > ucNotifyState [ x ] = = taskWAITING_NOTIFICATION )
{
/* The task was blocked to wait for a notification, but is
* now suspended , so no notification was received . */
pxTCB - > ucNotifyState [ x ] = taskNOT_WAITING_NOTIFICATION ;
}
}
}
# endif /* if ( configUSE_TASK_NOTIFICATIONS == 1 ) */
2023-09-14 12:35:31 -04:00
if ( xSchedulerRunning ! = pdFALSE )
2023-05-10 04:22:41 -04:00
{
2023-09-14 12:35:31 -04:00
/* Reset the next expected unblock time in case it referred to the
* task that is now in the Suspended state . */
2023-05-10 04:22:41 -04:00
prvResetNextTaskUnblockTime ( ) ;
}
2023-09-14 12:35:31 -04:00
else
2023-05-10 04:22:41 -04:00
{
2023-09-14 12:35:31 -04:00
mtCOVERAGE_TEST_MARKER ( ) ;
2023-05-10 04:22:41 -04:00
}
2023-09-14 12:35:31 -04:00
if ( taskIS_CURRENTLY_RUNNING_ON_CORE ( pxTCB , xCurCoreID ) = = pdTRUE )
2023-05-10 04:22:41 -04:00
{
2023-09-14 12:35:31 -04:00
if ( xSchedulerRunning ! = pdFALSE )
2023-05-10 04:22:41 -04:00
{
2023-09-14 12:35:31 -04:00
/* The current task has just been suspended. */
configASSERT ( uxSchedulerSuspended [ xCurCoreID ] = = 0 ) ;
portYIELD_WITHIN_API ( ) ;
2023-05-10 04:22:41 -04:00
}
else
{
2023-09-14 12:35:31 -04:00
/* The scheduler is not running, but the task that was pointed
* to by pxCurrentTCBs has just been suspended and pxCurrentTCBs
* must be adjusted to point to a different task . */
if ( listCURRENT_LIST_LENGTH ( & xSuspendedTaskList ) = = uxCurrentNumberOfTasks ) /*lint !e931 Right has no side effect, just volatile. */
{
/* No other tasks are ready, so set pxCurrentTCBs back to
* NULL so when the next task is created pxCurrentTCBs will
* be set to point to it no matter what its relative priority
* is . */
pxCurrentTCBs [ xCurCoreID ] = NULL ;
}
else
{
vTaskSwitchContext ( ) ;
}
2023-05-10 04:22:41 -04:00
}
}
2023-09-14 12:35:31 -04:00
# if ( configNUMBER_OF_CORES > 1 )
else if ( taskIS_CURRENTLY_RUNNING_ON_CORE ( pxTCB , ! xCurCoreID ) = = pdTRUE )
{
/* The other core's current task has just been suspended */
if ( xSchedulerRunning ! = pdFALSE )
{
taskYIELD_CORE ( ! xCurCoreID ) ;
}
else
{
/* The scheduler is not running, but the task that was
* pointed to by pxCurrentTCBs [ otherCore ] has just been
* suspended . We simply set the
* pxCurrentTCBs [ otherCore ] to NULL for now .
*
* Todo : Update vTaskSwitchContext ( ) to be able to run
* on behalf of the other core . */
pxCurrentTCBs [ ! xCurCoreID ] = NULL ;
}
}
# endif /* configNUMBER_OF_CORES > 1 */
else
{
mtCOVERAGE_TEST_MARKER ( ) ;
}
2023-05-10 04:22:41 -04:00
}
2023-09-07 12:29:57 -04:00
taskEXIT_CRITICAL ( & xKernelLock ) ;
2023-05-10 04:22:41 -04:00
}
# endif /* INCLUDE_vTaskSuspend */
/*-----------------------------------------------------------*/
# if ( INCLUDE_vTaskSuspend == 1 )
static BaseType_t prvTaskIsTaskSuspended ( const TaskHandle_t xTask )
{
BaseType_t xReturn = pdFALSE ;
const TCB_t * const pxTCB = xTask ;
/* Accesses xPendingReadyList so must be called from a critical
* section . */
/* It does not make sense to check if the calling task is suspended. */
configASSERT ( xTask ) ;
/* Is the task being resumed actually in the suspended list? */
if ( listIS_CONTAINED_WITHIN ( & xSuspendedTaskList , & ( pxTCB - > xStateListItem ) ) ! = pdFALSE )
{
/* Has the task already been resumed from within an ISR? */
2023-09-14 12:35:31 -04:00
# if ( configNUMBER_OF_CORES > 1 )
if ( ( listIS_CONTAINED_WITHIN ( & xPendingReadyList [ 0 ] , & ( pxTCB - > xEventListItem ) ) = = pdFALSE ) & &
( listIS_CONTAINED_WITHIN ( & xPendingReadyList [ 1 ] , & ( pxTCB - > xEventListItem ) ) = = pdFALSE ) )
# else
if ( listIS_CONTAINED_WITHIN ( & xPendingReadyList [ 0 ] , & ( pxTCB - > xEventListItem ) ) = = pdFALSE )
# endif /* configNUMBER_OF_CORES > 1 */
2023-05-10 04:22:41 -04:00
{
/* Is it in the suspended list because it is in the Suspended
* state , or because is is blocked with no timeout ? */
if ( listIS_CONTAINED_WITHIN ( NULL , & ( pxTCB - > xEventListItem ) ) ! = pdFALSE ) /*lint !e961. The cast is only redundant when NULL is used. */
{
xReturn = pdTRUE ;
}
else
{
mtCOVERAGE_TEST_MARKER ( ) ;
}
}
else
{
mtCOVERAGE_TEST_MARKER ( ) ;
}
}
else
{
mtCOVERAGE_TEST_MARKER ( ) ;
}
return xReturn ;
} /*lint !e818 xTask cannot be a pointer to const because it is a typedef. */
# endif /* INCLUDE_vTaskSuspend */
/*-----------------------------------------------------------*/
# if ( INCLUDE_vTaskSuspend == 1 )
void vTaskResume ( TaskHandle_t xTaskToResume )
{
TCB_t * const pxTCB = xTaskToResume ;
/* It does not make sense to resume the calling task. */
configASSERT ( xTaskToResume ) ;
2023-09-07 12:29:57 -04:00
taskENTER_CRITICAL ( & xKernelLock ) ;
2023-05-10 04:22:41 -04:00
{
2023-09-14 12:35:31 -04:00
/* The parameter cannot be NULL as it is impossible to resume the
* currently executing task . */
if ( ( taskIS_CURRENTLY_RUNNING ( pxTCB ) = = pdFALSE ) & & ( pxTCB ! = NULL ) )
2023-05-10 04:22:41 -04:00
{
if ( prvTaskIsTaskSuspended ( pxTCB ) ! = pdFALSE )
{
traceTASK_RESUME ( pxTCB ) ;
/* The ready list can be accessed even if the scheduler is
* suspended because this is inside a critical section . */
( void ) uxListRemove ( & ( pxTCB - > xStateListItem ) ) ;
prvAddTaskToReadyList ( pxTCB ) ;
/* A higher priority task may have just been resumed. */
2023-11-16 06:18:17 -05:00
if ( taskIS_YIELD_REQUIRED ( pxTCB , pdTRUE ) = = pdTRUE )
2023-05-10 04:22:41 -04:00
{
/* This yield may not cause the task just resumed to run,
* but will leave the lists in the correct state for the
* next yield . */
taskYIELD_IF_USING_PREEMPTION ( ) ;
}
else
{
mtCOVERAGE_TEST_MARKER ( ) ;
}
}
else
{
mtCOVERAGE_TEST_MARKER ( ) ;
}
}
2023-09-14 12:35:31 -04:00
else
{
mtCOVERAGE_TEST_MARKER ( ) ;
}
2023-05-10 04:22:41 -04:00
}
2023-09-07 12:29:57 -04:00
taskEXIT_CRITICAL ( & xKernelLock ) ;
2023-05-10 04:22:41 -04:00
}
# endif /* INCLUDE_vTaskSuspend */
/*-----------------------------------------------------------*/
# if ( ( INCLUDE_xTaskResumeFromISR == 1 ) && ( INCLUDE_vTaskSuspend == 1 ) )
BaseType_t xTaskResumeFromISR ( TaskHandle_t xTaskToResume )
{
BaseType_t xYieldRequired = pdFALSE ;
TCB_t * const pxTCB = xTaskToResume ;
UBaseType_t uxSavedInterruptStatus ;
configASSERT ( xTaskToResume ) ;
/* RTOS ports that support interrupt nesting have the concept of a
* maximum system call ( or maximum API call ) interrupt priority .
* Interrupts that are above the maximum system call priority are keep
* permanently enabled , even when the RTOS kernel is in a critical section ,
* but cannot make any calls to FreeRTOS API functions . If configASSERT ( )
* is defined in FreeRTOSConfig . h then
* portASSERT_IF_INTERRUPT_PRIORITY_INVALID ( ) will result in an assertion
* failure if a FreeRTOS API function is called from an interrupt that has
* been assigned a priority above the configured maximum system call
* priority . Only FreeRTOS functions that end in FromISR can be called
* from interrupts that have been assigned a priority at or ( logically )
* below the maximum system call interrupt priority . FreeRTOS maintains a
* separate interrupt safe API to ensure interrupt entry is as fast and as
* simple as possible . More information ( albeit Cortex - M specific ) is
* provided on the following link :
* https : //www.FreeRTOS.org/RTOS-Cortex-M3-M4.html */
portASSERT_IF_INTERRUPT_PRIORITY_INVALID ( ) ;
2023-09-07 12:29:57 -04:00
prvENTER_CRITICAL_OR_MASK_ISR ( & xKernelLock , uxSavedInterruptStatus ) ;
2023-05-10 04:22:41 -04:00
{
if ( prvTaskIsTaskSuspended ( pxTCB ) ! = pdFALSE )
{
2023-09-14 12:35:31 -04:00
/* Get current core ID as we can no longer be preempted. */
const BaseType_t xCurCoreID = portGET_CORE_ID ( ) ;
2023-05-10 04:22:41 -04:00
traceTASK_RESUME_FROM_ISR ( pxTCB ) ;
/* Check the ready lists can be accessed. */
2023-09-14 12:35:31 -04:00
if ( taskCAN_BE_SCHEDULED ( pxTCB ) = = pdTRUE )
2023-05-10 04:22:41 -04:00
{
/* Ready lists can be accessed so move the task from the
* suspended list to the ready list directly . */
2023-11-16 06:18:17 -05:00
if ( taskIS_YIELD_REQUIRED ( pxTCB , pdTRUE ) = = pdTRUE )
2023-05-10 04:22:41 -04:00
{
xYieldRequired = pdTRUE ;
/* Mark that a yield is pending in case the user is not
* using the return value to initiate a context switch
* from the ISR using portYIELD_FROM_ISR . */
2023-09-14 12:35:31 -04:00
xYieldPending [ xCurCoreID ] = pdTRUE ;
2023-05-10 04:22:41 -04:00
}
else
{
mtCOVERAGE_TEST_MARKER ( ) ;
}
( void ) uxListRemove ( & ( pxTCB - > xStateListItem ) ) ;
prvAddTaskToReadyList ( pxTCB ) ;
}
else
{
/* The delayed or ready lists cannot be accessed so the task
* is held in the pending ready list until the scheduler is
* unsuspended . */
2023-09-14 12:35:31 -04:00
vListInsertEnd ( & ( xPendingReadyList [ xCurCoreID ] ) , & ( pxTCB - > xEventListItem ) ) ;
2023-05-10 04:22:41 -04:00
}
}
else
{
mtCOVERAGE_TEST_MARKER ( ) ;
}
}
2023-09-07 12:29:57 -04:00
prvEXIT_CRITICAL_OR_UNMASK_ISR ( & xKernelLock , uxSavedInterruptStatus ) ;
2023-05-10 04:22:41 -04:00
return xYieldRequired ;
}
# endif /* ( ( INCLUDE_xTaskResumeFromISR == 1 ) && ( INCLUDE_vTaskSuspend == 1 ) ) */
/*-----------------------------------------------------------*/
2023-09-08 10:13:06 -04:00
static BaseType_t prvCreateIdleTasks ( void )
2023-05-10 04:22:41 -04:00
{
2023-09-08 10:13:06 -04:00
BaseType_t xReturn = pdPASS ;
BaseType_t xCoreID ;
2023-11-09 00:02:56 -05:00
# if ( configNUMBER_OF_CORES > 1 )
char cIdleName [ configMAX_TASK_NAME_LEN ] ;
# endif /* #if ( configNUMBER_OF_CORES > 1 ) */
2023-05-10 04:22:41 -04:00
2023-09-08 10:13:06 -04:00
/* Add each idle task at the lowest priority. */
for ( xCoreID = ( BaseType_t ) 0 ; xCoreID < ( BaseType_t ) configNUMBER_OF_CORES ; xCoreID + + )
2023-05-10 04:22:41 -04:00
{
2023-09-08 10:13:06 -04:00
# if ( configNUMBER_OF_CORES > 1 )
{
BaseType_t x ;
if ( xReturn = = pdFAIL )
{
/* TODO: IDF-8240 - Memory leaks occur if IDLE task creation fails on some core
* as we do not free memory for the successfully created IDLE tasks . */
break ;
}
else
{
mtCOVERAGE_TEST_MARKER ( ) ;
}
for ( x = ( BaseType_t ) 0 ; x < ( BaseType_t ) configMAX_TASK_NAME_LEN ; x + + )
{
cIdleName [ x ] = configIDLE_TASK_NAME [ x ] ;
/* Don't copy all configMAX_TASK_NAME_LEN if the string is shorter than
* configMAX_TASK_NAME_LEN characters just in case the memory after the
* string is not accessible ( extremely unlikely ) . */
if ( cIdleName [ x ] = = ( char ) 0x00 )
{
break ;
}
else
{
mtCOVERAGE_TEST_MARKER ( ) ;
}
}
/* Append the idle task number to the end of the name if there is space. */
if ( x < ( BaseType_t ) configMAX_TASK_NAME_LEN )
{
cIdleName [ x ] = ( char ) ( xCoreID + ' 0 ' ) ;
x + + ;
/* And append a null character if there is space. */
if ( x < ( BaseType_t ) configMAX_TASK_NAME_LEN )
{
cIdleName [ x ] = ' \0 ' ;
}
else
{
mtCOVERAGE_TEST_MARKER ( ) ;
}
}
else
{
mtCOVERAGE_TEST_MARKER ( ) ;
}
}
# endif /* #if ( configNUMBER_OF_CORES > 1 ) */
2023-09-14 12:35:31 -04:00
/* Add the idle task at the lowest priority. */
# if ( configSUPPORT_STATIC_ALLOCATION == 1 )
{
StaticTask_t * pxIdleTaskTCBBuffer = NULL ;
StackType_t * pxIdleTaskStackBuffer = NULL ;
uint32_t ulIdleTaskStackSize ;
/* The Idle task is created using user provided RAM - obtain the
* address of the RAM then create the idle task . */
vApplicationGetIdleTaskMemory ( & pxIdleTaskTCBBuffer , & pxIdleTaskStackBuffer , & ulIdleTaskStackSize ) ;
2023-09-08 10:13:06 -04:00
xIdleTaskHandle [ xCoreID ] = xTaskCreateStaticPinnedToCore ( prvIdleTask ,
# if ( configNUMBER_OF_CORES > 1 )
cIdleName ,
# else /* #if ( configNUMBER_OF_CORES > 1 ) */
configIDLE_TASK_NAME ,
# endif /* #if ( configNUMBER_OF_CORES > 1 ) */
ulIdleTaskStackSize ,
( void * ) NULL , /*lint !e961. The cast is not redundant for all compilers. */
portPRIVILEGE_BIT , /* In effect ( tskIDLE_PRIORITY | portPRIVILEGE_BIT ), but tskIDLE_PRIORITY is zero. */
pxIdleTaskStackBuffer ,
pxIdleTaskTCBBuffer , /*lint !e961 MISRA exception, justified as it is not a redundant explicit cast to all supported compilers. */
xCoreID ) ;
if ( xIdleTaskHandle [ xCoreID ] ! = NULL )
2023-09-14 12:35:31 -04:00
{
xReturn = pdPASS ;
}
else
{
xReturn = pdFAIL ;
}
2023-05-10 04:22:41 -04:00
}
2023-09-14 12:35:31 -04:00
# else /* if ( configSUPPORT_STATIC_ALLOCATION == 1 ) */
2023-05-10 04:22:41 -04:00
{
2023-09-14 12:35:31 -04:00
/* The Idle task is being created using dynamically allocated RAM. */
xReturn = xTaskCreatePinnedToCore ( prvIdleTask ,
2023-09-08 10:13:06 -04:00
# if ( configNUMBER_OF_CORES > 1 )
cIdleName ,
# else /* #if ( configNUMBER_OF_CORES > 1 ) */
configIDLE_TASK_NAME ,
# endif /* #if ( configNUMBER_OF_CORES > 1 ) */
2023-09-14 12:35:31 -04:00
configMINIMAL_STACK_SIZE ,
( void * ) NULL ,
portPRIVILEGE_BIT , /* In effect ( tskIDLE_PRIORITY | portPRIVILEGE_BIT ), but tskIDLE_PRIORITY is zero. */
& xIdleTaskHandle [ xCoreID ] , /*lint !e961 MISRA exception, justified as it is not a redundant explicit cast to all supported compilers. */
xCoreID ) ;
2023-09-08 10:13:06 -04:00
}
2023-09-14 12:35:31 -04:00
# endif /* configSUPPORT_STATIC_ALLOCATION */
2023-05-10 04:22:41 -04:00
}
2023-09-08 10:13:06 -04:00
return xReturn ;
}
/*-----------------------------------------------------------*/
void vTaskStartScheduler ( void )
{
BaseType_t xReturn ;
/* The code for prvCreateIdleTasks() has been backported from the upstream
* FreeRTOS - Kernel source . The reference for the same is on the mainline
* at the commit id # 2f 94 b181a2f049ec342deba0927bed51f7174ab0 . */
xReturn = prvCreateIdleTasks ( ) ;
2023-05-10 04:22:41 -04:00
# if ( configUSE_TIMERS == 1 )
{
if ( xReturn = = pdPASS )
{
xReturn = xTimerCreateTimerTask ( ) ;
}
else
{
mtCOVERAGE_TEST_MARKER ( ) ;
}
}
# endif /* configUSE_TIMERS */
if ( xReturn = = pdPASS )
{
/* freertos_tasks_c_additions_init() should only be called if the user
* definable macro FREERTOS_TASKS_C_ADDITIONS_INIT ( ) is defined , as that is
* the only macro called by the function . */
# ifdef FREERTOS_TASKS_C_ADDITIONS_INIT
{
freertos_tasks_c_additions_init ( ) ;
}
# endif
/* Interrupts are turned off here, to ensure a tick does not occur
* before or during the call to xPortStartScheduler ( ) . The stacks of
* the created tasks contain a status word with interrupts switched on
* so interrupts will automatically get re - enabled when the first task
* starts to run . */
portDISABLE_INTERRUPTS ( ) ;
2023-09-07 12:29:57 -04:00
/* For SMP, we need to take the kernel lock here as we are about to
* access kernel data structures . */
2023-10-31 12:02:58 -04:00
prvENTER_CRITICAL_SMP_ONLY ( & xKernelLock ) ;
2023-05-10 04:22:41 -04:00
{
2023-09-07 12:29:57 -04:00
# if ( ( configUSE_NEWLIB_REENTRANT == 1 ) || ( configUSE_C_RUNTIME_TLS_SUPPORT == 1 ) )
{
/* Switch C-Runtime's TLS Block to point to the TLS
* block specific to the task that will run first . */
configSET_TLS_BLOCK ( pxCurrentTCBs [ portGET_CORE_ID ( ) ] - > xTLSBlock ) ;
}
# endif
2023-05-10 04:22:41 -04:00
2023-09-07 12:29:57 -04:00
xNextTaskUnblockTime = portMAX_DELAY ;
xSchedulerRunning = pdTRUE ;
xTickCount = ( TickType_t ) configINITIAL_TICK_COUNT ;
}
/* Release the previously taken kernel lock. */
2023-10-31 12:02:58 -04:00
prvEXIT_CRITICAL_SMP_ONLY ( & xKernelLock ) ;
2023-05-10 04:22:41 -04:00
/* If configGENERATE_RUN_TIME_STATS is defined then the following
* macro must be defined to configure the timer / counter used to generate
* the run time counter time base . NOTE : If configGENERATE_RUN_TIME_STATS
* is set to 0 and the following line fails to build then ensure you do not
* have portCONFIGURE_TIMER_FOR_RUN_TIME_STATS ( ) defined in your
* FreeRTOSConfig . h file . */
portCONFIGURE_TIMER_FOR_RUN_TIME_STATS ( ) ;
traceTASK_SWITCHED_IN ( ) ;
/* Setting up the timer tick is hardware specific and thus in the
* portable interface . */
xPortStartScheduler ( ) ;
/* In most cases, xPortStartScheduler() will not return. If it
* returns pdTRUE then there was not enough heap memory available
* to create either the Idle or the Timer task . If it returned
* pdFALSE , then the application called xTaskEndScheduler ( ) .
* Most ports don ' t implement xTaskEndScheduler ( ) as there is
* nothing to return to . */
}
else
{
/* This line will only be reached if the kernel could not be started,
* because there was not enough FreeRTOS heap to create the idle task
* or the timer task . */
configASSERT ( xReturn ! = errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY ) ;
}
/* Prevent compiler warnings if INCLUDE_xTaskGetIdleTaskHandle is set to 0,
* meaning xIdleTaskHandle is not used anywhere else . */
2023-09-14 12:35:31 -04:00
( void ) xIdleTaskHandle [ 0 ] ;
2023-05-10 04:22:41 -04:00
/* OpenOCD makes use of uxTopUsedPriority for thread debugging. Prevent uxTopUsedPriority
* from getting optimized out as it is no longer used by the kernel . */
( void ) uxTopUsedPriority ;
}
/*-----------------------------------------------------------*/
void vTaskEndScheduler ( void )
{
/* Stop the scheduler interrupts and call the portable scheduler end
* routine so the original ISRs can be restored if necessary . The port
* layer must ensure interrupts enable bit is left in the correct state . */
portDISABLE_INTERRUPTS ( ) ;
2023-09-07 12:29:57 -04:00
/* For SMP, we need to take the kernel lock here as we are about to access
* kernel data structures . */
2023-10-31 12:02:58 -04:00
prvENTER_CRITICAL_SMP_ONLY ( & xKernelLock ) ;
2023-09-07 12:29:57 -04:00
{
xSchedulerRunning = pdFALSE ;
}
/* Release the previously taken kernel lock. */
2023-10-31 12:02:58 -04:00
prvEXIT_CRITICAL_SMP_ONLY ( & xKernelLock ) ;
2023-05-10 04:22:41 -04:00
vPortEndScheduler ( ) ;
}
/*----------------------------------------------------------*/
void vTaskSuspendAll ( void )
{
2024-05-14 10:32:25 -04:00
/* For SMP, we need to take the kernel lock here as we are about to access
* kernel data structures .
*
* For single - core , a critical section is not required as the variable is of type
2023-05-10 04:22:41 -04:00
* BaseType_t . Please read Richard Barry ' s reply in the following link to a
* post in the FreeRTOS support forum before reporting this as a bug ! -
* https : //goo.gl/wu4acr */
2024-05-14 10:32:25 -04:00
prvENTER_CRITICAL_SMP_ONLY ( & xKernelLock ) ;
{
/* portSOFTWARE_BARRIER() is only implemented for emulated/simulated ports that
* do not otherwise exhibit real time behaviour . */
portSOFTWARE_BARRIER ( ) ;
2023-05-10 04:22:41 -04:00
2024-05-14 10:32:25 -04:00
/* The scheduler is suspended if uxSchedulerSuspended is non-zero. An increment
* is used to allow calls to vTaskSuspendAll ( ) to nest . */
+ + uxSchedulerSuspended [ portGET_CORE_ID ( ) ] ;
2023-05-10 04:22:41 -04:00
2024-05-14 10:32:25 -04:00
/* Enforces ordering for ports and optimised compilers that may otherwise place
* the above increment elsewhere . */
portMEMORY_BARRIER ( ) ;
}
/* Release the previously taken kernel lock. */
prvEXIT_CRITICAL_SMP_ONLY ( & xKernelLock ) ;
2023-05-10 04:22:41 -04:00
}
/*----------------------------------------------------------*/
# if ( configUSE_TICKLESS_IDLE != 0 )
static TickType_t prvGetExpectedIdleTime ( void )
{
TickType_t xReturn ;
UBaseType_t uxHigherPriorityReadyTasks = pdFALSE ;
/* uxHigherPriorityReadyTasks takes care of the case where
* configUSE_PREEMPTION is 0 , so there may be tasks above the idle priority
* task that are in the Ready state , even though the idle task is
* running . */
# if ( configUSE_PORT_OPTIMISED_TASK_SELECTION == 0 )
{
if ( uxTopReadyPriority > tskIDLE_PRIORITY )
{
uxHigherPriorityReadyTasks = pdTRUE ;
}
}
# else
{
const UBaseType_t uxLeastSignificantBit = ( UBaseType_t ) 0x01 ;
/* When port optimised task selection is used the uxTopReadyPriority
* variable is used as a bit map . If bits other than the least
* significant bit are set then there are tasks that have a priority
* above the idle priority that are in the Ready state . This takes
* care of the case where the co - operative scheduler is in use . */
if ( uxTopReadyPriority > uxLeastSignificantBit )
{
uxHigherPriorityReadyTasks = pdTRUE ;
}
}
# endif /* if ( configUSE_PORT_OPTIMISED_TASK_SELECTION == 0 ) */
2023-09-14 12:35:31 -04:00
if ( pxCurrentTCBs [ portGET_CORE_ID ( ) ] - > uxPriority > tskIDLE_PRIORITY )
2023-05-10 04:22:41 -04:00
{
xReturn = 0 ;
}
2023-09-14 12:35:31 -04:00
else if ( listCURRENT_LIST_LENGTH ( & ( pxReadyTasksLists [ tskIDLE_PRIORITY ] ) ) > configNUMBER_OF_CORES )
2023-05-10 04:22:41 -04:00
{
/* There are other idle priority tasks in the ready state. If
* time slicing is used then the very next tick interrupt must be
* processed . */
xReturn = 0 ;
}
else if ( uxHigherPriorityReadyTasks ! = pdFALSE )
{
/* There are tasks in the Ready state that have a priority above the
* idle priority . This path can only be reached if
* configUSE_PREEMPTION is 0. */
xReturn = 0 ;
}
else
{
xReturn = xNextTaskUnblockTime - xTickCount ;
}
return xReturn ;
}
# endif /* configUSE_TICKLESS_IDLE */
/*----------------------------------------------------------*/
BaseType_t xTaskResumeAll ( void )
{
TCB_t * pxTCB = NULL ;
BaseType_t xAlreadyYielded = pdFALSE ;
/* If uxSchedulerSuspended is zero then this function does not match a
* previous call to vTaskSuspendAll ( ) . */
2023-09-14 12:35:31 -04:00
configASSERT ( taskIS_SCHEDULER_SUSPENDED ( ) = = pdTRUE ) ;
2023-05-10 04:22:41 -04:00
/* It is possible that an ISR caused a task to be removed from an event
* list while the scheduler was suspended . If this was the case then the
* removed task will have been added to the xPendingReadyList . Once the
* scheduler has been resumed it is safe to move all the pending ready
* tasks from this list into their appropriate ready list . */
2023-09-07 12:29:57 -04:00
taskENTER_CRITICAL ( & xKernelLock ) ;
2023-05-10 04:22:41 -04:00
{
2023-09-14 12:35:31 -04:00
/* Get current core ID as we can no longer be preempted. */
const BaseType_t xCurCoreID = portGET_CORE_ID ( ) ;
2023-05-10 04:22:41 -04:00
2023-09-14 12:35:31 -04:00
- - uxSchedulerSuspended [ xCurCoreID ] ;
if ( uxSchedulerSuspended [ xCurCoreID ] = = ( UBaseType_t ) pdFALSE )
2023-05-10 04:22:41 -04:00
{
if ( uxCurrentNumberOfTasks > ( UBaseType_t ) 0U )
{
/* Move any readied tasks from the pending list into the
* appropriate ready list . */
2023-09-14 12:35:31 -04:00
while ( listLIST_IS_EMPTY ( & xPendingReadyList [ xCurCoreID ] ) = = pdFALSE )
2023-05-10 04:22:41 -04:00
{
2023-11-10 03:23:51 -05:00
pxTCB = listGET_OWNER_OF_HEAD_ENTRY ( ( & xPendingReadyList [ xCurCoreID ] ) ) ; /*lint !e9079 void * is used as this macro is used with timers and co-routines too. Alignment is known to be fine as the type of the pointer stored and retrieved is the same. */
2023-05-10 04:22:41 -04:00
listREMOVE_ITEM ( & ( pxTCB - > xEventListItem ) ) ;
portMEMORY_BARRIER ( ) ;
listREMOVE_ITEM ( & ( pxTCB - > xStateListItem ) ) ;
prvAddTaskToReadyList ( pxTCB ) ;
/* If the moved task has a priority higher than or equal to
* the current task then a yield must be performed . */
2023-11-16 06:18:17 -05:00
if ( taskIS_YIELD_REQUIRED ( pxTCB , pdTRUE ) = = pdTRUE )
2023-05-10 04:22:41 -04:00
{
2023-09-14 12:35:31 -04:00
xYieldPending [ xCurCoreID ] = pdTRUE ;
2023-05-10 04:22:41 -04:00
}
else
{
mtCOVERAGE_TEST_MARKER ( ) ;
}
}
if ( pxTCB ! = NULL )
{
/* A task was unblocked while the scheduler was suspended,
* which may have prevented the next unblock time from being
* re - calculated , in which case re - calculate it now . Mainly
* important for low power tickless implementations , where
* this can prevent an unnecessary exit from low power
* state . */
prvResetNextTaskUnblockTime ( ) ;
}
2023-09-14 12:35:31 -04:00
# if ( configNUMBER_OF_CORES > 1 )
/* Core 0 is solely responsible for managing tick count, thus it
* must be the only core to unwind the pended ticks */
if ( xCurCoreID = = 0 )
# endif
2023-05-10 04:22:41 -04:00
/* If any ticks occurred while the scheduler was suspended then
* they should be processed now . This ensures the tick count does
* not slip , and that any delayed tasks are resumed at the correct
* time . */
{
TickType_t xPendedCounts = xPendedTicks ; /* Non-volatile copy. */
if ( xPendedCounts > ( TickType_t ) 0U )
{
do
{
if ( xTaskIncrementTick ( ) ! = pdFALSE )
{
2023-09-14 12:35:31 -04:00
xYieldPending [ xCurCoreID ] = pdTRUE ;
2023-05-10 04:22:41 -04:00
}
else
{
mtCOVERAGE_TEST_MARKER ( ) ;
}
- - xPendedCounts ;
} while ( xPendedCounts > ( TickType_t ) 0U ) ;
xPendedTicks = 0 ;
}
else
{
mtCOVERAGE_TEST_MARKER ( ) ;
}
}
2023-09-14 12:35:31 -04:00
if ( xYieldPending [ xCurCoreID ] ! = pdFALSE )
2023-05-10 04:22:41 -04:00
{
# if ( configUSE_PREEMPTION != 0 )
{
xAlreadyYielded = pdTRUE ;
}
# endif
taskYIELD_IF_USING_PREEMPTION ( ) ;
}
else
{
mtCOVERAGE_TEST_MARKER ( ) ;
}
}
}
else
{
mtCOVERAGE_TEST_MARKER ( ) ;
}
}
2023-09-07 12:29:57 -04:00
taskEXIT_CRITICAL ( & xKernelLock ) ;
2023-05-10 04:22:41 -04:00
return xAlreadyYielded ;
}
/*-----------------------------------------------------------*/
TickType_t xTaskGetTickCount ( void )
{
TickType_t xTicks ;
/* Critical section required if running on a 16 bit processor. */
portTICK_TYPE_ENTER_CRITICAL ( ) ;
{
xTicks = xTickCount ;
}
portTICK_TYPE_EXIT_CRITICAL ( ) ;
return xTicks ;
}
/*-----------------------------------------------------------*/
TickType_t xTaskGetTickCountFromISR ( void )
{
TickType_t xReturn ;
UBaseType_t uxSavedInterruptStatus ;
/* RTOS ports that support interrupt nesting have the concept of a maximum
* system call ( or maximum API call ) interrupt priority . Interrupts that are
* above the maximum system call priority are kept permanently enabled , even
* when the RTOS kernel is in a critical section , but cannot make any calls to
* FreeRTOS API functions . If configASSERT ( ) is defined in FreeRTOSConfig . h
* then portASSERT_IF_INTERRUPT_PRIORITY_INVALID ( ) will result in an assertion
* failure if a FreeRTOS API function is called from an interrupt that has been
* assigned a priority above the configured maximum system call priority .
* Only FreeRTOS functions that end in FromISR can be called from interrupts
* that have been assigned a priority at or ( logically ) below the maximum
* system call interrupt priority . FreeRTOS maintains a separate interrupt
* safe API to ensure interrupt entry is as fast and as simple as possible .
* More information ( albeit Cortex - M specific ) is provided on the following
* link : https : //www.FreeRTOS.org/RTOS-Cortex-M3-M4.html */
portASSERT_IF_INTERRUPT_PRIORITY_INVALID ( ) ;
2023-09-07 12:29:57 -04:00
/* For SMP, we need to take the kernel lock here as we are about to access
* kernel data structures . */
2023-10-31 12:02:58 -04:00
prvENTER_CRITICAL_ISR_SMP_ONLY ( & xKernelLock ) ;
2023-05-10 04:22:41 -04:00
{
2023-09-07 12:29:57 -04:00
uxSavedInterruptStatus = portTICK_TYPE_SET_INTERRUPT_MASK_FROM_ISR ( ) ;
{
xReturn = xTickCount ;
}
portTICK_TYPE_CLEAR_INTERRUPT_MASK_FROM_ISR ( uxSavedInterruptStatus ) ;
2023-05-10 04:22:41 -04:00
}
2023-09-07 12:29:57 -04:00
/* Release the previously taken kernel lock. */
2023-10-31 12:02:58 -04:00
prvEXIT_CRITICAL_ISR_SMP_ONLY ( & xKernelLock ) ;
2023-05-10 04:22:41 -04:00
return xReturn ;
}
/*-----------------------------------------------------------*/
UBaseType_t uxTaskGetNumberOfTasks ( void )
{
/* A critical section is not required because the variables are of type
* BaseType_t . */
return uxCurrentNumberOfTasks ;
}
/*-----------------------------------------------------------*/
char * pcTaskGetName ( TaskHandle_t xTaskToQuery ) /*lint !e971 Unqualified char types are allowed for strings and single characters only. */
{
TCB_t * pxTCB ;
/* If null is passed in here then the name of the calling task is being
* queried . */
pxTCB = prvGetTCBFromHandle ( xTaskToQuery ) ;
configASSERT ( pxTCB ) ;
return & ( pxTCB - > pcTaskName [ 0 ] ) ;
}
/*-----------------------------------------------------------*/
# if ( INCLUDE_xTaskGetHandle == 1 )
static TCB_t * prvSearchForNameWithinSingleList ( List_t * pxList ,
const char pcNameToQuery [ ] )
{
TCB_t * pxNextTCB ;
TCB_t * pxFirstTCB ;
TCB_t * pxReturn = NULL ;
UBaseType_t x ;
char cNextChar ;
BaseType_t xBreakLoop ;
/* This function is called with the scheduler suspended. */
if ( listCURRENT_LIST_LENGTH ( pxList ) > ( UBaseType_t ) 0 )
{
listGET_OWNER_OF_NEXT_ENTRY ( pxFirstTCB , pxList ) ; /*lint !e9079 void * is used as this macro is used with timers and co-routines too. Alignment is known to be fine as the type of the pointer stored and retrieved is the same. */
do
{
listGET_OWNER_OF_NEXT_ENTRY ( pxNextTCB , pxList ) ; /*lint !e9079 void * is used as this macro is used with timers and co-routines too. Alignment is known to be fine as the type of the pointer stored and retrieved is the same. */
/* Check each character in the name looking for a match or
* mismatch . */
xBreakLoop = pdFALSE ;
for ( x = ( UBaseType_t ) 0 ; x < ( UBaseType_t ) configMAX_TASK_NAME_LEN ; x + + )
{
cNextChar = pxNextTCB - > pcTaskName [ x ] ;
if ( cNextChar ! = pcNameToQuery [ x ] )
{
/* Characters didn't match. */
xBreakLoop = pdTRUE ;
}
else if ( cNextChar = = ( char ) 0x00 )
{
/* Both strings terminated, a match must have been
* found . */
pxReturn = pxNextTCB ;
xBreakLoop = pdTRUE ;
}
else
{
mtCOVERAGE_TEST_MARKER ( ) ;
}
if ( xBreakLoop ! = pdFALSE )
{
break ;
}
}
if ( pxReturn ! = NULL )
{
/* The handle has been found. */
break ;
}
} while ( pxNextTCB ! = pxFirstTCB ) ;
}
else
{
mtCOVERAGE_TEST_MARKER ( ) ;
}
return pxReturn ;
}
# endif /* INCLUDE_xTaskGetHandle */
/*-----------------------------------------------------------*/
# if ( INCLUDE_xTaskGetHandle == 1 )
TaskHandle_t xTaskGetHandle ( const char * pcNameToQuery ) /*lint !e971 Unqualified char types are allowed for strings and single characters only. */
{
UBaseType_t uxQueue = configMAX_PRIORITIES ;
TCB_t * pxTCB ;
/* Task names will be truncated to configMAX_TASK_NAME_LEN - 1 bytes. */
configASSERT ( strlen ( pcNameToQuery ) < configMAX_TASK_NAME_LEN ) ;
2023-09-07 12:29:57 -04:00
prvENTER_CRITICAL_OR_SUSPEND_ALL ( & xKernelLock ) ;
2023-05-10 04:22:41 -04:00
{
/* Search the ready lists. */
do
{
uxQueue - - ;
pxTCB = prvSearchForNameWithinSingleList ( ( List_t * ) & ( pxReadyTasksLists [ uxQueue ] ) , pcNameToQuery ) ;
if ( pxTCB ! = NULL )
{
/* Found the handle. */
break ;
}
} while ( uxQueue > ( UBaseType_t ) tskIDLE_PRIORITY ) ; /*lint !e961 MISRA exception as the casts are only redundant for some ports. */
/* Search the delayed lists. */
if ( pxTCB = = NULL )
{
pxTCB = prvSearchForNameWithinSingleList ( ( List_t * ) pxDelayedTaskList , pcNameToQuery ) ;
}
if ( pxTCB = = NULL )
{
pxTCB = prvSearchForNameWithinSingleList ( ( List_t * ) pxOverflowDelayedTaskList , pcNameToQuery ) ;
}
# if ( INCLUDE_vTaskSuspend == 1 )
{
if ( pxTCB = = NULL )
{
/* Search the suspended list. */
pxTCB = prvSearchForNameWithinSingleList ( & xSuspendedTaskList , pcNameToQuery ) ;
}
}
# endif
# if ( INCLUDE_vTaskDelete == 1 )
{
if ( pxTCB = = NULL )
{
/* Search the deleted list. */
pxTCB = prvSearchForNameWithinSingleList ( & xTasksWaitingTermination , pcNameToQuery ) ;
}
}
# endif
}
2023-09-07 12:29:57 -04:00
( void ) prvEXIT_CRITICAL_OR_RESUME_ALL ( & xKernelLock ) ;
2023-05-10 04:22:41 -04:00
return pxTCB ;
}
# endif /* INCLUDE_xTaskGetHandle */
2023-07-13 07:01:20 -04:00
/*-----------------------------------------------------------*/
# if ( configSUPPORT_STATIC_ALLOCATION == 1 )
BaseType_t xTaskGetStaticBuffers ( TaskHandle_t xTask ,
StackType_t * * ppuxStackBuffer ,
StaticTask_t * * ppxTaskBuffer )
{
BaseType_t xReturn ;
TCB_t * pxTCB ;
configASSERT ( ppuxStackBuffer ! = NULL ) ;
configASSERT ( ppxTaskBuffer ! = NULL ) ;
pxTCB = prvGetTCBFromHandle ( xTask ) ;
# if ( tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE == 1 )
{
if ( pxTCB - > ucStaticallyAllocated = = tskSTATICALLY_ALLOCATED_STACK_AND_TCB )
{
* ppuxStackBuffer = pxTCB - > pxStack ;
* ppxTaskBuffer = ( StaticTask_t * ) pxTCB ;
xReturn = pdTRUE ;
}
else if ( pxTCB - > ucStaticallyAllocated = = tskSTATICALLY_ALLOCATED_STACK_ONLY )
{
* ppuxStackBuffer = pxTCB - > pxStack ;
* ppxTaskBuffer = NULL ;
xReturn = pdTRUE ;
}
else
{
xReturn = pdFALSE ;
}
}
# else /* tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE == 1 */
{
* ppuxStackBuffer = pxTCB - > pxStack ;
* ppxTaskBuffer = ( StaticTask_t * ) pxTCB ;
xReturn = pdTRUE ;
}
# endif /* tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE == 1 */
return xReturn ;
}
# endif /* configSUPPORT_STATIC_ALLOCATION */
2023-05-10 04:22:41 -04:00
/*-----------------------------------------------------------*/
# if ( configUSE_TRACE_FACILITY == 1 )
UBaseType_t uxTaskGetSystemState ( TaskStatus_t * const pxTaskStatusArray ,
const UBaseType_t uxArraySize ,
configRUN_TIME_COUNTER_TYPE * const pulTotalRunTime )
{
UBaseType_t uxTask = 0 , uxQueue = configMAX_PRIORITIES ;
2023-09-07 12:29:57 -04:00
prvENTER_CRITICAL_OR_SUSPEND_ALL ( & xKernelLock ) ;
2023-05-10 04:22:41 -04:00
{
/* Is there a space in the array for each task in the system? */
if ( uxArraySize > = uxCurrentNumberOfTasks )
{
/* Fill in an TaskStatus_t structure with information on each
* task in the Ready state . */
do
{
uxQueue - - ;
uxTask + = prvListTasksWithinSingleList ( & ( pxTaskStatusArray [ uxTask ] ) , & ( pxReadyTasksLists [ uxQueue ] ) , eReady ) ;
} while ( uxQueue > ( UBaseType_t ) tskIDLE_PRIORITY ) ; /*lint !e961 MISRA exception as the casts are only redundant for some ports. */
/* Fill in an TaskStatus_t structure with information on each
* task in the Blocked state . */
uxTask + = prvListTasksWithinSingleList ( & ( pxTaskStatusArray [ uxTask ] ) , ( List_t * ) pxDelayedTaskList , eBlocked ) ;
uxTask + = prvListTasksWithinSingleList ( & ( pxTaskStatusArray [ uxTask ] ) , ( List_t * ) pxOverflowDelayedTaskList , eBlocked ) ;
# if ( INCLUDE_vTaskDelete == 1 )
{
/* Fill in an TaskStatus_t structure with information on
* each task that has been deleted but not yet cleaned up . */
uxTask + = prvListTasksWithinSingleList ( & ( pxTaskStatusArray [ uxTask ] ) , & xTasksWaitingTermination , eDeleted ) ;
}
# endif
# if ( INCLUDE_vTaskSuspend == 1 )
{
/* Fill in an TaskStatus_t structure with information on
* each task in the Suspended state . */
uxTask + = prvListTasksWithinSingleList ( & ( pxTaskStatusArray [ uxTask ] ) , & xSuspendedTaskList , eSuspended ) ;
}
# endif
# if ( configGENERATE_RUN_TIME_STATS == 1 )
{
if ( pulTotalRunTime ! = NULL )
{
# ifdef portALT_GET_RUN_TIME_COUNTER_VALUE
portALT_GET_RUN_TIME_COUNTER_VALUE ( ( * pulTotalRunTime ) ) ;
# else
* pulTotalRunTime = portGET_RUN_TIME_COUNTER_VALUE ( ) ;
# endif
}
}
# else /* if ( configGENERATE_RUN_TIME_STATS == 1 ) */
{
if ( pulTotalRunTime ! = NULL )
{
* pulTotalRunTime = 0 ;
}
}
# endif /* if ( configGENERATE_RUN_TIME_STATS == 1 ) */
}
else
{
mtCOVERAGE_TEST_MARKER ( ) ;
}
}
2023-09-07 12:29:57 -04:00
( void ) prvEXIT_CRITICAL_OR_RESUME_ALL ( & xKernelLock ) ;
2023-05-10 04:22:41 -04:00
return uxTask ;
}
# endif /* configUSE_TRACE_FACILITY */
/*----------------------------------------------------------*/
# if ( INCLUDE_xTaskGetIdleTaskHandle == 1 )
TaskHandle_t xTaskGetIdleTaskHandle ( void )
{
2023-09-14 12:35:31 -04:00
return xTaskGetIdleTaskHandleForCore ( portGET_CORE_ID ( ) ) ;
2023-05-10 04:22:41 -04:00
}
# endif /* INCLUDE_xTaskGetIdleTaskHandle */
/*----------------------------------------------------------*/
/* This conditional compilation should use inequality to 0, not equality to 1.
* This is to ensure vTaskStepTick ( ) is available when user defined low power mode
* implementations require configUSE_TICKLESS_IDLE to be set to a value other than
* 1. */
# if ( configUSE_TICKLESS_IDLE != 0 )
void vTaskStepTick ( TickType_t xTicksToJump )
{
2023-09-07 12:29:57 -04:00
/* SINGLE-CORE MODIFICATION: Expanded critical section so that SMP
* accesses xTickCount inside a critical section . */
taskENTER_CRITICAL ( & xKernelLock ) ;
2023-05-10 04:22:41 -04:00
{
2023-09-14 12:35:31 -04:00
/* Correct the tick count value after a period during which the tick
* was suppressed . Note this does * not * call the tick hook function for
* each stepped tick . */
configASSERT ( ( xTickCount + xTicksToJump ) < = xNextTaskUnblockTime ) ;
2023-05-10 04:22:41 -04:00
2023-09-14 12:35:31 -04:00
if ( ( xTickCount + xTicksToJump ) = = xNextTaskUnblockTime )
2023-05-10 04:22:41 -04:00
{
2023-09-14 12:35:31 -04:00
/* Arrange for xTickCount to reach xNextTaskUnblockTime in
* xTaskIncrementTick ( ) when the scheduler resumes . This ensures
* that any delayed tasks are resumed at the correct time . */
2023-10-20 04:34:20 -04:00
# if ( configNUMBER_OF_CORES > 1 )
{
/* In SMP, the entire tickless idle handling block
* is replaced with a critical section , taking the kernel lock . */
configASSERT ( taskIS_SCHEDULER_SUSPENDED ( ) = = pdFALSE ) ;
}
# else /* configNUMBER_OF_CORES > 1 */
{
/* In single-core, the entire tickless idle handling block
* is done with scheduler suspended . */
configASSERT ( taskIS_SCHEDULER_SUSPENDED ( ) = = pdTRUE ) ;
}
# endif /* configNUMBER_OF_CORES > 1 */
2023-09-14 12:35:31 -04:00
configASSERT ( xTicksToJump ! = ( TickType_t ) 0 ) ;
2023-05-10 04:22:41 -04:00
xPendedTicks + + ;
2023-09-14 12:35:31 -04:00
xTicksToJump - - ;
}
else
{
mtCOVERAGE_TEST_MARKER ( ) ;
2023-05-10 04:22:41 -04:00
}
2023-09-14 12:35:31 -04:00
xTickCount + = xTicksToJump ;
traceINCREASE_TICK_COUNT ( xTicksToJump ) ;
}
2023-09-07 12:29:57 -04:00
/* SINGLE-CORE MODIFICATION: Expanded critical section */
taskEXIT_CRITICAL ( & xKernelLock ) ;
2023-05-10 04:22:41 -04:00
}
# endif /* configUSE_TICKLESS_IDLE */
/*----------------------------------------------------------*/
BaseType_t xTaskCatchUpTicks ( TickType_t xTicksToCatchUp )
{
BaseType_t xYieldOccurred ;
/* Must not be called with the scheduler suspended as the implementation
* relies on xPendedTicks being wound down to 0 in xTaskResumeAll ( ) . */
2023-09-14 12:35:31 -04:00
configASSERT ( taskIS_SCHEDULER_SUSPENDED ( ) = = pdFALSE ) ;
2023-05-10 04:22:41 -04:00
/* Use xPendedTicks to mimic xTicksToCatchUp number of ticks occurring when
* the scheduler is suspended so the ticks are executed in xTaskResumeAll ( ) . */
vTaskSuspendAll ( ) ;
/* Prevent the tick interrupt modifying xPendedTicks simultaneously. */
2023-09-07 12:29:57 -04:00
taskENTER_CRITICAL ( & xKernelLock ) ;
2023-05-10 04:22:41 -04:00
{
xPendedTicks + = xTicksToCatchUp ;
}
2023-09-07 12:29:57 -04:00
taskEXIT_CRITICAL ( & xKernelLock ) ;
2023-05-10 04:22:41 -04:00
xYieldOccurred = xTaskResumeAll ( ) ;
return xYieldOccurred ;
}
/*----------------------------------------------------------*/
# if ( INCLUDE_xTaskAbortDelay == 1 )
BaseType_t xTaskAbortDelay ( TaskHandle_t xTask )
{
TCB_t * pxTCB = xTask ;
BaseType_t xReturn ;
configASSERT ( pxTCB ) ;
2023-09-07 12:29:57 -04:00
prvENTER_CRITICAL_OR_SUSPEND_ALL ( & xKernelLock ) ;
2023-05-10 04:22:41 -04:00
{
/* A task can only be prematurely removed from the Blocked state if
* it is actually in the Blocked state . */
if ( eTaskGetState ( xTask ) = = eBlocked )
{
xReturn = pdPASS ;
/* Remove the reference to the task from the blocked list. An
* interrupt won ' t touch the xStateListItem because the
* scheduler is suspended . */
( void ) uxListRemove ( & ( pxTCB - > xStateListItem ) ) ;
/* Is the task waiting on an event also? If so remove it from
* the event list too . Interrupts can touch the event list item ,
* even though the scheduler is suspended , so a critical section
* is used . */
2023-10-31 12:02:58 -04:00
prvENTER_CRITICAL_SC_ONLY ( & xKernelLock ) ;
2023-05-10 04:22:41 -04:00
{
if ( listLIST_ITEM_CONTAINER ( & ( pxTCB - > xEventListItem ) ) ! = NULL )
{
( void ) uxListRemove ( & ( pxTCB - > xEventListItem ) ) ;
/* This lets the task know it was forcibly removed from the
* blocked state so it should not re - evaluate its block time and
* then block again . */
pxTCB - > ucDelayAborted = pdTRUE ;
}
else
{
mtCOVERAGE_TEST_MARKER ( ) ;
}
}
2023-10-31 12:02:58 -04:00
prvEXIT_CRITICAL_SC_ONLY ( & xKernelLock ) ;
2023-05-10 04:22:41 -04:00
/* Place the unblocked task into the appropriate ready list. */
prvAddTaskToReadyList ( pxTCB ) ;
/* A task being unblocked cannot cause an immediate context
* switch if preemption is turned off . */
# if ( configUSE_PREEMPTION == 1 )
{
2023-09-14 12:35:31 -04:00
/* Get current core ID as we can no longer be preempted. */
const BaseType_t xCurCoreID = portGET_CORE_ID ( ) ;
2023-05-10 04:22:41 -04:00
/* Preemption is on, but a context switch should only be
* performed if the unblocked task has a priority that is
* higher than the currently executing task . */
2023-11-16 06:18:17 -05:00
if ( taskIS_YIELD_REQUIRED ( pxTCB , pdFALSE ) = = pdTRUE )
2023-05-10 04:22:41 -04:00
{
/* Pend the yield to be performed when the scheduler
* is unsuspended . */
2023-09-14 12:35:31 -04:00
xYieldPending [ xCurCoreID ] = pdTRUE ;
2023-05-10 04:22:41 -04:00
}
else
{
mtCOVERAGE_TEST_MARKER ( ) ;
}
}
# endif /* configUSE_PREEMPTION */
}
else
{
xReturn = pdFAIL ;
}
}
2023-09-07 12:29:57 -04:00
( void ) prvEXIT_CRITICAL_OR_RESUME_ALL ( & xKernelLock ) ;
2023-05-10 04:22:41 -04:00
return xReturn ;
}
# endif /* INCLUDE_xTaskAbortDelay */
/*----------------------------------------------------------*/
BaseType_t xTaskIncrementTick ( void )
{
2023-09-14 12:35:31 -04:00
# if ( configNUMBER_OF_CORES > 1 )
/* Only Core 0 should ever call this function. */
configASSERT ( portGET_CORE_ID ( ) = = 0 ) ;
# endif /* configNUMBER_OF_CORES > 1 */
2023-05-10 04:22:41 -04:00
TCB_t * pxTCB ;
TickType_t xItemValue ;
BaseType_t xSwitchRequired = pdFALSE ;
2023-09-07 12:29:57 -04:00
# if ( configUSE_TICK_HOOK == 1 )
BaseType_t xCallTickHook ;
# endif /* configUSE_TICK_HOOK == 1 */
2023-05-10 04:22:41 -04:00
/* Called by the portable layer each time a tick interrupt occurs.
* Increments the tick then checks to see if the new tick value will cause any
* tasks to be unblocked . */
traceTASK_INCREMENT_TICK ( xTickCount ) ;
2023-09-07 12:29:57 -04:00
/* For SMP, we need to take the kernel lock here as we are about to access
* kernel data structures ( unlike single core which calls this function with
* interrupts disabled ) . */
2023-10-31 12:02:58 -04:00
prvENTER_CRITICAL_SAFE_SMP_ONLY ( & xKernelLock ) ;
2023-05-10 04:22:41 -04:00
{
2023-09-07 12:29:57 -04:00
if ( uxSchedulerSuspended [ 0 ] = = ( UBaseType_t ) pdFALSE )
{
/* Minor optimisation. The tick count cannot change in this
* block . */
const TickType_t xConstTickCount = xTickCount + ( TickType_t ) 1 ;
2023-05-10 04:22:41 -04:00
2023-09-07 12:29:57 -04:00
/* Increment the RTOS tick, switching the delayed and overflowed
* delayed lists if it wraps to 0. */
xTickCount = xConstTickCount ;
2023-05-10 04:22:41 -04:00
2023-09-07 12:29:57 -04:00
if ( xConstTickCount = = ( TickType_t ) 0U ) /*lint !e774 'if' does not always evaluate to false as it is looking for an overflow. */
{
taskSWITCH_DELAYED_LISTS ( ) ;
}
else
{
mtCOVERAGE_TEST_MARKER ( ) ;
}
2023-05-10 04:22:41 -04:00
2023-09-07 12:29:57 -04:00
/* See if this tick has made a timeout expire. Tasks are stored in
* the queue in the order of their wake time - meaning once one task
* has been found whose block time has not expired there is no need to
* look any further down the list . */
if ( xConstTickCount > = xNextTaskUnblockTime )
2023-05-10 04:22:41 -04:00
{
2023-09-07 12:29:57 -04:00
for ( ; ; )
2023-05-10 04:22:41 -04:00
{
2023-09-07 12:29:57 -04:00
if ( listLIST_IS_EMPTY ( pxDelayedTaskList ) ! = pdFALSE )
2023-05-10 04:22:41 -04:00
{
2023-09-07 12:29:57 -04:00
/* The delayed list is empty. Set xNextTaskUnblockTime
* to the maximum possible value so it is extremely
* unlikely that the
* if ( xTickCount > = xNextTaskUnblockTime ) test will pass
* next time through . */
xNextTaskUnblockTime = portMAX_DELAY ; /*lint !e961 MISRA exception as the casts are only redundant for some ports. */
break ;
2023-05-10 04:22:41 -04:00
}
else
{
2023-09-07 12:29:57 -04:00
/* The delayed list is not empty, get the value of the
* item at the head of the delayed list . This is the time
* at which the task at the head of the delayed list must
* be removed from the Blocked state . */
pxTCB = listGET_OWNER_OF_HEAD_ENTRY ( pxDelayedTaskList ) ; /*lint !e9079 void * is used as this macro is used with timers and co-routines too. Alignment is known to be fine as the type of the pointer stored and retrieved is the same. */
xItemValue = listGET_LIST_ITEM_VALUE ( & ( pxTCB - > xStateListItem ) ) ;
if ( xConstTickCount < xItemValue )
{
/* It is not time to unblock this item yet, but the
* item value is the time at which the task at the head
* of the blocked list must be removed from the Blocked
* state - so record the item value in
* xNextTaskUnblockTime . */
xNextTaskUnblockTime = xItemValue ;
break ; /*lint !e9011 Code structure here is deemed easier to understand with multiple breaks. */
}
else
{
mtCOVERAGE_TEST_MARKER ( ) ;
}
2023-05-10 04:22:41 -04:00
2023-09-07 12:29:57 -04:00
/* It is time to remove the item from the Blocked state. */
listREMOVE_ITEM ( & ( pxTCB - > xStateListItem ) ) ;
2023-05-10 04:22:41 -04:00
2023-09-07 12:29:57 -04:00
/* Is the task waiting on an event also? If so remove
* it from the event list . */
if ( listLIST_ITEM_CONTAINER ( & ( pxTCB - > xEventListItem ) ) ! = NULL )
2023-05-10 04:22:41 -04:00
{
2023-09-07 12:29:57 -04:00
listREMOVE_ITEM ( & ( pxTCB - > xEventListItem ) ) ;
2023-05-10 04:22:41 -04:00
}
else
{
mtCOVERAGE_TEST_MARKER ( ) ;
}
2023-09-07 12:29:57 -04:00
/* Place the unblocked task into the appropriate ready
* list . */
prvAddTaskToReadyList ( pxTCB ) ;
/* A task being unblocked cannot cause an immediate
* context switch if preemption is turned off . */
# if ( configUSE_PREEMPTION == 1 )
{
/* Preemption is on, but a context switch should
* only be performed if the unblocked task has a
* priority that is equal to or higher than the
* currently executing task .
*
* For SMP , since this function is only run on core
* 0 , we only need to context switch if the unblocked
* task can run on core 0 and has a higher priority
2024-01-02 11:14:02 -05:00
* than the current task .
*
* If the unblocked task has affinity to the other
* core or no affinity then we need to set xYieldPending
* for the other core if the unblocked task has a priority
* higher than the priority of the currently running task
* on the other core . */
if ( taskIS_AFFINITY_COMPATIBLE ( 0 , pxTCB ) = = pdTRUE )
2023-09-07 12:29:57 -04:00
{
2024-01-02 11:14:02 -05:00
if ( pxTCB - > uxPriority > pxCurrentTCBs [ 0 ] - > uxPriority )
{
xSwitchRequired = pdTRUE ;
}
# if ( configNUMBER_OF_CORES > 1 )
else if ( pxTCB - > xCoreID = = tskNO_AFFINITY )
{
if ( pxTCB - > uxPriority > pxCurrentTCBs [ 1 ] - > uxPriority )
{
xYieldPending [ 1 ] = pdTRUE ;
}
else
{
mtCOVERAGE_TEST_MARKER ( ) ;
}
}
# endif /* if ( configNUMBER_OF_CORES > 1 ) */
else
{
mtCOVERAGE_TEST_MARKER ( ) ;
}
2023-09-07 12:29:57 -04:00
}
2024-01-02 11:14:02 -05:00
# if ( configNUMBER_OF_CORES > 1 )
else
{
if ( pxTCB - > uxPriority > pxCurrentTCBs [ 1 ] - > uxPriority )
{
xYieldPending [ 1 ] = pdTRUE ;
}
else
{
mtCOVERAGE_TEST_MARKER ( ) ;
}
}
# endif /* if ( configNUMBER_OF_CORES > 1 ) */
2023-09-07 12:29:57 -04:00
}
# endif /* configUSE_PREEMPTION */
2023-05-10 04:22:41 -04:00
}
}
}
2023-09-07 12:29:57 -04:00
/* Tasks of equal priority to the currently running task will share
* processing time ( time slice ) if preemption is on , and the application
* writer has not explicitly turned time slicing off . */
# if ( ( configUSE_PREEMPTION == 1 ) && ( configUSE_TIME_SLICING == 1 ) )
2023-05-10 04:22:41 -04:00
{
2023-09-07 12:29:57 -04:00
if ( listCURRENT_LIST_LENGTH ( & ( pxReadyTasksLists [ pxCurrentTCBs [ 0 ] - > uxPriority ] ) ) > ( UBaseType_t ) 1 )
{
xSwitchRequired = pdTRUE ;
}
else
{
mtCOVERAGE_TEST_MARKER ( ) ;
}
2023-05-10 04:22:41 -04:00
}
2023-09-07 12:29:57 -04:00
# endif /* ( ( configUSE_PREEMPTION == 1 ) && ( configUSE_TIME_SLICING == 1 ) ) */
2023-05-10 04:22:41 -04:00
2023-09-07 12:29:57 -04:00
# if ( configUSE_TICK_HOOK == 1 )
2023-05-10 04:22:41 -04:00
{
2023-09-07 12:29:57 -04:00
/* Guard against the tick hook being called when the pended tick
* count is being unwound ( when the scheduler is being unlocked ) . */
2024-03-01 04:46:32 -05:00
if ( xPendedTicks = = ( TickType_t ) 0 )
2023-09-07 12:29:57 -04:00
{
xCallTickHook = pdTRUE ;
}
else
{
xCallTickHook = pdFALSE ;
}
2023-05-10 04:22:41 -04:00
}
2023-09-07 12:29:57 -04:00
# endif /* configUSE_TICK_HOOK */
# if ( configUSE_PREEMPTION == 1 )
2023-05-10 04:22:41 -04:00
{
2023-09-07 12:29:57 -04:00
if ( xYieldPending [ 0 ] ! = pdFALSE )
{
xSwitchRequired = pdTRUE ;
}
else
{
mtCOVERAGE_TEST_MARKER ( ) ;
}
2023-05-10 04:22:41 -04:00
}
2023-09-07 12:29:57 -04:00
# endif /* configUSE_PREEMPTION */
2023-05-10 04:22:41 -04:00
}
2023-09-07 12:29:57 -04:00
else
2023-05-10 04:22:41 -04:00
{
2023-09-07 12:29:57 -04:00
+ + xPendedTicks ;
/* The tick hook gets called at regular intervals, even if the
* scheduler is locked . */
# if ( configUSE_TICK_HOOK == 1 )
2023-05-10 04:22:41 -04:00
{
2023-09-07 12:29:57 -04:00
xCallTickHook = pdTRUE ;
2023-05-10 04:22:41 -04:00
}
2023-09-07 12:29:57 -04:00
# endif
2023-05-10 04:22:41 -04:00
}
}
2023-09-07 12:29:57 -04:00
/* Release the previously taken kernel lock as we have finished accessing
* the kernel data structures . */
2023-10-31 12:02:58 -04:00
prvEXIT_CRITICAL_SAFE_SMP_ONLY ( & xKernelLock ) ;
2023-09-07 12:29:57 -04:00
# if ( configUSE_TICK_HOOK == 1 )
{
if ( xCallTickHook = = pdTRUE )
2023-05-10 04:22:41 -04:00
{
vApplicationTickHook ( ) ;
}
}
2023-09-07 12:29:57 -04:00
# endif
2023-05-10 04:22:41 -04:00
return xSwitchRequired ;
}
/*-----------------------------------------------------------*/
# if ( configUSE_APPLICATION_TASK_TAG == 1 )
void vTaskSetApplicationTaskTag ( TaskHandle_t xTask ,
TaskHookFunction_t pxHookFunction )
{
TCB_t * xTCB ;
/* If xTask is NULL then it is the task hook of the calling task that is
* getting set . */
if ( xTask = = NULL )
{
2023-09-14 12:35:31 -04:00
xTCB = ( TCB_t * ) xTaskGetCurrentTaskHandle ( ) ;
2023-05-10 04:22:41 -04:00
}
else
{
xTCB = xTask ;
}
/* Save the hook function in the TCB. A critical section is required as
* the value can be accessed from an interrupt . */
2023-09-07 12:29:57 -04:00
taskENTER_CRITICAL ( & xKernelLock ) ;
2023-05-10 04:22:41 -04:00
{
xTCB - > pxTaskTag = pxHookFunction ;
}
2023-09-07 12:29:57 -04:00
taskEXIT_CRITICAL ( & xKernelLock ) ;
2023-05-10 04:22:41 -04:00
}
# endif /* configUSE_APPLICATION_TASK_TAG */
/*-----------------------------------------------------------*/
# if ( configUSE_APPLICATION_TASK_TAG == 1 )
TaskHookFunction_t xTaskGetApplicationTaskTag ( TaskHandle_t xTask )
{
TCB_t * pxTCB ;
TaskHookFunction_t xReturn ;
/* If xTask is NULL then set the calling task's hook. */
pxTCB = prvGetTCBFromHandle ( xTask ) ;
/* Save the hook function in the TCB. A critical section is required as
* the value can be accessed from an interrupt . */
2023-09-07 12:29:57 -04:00
taskENTER_CRITICAL ( & xKernelLock ) ;
2023-05-10 04:22:41 -04:00
{
xReturn = pxTCB - > pxTaskTag ;
}
2023-09-07 12:29:57 -04:00
taskEXIT_CRITICAL ( & xKernelLock ) ;
2023-05-10 04:22:41 -04:00
return xReturn ;
}
# endif /* configUSE_APPLICATION_TASK_TAG */
/*-----------------------------------------------------------*/
# if ( configUSE_APPLICATION_TASK_TAG == 1 )
TaskHookFunction_t xTaskGetApplicationTaskTagFromISR ( TaskHandle_t xTask )
{
TCB_t * pxTCB ;
TaskHookFunction_t xReturn ;
UBaseType_t uxSavedInterruptStatus ;
/* If xTask is NULL then set the calling task's hook. */
pxTCB = prvGetTCBFromHandle ( xTask ) ;
/* Save the hook function in the TCB. A critical section is required as
* the value can be accessed from an interrupt . */
2023-09-07 12:29:57 -04:00
prvENTER_CRITICAL_OR_MASK_ISR ( & xKernelLock , uxSavedInterruptStatus ) ;
2023-05-10 04:22:41 -04:00
{
xReturn = pxTCB - > pxTaskTag ;
}
2023-09-07 12:29:57 -04:00
prvEXIT_CRITICAL_OR_UNMASK_ISR ( & xKernelLock , uxSavedInterruptStatus ) ;
2023-05-10 04:22:41 -04:00
return xReturn ;
}
# endif /* configUSE_APPLICATION_TASK_TAG */
/*-----------------------------------------------------------*/
# if ( configUSE_APPLICATION_TASK_TAG == 1 )
BaseType_t xTaskCallApplicationTaskHook ( TaskHandle_t xTask ,
void * pvParameter )
{
TCB_t * xTCB ;
BaseType_t xReturn ;
/* If xTask is NULL then we are calling our own task hook. */
if ( xTask = = NULL )
{
2023-09-14 12:35:31 -04:00
xTCB = xTaskGetCurrentTaskHandle ( ) ;
2023-05-10 04:22:41 -04:00
}
else
{
xTCB = xTask ;
}
if ( xTCB - > pxTaskTag ! = NULL )
{
xReturn = xTCB - > pxTaskTag ( pvParameter ) ;
}
else
{
xReturn = pdFAIL ;
}
return xReturn ;
}
# endif /* configUSE_APPLICATION_TASK_TAG */
/*-----------------------------------------------------------*/
2023-09-14 12:35:31 -04:00
# if ( configNUMBER_OF_CORES > 1 )
static void prvSelectHighestPriorityTaskSMP ( void )
{
/* This function is called from a critical section. So some optimizations are made */
BaseType_t uxCurPriority ;
BaseType_t xTaskScheduled = pdFALSE ;
BaseType_t xNewTopPrioritySet = pdFALSE ;
BaseType_t xCurCoreID = portGET_CORE_ID ( ) ;
/* Search for tasks, starting form the highest ready priority. If nothing is
* found , we eventually default to the IDLE tasks at priority 0 */
for ( uxCurPriority = uxTopReadyPriority ; uxCurPriority > = 0 & & xTaskScheduled = = pdFALSE ; uxCurPriority - - )
{
/* Check if current priority has one or more ready tasks. Skip if none */
if ( listLIST_IS_EMPTY ( & ( pxReadyTasksLists [ uxCurPriority ] ) ) )
{
continue ;
}
/* Save a copy of highest priority that has a ready state task */
if ( xNewTopPrioritySet = = pdFALSE )
{
xNewTopPrioritySet = pdTRUE ;
uxTopReadyPriority = uxCurPriority ;
}
/* We now search this priority's ready task list for a runnable task.
* We always start searching from the head of the list , so we reset
* pxIndex to point to the tail so that we start walking the list from
* the first item */
pxReadyTasksLists [ uxCurPriority ] . pxIndex = ( ListItem_t * ) & ( pxReadyTasksLists [ uxCurPriority ] . xListEnd ) ;
/* Get the first item on the list */
TCB_t * pxTCBCur ;
TCB_t * pxTCBFirst ;
listGET_OWNER_OF_NEXT_ENTRY ( pxTCBCur , & ( pxReadyTasksLists [ uxCurPriority ] ) ) ;
pxTCBFirst = pxTCBCur ;
do
{
/* Check if the current task is currently being executed. However, if
* it ' s being executed by the current core , we can still schedule it .
* Todo : Each task can store a xTaskRunState , instead of needing to
* check each core */
UBaseType_t x ;
for ( x = 0 ; x < configNUMBER_OF_CORES ; x + + )
{
if ( x = = xCurCoreID )
{
continue ;
}
else if ( pxCurrentTCBs [ x ] = = pxTCBCur )
{
/* Current task is already being executed. Get the next task */
goto get_next_task ;
}
}
/* Check if the current task has a compatible affinity */
2023-11-16 06:18:17 -05:00
if ( taskIS_AFFINITY_COMPATIBLE ( xCurCoreID , pxTCBCur ) = = pdFALSE )
2023-09-14 12:35:31 -04:00
{
goto get_next_task ;
}
/* The current task is runnable. Schedule it */
pxCurrentTCBs [ xCurCoreID ] = pxTCBCur ;
xTaskScheduled = pdTRUE ;
/* Move the current tasks list item to the back of the list in order
* to implement best effort round robin . To do this , we need to reset
* the pxIndex to point to the tail again . */
pxReadyTasksLists [ uxCurPriority ] . pxIndex = ( ListItem_t * ) & ( pxReadyTasksLists [ uxCurPriority ] . xListEnd ) ;
listREMOVE_ITEM ( & ( pxTCBCur - > xStateListItem ) ) ;
listINSERT_END ( & ( pxReadyTasksLists [ uxCurPriority ] ) , & ( pxTCBCur - > xStateListItem ) ) ;
break ;
get_next_task :
/* The current task cannot be scheduled. Get the next task in the list */
listGET_OWNER_OF_NEXT_ENTRY ( pxTCBCur , & ( pxReadyTasksLists [ uxCurPriority ] ) ) ;
} while ( pxTCBCur ! = pxTCBFirst ) ; /* Check to see if we've walked the entire list */
}
configASSERT ( xTaskScheduled = = pdTRUE ) ; /* At this point, a task MUST have been scheduled */
}
# endif /* configNUMBER_OF_CORES > 1 */
/*-----------------------------------------------------------*/
2023-05-10 04:22:41 -04:00
void vTaskSwitchContext ( void )
{
2023-09-07 12:29:57 -04:00
/* For SMP, we need to take the kernel lock here as we are about to access
* kernel data structures ( unlike single core which calls this function with
* either interrupts disabled or when the scheduler hasn ' t started yet ) . */
2023-10-31 12:02:58 -04:00
prvENTER_CRITICAL_SAFE_SMP_ONLY ( & xKernelLock ) ;
2023-05-10 04:22:41 -04:00
{
2023-09-07 12:29:57 -04:00
/* Get current core ID as we can no longer be preempted. */
const BaseType_t xCurCoreID = portGET_CORE_ID ( ) ;
2023-05-10 04:22:41 -04:00
2023-09-07 12:29:57 -04:00
if ( uxSchedulerSuspended [ xCurCoreID ] ! = ( UBaseType_t ) pdFALSE )
2023-05-10 04:22:41 -04:00
{
2023-09-07 12:29:57 -04:00
/* The scheduler is currently suspended - do not allow a context
* switch . */
xYieldPending [ xCurCoreID ] = pdTRUE ;
}
else
{
xYieldPending [ xCurCoreID ] = pdFALSE ;
traceTASK_SWITCHED_OUT ( ) ;
2023-05-10 04:22:41 -04:00
2023-09-07 12:29:57 -04:00
# if ( configGENERATE_RUN_TIME_STATS == 1 )
2023-05-10 04:22:41 -04:00
{
2023-09-07 12:29:57 -04:00
# ifdef portALT_GET_RUN_TIME_COUNTER_VALUE
portALT_GET_RUN_TIME_COUNTER_VALUE ( ulTotalRunTime ) ;
# else
ulTotalRunTime = portGET_RUN_TIME_COUNTER_VALUE ( ) ;
# endif
2023-05-10 04:22:41 -04:00
2023-09-07 12:29:57 -04:00
/* Add the amount of time the task has been running to the
* accumulated time so far . The time the task started running was
* stored in ulTaskSwitchedInTime . Note that there is no overflow
* protection here so count values are only valid until the timer
* overflows . The guard against negative values is to protect
* against suspect run time stat counter implementations - which
* are provided by the application , not the kernel . */
if ( ulTotalRunTime > ulTaskSwitchedInTime [ xCurCoreID ] )
{
pxCurrentTCBs [ xCurCoreID ] - > ulRunTimeCounter + = ( ulTotalRunTime - ulTaskSwitchedInTime [ xCurCoreID ] ) ;
}
else
{
mtCOVERAGE_TEST_MARKER ( ) ;
}
2023-05-10 04:22:41 -04:00
2023-09-07 12:29:57 -04:00
ulTaskSwitchedInTime [ xCurCoreID ] = ulTotalRunTime ;
}
# endif /* configGENERATE_RUN_TIME_STATS */
2023-05-10 04:22:41 -04:00
2023-09-07 12:29:57 -04:00
/* Check for stack overflow, if configured. */
taskCHECK_FOR_STACK_OVERFLOW ( xCurCoreID ) ;
2023-05-10 04:22:41 -04:00
2023-09-07 12:29:57 -04:00
/* Before the currently running task is switched out, save its errno. */
# if ( configUSE_POSIX_ERRNO == 1 )
{
pxCurrentTCBs [ xCurCoreID ] - > iTaskErrno = FreeRTOS_errno ;
}
# endif
2023-05-10 04:22:41 -04:00
2023-09-07 12:29:57 -04:00
/* Select a new task to run using either the generic C or port
* optimised asm code . */
taskSELECT_HIGHEST_PRIORITY_TASK ( ) ; /*lint !e9079 void * is used as this macro is used with timers and co-routines too. Alignment is known to be fine as the type of the pointer stored and retrieved is the same. */
traceTASK_SWITCHED_IN ( ) ;
2023-05-10 04:22:41 -04:00
2023-09-07 12:29:57 -04:00
/* After the new task is switched in, update the global errno. */
# if ( configUSE_POSIX_ERRNO == 1 )
{
FreeRTOS_errno = pxCurrentTCBs [ xCurCoreID ] - > iTaskErrno ;
}
# endif
2023-10-20 16:34:52 -04:00
/* Wrap this call in a macro. IDF-8434 */
# if CONFIG_FREERTOS_WATCHPOINT_END_OF_STACK
{
vPortSetStackWatchpoint ( pxCurrentTCBs [ xCurCoreID ] - > pxStack ) ;
}
# endif /* CONFIG_FREERTOS_WATCHPOINT_END_OF_STACK */
2023-09-07 12:29:57 -04:00
# if ( ( configUSE_NEWLIB_REENTRANT == 1 ) || ( configUSE_C_RUNTIME_TLS_SUPPORT == 1 ) )
{
/* Switch C-Runtime's TLS Block to point to the TLS
* Block specific to this task . */
configSET_TLS_BLOCK ( pxCurrentTCBs [ xCurCoreID ] - > xTLSBlock ) ;
}
# endif
2023-05-10 04:22:41 -04:00
}
}
2023-09-07 12:29:57 -04:00
/* Release the previously taken kernel lock as we have finished accessing
* the kernel data structures . */
2023-10-31 12:02:58 -04:00
prvEXIT_CRITICAL_SAFE_SMP_ONLY ( & xKernelLock ) ;
2023-05-10 04:22:41 -04:00
}
/*-----------------------------------------------------------*/
void vTaskPlaceOnEventList ( List_t * const pxEventList ,
const TickType_t xTicksToWait )
{
configASSERT ( pxEventList ) ;
2023-09-07 12:29:57 -04:00
/* IN SINGLE-CORE THIS FUNCTION MUST BE CALLED WITH EITHER INTERRUPTS DISABLED
* OR THE SCHEDULER SUSPENDED AND THE QUEUE BEING ACCESSED LOCKED . IN SMP
* THIS FUNCTION MUST BE CALLED WITH THE QUEUE ' S xQueueLock TAKEN . */
/* For SMP, we need to take the kernel lock here as we are about to access
* kernel data structures . */
2023-10-31 12:02:58 -04:00
prvENTER_CRITICAL_SMP_ONLY ( & xKernelLock ) ;
2023-09-07 12:29:57 -04:00
{
/* Place the event list item of the TCB in the appropriate event list.
* This is placed in the list in priority order so the highest priority task
* is the first to be woken by the event .
*
* Note : Lists are sorted in ascending order by ListItem_t . xItemValue .
* Normally , the xItemValue of a TCB ' s ListItem_t members is :
* xItemValue = ( configMAX_PRIORITIES - uxPriority )
* Therefore , the event list is sorted in descending priority order .
*
* The queue that contains the event list is locked , preventing
* simultaneous access from interrupts . */
vListInsert ( pxEventList , & ( pxCurrentTCBs [ portGET_CORE_ID ( ) ] - > xEventListItem ) ) ;
prvAddCurrentTaskToDelayedList ( xTicksToWait , pdTRUE ) ;
}
/* Release the previously taken kernel lock. */
2023-10-31 12:02:58 -04:00
prvEXIT_CRITICAL_SMP_ONLY ( & xKernelLock ) ;
2023-05-10 04:22:41 -04:00
}
/*-----------------------------------------------------------*/
void vTaskPlaceOnUnorderedEventList ( List_t * pxEventList ,
const TickType_t xItemValue ,
const TickType_t xTicksToWait )
{
2023-09-14 12:35:31 -04:00
/* Get current core ID as we can no longer be preempted. */
const BaseType_t xCurCoreID = portGET_CORE_ID ( ) ;
2023-05-10 04:22:41 -04:00
configASSERT ( pxEventList ) ;
2023-09-07 12:29:57 -04:00
# if ( configNUMBER_OF_CORES > 1 )
{
/* IN SMP, THIS FUNCTION MUST BE CALLED WITH THE EVENT GROUP'S
* xEventGroupLock ALREADY TAKEN . */
}
# else /* configNUMBER_OF_CORES > 1 */
{
/* IN SINGLE-CORE, THIS FUNCTION MUST BE CALLED WITH THE SCHEDULER SUSPENDED.
* It is used by the event groups implementation . */
configASSERT ( uxSchedulerSuspended [ xCurCoreID ] ! = 0 ) ;
}
# endif /* configNUMBER_OF_CORES > 1 */
2023-05-10 04:22:41 -04:00
2023-09-07 12:29:57 -04:00
/* For SMP, we need to take the kernel lock here as we are about to access
* kernel data structures . */
2023-10-31 12:02:58 -04:00
prvENTER_CRITICAL_SMP_ONLY ( & xKernelLock ) ;
2023-09-07 12:29:57 -04:00
{
/* Store the item value in the event list item. It is safe to access the
* event list item here as interrupts won ' t access the event list item of a
* task that is not in the Blocked state . */
listSET_LIST_ITEM_VALUE ( & ( pxCurrentTCBs [ xCurCoreID ] - > xEventListItem ) , xItemValue | taskEVENT_LIST_ITEM_VALUE_IN_USE ) ;
/* Place the event list item of the TCB at the end of the appropriate event
* list . It is safe to access the event list here because it is part of an
* event group implementation - and interrupts don ' t access event groups
* directly ( instead they access them indirectly by pending function calls to
* the task level ) . */
listINSERT_END ( pxEventList , & ( pxCurrentTCBs [ xCurCoreID ] - > xEventListItem ) ) ;
prvAddCurrentTaskToDelayedList ( xTicksToWait , pdTRUE ) ;
}
/* Release the previously taken kernel lock. */
2023-10-31 12:02:58 -04:00
prvEXIT_CRITICAL_SMP_ONLY ( & xKernelLock ) ;
2023-05-10 04:22:41 -04:00
}
/*-----------------------------------------------------------*/
# if ( configUSE_TIMERS == 1 )
void vTaskPlaceOnEventListRestricted ( List_t * const pxEventList ,
TickType_t xTicksToWait ,
const BaseType_t xWaitIndefinitely )
{
configASSERT ( pxEventList ) ;
/* This function should not be called by application code hence the
* ' Restricted ' in its name . It is not part of the public API . It is
* designed for use by kernel code , and has special calling requirements -
2023-09-07 12:29:57 -04:00
* it should be called with the scheduler suspended in single - core , or
* with the queue ' s xQueueLock already taken in SMP . */
2023-05-10 04:22:41 -04:00
2023-09-07 12:29:57 -04:00
/* For SMP, we need to take the kernel lock here as we are about to access
* kernel data structures . */
2023-10-31 12:02:58 -04:00
prvENTER_CRITICAL_SMP_ONLY ( & xKernelLock ) ;
2023-09-07 12:29:57 -04:00
{
/* Place the event list item of the TCB in the appropriate event list.
* In this case it is assume that this is the only task that is going to
* be waiting on this event list , so the faster vListInsertEnd ( ) function
* can be used in place of vListInsert . */
listINSERT_END ( pxEventList , & ( pxCurrentTCBs [ portGET_CORE_ID ( ) ] - > xEventListItem ) ) ;
2023-05-10 04:22:41 -04:00
2023-09-07 12:29:57 -04:00
/* If the task should block indefinitely then set the block time to a
* value that will be recognised as an indefinite delay inside the
* prvAddCurrentTaskToDelayedList ( ) function . */
if ( xWaitIndefinitely ! = pdFALSE )
{
xTicksToWait = portMAX_DELAY ;
}
2023-05-10 04:22:41 -04:00
2023-09-07 12:29:57 -04:00
traceTASK_DELAY_UNTIL ( ( xTickCount + xTicksToWait ) ) ;
prvAddCurrentTaskToDelayedList ( xTicksToWait , xWaitIndefinitely ) ;
2023-05-10 04:22:41 -04:00
}
2023-09-07 12:29:57 -04:00
/* Release the previously taken kernel lock. */
taskEXIT_CRITICAL ( & xKernelLock ) ;
2023-05-10 04:22:41 -04:00
}
# endif /* configUSE_TIMERS */
/*-----------------------------------------------------------*/
2023-09-14 12:35:31 -04:00
# if ( configNUMBER_OF_CORES > 1 )
2023-05-10 04:22:41 -04:00
2023-09-14 12:35:31 -04:00
BaseType_t xTaskRemoveFromEventList ( const List_t * const pxEventList )
{
TCB_t * pxUnblockedTCB ;
BaseType_t xReturn ;
2023-05-10 04:22:41 -04:00
2023-09-07 12:29:57 -04:00
/* For SMP, we need to take the kernel lock here as we are about to access
* kernel data structures .
* This function can also be called from an ISR context , so we
* need to check whether we are in an ISR . */
if ( portCHECK_IF_IN_ISR ( ) = = pdFALSE )
{
taskENTER_CRITICAL ( & xKernelLock ) ;
}
else
{
taskENTER_CRITICAL_ISR ( & xKernelLock ) ;
}
2023-05-10 04:22:41 -04:00
2023-09-07 12:29:57 -04:00
{
/* Before taking the kernel lock, another task/ISR could have already
* emptied the pxEventList . So we insert a check here to see if
* pxEventList is empty before attempting to remove an item from it . */
if ( listLIST_IS_EMPTY ( pxEventList ) = = pdFALSE )
2023-09-14 12:35:31 -04:00
{
2023-09-07 12:29:57 -04:00
/* Get current core ID as we can no longer be preempted. */
const BaseType_t xCurCoreID = portGET_CORE_ID ( ) ;
2023-09-14 12:35:31 -04:00
2023-09-07 12:29:57 -04:00
/* Remove the task from its current event list */
pxUnblockedTCB = listGET_OWNER_OF_HEAD_ENTRY ( pxEventList ) ;
configASSERT ( pxUnblockedTCB ) ;
listREMOVE_ITEM ( & ( pxUnblockedTCB - > xEventListItem ) ) ;
/* Add the task to the ready list if a core with compatible affinity
* has NOT suspended its scheduler . This occurs when :
* - The task is pinned , and the pinned core ' s scheduler is running
* - The task is unpinned , and at least one of the core ' s scheduler is running */
if ( taskCAN_BE_SCHEDULED ( pxUnblockedTCB ) = = pdTRUE )
2023-09-14 12:35:31 -04:00
{
2023-09-07 12:29:57 -04:00
listREMOVE_ITEM ( & ( pxUnblockedTCB - > xStateListItem ) ) ;
prvAddTaskToReadyList ( pxUnblockedTCB ) ;
2023-09-14 12:35:31 -04:00
2023-09-07 12:29:57 -04:00
# if ( configUSE_TICKLESS_IDLE != 0 )
{
/* If a task is blocked on a kernel object then xNextTaskUnblockTime
* might be set to the blocked task ' s time out time . If the task is
* unblocked for a reason other than a timeout xNextTaskUnblockTime is
* normally left unchanged , because it is automatically reset to a new
* value when the tick count equals xNextTaskUnblockTime . However if
* tickless idling is used it might be more important to enter sleep mode
* at the earliest possible time - so reset xNextTaskUnblockTime here to
* ensure it is updated at the earliest possible time . */
prvResetNextTaskUnblockTime ( ) ;
}
# endif
}
else
{
/* We arrive here due to one of the following possibilities:
* - The task is pinned to core X and core X has suspended its scheduler
* - The task is unpinned and both cores have suspend their schedulers
* Therefore , we add the task to one of the pending lists :
* - If the task is pinned to core X , add it to core X ' s pending list
* - If the task is unpinned , add it to the current core ' s pending list */
UBaseType_t uxPendCore = ( ( pxUnblockedTCB - > xCoreID = = tskNO_AFFINITY ) ? xCurCoreID : pxUnblockedTCB - > xCoreID ) ;
configASSERT ( uxSchedulerSuspended [ uxPendCore ] ! = ( UBaseType_t ) 0U ) ;
/* Add the task to the current core's pending list */
listINSERT_END ( & ( xPendingReadyList [ uxPendCore ] ) , & ( pxUnblockedTCB - > xEventListItem ) ) ;
}
2023-09-14 12:35:31 -04:00
2023-11-16 06:18:17 -05:00
if ( taskIS_YIELD_REQUIRED ( pxUnblockedTCB , pdFALSE ) = = pdTRUE )
2023-09-07 12:29:57 -04:00
{
/* The unblocked task requires a the current core to yield */
xReturn = pdTRUE ;
2023-09-14 12:35:31 -04:00
2023-09-07 12:29:57 -04:00
/* Mark that a yield is pending in case the user is not using the
* " xHigherPriorityTaskWoken " parameter to an ISR safe FreeRTOS function . */
xYieldPending [ xCurCoreID ] = pdTRUE ;
}
else
{
xReturn = pdFALSE ;
}
2023-09-14 12:35:31 -04:00
}
else
{
2023-09-07 12:29:57 -04:00
/* The pxEventList was emptied before we entered the critical
* section , Nothing to do except return pdFALSE . */
2023-09-14 12:35:31 -04:00
xReturn = pdFALSE ;
}
}
2023-09-07 12:29:57 -04:00
/* Release the previously taken kernel lock. */
if ( portCHECK_IF_IN_ISR ( ) = = pdFALSE )
{
taskEXIT_CRITICAL ( & xKernelLock ) ;
}
2023-09-14 12:35:31 -04:00
else
2023-05-10 04:22:41 -04:00
{
2023-09-07 12:29:57 -04:00
taskEXIT_CRITICAL_ISR ( & xKernelLock ) ;
2023-05-10 04:22:41 -04:00
}
2023-09-14 12:35:31 -04:00
return xReturn ;
2023-05-10 04:22:41 -04:00
}
2023-09-14 12:35:31 -04:00
# else /* configNUMBER_OF_CORES > 1 */
BaseType_t xTaskRemoveFromEventList ( const List_t * const pxEventList )
2023-05-10 04:22:41 -04:00
{
2023-09-14 12:35:31 -04:00
TCB_t * pxUnblockedTCB ;
BaseType_t xReturn ;
/* THIS FUNCTION MUST BE CALLED FROM A CRITICAL SECTION. It can also be
* called from a critical section within an ISR . */
/* The event list is sorted in priority order, so the first in the list can
* be removed as it is known to be the highest priority . Remove the TCB from
* the delayed list , and add it to the ready list .
*
* If an event is for a queue that is locked then this function will never
* get called - the lock count on the queue will get modified instead . This
* means exclusive access to the event list is guaranteed here .
*
* This function assumes that a check has already been made to ensure that
* pxEventList is not empty . */
pxUnblockedTCB = listGET_OWNER_OF_HEAD_ENTRY ( pxEventList ) ; /*lint !e9079 void * is used as this macro is used with timers and co-routines too. Alignment is known to be fine as the type of the pointer stored and retrieved is the same. */
configASSERT ( pxUnblockedTCB ) ;
listREMOVE_ITEM ( & ( pxUnblockedTCB - > xEventListItem ) ) ;
if ( uxSchedulerSuspended [ 0 ] = = ( UBaseType_t ) pdFALSE )
{
listREMOVE_ITEM ( & ( pxUnblockedTCB - > xStateListItem ) ) ;
prvAddTaskToReadyList ( pxUnblockedTCB ) ;
# if ( configUSE_TICKLESS_IDLE != 0 )
{
/* If a task is blocked on a kernel object then xNextTaskUnblockTime
* might be set to the blocked task ' s time out time . If the task is
* unblocked for a reason other than a timeout xNextTaskUnblockTime is
* normally left unchanged , because it is automatically reset to a new
* value when the tick count equals xNextTaskUnblockTime . However if
* tickless idling is used it might be more important to enter sleep mode
* at the earliest possible time - so reset xNextTaskUnblockTime here to
* ensure it is updated at the earliest possible time . */
prvResetNextTaskUnblockTime ( ) ;
}
# endif
}
else
{
/* The delayed and ready lists cannot be accessed, so hold this task
* pending until the scheduler is resumed . */
listINSERT_END ( & ( xPendingReadyList [ 0 ] ) , & ( pxUnblockedTCB - > xEventListItem ) ) ;
}
if ( pxUnblockedTCB - > uxPriority > pxCurrentTCBs [ 0 ] - > uxPriority )
{
/* Return true if the task removed from the event list has a higher
* priority than the calling task . This allows the calling task to know if
* it should force a context switch now . */
xReturn = pdTRUE ;
/* Mark that a yield is pending in case the user is not using the
* " xHigherPriorityTaskWoken " parameter to an ISR safe FreeRTOS function . */
xYieldPending [ 0 ] = pdTRUE ;
}
else
{
xReturn = pdFALSE ;
}
return xReturn ;
2023-05-10 04:22:41 -04:00
}
2023-09-14 12:35:31 -04:00
# endif /* configNUMBER_OF_CORES > 1 */
2023-05-10 04:22:41 -04:00
/*-----------------------------------------------------------*/
void vTaskRemoveFromUnorderedEventList ( ListItem_t * pxEventListItem ,
const TickType_t xItemValue )
{
TCB_t * pxUnblockedTCB ;
2023-09-14 12:35:31 -04:00
/* Get current core ID as we can no longer be preempted. */
const BaseType_t xCurCoreID = portGET_CORE_ID ( ) ;
2023-05-10 04:22:41 -04:00
2023-09-14 12:35:31 -04:00
# if ( configNUM_CORES > 1 )
/* THIS FUNCTION MUST BE CALLED WITH THE KERNEL LOCK ALREADY TAKEN.
* It is used by the event flags implementation , thus those functions
* should call prvTakeKernelLock ( ) before calling this function . */
# else /* configNUM_CORES > 1 */
/* THIS FUNCTION MUST BE CALLED WITH THE SCHEDULER SUSPENDED. It is used by
* the event flags implementation . */
configASSERT ( uxSchedulerSuspended [ 0 ] ! = ( UBaseType_t ) 0U ) ;
# endif /* configNUM_CORES > 1 */
2023-05-10 04:22:41 -04:00
/* Store the new item value in the event list. */
listSET_LIST_ITEM_VALUE ( pxEventListItem , xItemValue | taskEVENT_LIST_ITEM_VALUE_IN_USE ) ;
/* Remove the event list form the event flag. Interrupts do not access
* event flags . */
pxUnblockedTCB = listGET_LIST_ITEM_OWNER ( pxEventListItem ) ; /*lint !e9079 void * is used as this macro is used with timers and co-routines too. Alignment is known to be fine as the type of the pointer stored and retrieved is the same. */
configASSERT ( pxUnblockedTCB ) ;
listREMOVE_ITEM ( pxEventListItem ) ;
# if ( configUSE_TICKLESS_IDLE != 0 )
{
/* If a task is blocked on a kernel object then xNextTaskUnblockTime
* might be set to the blocked task ' s time out time . If the task is
* unblocked for a reason other than a timeout xNextTaskUnblockTime is
* normally left unchanged , because it is automatically reset to a new
* value when the tick count equals xNextTaskUnblockTime . However if
* tickless idling is used it might be more important to enter sleep mode
* at the earliest possible time - so reset xNextTaskUnblockTime here to
* ensure it is updated at the earliest possible time . */
prvResetNextTaskUnblockTime ( ) ;
}
# endif
2023-09-14 12:35:31 -04:00
# if ( configNUM_CORES > 1 )
2023-05-10 04:22:41 -04:00
2023-09-14 12:35:31 -04:00
/* Add the task to the ready list if a core with compatible affinity
* has NOT suspended its scheduler . This occurs when :
* - The task is pinned , and the pinned core ' s scheduler is running
* - The task is unpinned , and at least one of the core ' s scheduler is
* running */
if ( taskCAN_BE_SCHEDULED ( pxUnblockedTCB ) = = pdFALSE )
{
/* We arrive here due to one of the following possibilities:
* - The task is pinned to core X and core X has suspended its scheduler
* - The task is unpinned and both cores have suspend their schedulers
* Therefore , we add the task to one of the pending lists :
* - If the task is pinned to core X , add it to core X ' s pending list
* - If the task is unpinned , add it to the current core ' s pending list */
BaseType_t xPendingListCore = ( ( pxUnblockedTCB - > xCoreID = = tskNO_AFFINITY ) ? xCurCoreID : pxUnblockedTCB - > xCoreID ) ;
configASSERT ( uxSchedulerSuspended [ xPendingListCore ] ! = ( UBaseType_t ) 0U ) ;
/* The delayed and ready lists cannot be accessed, so hold this task
* pending until the scheduler is resumed . */
listINSERT_END ( & ( xPendingReadyList [ xPendingListCore ] ) , & ( pxUnblockedTCB - > xEventListItem ) ) ;
}
else
# else /* configNUM_CORES > 1 */
/* In single core, the caller of this function has already suspended the
* scheduler , which means we have exclusive access to the ready list .
* We add the unblocked task to the ready list directly . */
# endif /* configNUM_CORES > 1 */
2023-05-10 04:22:41 -04:00
{
2023-09-14 12:35:31 -04:00
/* Remove the task from the delayed list and add it to the ready list. The
* scheduler is suspended so interrupts will not be accessing the ready
* lists . */
listREMOVE_ITEM ( & ( pxUnblockedTCB - > xStateListItem ) ) ;
prvAddTaskToReadyList ( pxUnblockedTCB ) ;
2023-11-16 06:18:17 -05:00
if ( taskIS_YIELD_REQUIRED ( pxUnblockedTCB , pdFALSE ) = = pdTRUE )
2023-09-14 12:35:31 -04:00
{
/* The unblocked task has a priority above that of the calling task, so
* a context switch is required . This function is called with the
* scheduler suspended so xYieldPending is set so the context switch
* occurs immediately that the scheduler is resumed ( unsuspended ) . */
xYieldPending [ xCurCoreID ] = pdTRUE ;
}
2023-05-10 04:22:41 -04:00
}
}
/*-----------------------------------------------------------*/
void vTaskSetTimeOutState ( TimeOut_t * const pxTimeOut )
{
configASSERT ( pxTimeOut ) ;
2023-09-07 12:29:57 -04:00
taskENTER_CRITICAL ( & xKernelLock ) ;
2023-05-10 04:22:41 -04:00
{
pxTimeOut - > xOverflowCount = xNumOfOverflows ;
pxTimeOut - > xTimeOnEntering = xTickCount ;
}
2023-09-07 12:29:57 -04:00
taskEXIT_CRITICAL ( & xKernelLock ) ;
2023-05-10 04:22:41 -04:00
}
/*-----------------------------------------------------------*/
void vTaskInternalSetTimeOutState ( TimeOut_t * const pxTimeOut )
{
/* For internal use only as it does not use a critical section. */
pxTimeOut - > xOverflowCount = xNumOfOverflows ;
pxTimeOut - > xTimeOnEntering = xTickCount ;
}
/*-----------------------------------------------------------*/
BaseType_t xTaskCheckForTimeOut ( TimeOut_t * const pxTimeOut ,
TickType_t * const pxTicksToWait )
{
BaseType_t xReturn ;
configASSERT ( pxTimeOut ) ;
configASSERT ( pxTicksToWait ) ;
2023-09-07 12:29:57 -04:00
taskENTER_CRITICAL ( & xKernelLock ) ;
2023-05-10 04:22:41 -04:00
{
/* Minor optimisation. The tick count cannot change in this block. */
const TickType_t xConstTickCount = xTickCount ;
const TickType_t xElapsedTime = xConstTickCount - pxTimeOut - > xTimeOnEntering ;
2023-09-14 12:35:31 -04:00
/* Get current core ID as we can no longer be preempted. */
const BaseType_t xCurCoreID = portGET_CORE_ID ( ) ;
2023-05-10 04:22:41 -04:00
# if ( INCLUDE_xTaskAbortDelay == 1 )
2023-09-14 12:35:31 -04:00
if ( pxCurrentTCBs [ xCurCoreID ] - > ucDelayAborted ! = ( uint8_t ) pdFALSE )
2023-05-10 04:22:41 -04:00
{
/* The delay was aborted, which is not the same as a time out,
* but has the same result . */
2023-09-14 12:35:31 -04:00
pxCurrentTCBs [ xCurCoreID ] - > ucDelayAborted = pdFALSE ;
2023-05-10 04:22:41 -04:00
xReturn = pdTRUE ;
}
else
# endif
# if ( INCLUDE_vTaskSuspend == 1 )
if ( * pxTicksToWait = = portMAX_DELAY )
{
/* If INCLUDE_vTaskSuspend is set to 1 and the block time
* specified is the maximum block time then the task should block
* indefinitely , and therefore never time out . */
xReturn = pdFALSE ;
}
else
# endif
if ( ( xNumOfOverflows ! = pxTimeOut - > xOverflowCount ) & & ( xConstTickCount > = pxTimeOut - > xTimeOnEntering ) ) /*lint !e525 Indentation preferred as is to make code within pre-processor directives clearer. */
{
/* The tick count is greater than the time at which
* vTaskSetTimeout ( ) was called , but has also overflowed since
* vTaskSetTimeOut ( ) was called . It must have wrapped all the way
* around and gone past again . This passed since vTaskSetTimeout ( )
* was called . */
xReturn = pdTRUE ;
* pxTicksToWait = ( TickType_t ) 0 ;
}
else if ( xElapsedTime < * pxTicksToWait ) /*lint !e961 Explicit casting is only redundant with some compilers, whereas others require it to prevent integer conversion errors. */
{
/* Not a genuine timeout. Adjust parameters for time remaining. */
* pxTicksToWait - = xElapsedTime ;
vTaskInternalSetTimeOutState ( pxTimeOut ) ;
xReturn = pdFALSE ;
}
else
{
* pxTicksToWait = ( TickType_t ) 0 ;
xReturn = pdTRUE ;
}
}
2023-09-07 12:29:57 -04:00
taskEXIT_CRITICAL ( & xKernelLock ) ;
2023-05-10 04:22:41 -04:00
return xReturn ;
}
/*-----------------------------------------------------------*/
void vTaskMissedYield ( void )
{
2023-09-14 12:35:31 -04:00
xYieldPending [ portGET_CORE_ID ( ) ] = pdTRUE ;
2023-05-10 04:22:41 -04:00
}
/*-----------------------------------------------------------*/
# if ( configUSE_TRACE_FACILITY == 1 )
UBaseType_t uxTaskGetTaskNumber ( TaskHandle_t xTask )
{
UBaseType_t uxReturn ;
TCB_t const * pxTCB ;
if ( xTask ! = NULL )
{
pxTCB = xTask ;
uxReturn = pxTCB - > uxTaskNumber ;
}
else
{
uxReturn = 0U ;
}
return uxReturn ;
}
# endif /* configUSE_TRACE_FACILITY */
/*-----------------------------------------------------------*/
# if ( configUSE_TRACE_FACILITY == 1 )
void vTaskSetTaskNumber ( TaskHandle_t xTask ,
const UBaseType_t uxHandle )
{
TCB_t * pxTCB ;
if ( xTask ! = NULL )
{
pxTCB = xTask ;
pxTCB - > uxTaskNumber = uxHandle ;
}
}
# endif /* configUSE_TRACE_FACILITY */
/*
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
* The Idle task .
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
*
* The portTASK_FUNCTION ( ) macro is used to allow port / compiler specific
* language extensions . The equivalent prototype for this function is :
*
* void prvIdleTask ( void * pvParameters ) ;
*
*/
static portTASK_FUNCTION ( prvIdleTask , pvParameters )
{
/* Stop warnings. */
( void ) pvParameters ;
/** THIS IS THE RTOS IDLE TASK - WHICH IS CREATED AUTOMATICALLY WHEN THE
* SCHEDULER IS STARTED . * */
/* In case a task that has a secure context deletes itself, in which case
* the idle task is responsible for deleting the task ' s secure context , if
* any . */
portALLOCATE_SECURE_CONTEXT ( configMINIMAL_SECURE_STACK_SIZE ) ;
for ( ; ; )
{
/* See if any tasks have deleted themselves - if so then the idle task
* is responsible for freeing the deleted task ' s TCB and stack . */
prvCheckTasksWaitingTermination ( ) ;
# if ( configUSE_PREEMPTION == 0 )
{
/* If we are not using preemption we keep forcing a task switch to
* see if any other task has become available . If we are using
* preemption we don ' t need to do this as any task becoming available
* will automatically get the processor anyway . */
taskYIELD ( ) ;
}
# endif /* configUSE_PREEMPTION */
# if ( ( configUSE_PREEMPTION == 1 ) && ( configIDLE_SHOULD_YIELD == 1 ) )
{
/* When using preemption tasks of equal priority will be
* timesliced . If a task that is sharing the idle priority is ready
* to run then the idle task should yield before the end of the
* timeslice .
*
* A critical region is not required here as we are just reading from
* the list , and an occasional incorrect value will not matter . If
* the ready list at the idle priority contains more than one task
* then a task other than the idle task is ready to execute . */
if ( listCURRENT_LIST_LENGTH ( & ( pxReadyTasksLists [ tskIDLE_PRIORITY ] ) ) > ( UBaseType_t ) 1 )
{
taskYIELD ( ) ;
}
else
{
mtCOVERAGE_TEST_MARKER ( ) ;
}
}
# endif /* ( ( configUSE_PREEMPTION == 1 ) && ( configIDLE_SHOULD_YIELD == 1 ) ) */
# if ( configUSE_IDLE_HOOK == 1 )
{
extern void vApplicationIdleHook ( void ) ;
/* Call the user defined function from within the idle task. This
* allows the application designer to add background functionality
* without the overhead of a separate task .
* NOTE : vApplicationIdleHook ( ) MUST NOT , UNDER ANY CIRCUMSTANCES ,
* CALL A FUNCTION THAT MIGHT BLOCK . */
vApplicationIdleHook ( ) ;
}
# endif /* configUSE_IDLE_HOOK */
2023-09-04 13:07:23 -04:00
/* Call the esp-idf idle hook system. Todo IDF-8180 */
extern void esp_vApplicationIdleHook ( void ) ;
esp_vApplicationIdleHook ( ) ;
2023-05-10 04:22:41 -04:00
/* This conditional compilation should use inequality to 0, not equality
* to 1. This is to ensure portSUPPRESS_TICKS_AND_SLEEP ( ) is called when
* user defined low power mode implementations require
* configUSE_TICKLESS_IDLE to be set to a value other than 1. */
# if ( configUSE_TICKLESS_IDLE != 0 )
{
TickType_t xExpectedIdleTime ;
/* It is not desirable to suspend then resume the scheduler on
* each iteration of the idle task . Therefore , a preliminary
* test of the expected idle time is performed without the
* scheduler suspended . The result here is not necessarily
* valid . */
xExpectedIdleTime = prvGetExpectedIdleTime ( ) ;
if ( xExpectedIdleTime > = configEXPECTED_IDLE_TIME_BEFORE_SLEEP )
{
2023-09-07 12:29:57 -04:00
prvENTER_CRITICAL_OR_SUSPEND_ALL ( & xKernelLock ) ;
2023-05-10 04:22:41 -04:00
{
/* Now the scheduler is suspended, the expected idle
* time can be sampled again , and this time its value can
* be used . */
configASSERT ( xNextTaskUnblockTime > = xTickCount ) ;
xExpectedIdleTime = prvGetExpectedIdleTime ( ) ;
/* Define the following macro to set xExpectedIdleTime to 0
* if the application does not want
* portSUPPRESS_TICKS_AND_SLEEP ( ) to be called . */
configPRE_SUPPRESS_TICKS_AND_SLEEP_PROCESSING ( xExpectedIdleTime ) ;
if ( xExpectedIdleTime > = configEXPECTED_IDLE_TIME_BEFORE_SLEEP )
{
traceLOW_POWER_IDLE_BEGIN ( ) ;
portSUPPRESS_TICKS_AND_SLEEP ( xExpectedIdleTime ) ;
traceLOW_POWER_IDLE_END ( ) ;
}
else
{
mtCOVERAGE_TEST_MARKER ( ) ;
}
}
2023-09-07 12:29:57 -04:00
( void ) prvEXIT_CRITICAL_OR_RESUME_ALL ( & xKernelLock ) ;
2023-05-10 04:22:41 -04:00
}
else
{
mtCOVERAGE_TEST_MARKER ( ) ;
}
}
# endif /* configUSE_TICKLESS_IDLE */
}
}
/*-----------------------------------------------------------*/
# if ( configUSE_TICKLESS_IDLE != 0 )
eSleepModeStatus eTaskConfirmSleepModeStatus ( void )
{
# if ( INCLUDE_vTaskSuspend == 1 )
/* The idle task exists in addition to the application tasks. */
const UBaseType_t uxNonApplicationTasks = 1 ;
# endif /* INCLUDE_vTaskSuspend */
eSleepModeStatus eReturn = eStandardSleep ;
/* This function must be called from a critical section. */
2023-09-14 12:35:31 -04:00
/* Get current core ID as we can no longer be preempted. */
const BaseType_t xCurCoreID = portGET_CORE_ID ( ) ;
if ( listCURRENT_LIST_LENGTH ( & xPendingReadyList [ xCurCoreID ] ) ! = 0 )
2023-05-10 04:22:41 -04:00
{
/* A task was made ready while the scheduler was suspended. */
eReturn = eAbortSleep ;
}
2023-09-14 12:35:31 -04:00
else if ( xYieldPending [ xCurCoreID ] ! = pdFALSE )
2023-05-10 04:22:41 -04:00
{
/* A yield was pended while the scheduler was suspended. */
eReturn = eAbortSleep ;
}
2023-09-14 12:35:31 -04:00
# if ( configNUMBER_OF_CORES == 1 )
else if ( xPendedTicks ! = 0 )
{
/* A tick interrupt has already occurred but was held pending
* because the scheduler is suspended . */
eReturn = eAbortSleep ;
}
# endif /* configNUMBER_OF_CORES == 1 */
2023-05-10 04:22:41 -04:00
# if ( INCLUDE_vTaskSuspend == 1 )
else if ( listCURRENT_LIST_LENGTH ( & xSuspendedTaskList ) = = ( uxCurrentNumberOfTasks - uxNonApplicationTasks ) )
{
/* If all the tasks are in the suspended list (which might mean they
* have an infinite block time rather than actually being suspended )
* then it is safe to turn all clocks off and just wait for external
* interrupts . */
eReturn = eNoTasksWaitingTimeout ;
}
# endif /* INCLUDE_vTaskSuspend */
else
{
mtCOVERAGE_TEST_MARKER ( ) ;
}
return eReturn ;
}
# endif /* configUSE_TICKLESS_IDLE */
/*-----------------------------------------------------------*/
# if ( configNUM_THREAD_LOCAL_STORAGE_POINTERS != 0 )
void vTaskSetThreadLocalStoragePointer ( TaskHandle_t xTaskToSet ,
BaseType_t xIndex ,
void * pvValue )
{
TCB_t * pxTCB ;
if ( ( xIndex > = 0 ) & &
( xIndex < configNUM_THREAD_LOCAL_STORAGE_POINTERS ) )
{
pxTCB = prvGetTCBFromHandle ( xTaskToSet ) ;
configASSERT ( pxTCB ! = NULL ) ;
pxTCB - > pvThreadLocalStoragePointers [ xIndex ] = pvValue ;
}
}
# endif /* configNUM_THREAD_LOCAL_STORAGE_POINTERS */
/*-----------------------------------------------------------*/
# if ( configNUM_THREAD_LOCAL_STORAGE_POINTERS != 0 )
void * pvTaskGetThreadLocalStoragePointer ( TaskHandle_t xTaskToQuery ,
BaseType_t xIndex )
{
void * pvReturn = NULL ;
TCB_t * pxTCB ;
if ( ( xIndex > = 0 ) & &
( xIndex < configNUM_THREAD_LOCAL_STORAGE_POINTERS ) )
{
pxTCB = prvGetTCBFromHandle ( xTaskToQuery ) ;
pvReturn = pxTCB - > pvThreadLocalStoragePointers [ xIndex ] ;
}
else
{
pvReturn = NULL ;
}
return pvReturn ;
}
# endif /* configNUM_THREAD_LOCAL_STORAGE_POINTERS */
/*-----------------------------------------------------------*/
# if ( portUSING_MPU_WRAPPERS == 1 )
void vTaskAllocateMPURegions ( TaskHandle_t xTaskToModify ,
const MemoryRegion_t * const xRegions )
{
TCB_t * pxTCB ;
/* If null is passed in here then we are modifying the MPU settings of
* the calling task . */
pxTCB = prvGetTCBFromHandle ( xTaskToModify ) ;
vPortStoreTaskMPUSettings ( & ( pxTCB - > xMPUSettings ) , xRegions , NULL , 0 ) ;
}
# endif /* portUSING_MPU_WRAPPERS */
/*-----------------------------------------------------------*/
static void prvInitialiseTaskLists ( void )
{
UBaseType_t uxPriority ;
2023-09-14 12:35:31 -04:00
UBaseType_t x ;
2023-05-10 04:22:41 -04:00
for ( uxPriority = ( UBaseType_t ) 0U ; uxPriority < ( UBaseType_t ) configMAX_PRIORITIES ; uxPriority + + )
{
vListInitialise ( & ( pxReadyTasksLists [ uxPriority ] ) ) ;
}
vListInitialise ( & xDelayedTaskList1 ) ;
vListInitialise ( & xDelayedTaskList2 ) ;
2023-09-14 12:35:31 -04:00
for ( x = 0 ; x < configNUMBER_OF_CORES ; x + + )
{
vListInitialise ( & xPendingReadyList [ x ] ) ;
}
2023-05-10 04:22:41 -04:00
# if ( INCLUDE_vTaskDelete == 1 )
{
vListInitialise ( & xTasksWaitingTermination ) ;
}
# endif /* INCLUDE_vTaskDelete */
# if ( INCLUDE_vTaskSuspend == 1 )
{
vListInitialise ( & xSuspendedTaskList ) ;
}
# endif /* INCLUDE_vTaskSuspend */
/* Start with pxDelayedTaskList using list1 and the pxOverflowDelayedTaskList
* using list2 . */
pxDelayedTaskList = & xDelayedTaskList1 ;
pxOverflowDelayedTaskList = & xDelayedTaskList2 ;
}
/*-----------------------------------------------------------*/
static void prvCheckTasksWaitingTermination ( void )
{
/** THIS FUNCTION IS CALLED FROM THE RTOS IDLE TASK **/
# if ( INCLUDE_vTaskDelete == 1 )
{
TCB_t * pxTCB ;
/* uxDeletedTasksWaitingCleanUp is used to prevent taskENTER_CRITICAL()
* being called too often in the idle task . */
while ( uxDeletedTasksWaitingCleanUp > ( UBaseType_t ) 0U )
{
2023-09-14 12:35:31 -04:00
# if ( configNUMBER_OF_CORES > 1 )
2023-05-10 04:22:41 -04:00
{
2023-09-14 12:35:31 -04:00
pxTCB = NULL ;
2023-09-07 12:29:57 -04:00
taskENTER_CRITICAL ( & xKernelLock ) ;
2023-09-14 12:35:31 -04:00
{
/* List may have already been cleared by the other core. Check again */
if ( listLIST_IS_EMPTY ( & xTasksWaitingTermination ) = = pdFALSE )
{
/* We can't delete a task if it is still running on
* the other core . Keep walking the list until we
* find a task we can free , or until we walk the
* entire list . */
ListItem_t * xEntry ;
2023-05-10 04:22:41 -04:00
2023-09-14 12:35:31 -04:00
for ( xEntry = listGET_HEAD_ENTRY ( & xTasksWaitingTermination ) ; xEntry ! = listGET_END_MARKER ( & xTasksWaitingTermination ) ; xEntry = listGET_NEXT ( xEntry ) )
{
if ( taskIS_CURRENTLY_RUNNING ( ( ( TCB_t * ) listGET_LIST_ITEM_OWNER ( xEntry ) ) ) = = pdFALSE )
{
pxTCB = ( TCB_t * ) listGET_LIST_ITEM_OWNER ( xEntry ) ;
( void ) uxListRemove ( & ( pxTCB - > xStateListItem ) ) ;
- - uxCurrentNumberOfTasks ;
- - uxDeletedTasksWaitingCleanUp ;
break ;
}
}
}
}
2023-09-07 12:29:57 -04:00
taskEXIT_CRITICAL ( & xKernelLock ) ;
2023-09-14 12:35:31 -04:00
if ( pxTCB ! = NULL )
{
prvDeleteTCB ( pxTCB ) ;
}
else
{
/* No task found to delete, break out of loop */
break ;
}
}
# else /* configNUMBER_OF_CORES > 1 */
{
2023-09-07 12:29:57 -04:00
taskENTER_CRITICAL ( & xKernelLock ) ;
2023-09-14 12:35:31 -04:00
{
pxTCB = listGET_OWNER_OF_HEAD_ENTRY ( ( & xTasksWaitingTermination ) ) ; /*lint !e9079 void * is used as this macro is used with timers and co-routines too. Alignment is known to be fine as the type of the pointer stored and retrieved is the same. */
( void ) uxListRemove ( & ( pxTCB - > xStateListItem ) ) ;
- - uxCurrentNumberOfTasks ;
- - uxDeletedTasksWaitingCleanUp ;
}
2023-09-07 12:29:57 -04:00
taskEXIT_CRITICAL ( & xKernelLock ) ;
2023-09-14 12:35:31 -04:00
prvDeleteTCB ( pxTCB ) ;
}
# endif /* configNUMBER_OF_CORES > 1 */
2023-05-10 04:22:41 -04:00
}
}
# endif /* INCLUDE_vTaskDelete */
}
/*-----------------------------------------------------------*/
# if ( configUSE_TRACE_FACILITY == 1 )
void vTaskGetInfo ( TaskHandle_t xTask ,
TaskStatus_t * pxTaskStatus ,
BaseType_t xGetFreeStackSpace ,
eTaskState eState )
{
TCB_t * pxTCB ;
/* xTask is NULL then get the state of the calling task. */
pxTCB = prvGetTCBFromHandle ( xTask ) ;
2023-09-07 12:29:57 -04:00
/* A critical section is required for SMP in case another core modifies
* the task simultaneously . */
2023-10-31 12:02:58 -04:00
prvENTER_CRITICAL_SMP_ONLY ( & xKernelLock ) ;
2023-09-07 12:29:57 -04:00
{
pxTaskStatus - > xHandle = ( TaskHandle_t ) pxTCB ;
pxTaskStatus - > pcTaskName = ( const char * ) & ( pxTCB - > pcTaskName [ 0 ] ) ;
pxTaskStatus - > uxCurrentPriority = pxTCB - > uxPriority ;
pxTaskStatus - > pxStackBase = pxTCB - > pxStack ;
# if ( ( portSTACK_GROWTH > 0 ) && ( configRECORD_STACK_HIGH_ADDRESS == 1 ) )
pxTaskStatus - > pxTopOfStack = pxTCB - > pxTopOfStack ;
pxTaskStatus - > pxEndOfStack = pxTCB - > pxEndOfStack ;
# endif
pxTaskStatus - > xTaskNumber = pxTCB - > uxTCBNumber ;
2023-11-16 06:41:24 -05:00
# if ( configTASKLIST_INCLUDE_COREID == 1 )
{
# if ( configNUMBER_OF_CORES > 1 )
{
pxTaskStatus - > xCoreID = pxTCB - > xCoreID ;
}
# else /* configNUMBER_OF_CORES > 1 */
{
pxTaskStatus - > xCoreID = 0 ;
}
# endif /* configNUMBER_OF_CORES > 1 */
}
# endif /* configTASKLIST_INCLUDE_COREID == 1 */
2023-05-10 04:22:41 -04:00
2023-09-07 12:29:57 -04:00
# if ( configUSE_MUTEXES == 1 )
{
pxTaskStatus - > uxBasePriority = pxTCB - > uxBasePriority ;
}
# else
{
pxTaskStatus - > uxBasePriority = 0 ;
}
# endif
2023-05-10 04:22:41 -04:00
2023-09-07 12:29:57 -04:00
# if ( configGENERATE_RUN_TIME_STATS == 1 )
2023-05-10 04:22:41 -04:00
{
2023-09-07 12:29:57 -04:00
pxTaskStatus - > ulRunTimeCounter = pxTCB - > ulRunTimeCounter ;
2023-05-10 04:22:41 -04:00
}
2023-09-07 12:29:57 -04:00
# else
2023-05-10 04:22:41 -04:00
{
2023-09-07 12:29:57 -04:00
pxTaskStatus - > ulRunTimeCounter = ( configRUN_TIME_COUNTER_TYPE ) 0 ;
}
# endif
2023-05-10 04:22:41 -04:00
2023-09-07 12:29:57 -04:00
/* Obtaining the task state is a little fiddly, so is only done if the
* value of eState passed into this function is eInvalid - otherwise the
* state is just set to whatever is passed in . */
if ( eState ! = eInvalid )
{
if ( pxTCB = = pxCurrentTCBs [ portGET_CORE_ID ( ) ] )
{
pxTaskStatus - > eCurrentState = eRunning ;
}
else
2023-05-10 04:22:41 -04:00
{
2023-09-07 12:29:57 -04:00
pxTaskStatus - > eCurrentState = eState ;
# if ( INCLUDE_vTaskSuspend == 1 )
2023-05-10 04:22:41 -04:00
{
2023-09-07 12:29:57 -04:00
/* If the task is in the suspended list then there is a
* chance it is actually just blocked indefinitely - so really
* it should be reported as being in the Blocked state . */
if ( eState = = eSuspended )
2023-05-10 04:22:41 -04:00
{
2023-09-07 12:29:57 -04:00
# if ( configNUMBER_OF_CORES == 1 )
2023-05-10 04:22:41 -04:00
{
2023-09-07 12:29:57 -04:00
/* Single core uses a scheduler suspension to
* atomically check if the task task is blocked . */
vTaskSuspendAll ( ) ;
2023-05-10 04:22:41 -04:00
}
2023-09-07 12:29:57 -04:00
# endif /* configNUMBER_OF_CORES == 1 */
{
if ( listLIST_ITEM_CONTAINER ( & ( pxTCB - > xEventListItem ) ) ! = NULL )
{
pxTaskStatus - > eCurrentState = eBlocked ;
}
}
# if ( configNUMBER_OF_CORES == 1 )
{
( void ) xTaskResumeAll ( ) ;
}
# endif /* configNUMBER_OF_CORES == 1 */
2023-05-10 04:22:41 -04:00
}
}
2023-09-07 12:29:57 -04:00
# endif /* INCLUDE_vTaskSuspend */
2023-05-10 04:22:41 -04:00
}
}
2023-09-07 12:29:57 -04:00
else
{
pxTaskStatus - > eCurrentState = eTaskGetState ( pxTCB ) ;
}
2023-05-10 04:22:41 -04:00
2023-09-07 12:29:57 -04:00
/* Obtaining the stack space takes some time, so the xGetFreeStackSpace
* parameter is provided to allow it to be skipped . */
if ( xGetFreeStackSpace ! = pdFALSE )
2023-05-10 04:22:41 -04:00
{
2023-09-07 12:29:57 -04:00
# if ( portSTACK_GROWTH > 0 )
{
pxTaskStatus - > usStackHighWaterMark = prvTaskCheckFreeStackSpace ( ( uint8_t * ) pxTCB - > pxEndOfStack ) ;
}
# else
{
pxTaskStatus - > usStackHighWaterMark = prvTaskCheckFreeStackSpace ( ( uint8_t * ) pxTCB - > pxStack ) ;
}
# endif
2023-05-10 04:22:41 -04:00
}
2023-09-07 12:29:57 -04:00
else
2023-05-10 04:22:41 -04:00
{
2023-09-07 12:29:57 -04:00
pxTaskStatus - > usStackHighWaterMark = 0 ;
2023-05-10 04:22:41 -04:00
}
}
2023-09-07 12:29:57 -04:00
/* Exit the previously entered critical section. */
2023-10-31 12:02:58 -04:00
prvEXIT_CRITICAL_SMP_ONLY ( & xKernelLock ) ;
2023-05-10 04:22:41 -04:00
}
# endif /* configUSE_TRACE_FACILITY */
/*-----------------------------------------------------------*/
# if ( configUSE_TRACE_FACILITY == 1 )
static UBaseType_t prvListTasksWithinSingleList ( TaskStatus_t * pxTaskStatusArray ,
List_t * pxList ,
eTaskState eState )
{
configLIST_VOLATILE TCB_t * pxNextTCB ;
configLIST_VOLATILE TCB_t * pxFirstTCB ;
UBaseType_t uxTask = 0 ;
if ( listCURRENT_LIST_LENGTH ( pxList ) > ( UBaseType_t ) 0 )
{
listGET_OWNER_OF_NEXT_ENTRY ( pxFirstTCB , pxList ) ; /*lint !e9079 void * is used as this macro is used with timers and co-routines too. Alignment is known to be fine as the type of the pointer stored and retrieved is the same. */
/* Populate an TaskStatus_t structure within the
* pxTaskStatusArray array for each task that is referenced from
* pxList . See the definition of TaskStatus_t in task . h for the
* meaning of each TaskStatus_t structure member . */
do
{
listGET_OWNER_OF_NEXT_ENTRY ( pxNextTCB , pxList ) ; /*lint !e9079 void * is used as this macro is used with timers and co-routines too. Alignment is known to be fine as the type of the pointer stored and retrieved is the same. */
vTaskGetInfo ( ( TaskHandle_t ) pxNextTCB , & ( pxTaskStatusArray [ uxTask ] ) , pdTRUE , eState ) ;
uxTask + + ;
} while ( pxNextTCB ! = pxFirstTCB ) ;
}
else
{
mtCOVERAGE_TEST_MARKER ( ) ;
}
return uxTask ;
}
# endif /* configUSE_TRACE_FACILITY */
/*-----------------------------------------------------------*/
# if ( ( configUSE_TRACE_FACILITY == 1 ) || ( INCLUDE_uxTaskGetStackHighWaterMark == 1 ) || ( INCLUDE_uxTaskGetStackHighWaterMark2 == 1 ) )
static configSTACK_DEPTH_TYPE prvTaskCheckFreeStackSpace ( const uint8_t * pucStackByte )
{
uint32_t ulCount = 0U ;
while ( * pucStackByte = = ( uint8_t ) tskSTACK_FILL_BYTE )
{
pucStackByte - = portSTACK_GROWTH ;
ulCount + + ;
}
ulCount / = ( uint32_t ) sizeof ( StackType_t ) ; /*lint !e961 Casting is not redundant on smaller architectures. */
return ( configSTACK_DEPTH_TYPE ) ulCount ;
}
# endif /* ( ( configUSE_TRACE_FACILITY == 1 ) || ( INCLUDE_uxTaskGetStackHighWaterMark == 1 ) || ( INCLUDE_uxTaskGetStackHighWaterMark2 == 1 ) ) */
/*-----------------------------------------------------------*/
# if ( INCLUDE_uxTaskGetStackHighWaterMark2 == 1 )
/* uxTaskGetStackHighWaterMark() and uxTaskGetStackHighWaterMark2() are the
* same except for their return type . Using configSTACK_DEPTH_TYPE allows the
* user to determine the return type . It gets around the problem of the value
* overflowing on 8 - bit types without breaking backward compatibility for
* applications that expect an 8 - bit return type . */
configSTACK_DEPTH_TYPE uxTaskGetStackHighWaterMark2 ( TaskHandle_t xTask )
{
TCB_t * pxTCB ;
uint8_t * pucEndOfStack ;
configSTACK_DEPTH_TYPE uxReturn ;
/* uxTaskGetStackHighWaterMark() and uxTaskGetStackHighWaterMark2() are
* the same except for their return type . Using configSTACK_DEPTH_TYPE
* allows the user to determine the return type . It gets around the
* problem of the value overflowing on 8 - bit types without breaking
* backward compatibility for applications that expect an 8 - bit return
* type . */
pxTCB = prvGetTCBFromHandle ( xTask ) ;
# if portSTACK_GROWTH < 0
{
pucEndOfStack = ( uint8_t * ) pxTCB - > pxStack ;
}
# else
{
pucEndOfStack = ( uint8_t * ) pxTCB - > pxEndOfStack ;
}
# endif
uxReturn = prvTaskCheckFreeStackSpace ( pucEndOfStack ) ;
return uxReturn ;
}
# endif /* INCLUDE_uxTaskGetStackHighWaterMark2 */
/*-----------------------------------------------------------*/
# if ( INCLUDE_uxTaskGetStackHighWaterMark == 1 )
UBaseType_t uxTaskGetStackHighWaterMark ( TaskHandle_t xTask )
{
TCB_t * pxTCB ;
uint8_t * pucEndOfStack ;
UBaseType_t uxReturn ;
pxTCB = prvGetTCBFromHandle ( xTask ) ;
# if portSTACK_GROWTH < 0
{
pucEndOfStack = ( uint8_t * ) pxTCB - > pxStack ;
}
# else
{
pucEndOfStack = ( uint8_t * ) pxTCB - > pxEndOfStack ;
}
# endif
uxReturn = ( UBaseType_t ) prvTaskCheckFreeStackSpace ( pucEndOfStack ) ;
return uxReturn ;
}
# endif /* INCLUDE_uxTaskGetStackHighWaterMark */
/*-----------------------------------------------------------*/
# if ( INCLUDE_vTaskDelete == 1 )
static void prvDeleteTCB ( TCB_t * pxTCB )
{
/* This call is required specifically for the TriCore port. It must be
* above the vPortFree ( ) calls . The call is also used by ports / demos that
* want to allocate and clean RAM statically . */
portCLEAN_UP_TCB ( pxTCB ) ;
# if ( ( configUSE_NEWLIB_REENTRANT == 1 ) || ( configUSE_C_RUNTIME_TLS_SUPPORT == 1 ) )
{
/* Free up the memory allocated for the task's TLS Block. */
2023-09-14 12:35:31 -04:00
/* Note: Fixed bug in upstream. Free TLS block of pxTCB, NOT pxCurrentTCBs */
configDEINIT_TLS_BLOCK ( pxTCB - > xTLSBlock ) ;
2023-05-10 04:22:41 -04:00
}
# endif
# if ( ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) && ( configSUPPORT_STATIC_ALLOCATION == 0 ) && ( portUSING_MPU_WRAPPERS == 0 ) )
{
/* The task can only have been allocated dynamically - free both
* the stack and TCB . */
vPortFreeStack ( pxTCB - > pxStack ) ;
vPortFree ( pxTCB ) ;
}
# elif ( tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE != 0 ) /*lint !e731 !e9029 Macro has been consolidated for readability reasons. */
{
/* The task could have been allocated statically or dynamically, so
* check what was statically allocated before trying to free the
* memory . */
if ( pxTCB - > ucStaticallyAllocated = = tskDYNAMICALLY_ALLOCATED_STACK_AND_TCB )
{
/* Both the stack and TCB were allocated dynamically, so both
* must be freed . */
vPortFreeStack ( pxTCB - > pxStack ) ;
vPortFree ( pxTCB ) ;
}
else if ( pxTCB - > ucStaticallyAllocated = = tskSTATICALLY_ALLOCATED_STACK_ONLY )
{
/* Only the stack was statically allocated, so the TCB is the
* only memory that must be freed . */
vPortFree ( pxTCB ) ;
}
else
{
/* Neither the stack nor the TCB were allocated dynamically, so
* nothing needs to be freed . */
configASSERT ( pxTCB - > ucStaticallyAllocated = = tskSTATICALLY_ALLOCATED_STACK_AND_TCB ) ;
mtCOVERAGE_TEST_MARKER ( ) ;
}
}
# endif /* configSUPPORT_DYNAMIC_ALLOCATION */
}
# endif /* INCLUDE_vTaskDelete */
/*-----------------------------------------------------------*/
static void prvResetNextTaskUnblockTime ( void )
{
if ( listLIST_IS_EMPTY ( pxDelayedTaskList ) ! = pdFALSE )
{
/* The new current delayed list is empty. Set xNextTaskUnblockTime to
* the maximum possible value so it is extremely unlikely that the
* if ( xTickCount > = xNextTaskUnblockTime ) test will pass until
* there is an item in the delayed list . */
xNextTaskUnblockTime = portMAX_DELAY ;
}
else
{
/* The new current delayed list is not empty, get the value of
* the item at the head of the delayed list . This is the time at
* which the task at the head of the delayed list should be removed
* from the Blocked state . */
xNextTaskUnblockTime = listGET_ITEM_VALUE_OF_HEAD_ENTRY ( pxDelayedTaskList ) ;
}
}
/*-----------------------------------------------------------*/
# if ( ( INCLUDE_xTaskGetCurrentTaskHandle == 1 ) || ( configUSE_MUTEXES == 1 ) )
TaskHandle_t xTaskGetCurrentTaskHandle ( void )
{
2023-10-19 09:45:08 -04:00
TaskHandle_t xReturn ;
UBaseType_t uxSavedInterruptStatus ;
/* For SMP, we need to disable interrupts to ensure the caller does not
* switch cores in between portGET_CORE_ID ( ) and fetching the current
* core ' s TCB . We use the ISR versions of interrupt macros as this
* function could be called inside critical sections .
*
* For single - core a critical section is not required as this is not
* called from an interrupt and the current TCB will always be the same
* for any individual execution thread . */
2023-10-31 12:02:58 -04:00
uxSavedInterruptStatus = prvDISABLE_INTERRUPTS_ISR_SMP_ONLY ( ) ;
2023-10-19 09:45:08 -04:00
{
xReturn = pxCurrentTCBs [ portGET_CORE_ID ( ) ] ;
}
2023-10-31 12:02:58 -04:00
prvENABLE_INTERRUPTS_ISR_SMP_ONLY ( uxSavedInterruptStatus ) ;
2023-10-19 09:45:08 -04:00
return xReturn ;
2023-05-10 04:22:41 -04:00
}
# endif /* ( ( INCLUDE_xTaskGetCurrentTaskHandle == 1 ) || ( configUSE_MUTEXES == 1 ) ) */
/*-----------------------------------------------------------*/
# if ( ( INCLUDE_xTaskGetSchedulerState == 1 ) || ( configUSE_TIMERS == 1 ) )
BaseType_t xTaskGetSchedulerState ( void )
{
BaseType_t xReturn ;
2023-10-19 09:45:08 -04:00
UBaseType_t uxSavedInterruptStatus ;
2023-05-10 04:22:41 -04:00
2023-10-19 09:45:08 -04:00
/* For SMP, we need to disable interrupts here to ensure we don't switch
* cores midway . We forego taking the kernel lock here as a minor
* optimization as it is not required .
*
* - xSchedulerRunning is only ever set by core 0 atomically
* - Each core will only ever update its own copy of uxSchedulerSuspended .
*
* We use the ISR versions of interrupt macros as this function could be
* called inside critical sections . */
2023-10-31 12:02:58 -04:00
uxSavedInterruptStatus = prvDISABLE_INTERRUPTS_ISR_SMP_ONLY ( ) ;
2023-05-10 04:22:41 -04:00
{
2023-09-07 12:29:57 -04:00
if ( xSchedulerRunning = = pdFALSE )
2023-05-10 04:22:41 -04:00
{
2023-09-07 12:29:57 -04:00
xReturn = taskSCHEDULER_NOT_STARTED ;
2023-05-10 04:22:41 -04:00
}
else
{
2023-09-07 12:29:57 -04:00
if ( uxSchedulerSuspended [ portGET_CORE_ID ( ) ] = = ( UBaseType_t ) pdFALSE )
{
xReturn = taskSCHEDULER_RUNNING ;
}
else
{
xReturn = taskSCHEDULER_SUSPENDED ;
}
2023-05-10 04:22:41 -04:00
}
}
2023-10-31 12:02:58 -04:00
prvENABLE_INTERRUPTS_ISR_SMP_ONLY ( uxSavedInterruptStatus ) ;
2023-05-10 04:22:41 -04:00
return xReturn ;
}
# endif /* ( ( INCLUDE_xTaskGetSchedulerState == 1 ) || ( configUSE_TIMERS == 1 ) ) */
/*-----------------------------------------------------------*/
# if ( configUSE_MUTEXES == 1 )
BaseType_t xTaskPriorityInherit ( TaskHandle_t const pxMutexHolder )
{
TCB_t * const pxMutexHolderTCB = pxMutexHolder ;
BaseType_t xReturn = pdFALSE ;
2023-09-07 12:29:57 -04:00
/* For SMP, we need to take the kernel lock here as we are about to
* access kernel data structures . */
2023-10-31 12:02:58 -04:00
prvENTER_CRITICAL_SMP_ONLY ( & xKernelLock ) ;
2023-05-10 04:22:41 -04:00
{
2023-09-07 12:29:57 -04:00
/* Get current core ID as we can no longer be preempted. */
const BaseType_t xCurCoreID = portGET_CORE_ID ( ) ;
2023-05-10 04:22:41 -04:00
2023-09-07 12:29:57 -04:00
/* If the mutex was given back by an interrupt while the queue was
* locked then the mutex holder might now be NULL . _RB_ Is this still
* needed as interrupts can no longer use mutexes ? */
if ( pxMutexHolder ! = NULL )
{
/* If the holder of the mutex has a priority below the priority of
* the task attempting to obtain the mutex then it will temporarily
* inherit the priority of the task attempting to obtain the mutex . */
if ( pxMutexHolderTCB - > uxPriority < pxCurrentTCBs [ xCurCoreID ] - > uxPriority )
2023-05-10 04:22:41 -04:00
{
2023-09-07 12:29:57 -04:00
/* Adjust the mutex holder state to account for its new
* priority . Only reset the event list item value if the value is
* not being used for anything else . */
if ( ( listGET_LIST_ITEM_VALUE ( & ( pxMutexHolderTCB - > xEventListItem ) ) & taskEVENT_LIST_ITEM_VALUE_IN_USE ) = = 0UL )
2023-05-10 04:22:41 -04:00
{
2023-09-07 12:29:57 -04:00
listSET_LIST_ITEM_VALUE ( & ( pxMutexHolderTCB - > xEventListItem ) , ( TickType_t ) configMAX_PRIORITIES - ( TickType_t ) pxCurrentTCBs [ xCurCoreID ] - > uxPriority ) ; /*lint !e961 MISRA exception as the casts are only redundant for some ports. */
2023-05-10 04:22:41 -04:00
}
else
{
mtCOVERAGE_TEST_MARKER ( ) ;
}
2023-09-07 12:29:57 -04:00
/* If the task being modified is in the ready state it will need
* to be moved into a new list . */
if ( listIS_CONTAINED_WITHIN ( & ( pxReadyTasksLists [ pxMutexHolderTCB - > uxPriority ] ) , & ( pxMutexHolderTCB - > xStateListItem ) ) ! = pdFALSE )
{
if ( uxListRemove ( & ( pxMutexHolderTCB - > 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 ( pxMutexHolderTCB - > uxPriority , uxTopReadyPriority ) ;
}
else
{
mtCOVERAGE_TEST_MARKER ( ) ;
}
/* Inherit the priority before being moved into the new list. */
pxMutexHolderTCB - > uxPriority = pxCurrentTCBs [ xCurCoreID ] - > uxPriority ;
prvAddTaskToReadyList ( pxMutexHolderTCB ) ;
}
else
{
/* Just inherit the priority. */
pxMutexHolderTCB - > uxPriority = pxCurrentTCBs [ xCurCoreID ] - > uxPriority ;
}
2023-05-10 04:22:41 -04:00
2023-09-07 12:29:57 -04:00
traceTASK_PRIORITY_INHERIT ( pxMutexHolderTCB , pxCurrentTCBs [ xCurCoreID ] - > uxPriority ) ;
2023-05-10 04:22:41 -04:00
2023-09-07 12:29:57 -04:00
/* Inheritance occurred. */
2023-05-10 04:22:41 -04:00
xReturn = pdTRUE ;
}
else
{
2023-09-07 12:29:57 -04:00
if ( pxMutexHolderTCB - > uxBasePriority < pxCurrentTCBs [ xCurCoreID ] - > uxPriority )
{
/* The base priority of the mutex holder is lower than the
* priority of the task attempting to take the mutex , but the
* current priority of the mutex holder is not lower than the
* priority of the task attempting to take the mutex .
* Therefore the mutex holder must have already inherited a
* priority , but inheritance would have occurred if that had
* not been the case . */
xReturn = pdTRUE ;
}
else
{
mtCOVERAGE_TEST_MARKER ( ) ;
}
2023-05-10 04:22:41 -04:00
}
}
2023-09-07 12:29:57 -04:00
else
{
mtCOVERAGE_TEST_MARKER ( ) ;
}
2023-05-10 04:22:41 -04:00
}
2023-09-07 12:29:57 -04:00
/* Release the previously taken kernel lock. */
2023-10-31 12:02:58 -04:00
prvEXIT_CRITICAL_SMP_ONLY ( & xKernelLock ) ;
2023-05-10 04:22:41 -04:00
return xReturn ;
}
# endif /* configUSE_MUTEXES */
/*-----------------------------------------------------------*/
# if ( configUSE_MUTEXES == 1 )
BaseType_t xTaskPriorityDisinherit ( TaskHandle_t const pxMutexHolder )
{
TCB_t * const pxTCB = pxMutexHolder ;
BaseType_t xReturn = pdFALSE ;
2023-09-07 12:29:57 -04:00
/* For SMP, we need to take the kernel lock here as we are about to
* access kernel data structures . */
2023-10-31 12:02:58 -04:00
prvENTER_CRITICAL_SMP_ONLY ( & xKernelLock ) ;
2023-05-10 04:22:41 -04:00
{
2023-09-07 12:29:57 -04:00
if ( pxMutexHolder ! = NULL )
2023-05-10 04:22:41 -04:00
{
2023-09-07 12:29:57 -04:00
/* A task can only have an inherited priority if it holds the mutex.
* If the mutex is held by a task then it cannot be given from an
* interrupt , and if a mutex is given by the holding task then it must
* be the running state task . */
configASSERT ( pxTCB = = pxCurrentTCBs [ portGET_CORE_ID ( ) ] ) ;
configASSERT ( pxTCB - > uxMutexesHeld ) ;
( pxTCB - > uxMutexesHeld ) - - ;
/* Has the holder of the mutex inherited the priority of another
* task ? */
if ( pxTCB - > uxPriority ! = pxTCB - > uxBasePriority )
2023-05-10 04:22:41 -04:00
{
2023-09-07 12:29:57 -04:00
/* Only disinherit if no other mutexes are held. */
if ( pxTCB - > uxMutexesHeld = = ( UBaseType_t ) 0 )
2023-05-10 04:22:41 -04:00
{
2023-09-07 12:29:57 -04:00
/* A task can only have an inherited priority if it holds
* the mutex . If the mutex is held by a task then it cannot be
* given from an interrupt , and if a mutex is given by the
* holding task then it must be the running state task . Remove
* the holding task from the ready list . */
if ( uxListRemove ( & ( pxTCB - > xStateListItem ) ) = = ( UBaseType_t ) 0 )
{
portRESET_READY_PRIORITY ( pxTCB - > uxPriority , uxTopReadyPriority ) ;
}
else
{
mtCOVERAGE_TEST_MARKER ( ) ;
}
/* Disinherit the priority before adding the task into the
* new ready list . */
traceTASK_PRIORITY_DISINHERIT ( pxTCB , pxTCB - > uxBasePriority ) ;
pxTCB - > uxPriority = pxTCB - > uxBasePriority ;
/* Reset the event list item value. It cannot be in use for
* any other purpose if this task is running , and it must be
* running to give back the mutex . */
listSET_LIST_ITEM_VALUE ( & ( pxTCB - > xEventListItem ) , ( TickType_t ) configMAX_PRIORITIES - ( TickType_t ) pxTCB - > uxPriority ) ; /*lint !e961 MISRA exception as the casts are only redundant for some ports. */
prvAddTaskToReadyList ( pxTCB ) ;
/* Return true to indicate that a context switch is required.
* This is only actually required in the corner case whereby
* multiple mutexes were held and the mutexes were given back
* in an order different to that in which they were taken .
* If a context switch did not occur when the first mutex was
* returned , even if a task was waiting on it , then a context
* switch should occur when the last mutex is returned whether
* a task is waiting on it or not . */
xReturn = pdTRUE ;
2023-05-10 04:22:41 -04:00
}
else
{
mtCOVERAGE_TEST_MARKER ( ) ;
}
}
else
{
mtCOVERAGE_TEST_MARKER ( ) ;
}
}
else
{
mtCOVERAGE_TEST_MARKER ( ) ;
}
}
2023-09-07 12:29:57 -04:00
/* Release the previously taken kernel lock. */
2023-10-31 12:02:58 -04:00
prvEXIT_CRITICAL_SMP_ONLY ( & xKernelLock ) ;
2023-05-10 04:22:41 -04:00
return xReturn ;
}
# endif /* configUSE_MUTEXES */
/*-----------------------------------------------------------*/
# if ( configUSE_MUTEXES == 1 )
void vTaskPriorityDisinheritAfterTimeout ( TaskHandle_t const pxMutexHolder ,
UBaseType_t uxHighestPriorityWaitingTask )
{
TCB_t * const pxTCB = pxMutexHolder ;
UBaseType_t uxPriorityUsedOnEntry , uxPriorityToUse ;
const UBaseType_t uxOnlyOneMutexHeld = ( UBaseType_t ) 1 ;
2023-09-07 12:29:57 -04:00
/* For SMP, we need to take the kernel lock here as we are about to
* access kernel data structures . */
2023-10-31 12:02:58 -04:00
prvENTER_CRITICAL_SMP_ONLY ( & xKernelLock ) ;
2023-05-10 04:22:41 -04:00
{
2023-09-07 12:29:57 -04:00
if ( pxMutexHolder ! = NULL )
2023-05-10 04:22:41 -04:00
{
2023-09-07 12:29:57 -04:00
/* If pxMutexHolder is not NULL then the holder must hold at least
* one mutex . */
configASSERT ( pxTCB - > uxMutexesHeld ) ;
2023-05-10 04:22:41 -04:00
2023-09-07 12:29:57 -04:00
/* Determine the priority to which the priority of the task that
* holds the mutex should be set . This will be the greater of the
* holding task ' s base priority and the priority of the highest
* priority task that is waiting to obtain the mutex . */
if ( pxTCB - > uxBasePriority < uxHighestPriorityWaitingTask )
2023-05-10 04:22:41 -04:00
{
2023-09-07 12:29:57 -04:00
uxPriorityToUse = uxHighestPriorityWaitingTask ;
}
else
{
uxPriorityToUse = pxTCB - > uxBasePriority ;
}
2023-05-10 04:22:41 -04:00
2023-09-07 12:29:57 -04:00
/* Does the priority need to change? */
if ( pxTCB - > uxPriority ! = uxPriorityToUse )
{
/* Only disinherit if no other mutexes are held. This is a
* simplification in the priority inheritance implementation . If
* the task that holds the mutex is also holding other mutexes then
* the other mutexes may have caused the priority inheritance . */
if ( pxTCB - > uxMutexesHeld = = uxOnlyOneMutexHeld )
2023-05-10 04:22:41 -04:00
{
2023-09-07 12:29:57 -04:00
/* If a task has timed out because it already holds the
* mutex it was trying to obtain then it cannot of inherited
* its own priority . */
configASSERT ( pxTCB ! = pxCurrentTCBs [ portGET_CORE_ID ( ) ] ) ;
/* Disinherit the priority, remembering the previous
* priority to facilitate determining the subject task ' s
* state . */
traceTASK_PRIORITY_DISINHERIT ( pxTCB , uxPriorityToUse ) ;
uxPriorityUsedOnEntry = pxTCB - > uxPriority ;
pxTCB - > uxPriority = uxPriorityToUse ;
/* 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 )
2023-05-10 04:22:41 -04:00
{
2023-09-07 12:29:57 -04:00
listSET_LIST_ITEM_VALUE ( & ( pxTCB - > xEventListItem ) , ( TickType_t ) configMAX_PRIORITIES - ( TickType_t ) uxPriorityToUse ) ; /*lint !e961 MISRA exception as the casts are only redundant for some ports. */
2023-05-10 04:22:41 -04:00
}
else
{
mtCOVERAGE_TEST_MARKER ( ) ;
}
2023-09-07 12:29:57 -04:00
/* If the running task is not the task that holds the mutex
* then the task that holds the mutex could be in either the
* Ready , Blocked or Suspended states . Only remove the task
* from its current state list if it is in the Ready state as
* the task ' s priority is going to change and there is one
* Ready list per priority . */
if ( listIS_CONTAINED_WITHIN ( & ( pxReadyTasksLists [ uxPriorityUsedOnEntry ] ) , & ( pxTCB - > xStateListItem ) ) ! = pdFALSE )
{
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 ( pxTCB - > uxPriority , uxTopReadyPriority ) ;
}
else
{
mtCOVERAGE_TEST_MARKER ( ) ;
}
prvAddTaskToReadyList ( pxTCB ) ;
}
else
{
mtCOVERAGE_TEST_MARKER ( ) ;
}
2023-05-10 04:22:41 -04:00
}
else
{
mtCOVERAGE_TEST_MARKER ( ) ;
}
}
else
{
mtCOVERAGE_TEST_MARKER ( ) ;
}
}
else
{
mtCOVERAGE_TEST_MARKER ( ) ;
}
}
2023-09-07 12:29:57 -04:00
/* Release the previously taken kernel lock. */
2023-10-31 12:02:58 -04:00
prvEXIT_CRITICAL_SMP_ONLY ( & xKernelLock ) ;
2023-05-10 04:22:41 -04:00
}
# endif /* configUSE_MUTEXES */
/*-----------------------------------------------------------*/
# if ( portCRITICAL_NESTING_IN_TCB == 1 )
void vTaskEnterCritical ( void )
{
portDISABLE_INTERRUPTS ( ) ;
if ( xSchedulerRunning ! = pdFALSE )
{
2023-09-14 12:35:31 -04:00
/* Get current core ID as we can no longer be preempted. */
const BaseType_t xCurCoreID = portGET_CORE_ID ( ) ;
( pxCurrentTCBs [ xCurCoreID ] - > uxCriticalNesting ) + + ;
2023-05-10 04:22:41 -04:00
/* This is not the interrupt safe version of the enter critical
* function so assert ( ) if it is being called from an interrupt
* context . Only API functions that end in " FromISR " can be used in an
* interrupt . Only assert if the critical nesting count is 1 to
* protect against recursive calls if the assert function also uses a
* critical section . */
2023-09-14 12:35:31 -04:00
if ( pxCurrentTCBs [ xCurCoreID ] - > uxCriticalNesting = = 1 )
2023-05-10 04:22:41 -04:00
{
portASSERT_IF_IN_ISR ( ) ;
}
}
else
{
mtCOVERAGE_TEST_MARKER ( ) ;
}
}
# endif /* portCRITICAL_NESTING_IN_TCB */
/*-----------------------------------------------------------*/
# if ( portCRITICAL_NESTING_IN_TCB == 1 )
void vTaskExitCritical ( void )
{
if ( xSchedulerRunning ! = pdFALSE )
{
2023-09-14 12:35:31 -04:00
/* Get current core ID as we can no longer be preempted. */
const BaseType_t xCurCoreID = portGET_CORE_ID ( ) ;
if ( pxCurrentTCBs [ xCurCoreID ] - > uxCriticalNesting > 0U )
2023-05-10 04:22:41 -04:00
{
2023-09-14 12:35:31 -04:00
( pxCurrentTCBs [ xCurCoreID ] - > uxCriticalNesting ) - - ;
2023-05-10 04:22:41 -04:00
2023-09-14 12:35:31 -04:00
if ( pxCurrentTCBs [ xCurCoreID ] - > uxCriticalNesting = = 0U )
2023-05-10 04:22:41 -04:00
{
portENABLE_INTERRUPTS ( ) ;
}
else
{
mtCOVERAGE_TEST_MARKER ( ) ;
}
}
else
{
mtCOVERAGE_TEST_MARKER ( ) ;
}
}
else
{
mtCOVERAGE_TEST_MARKER ( ) ;
}
}
# endif /* portCRITICAL_NESTING_IN_TCB */
/*-----------------------------------------------------------*/
# if ( configUSE_STATS_FORMATTING_FUNCTIONS > 0 )
static char * prvWriteNameToBuffer ( char * pcBuffer ,
const char * pcTaskName )
{
size_t x ;
/* Start by copying the entire string. */
strcpy ( pcBuffer , pcTaskName ) ;
/* Pad the end of the string with spaces to ensure columns line up when
* printed out . */
for ( x = strlen ( pcBuffer ) ; x < ( size_t ) ( configMAX_TASK_NAME_LEN - 1 ) ; x + + )
{
pcBuffer [ x ] = ' ' ;
}
/* Terminate. */
pcBuffer [ x ] = ( char ) 0x00 ;
/* Return the new end of string. */
return & ( pcBuffer [ x ] ) ;
}
# endif /* ( configUSE_STATS_FORMATTING_FUNCTIONS > 0 ) */
/*-----------------------------------------------------------*/
# if ( ( configUSE_TRACE_FACILITY == 1 ) && ( configUSE_STATS_FORMATTING_FUNCTIONS > 0 ) )
void vTaskList ( char * pcWriteBuffer )
{
TaskStatus_t * pxTaskStatusArray ;
UBaseType_t uxArraySize , x ;
char cStatus ;
/*
* PLEASE NOTE :
*
* This function is provided for convenience only , and is used by many
* of the demo applications . Do not consider it to be part of the
* scheduler .
*
* vTaskList ( ) calls uxTaskGetSystemState ( ) , then formats part of the
* uxTaskGetSystemState ( ) output into a human readable table that
* displays task : names , states , priority , stack usage and task number .
* Stack usage specified as the number of unused StackType_t words stack can hold
* on top of stack - not the number of bytes .
*
* vTaskList ( ) has a dependency on the sprintf ( ) C library function that
* might bloat the code size , use a lot of stack , and provide different
* results on different platforms . An alternative , tiny , third party ,
* and limited functionality implementation of sprintf ( ) is provided in
* many of the FreeRTOS / Demo sub - directories in a file called
* printf - stdarg . c ( note printf - stdarg . c does not provide a full
* snprintf ( ) implementation ! ) .
*
* It is recommended that production systems call uxTaskGetSystemState ( )
* directly to get access to raw stats data , rather than indirectly
* through a call to vTaskList ( ) .
*/
/* Make sure the write buffer does not contain a string. */
* pcWriteBuffer = ( char ) 0x00 ;
/* Take a snapshot of the number of tasks in case it changes while this
* function is executing . */
uxArraySize = uxCurrentNumberOfTasks ;
/* Allocate an array index for each task. NOTE! if
* configSUPPORT_DYNAMIC_ALLOCATION is set to 0 then pvPortMalloc ( ) will
* equate to NULL . */
pxTaskStatusArray = pvPortMalloc ( uxCurrentNumberOfTasks * sizeof ( TaskStatus_t ) ) ; /*lint !e9079 All values returned by pvPortMalloc() have at least the alignment required by the MCU's stack and this allocation allocates a struct that has the alignment requirements of a pointer. */
if ( pxTaskStatusArray ! = NULL )
{
/* Generate the (binary) data. */
uxArraySize = uxTaskGetSystemState ( pxTaskStatusArray , uxArraySize , NULL ) ;
/* Create a human readable table from the binary data. */
for ( x = 0 ; x < uxArraySize ; x + + )
{
switch ( pxTaskStatusArray [ x ] . eCurrentState )
{
case eRunning :
cStatus = tskRUNNING_CHAR ;
break ;
case eReady :
cStatus = tskREADY_CHAR ;
break ;
case eBlocked :
cStatus = tskBLOCKED_CHAR ;
break ;
case eSuspended :
cStatus = tskSUSPENDED_CHAR ;
break ;
case eDeleted :
cStatus = tskDELETED_CHAR ;
break ;
case eInvalid : /* Fall through. */
default : /* Should not get here, but it is included
* to prevent static checking errors . */
cStatus = ( char ) 0x00 ;
break ;
}
/* Write the task name to the string, padding with spaces so it
* can be printed in tabular form more easily . */
pcWriteBuffer = prvWriteNameToBuffer ( pcWriteBuffer , pxTaskStatusArray [ x ] . pcTaskName ) ;
/* Write the rest of the string. */
2023-11-16 06:41:24 -05:00
# if ( configTASKLIST_INCLUDE_COREID == 1 )
{
2024-01-02 11:14:02 -05:00
const BaseType_t xCoreID = ( pxTaskStatusArray [ x ] . xCoreID = = tskNO_AFFINITY ) ? - 1 : pxTaskStatusArray [ x ] . xCoreID ;
2024-04-24 05:01:24 -04:00
sprintf ( pcWriteBuffer , " \t %c \t %u \t %u \t %u \t %d \r \n " , cStatus , ( unsigned int ) pxTaskStatusArray [ x ] . uxCurrentPriority , ( unsigned int ) pxTaskStatusArray [ x ] . usStackHighWaterMark , ( unsigned int ) pxTaskStatusArray [ x ] . xTaskNumber , ( int ) xCoreID ) ; /*lint !e586 sprintf() allowed as this is compiled with many compilers and this is a utility function only - not part of the core kernel implementation. */
2023-11-16 06:41:24 -05:00
}
# else /* configTASKLIST_INCLUDE_COREID == 1 */
{
sprintf ( pcWriteBuffer , " \t %c \t %u \t %u \t %u \r \n " , cStatus , ( unsigned int ) pxTaskStatusArray [ x ] . uxCurrentPriority , ( unsigned int ) pxTaskStatusArray [ x ] . usStackHighWaterMark , ( unsigned int ) pxTaskStatusArray [ x ] . xTaskNumber ) ; /*lint !e586 sprintf() allowed as this is compiled with many compilers and this is a utility function only - not part of the core kernel implementation. */
}
# endif /* configTASKLIST_INCLUDE_COREID == 1 */
pcWriteBuffer + = strlen ( pcWriteBuffer ) ; /*lint !e9016 Pointer arithmetic ok on char pointers especially as in this case where it best denotes the intent of the code. */
2023-05-10 04:22:41 -04:00
}
/* Free the array again. NOTE! If configSUPPORT_DYNAMIC_ALLOCATION
* is 0 then vPortFree ( ) will be # defined to nothing . */
vPortFree ( pxTaskStatusArray ) ;
}
else
{
mtCOVERAGE_TEST_MARKER ( ) ;
}
}
# endif /* ( ( configUSE_TRACE_FACILITY == 1 ) && ( configUSE_STATS_FORMATTING_FUNCTIONS > 0 ) ) */
/*----------------------------------------------------------*/
# if ( ( configGENERATE_RUN_TIME_STATS == 1 ) && ( configUSE_STATS_FORMATTING_FUNCTIONS > 0 ) && ( configUSE_TRACE_FACILITY == 1 ) )
void vTaskGetRunTimeStats ( char * pcWriteBuffer )
{
TaskStatus_t * pxTaskStatusArray ;
UBaseType_t uxArraySize , x ;
configRUN_TIME_COUNTER_TYPE ulTotalTime , ulStatsAsPercentage ;
/*
* PLEASE NOTE :
*
* This function is provided for convenience only , and is used by many
* of the demo applications . Do not consider it to be part of the
* scheduler .
*
* vTaskGetRunTimeStats ( ) calls uxTaskGetSystemState ( ) , then formats part
* of the uxTaskGetSystemState ( ) output into a human readable table that
* displays the amount of time each task has spent in the Running state
* in both absolute and percentage terms .
*
* vTaskGetRunTimeStats ( ) has a dependency on the sprintf ( ) C library
* function that might bloat the code size , use a lot of stack , and
* provide different results on different platforms . An alternative ,
* tiny , third party , and limited functionality implementation of
* sprintf ( ) is provided in many of the FreeRTOS / Demo sub - directories in
* a file called printf - stdarg . c ( note printf - stdarg . c does not provide
* a full snprintf ( ) implementation ! ) .
*
* It is recommended that production systems call uxTaskGetSystemState ( )
* directly to get access to raw stats data , rather than indirectly
* through a call to vTaskGetRunTimeStats ( ) .
*/
/* Make sure the write buffer does not contain a string. */
* pcWriteBuffer = ( char ) 0x00 ;
/* Take a snapshot of the number of tasks in case it changes while this
* function is executing . */
uxArraySize = uxCurrentNumberOfTasks ;
/* Allocate an array index for each task. NOTE! If
* configSUPPORT_DYNAMIC_ALLOCATION is set to 0 then pvPortMalloc ( ) will
* equate to NULL . */
pxTaskStatusArray = pvPortMalloc ( uxCurrentNumberOfTasks * sizeof ( TaskStatus_t ) ) ; /*lint !e9079 All values returned by pvPortMalloc() have at least the alignment required by the MCU's stack and this allocation allocates a struct that has the alignment requirements of a pointer. */
if ( pxTaskStatusArray ! = NULL )
{
/* Generate the (binary) data. */
uxArraySize = uxTaskGetSystemState ( pxTaskStatusArray , uxArraySize , & ulTotalTime ) ;
/* For percentage calculations. */
ulTotalTime / = 100UL ;
/* Avoid divide by zero errors. */
if ( ulTotalTime > 0UL )
{
/* Create a human readable table from the binary data. */
for ( x = 0 ; x < uxArraySize ; x + + )
{
/* What percentage of the total run time has the task used?
* This will always be rounded down to the nearest integer .
* ulTotalRunTime has already been divided by 100. */
ulStatsAsPercentage = pxTaskStatusArray [ x ] . ulRunTimeCounter / ulTotalTime ;
/* Write the task name to the string, padding with
* spaces so it can be printed in tabular form more
* easily . */
pcWriteBuffer = prvWriteNameToBuffer ( pcWriteBuffer , pxTaskStatusArray [ x ] . pcTaskName ) ;
if ( ulStatsAsPercentage > 0UL )
{
# ifdef portLU_PRINTF_SPECIFIER_REQUIRED
{
sprintf ( pcWriteBuffer , " \t %lu \t \t %lu%% \r \n " , pxTaskStatusArray [ x ] . ulRunTimeCounter , ulStatsAsPercentage ) ;
}
# else
{
/* sizeof( int ) == sizeof( long ) so a smaller
* printf ( ) library can be used . */
sprintf ( pcWriteBuffer , " \t %u \t \t %u%% \r \n " , ( unsigned int ) pxTaskStatusArray [ x ] . ulRunTimeCounter , ( unsigned int ) ulStatsAsPercentage ) ; /*lint !e586 sprintf() allowed as this is compiled with many compilers and this is a utility function only - not part of the core kernel implementation. */
}
# endif
}
else
{
/* If the percentage is zero here then the task has
* consumed less than 1 % of the total run time . */
# ifdef portLU_PRINTF_SPECIFIER_REQUIRED
{
sprintf ( pcWriteBuffer , " \t %lu \t \t <1%% \r \n " , pxTaskStatusArray [ x ] . ulRunTimeCounter ) ;
}
# else
{
/* sizeof( int ) == sizeof( long ) so a smaller
* printf ( ) library can be used . */
sprintf ( pcWriteBuffer , " \t %u \t \t <1%% \r \n " , ( unsigned int ) pxTaskStatusArray [ x ] . ulRunTimeCounter ) ; /*lint !e586 sprintf() allowed as this is compiled with many compilers and this is a utility function only - not part of the core kernel implementation. */
}
# endif
}
pcWriteBuffer + = strlen ( pcWriteBuffer ) ; /*lint !e9016 Pointer arithmetic ok on char pointers especially as in this case where it best denotes the intent of the code. */
}
}
else
{
mtCOVERAGE_TEST_MARKER ( ) ;
}
/* Free the array again. NOTE! If configSUPPORT_DYNAMIC_ALLOCATION
* is 0 then vPortFree ( ) will be # defined to nothing . */
vPortFree ( pxTaskStatusArray ) ;
}
else
{
mtCOVERAGE_TEST_MARKER ( ) ;
}
}
# endif /* ( ( configGENERATE_RUN_TIME_STATS == 1 ) && ( configUSE_STATS_FORMATTING_FUNCTIONS > 0 ) ) */
/*-----------------------------------------------------------*/
TickType_t uxTaskResetEventItemValue ( void )
{
TickType_t uxReturn ;
2023-09-07 12:29:57 -04:00
/* For SMP, we need to take the kernel lock here to ensure nothing else
* modifies the task ' s event item value simultaneously . */
2023-10-31 12:02:58 -04:00
prvENTER_CRITICAL_SMP_ONLY ( & xKernelLock ) ;
2023-09-07 12:29:57 -04:00
{
/* Get current core ID as we can no longer be preempted. */
const BaseType_t xCurCoreID = portGET_CORE_ID ( ) ;
2023-09-14 12:35:31 -04:00
2023-09-07 12:29:57 -04:00
uxReturn = listGET_LIST_ITEM_VALUE ( & ( pxCurrentTCBs [ xCurCoreID ] - > xEventListItem ) ) ;
2023-05-10 04:22:41 -04:00
2023-09-07 12:29:57 -04:00
/* Reset the event list item to its normal value - so it can be used with
* queues and semaphores . */
listSET_LIST_ITEM_VALUE ( & ( pxCurrentTCBs [ xCurCoreID ] - > xEventListItem ) , ( ( TickType_t ) configMAX_PRIORITIES - ( TickType_t ) pxCurrentTCBs [ xCurCoreID ] - > uxPriority ) ) ; /*lint !e961 MISRA exception as the casts are only redundant for some ports. */
}
2023-10-31 12:02:58 -04:00
prvEXIT_CRITICAL_SMP_ONLY ( & xKernelLock ) ;
2023-09-07 12:29:57 -04:00
/* Release the previously taken kernel lock. */
2023-05-10 04:22:41 -04:00
return uxReturn ;
}
/*-----------------------------------------------------------*/
# if ( configUSE_MUTEXES == 1 )
TaskHandle_t pvTaskIncrementMutexHeldCount ( void )
{
2023-09-14 12:35:31 -04:00
TaskHandle_t xReturn ;
2023-09-07 12:29:57 -04:00
/* For SMP, we need to take the kernel lock here as we are about to
* access kernel data structures . */
2023-10-31 12:02:58 -04:00
prvENTER_CRITICAL_SMP_ONLY ( & xKernelLock ) ;
2023-05-10 04:22:41 -04:00
{
2023-09-07 12:29:57 -04:00
/* Get current core ID as we can no longer be preempted. */
const BaseType_t xCurCoreID = portGET_CORE_ID ( ) ;
2023-05-10 04:22:41 -04:00
2023-09-07 12:29:57 -04:00
/* If xSemaphoreCreateMutex() is called before any tasks have been created
* then pxCurrentTCBs will be NULL . */
if ( pxCurrentTCBs [ xCurCoreID ] ! = NULL )
{
( pxCurrentTCBs [ xCurCoreID ] - > uxMutexesHeld ) + + ;
}
xReturn = pxCurrentTCBs [ xCurCoreID ] ;
}
/* Release the previously taken kernel lock. */
2023-10-31 12:02:58 -04:00
prvEXIT_CRITICAL_SMP_ONLY ( & xKernelLock ) ;
2023-09-14 12:35:31 -04:00
return xReturn ;
2023-05-10 04:22:41 -04:00
}
# endif /* configUSE_MUTEXES */
/*-----------------------------------------------------------*/
# if ( configUSE_TASK_NOTIFICATIONS == 1 )
uint32_t ulTaskGenericNotifyTake ( UBaseType_t uxIndexToWait ,
BaseType_t xClearCountOnExit ,
TickType_t xTicksToWait )
{
uint32_t ulReturn ;
configASSERT ( uxIndexToWait < configTASK_NOTIFICATION_ARRAY_ENTRIES ) ;
2023-09-07 12:29:57 -04:00
taskENTER_CRITICAL ( & xKernelLock ) ;
2023-05-10 04:22:41 -04:00
{
2023-09-14 12:35:31 -04:00
/* Get current core ID as we can no longer be preempted. */
const BaseType_t xCurCoreID = portGET_CORE_ID ( ) ;
2023-05-10 04:22:41 -04:00
/* Only block if the notification count is not already non-zero. */
2023-09-14 12:35:31 -04:00
if ( pxCurrentTCBs [ xCurCoreID ] - > ulNotifiedValue [ uxIndexToWait ] = = 0UL )
2023-05-10 04:22:41 -04:00
{
/* Mark this task as waiting for a notification. */
2023-09-14 12:35:31 -04:00
pxCurrentTCBs [ xCurCoreID ] - > ucNotifyState [ uxIndexToWait ] = taskWAITING_NOTIFICATION ;
2023-05-10 04:22:41 -04:00
if ( xTicksToWait > ( TickType_t ) 0 )
{
prvAddCurrentTaskToDelayedList ( xTicksToWait , pdTRUE ) ;
traceTASK_NOTIFY_TAKE_BLOCK ( uxIndexToWait ) ;
/* All ports are written to allow a yield in a critical
* section ( some will yield immediately , others wait until the
* critical section exits ) - but it is not something that
* application code should ever do . */
portYIELD_WITHIN_API ( ) ;
}
else
{
mtCOVERAGE_TEST_MARKER ( ) ;
}
}
else
{
mtCOVERAGE_TEST_MARKER ( ) ;
}
}
2023-09-07 12:29:57 -04:00
taskEXIT_CRITICAL ( & xKernelLock ) ;
2023-05-10 04:22:41 -04:00
2023-09-07 12:29:57 -04:00
taskENTER_CRITICAL ( & xKernelLock ) ;
2023-05-10 04:22:41 -04:00
{
2023-09-14 12:35:31 -04:00
/* Get current core ID as we can no longer be preempted. */
const BaseType_t xCurCoreID = portGET_CORE_ID ( ) ;
2023-05-10 04:22:41 -04:00
traceTASK_NOTIFY_TAKE ( uxIndexToWait ) ;
2023-09-14 12:35:31 -04:00
ulReturn = pxCurrentTCBs [ xCurCoreID ] - > ulNotifiedValue [ uxIndexToWait ] ;
2023-05-10 04:22:41 -04:00
if ( ulReturn ! = 0UL )
{
if ( xClearCountOnExit ! = pdFALSE )
{
2023-09-14 12:35:31 -04:00
pxCurrentTCBs [ xCurCoreID ] - > ulNotifiedValue [ uxIndexToWait ] = 0UL ;
2023-05-10 04:22:41 -04:00
}
else
{
2023-09-14 12:35:31 -04:00
pxCurrentTCBs [ xCurCoreID ] - > ulNotifiedValue [ uxIndexToWait ] = ulReturn - ( uint32_t ) 1 ;
2023-05-10 04:22:41 -04:00
}
}
else
{
mtCOVERAGE_TEST_MARKER ( ) ;
}
2023-09-14 12:35:31 -04:00
pxCurrentTCBs [ xCurCoreID ] - > ucNotifyState [ uxIndexToWait ] = taskNOT_WAITING_NOTIFICATION ;
2023-05-10 04:22:41 -04:00
}
2023-09-07 12:29:57 -04:00
taskEXIT_CRITICAL ( & xKernelLock ) ;
2023-05-10 04:22:41 -04:00
return ulReturn ;
}
# endif /* configUSE_TASK_NOTIFICATIONS */
/*-----------------------------------------------------------*/
# if ( configUSE_TASK_NOTIFICATIONS == 1 )
BaseType_t xTaskGenericNotifyWait ( UBaseType_t uxIndexToWait ,
uint32_t ulBitsToClearOnEntry ,
uint32_t ulBitsToClearOnExit ,
uint32_t * pulNotificationValue ,
TickType_t xTicksToWait )
{
BaseType_t xReturn ;
configASSERT ( uxIndexToWait < configTASK_NOTIFICATION_ARRAY_ENTRIES ) ;
2023-09-07 12:29:57 -04:00
taskENTER_CRITICAL ( & xKernelLock ) ;
2023-05-10 04:22:41 -04:00
{
2023-09-14 12:35:31 -04:00
/* Get current core ID as we can no longer be preempted. */
const BaseType_t xCurCoreID = portGET_CORE_ID ( ) ;
2023-05-10 04:22:41 -04:00
/* Only block if a notification is not already pending. */
2023-09-14 12:35:31 -04:00
if ( pxCurrentTCBs [ xCurCoreID ] - > ucNotifyState [ uxIndexToWait ] ! = taskNOTIFICATION_RECEIVED )
2023-05-10 04:22:41 -04:00
{
/* Clear bits in the task's notification value as bits may get
* set by the notifying task or interrupt . This can be used to
* clear the value to zero . */
2023-09-14 12:35:31 -04:00
pxCurrentTCBs [ xCurCoreID ] - > ulNotifiedValue [ uxIndexToWait ] & = ~ ulBitsToClearOnEntry ;
2023-05-10 04:22:41 -04:00
/* Mark this task as waiting for a notification. */
2023-09-14 12:35:31 -04:00
pxCurrentTCBs [ xCurCoreID ] - > ucNotifyState [ uxIndexToWait ] = taskWAITING_NOTIFICATION ;
2023-05-10 04:22:41 -04:00
if ( xTicksToWait > ( TickType_t ) 0 )
{
prvAddCurrentTaskToDelayedList ( xTicksToWait , pdTRUE ) ;
traceTASK_NOTIFY_WAIT_BLOCK ( uxIndexToWait ) ;
/* All ports are written to allow a yield in a critical
* section ( some will yield immediately , others wait until the
* critical section exits ) - but it is not something that
* application code should ever do . */
portYIELD_WITHIN_API ( ) ;
}
else
{
mtCOVERAGE_TEST_MARKER ( ) ;
}
}
else
{
mtCOVERAGE_TEST_MARKER ( ) ;
}
}
2023-09-07 12:29:57 -04:00
taskEXIT_CRITICAL ( & xKernelLock ) ;
2023-05-10 04:22:41 -04:00
2023-09-07 12:29:57 -04:00
taskENTER_CRITICAL ( & xKernelLock ) ;
2023-05-10 04:22:41 -04:00
{
2023-09-14 12:35:31 -04:00
/* Get current core ID as we can no longer be preempted. */
const BaseType_t xCurCoreID = portGET_CORE_ID ( ) ;
2023-05-10 04:22:41 -04:00
traceTASK_NOTIFY_WAIT ( uxIndexToWait ) ;
if ( pulNotificationValue ! = NULL )
{
/* Output the current notification value, which may or may not
* have changed . */
2023-09-14 12:35:31 -04:00
* pulNotificationValue = pxCurrentTCBs [ xCurCoreID ] - > ulNotifiedValue [ uxIndexToWait ] ;
2023-05-10 04:22:41 -04:00
}
/* If ucNotifyValue is set then either the task never entered the
* blocked state ( because a notification was already pending ) or the
* task unblocked because of a notification . Otherwise the task
* unblocked because of a timeout . */
2023-09-14 12:35:31 -04:00
if ( pxCurrentTCBs [ xCurCoreID ] - > ucNotifyState [ uxIndexToWait ] ! = taskNOTIFICATION_RECEIVED )
2023-05-10 04:22:41 -04:00
{
/* A notification was not received. */
xReturn = pdFALSE ;
}
else
{
/* A notification was already pending or a notification was
* received while the task was waiting . */
2023-09-14 12:35:31 -04:00
pxCurrentTCBs [ xCurCoreID ] - > ulNotifiedValue [ uxIndexToWait ] & = ~ ulBitsToClearOnExit ;
2023-05-10 04:22:41 -04:00
xReturn = pdTRUE ;
}
2023-09-14 12:35:31 -04:00
pxCurrentTCBs [ xCurCoreID ] - > ucNotifyState [ uxIndexToWait ] = taskNOT_WAITING_NOTIFICATION ;
2023-05-10 04:22:41 -04:00
}
2023-09-07 12:29:57 -04:00
taskEXIT_CRITICAL ( & xKernelLock ) ;
2023-05-10 04:22:41 -04:00
return xReturn ;
}
# endif /* configUSE_TASK_NOTIFICATIONS */
/*-----------------------------------------------------------*/
# if ( configUSE_TASK_NOTIFICATIONS == 1 )
BaseType_t xTaskGenericNotify ( TaskHandle_t xTaskToNotify ,
UBaseType_t uxIndexToNotify ,
uint32_t ulValue ,
eNotifyAction eAction ,
uint32_t * pulPreviousNotificationValue )
{
TCB_t * pxTCB ;
BaseType_t xReturn = pdPASS ;
uint8_t ucOriginalNotifyState ;
configASSERT ( uxIndexToNotify < configTASK_NOTIFICATION_ARRAY_ENTRIES ) ;
configASSERT ( xTaskToNotify ) ;
pxTCB = xTaskToNotify ;
2023-09-07 12:29:57 -04:00
taskENTER_CRITICAL ( & xKernelLock ) ;
2023-05-10 04:22:41 -04:00
{
if ( pulPreviousNotificationValue ! = NULL )
{
* pulPreviousNotificationValue = pxTCB - > ulNotifiedValue [ uxIndexToNotify ] ;
}
ucOriginalNotifyState = pxTCB - > ucNotifyState [ uxIndexToNotify ] ;
pxTCB - > ucNotifyState [ uxIndexToNotify ] = taskNOTIFICATION_RECEIVED ;
switch ( eAction )
{
case eSetBits :
pxTCB - > ulNotifiedValue [ uxIndexToNotify ] | = ulValue ;
break ;
case eIncrement :
( pxTCB - > ulNotifiedValue [ uxIndexToNotify ] ) + + ;
break ;
case eSetValueWithOverwrite :
pxTCB - > ulNotifiedValue [ uxIndexToNotify ] = ulValue ;
break ;
case eSetValueWithoutOverwrite :
if ( ucOriginalNotifyState ! = taskNOTIFICATION_RECEIVED )
{
pxTCB - > ulNotifiedValue [ uxIndexToNotify ] = ulValue ;
}
else
{
/* The value could not be written to the task. */
xReturn = pdFAIL ;
}
break ;
case eNoAction :
/* The task is being notified without its notify value being
* updated . */
break ;
default :
/* Should not get here if all enums are handled.
* Artificially force an assert by testing a value the
* compiler can ' t assume is const . */
configASSERT ( xTickCount = = ( TickType_t ) 0 ) ;
break ;
}
traceTASK_NOTIFY ( uxIndexToNotify ) ;
/* If the task is in the blocked state specifically to wait for a
* notification then unblock it now . */
if ( ucOriginalNotifyState = = taskWAITING_NOTIFICATION )
{
listREMOVE_ITEM ( & ( pxTCB - > xStateListItem ) ) ;
prvAddTaskToReadyList ( pxTCB ) ;
/* The task should not have been on an event list. */
configASSERT ( listLIST_ITEM_CONTAINER ( & ( pxTCB - > xEventListItem ) ) = = NULL ) ;
# if ( configUSE_TICKLESS_IDLE != 0 )
{
/* If a task is blocked waiting for a notification then
* xNextTaskUnblockTime might be set to the blocked task ' s time
* out time . If the task is unblocked for a reason other than
* a timeout xNextTaskUnblockTime is normally left unchanged ,
* because it will automatically get reset to a new value when
* the tick count equals xNextTaskUnblockTime . However if
* tickless idling is used it might be more important to enter
* sleep mode at the earliest possible time - so reset
* xNextTaskUnblockTime here to ensure it is updated at the
* earliest possible time . */
prvResetNextTaskUnblockTime ( ) ;
}
# endif
2023-11-16 06:18:17 -05:00
if ( taskIS_YIELD_REQUIRED ( pxTCB , pdFALSE ) = = pdTRUE )
2023-05-10 04:22:41 -04:00
{
/* The notified task has a priority above the currently
* executing task so a yield is required . */
taskYIELD_IF_USING_PREEMPTION ( ) ;
}
else
{
mtCOVERAGE_TEST_MARKER ( ) ;
}
}
else
{
mtCOVERAGE_TEST_MARKER ( ) ;
}
}
2023-09-07 12:29:57 -04:00
taskEXIT_CRITICAL ( & xKernelLock ) ;
2023-05-10 04:22:41 -04:00
return xReturn ;
}
# endif /* configUSE_TASK_NOTIFICATIONS */
/*-----------------------------------------------------------*/
# if ( configUSE_TASK_NOTIFICATIONS == 1 )
BaseType_t xTaskGenericNotifyFromISR ( TaskHandle_t xTaskToNotify ,
UBaseType_t uxIndexToNotify ,
uint32_t ulValue ,
eNotifyAction eAction ,
uint32_t * pulPreviousNotificationValue ,
BaseType_t * pxHigherPriorityTaskWoken )
{
TCB_t * pxTCB ;
uint8_t ucOriginalNotifyState ;
BaseType_t xReturn = pdPASS ;
UBaseType_t uxSavedInterruptStatus ;
configASSERT ( xTaskToNotify ) ;
configASSERT ( uxIndexToNotify < configTASK_NOTIFICATION_ARRAY_ENTRIES ) ;
/* RTOS ports that support interrupt nesting have the concept of a
* maximum system call ( or maximum API call ) interrupt priority .
* Interrupts that are above the maximum system call priority are keep
* permanently enabled , even when the RTOS kernel is in a critical section ,
* but cannot make any calls to FreeRTOS API functions . If configASSERT ( )
* is defined in FreeRTOSConfig . h then
* portASSERT_IF_INTERRUPT_PRIORITY_INVALID ( ) will result in an assertion
* failure if a FreeRTOS API function is called from an interrupt that has
* been assigned a priority above the configured maximum system call
* priority . Only FreeRTOS functions that end in FromISR can be called
* from interrupts that have been assigned a priority at or ( logically )
* below the maximum system call interrupt priority . FreeRTOS maintains a
* separate interrupt safe API to ensure interrupt entry is as fast and as
* simple as possible . More information ( albeit Cortex - M specific ) is
* provided on the following link :
* https : //www.FreeRTOS.org/RTOS-Cortex-M3-M4.html */
portASSERT_IF_INTERRUPT_PRIORITY_INVALID ( ) ;
pxTCB = xTaskToNotify ;
2023-09-07 12:29:57 -04:00
prvENTER_CRITICAL_OR_MASK_ISR ( & xKernelLock , uxSavedInterruptStatus ) ;
2023-05-10 04:22:41 -04:00
{
2023-09-14 12:35:31 -04:00
/* Get current core ID as we can no longer be preempted. */
const BaseType_t xCurCoreID = portGET_CORE_ID ( ) ;
2023-05-10 04:22:41 -04:00
if ( pulPreviousNotificationValue ! = NULL )
{
* pulPreviousNotificationValue = pxTCB - > ulNotifiedValue [ uxIndexToNotify ] ;
}
ucOriginalNotifyState = pxTCB - > ucNotifyState [ uxIndexToNotify ] ;
pxTCB - > ucNotifyState [ uxIndexToNotify ] = taskNOTIFICATION_RECEIVED ;
switch ( eAction )
{
case eSetBits :
pxTCB - > ulNotifiedValue [ uxIndexToNotify ] | = ulValue ;
break ;
case eIncrement :
( pxTCB - > ulNotifiedValue [ uxIndexToNotify ] ) + + ;
break ;
case eSetValueWithOverwrite :
pxTCB - > ulNotifiedValue [ uxIndexToNotify ] = ulValue ;
break ;
case eSetValueWithoutOverwrite :
if ( ucOriginalNotifyState ! = taskNOTIFICATION_RECEIVED )
{
pxTCB - > ulNotifiedValue [ uxIndexToNotify ] = ulValue ;
}
else
{
/* The value could not be written to the task. */
xReturn = pdFAIL ;
}
break ;
case eNoAction :
/* The task is being notified without its notify value being
* updated . */
break ;
default :
/* Should not get here if all enums are handled.
* Artificially force an assert by testing a value the
* compiler can ' t assume is const . */
configASSERT ( xTickCount = = ( TickType_t ) 0 ) ;
break ;
}
traceTASK_NOTIFY_FROM_ISR ( uxIndexToNotify ) ;
/* If the task is in the blocked state specifically to wait for a
* notification then unblock it now . */
if ( ucOriginalNotifyState = = taskWAITING_NOTIFICATION )
{
/* The task should not have been on an event list. */
configASSERT ( listLIST_ITEM_CONTAINER ( & ( pxTCB - > xEventListItem ) ) = = NULL ) ;
2023-09-14 12:35:31 -04:00
if ( taskCAN_BE_SCHEDULED ( pxTCB ) = = pdTRUE )
2023-05-10 04:22:41 -04:00
{
listREMOVE_ITEM ( & ( pxTCB - > xStateListItem ) ) ;
prvAddTaskToReadyList ( pxTCB ) ;
}
else
{
/* The delayed and ready lists cannot be accessed, so hold
* this task pending until the scheduler is resumed . */
2023-09-14 12:35:31 -04:00
listINSERT_END ( & ( xPendingReadyList [ xCurCoreID ] ) , & ( pxTCB - > xEventListItem ) ) ;
2023-05-10 04:22:41 -04:00
}
2023-11-16 06:18:17 -05:00
if ( taskIS_YIELD_REQUIRED ( pxTCB , pdFALSE ) = = pdTRUE )
2023-05-10 04:22:41 -04:00
{
/* The notified task has a priority above the currently
* executing task so a yield is required . */
if ( pxHigherPriorityTaskWoken ! = NULL )
{
* pxHigherPriorityTaskWoken = pdTRUE ;
}
/* Mark that a yield is pending in case the user is not
* using the " xHigherPriorityTaskWoken " parameter to an ISR
* safe FreeRTOS function . */
2023-09-14 12:35:31 -04:00
xYieldPending [ xCurCoreID ] = pdTRUE ;
2023-05-10 04:22:41 -04:00
}
else
{
mtCOVERAGE_TEST_MARKER ( ) ;
}
}
}
2023-09-07 12:29:57 -04:00
prvEXIT_CRITICAL_OR_UNMASK_ISR ( & xKernelLock , uxSavedInterruptStatus ) ;
2023-05-10 04:22:41 -04:00
return xReturn ;
}
# endif /* configUSE_TASK_NOTIFICATIONS */
/*-----------------------------------------------------------*/
# if ( configUSE_TASK_NOTIFICATIONS == 1 )
void vTaskGenericNotifyGiveFromISR ( TaskHandle_t xTaskToNotify ,
UBaseType_t uxIndexToNotify ,
BaseType_t * pxHigherPriorityTaskWoken )
{
TCB_t * pxTCB ;
uint8_t ucOriginalNotifyState ;
UBaseType_t uxSavedInterruptStatus ;
configASSERT ( xTaskToNotify ) ;
configASSERT ( uxIndexToNotify < configTASK_NOTIFICATION_ARRAY_ENTRIES ) ;
/* RTOS ports that support interrupt nesting have the concept of a
* maximum system call ( or maximum API call ) interrupt priority .
* Interrupts that are above the maximum system call priority are keep
* permanently enabled , even when the RTOS kernel is in a critical section ,
* but cannot make any calls to FreeRTOS API functions . If configASSERT ( )
* is defined in FreeRTOSConfig . h then
* portASSERT_IF_INTERRUPT_PRIORITY_INVALID ( ) will result in an assertion
* failure if a FreeRTOS API function is called from an interrupt that has
* been assigned a priority above the configured maximum system call
* priority . Only FreeRTOS functions that end in FromISR can be called
* from interrupts that have been assigned a priority at or ( logically )
* below the maximum system call interrupt priority . FreeRTOS maintains a
* separate interrupt safe API to ensure interrupt entry is as fast and as
* simple as possible . More information ( albeit Cortex - M specific ) is
* provided on the following link :
* https : //www.FreeRTOS.org/RTOS-Cortex-M3-M4.html */
portASSERT_IF_INTERRUPT_PRIORITY_INVALID ( ) ;
pxTCB = xTaskToNotify ;
2023-09-07 12:29:57 -04:00
prvENTER_CRITICAL_OR_MASK_ISR ( & xKernelLock , uxSavedInterruptStatus ) ;
2023-05-10 04:22:41 -04:00
{
2023-09-14 12:35:31 -04:00
/* Get current core ID as we can no longer be preempted. */
const BaseType_t xCurCoreID = portGET_CORE_ID ( ) ;
2023-05-10 04:22:41 -04:00
ucOriginalNotifyState = pxTCB - > ucNotifyState [ uxIndexToNotify ] ;
pxTCB - > ucNotifyState [ uxIndexToNotify ] = taskNOTIFICATION_RECEIVED ;
/* 'Giving' is equivalent to incrementing a count in a counting
* semaphore . */
( pxTCB - > ulNotifiedValue [ uxIndexToNotify ] ) + + ;
traceTASK_NOTIFY_GIVE_FROM_ISR ( uxIndexToNotify ) ;
/* If the task is in the blocked state specifically to wait for a
* notification then unblock it now . */
if ( ucOriginalNotifyState = = taskWAITING_NOTIFICATION )
{
/* The task should not have been on an event list. */
configASSERT ( listLIST_ITEM_CONTAINER ( & ( pxTCB - > xEventListItem ) ) = = NULL ) ;
2023-09-14 12:35:31 -04:00
if ( taskCAN_BE_SCHEDULED ( pxTCB ) = = pdTRUE )
2023-05-10 04:22:41 -04:00
{
listREMOVE_ITEM ( & ( pxTCB - > xStateListItem ) ) ;
prvAddTaskToReadyList ( pxTCB ) ;
}
else
{
/* The delayed and ready lists cannot be accessed, so hold
* this task pending until the scheduler is resumed . */
2023-09-14 12:35:31 -04:00
listINSERT_END ( & ( xPendingReadyList [ xCurCoreID ] ) , & ( pxTCB - > xEventListItem ) ) ;
2023-05-10 04:22:41 -04:00
}
2023-11-16 06:18:17 -05:00
if ( taskIS_YIELD_REQUIRED ( pxTCB , pdFALSE ) = = pdTRUE )
2023-05-10 04:22:41 -04:00
{
/* The notified task has a priority above the currently
* executing task so a yield is required . */
if ( pxHigherPriorityTaskWoken ! = NULL )
{
* pxHigherPriorityTaskWoken = pdTRUE ;
}
/* Mark that a yield is pending in case the user is not
* using the " xHigherPriorityTaskWoken " parameter in an ISR
* safe FreeRTOS function . */
2023-09-14 12:35:31 -04:00
xYieldPending [ xCurCoreID ] = pdTRUE ;
2023-05-10 04:22:41 -04:00
}
else
{
mtCOVERAGE_TEST_MARKER ( ) ;
}
}
}
2023-09-07 12:29:57 -04:00
prvEXIT_CRITICAL_OR_UNMASK_ISR ( & xKernelLock , uxSavedInterruptStatus ) ;
2023-05-10 04:22:41 -04:00
}
# endif /* configUSE_TASK_NOTIFICATIONS */
/*-----------------------------------------------------------*/
# if ( configUSE_TASK_NOTIFICATIONS == 1 )
BaseType_t xTaskGenericNotifyStateClear ( TaskHandle_t xTask ,
UBaseType_t uxIndexToClear )
{
TCB_t * pxTCB ;
BaseType_t xReturn ;
configASSERT ( uxIndexToClear < configTASK_NOTIFICATION_ARRAY_ENTRIES ) ;
/* If null is passed in here then it is the calling task that is having
* its notification state cleared . */
pxTCB = prvGetTCBFromHandle ( xTask ) ;
2023-09-07 12:29:57 -04:00
taskENTER_CRITICAL ( & xKernelLock ) ;
2023-05-10 04:22:41 -04:00
{
if ( pxTCB - > ucNotifyState [ uxIndexToClear ] = = taskNOTIFICATION_RECEIVED )
{
pxTCB - > ucNotifyState [ uxIndexToClear ] = taskNOT_WAITING_NOTIFICATION ;
xReturn = pdPASS ;
}
else
{
xReturn = pdFAIL ;
}
}
2023-09-07 12:29:57 -04:00
taskEXIT_CRITICAL ( & xKernelLock ) ;
2023-05-10 04:22:41 -04:00
return xReturn ;
}
# endif /* configUSE_TASK_NOTIFICATIONS */
/*-----------------------------------------------------------*/
# if ( configUSE_TASK_NOTIFICATIONS == 1 )
uint32_t ulTaskGenericNotifyValueClear ( TaskHandle_t xTask ,
UBaseType_t uxIndexToClear ,
uint32_t ulBitsToClear )
{
TCB_t * pxTCB ;
uint32_t ulReturn ;
/* If null is passed in here then it is the calling task that is having
* its notification state cleared . */
pxTCB = prvGetTCBFromHandle ( xTask ) ;
2023-09-07 12:29:57 -04:00
taskENTER_CRITICAL ( & xKernelLock ) ;
2023-05-10 04:22:41 -04:00
{
/* Return the notification as it was before the bits were cleared,
* then clear the bit mask . */
ulReturn = pxTCB - > ulNotifiedValue [ uxIndexToClear ] ;
pxTCB - > ulNotifiedValue [ uxIndexToClear ] & = ~ ulBitsToClear ;
}
2023-09-07 12:29:57 -04:00
taskEXIT_CRITICAL ( & xKernelLock ) ;
2023-05-10 04:22:41 -04:00
return ulReturn ;
}
# endif /* configUSE_TASK_NOTIFICATIONS */
/*-----------------------------------------------------------*/
# if ( ( configGENERATE_RUN_TIME_STATS == 1 ) && ( INCLUDE_xTaskGetIdleTaskHandle == 1 ) )
configRUN_TIME_COUNTER_TYPE ulTaskGetIdleRunTimeCounter ( void )
{
2023-09-14 12:35:31 -04:00
return ulTaskGetIdleRunTimeCounterForCore ( portGET_CORE_ID ( ) ) ;
2023-05-10 04:22:41 -04:00
}
# endif
/*-----------------------------------------------------------*/
# if ( ( configGENERATE_RUN_TIME_STATS == 1 ) && ( INCLUDE_xTaskGetIdleTaskHandle == 1 ) )
configRUN_TIME_COUNTER_TYPE ulTaskGetIdleRunTimePercent ( void )
{
2023-09-14 12:35:31 -04:00
return ulTaskGetIdleRunTimePercentForCore ( portGET_CORE_ID ( ) ) ;
2023-05-10 04:22:41 -04:00
}
# endif /* if ( ( configGENERATE_RUN_TIME_STATS == 1 ) && ( INCLUDE_xTaskGetIdleTaskHandle == 1 ) ) */
/*-----------------------------------------------------------*/
static void prvAddCurrentTaskToDelayedList ( TickType_t xTicksToWait ,
const BaseType_t xCanBlockIndefinitely )
{
TickType_t xTimeToWake ;
const TickType_t xConstTickCount = xTickCount ;
2023-09-14 12:35:31 -04:00
/* Get current core ID as we can no longer be preempted. */
const BaseType_t xCurCoreID = portGET_CORE_ID ( ) ;
# if ( configNUMBER_OF_CORES > 1 )
{
if ( listIS_CONTAINED_WITHIN ( & xTasksWaitingTermination , & ( pxCurrentTCBs [ xCurCoreID ] - > xStateListItem ) ) = = pdTRUE )
{
/* In SMP, it is possible that another core has already deleted the
* current task ( via vTaskDelete ( ) ) which will result in the current
* task being placed on the waiting termination list . In this case ,
* we do nothing and return , the current task will yield as soon
* as it re - enables interrupts . */
return ;
}
}
# endif /* configNUMBER_OF_CORES > 1 */
2023-05-10 04:22:41 -04:00
# if ( INCLUDE_xTaskAbortDelay == 1 )
{
/* About to enter a delayed list, so ensure the ucDelayAborted flag is
* reset to pdFALSE so it can be detected as having been set to pdTRUE
* when the task leaves the Blocked state . */
2023-09-14 12:35:31 -04:00
pxCurrentTCBs [ xCurCoreID ] - > ucDelayAborted = pdFALSE ;
2023-05-10 04:22:41 -04:00
}
# endif
/* Remove the task from the ready list before adding it to the blocked list
* as the same list item is used for both lists . */
2023-09-14 12:35:31 -04:00
if ( uxListRemove ( & ( pxCurrentTCBs [ xCurCoreID ] - > xStateListItem ) ) = = ( UBaseType_t ) 0 )
2023-05-10 04:22:41 -04:00
{
/* The current task must be in a ready list, so there is no need to
* check , and the port reset macro can be called directly . */
2023-09-14 12:35:31 -04:00
portRESET_READY_PRIORITY ( pxCurrentTCBs [ xCurCoreID ] - > uxPriority , uxTopReadyPriority ) ; /*lint !e931 pxCurrentTCBs cannot change as it is the calling task. pxCurrentTCBs->uxPriority and uxTopReadyPriority cannot change as called with scheduler suspended or in a critical section. */
2023-05-10 04:22:41 -04:00
}
else
{
mtCOVERAGE_TEST_MARKER ( ) ;
}
# if ( INCLUDE_vTaskSuspend == 1 )
{
if ( ( xTicksToWait = = portMAX_DELAY ) & & ( xCanBlockIndefinitely ! = pdFALSE ) )
{
/* Add the task to the suspended task list instead of a delayed task
* list to ensure it is not woken by a timing event . It will block
* indefinitely . */
2023-09-14 12:35:31 -04:00
listINSERT_END ( & xSuspendedTaskList , & ( pxCurrentTCBs [ xCurCoreID ] - > xStateListItem ) ) ;
2023-05-10 04:22:41 -04:00
}
else
{
/* Calculate the time at which the task should be woken if the event
* does not occur . This may overflow but this doesn ' t matter , the
* kernel will manage it correctly . */
xTimeToWake = xConstTickCount + xTicksToWait ;
/* The list item will be inserted in wake time order. */
2023-09-14 12:35:31 -04:00
listSET_LIST_ITEM_VALUE ( & ( pxCurrentTCBs [ xCurCoreID ] - > xStateListItem ) , xTimeToWake ) ;
2023-05-10 04:22:41 -04:00
if ( xTimeToWake < xConstTickCount )
{
/* Wake time has overflowed. Place this item in the overflow
* list . */
2023-09-14 12:35:31 -04:00
vListInsert ( pxOverflowDelayedTaskList , & ( pxCurrentTCBs [ xCurCoreID ] - > xStateListItem ) ) ;
2023-05-10 04:22:41 -04:00
}
else
{
/* The wake time has not overflowed, so the current block list
* is used . */
2023-09-14 12:35:31 -04:00
vListInsert ( pxDelayedTaskList , & ( pxCurrentTCBs [ xCurCoreID ] - > xStateListItem ) ) ;
2023-05-10 04:22:41 -04:00
/* If the task entering the blocked state was placed at the
* head of the list of blocked tasks then xNextTaskUnblockTime
* needs to be updated too . */
if ( xTimeToWake < xNextTaskUnblockTime )
{
xNextTaskUnblockTime = xTimeToWake ;
}
else
{
mtCOVERAGE_TEST_MARKER ( ) ;
}
}
}
}
# else /* INCLUDE_vTaskSuspend */
{
/* Calculate the time at which the task should be woken if the event
* does not occur . This may overflow but this doesn ' t matter , the kernel
* will manage it correctly . */
xTimeToWake = xConstTickCount + xTicksToWait ;
/* The list item will be inserted in wake time order. */
2023-09-14 12:35:31 -04:00
listSET_LIST_ITEM_VALUE ( & ( pxCurrentTCBs [ xCurCoreID ] - > xStateListItem ) , xTimeToWake ) ;
2023-05-10 04:22:41 -04:00
if ( xTimeToWake < xConstTickCount )
{
/* Wake time has overflowed. Place this item in the overflow list. */
2023-09-14 12:35:31 -04:00
vListInsert ( pxOverflowDelayedTaskList , & ( pxCurrentTCBs [ xCurCoreID ] - > xStateListItem ) ) ;
2023-05-10 04:22:41 -04:00
}
else
{
/* The wake time has not overflowed, so the current block list is used. */
2023-09-14 12:35:31 -04:00
vListInsert ( pxDelayedTaskList , & ( pxCurrentTCBs [ xCurCoreID ] - > xStateListItem ) ) ;
2023-05-10 04:22:41 -04:00
/* If the task entering the blocked state was placed at the head of the
* list of blocked tasks then xNextTaskUnblockTime needs to be updated
* too . */
if ( xTimeToWake < xNextTaskUnblockTime )
{
xNextTaskUnblockTime = xTimeToWake ;
}
else
{
mtCOVERAGE_TEST_MARKER ( ) ;
}
}
/* Avoid compiler warning when INCLUDE_vTaskSuspend is not 1. */
( void ) xCanBlockIndefinitely ;
}
# endif /* INCLUDE_vTaskSuspend */
}
/* Code below here allows additional code to be inserted into this source file,
* especially where access to file scope functions and data is needed ( for example
* when performing module tests ) . */
# ifdef FREERTOS_MODULE_TEST
# include "tasks_test_access_functions.h"
# endif
# if ( configINCLUDE_FREERTOS_TASK_C_ADDITIONS_H == 1 )
# include "freertos_tasks_c_additions.h"
# ifdef FREERTOS_TASKS_C_ADDITIONS_INIT
static void freertos_tasks_c_additions_init ( void )
{
FREERTOS_TASKS_C_ADDITIONS_INIT ( ) ;
}
# endif
# endif /* if ( configINCLUDE_FREERTOS_TASK_C_ADDITIONS_H == 1 ) */