mirror of
https://github.com/espressif/esp-idf.git
synced 2025-08-22 01:02:57 +00:00
feat(freertos): Add SMP kernel changes to FreeRTOS v10.5.1
This commit adds the key kernel changes to the v10.5.1 kernel to support dual-core SMP. These changes are temporarily documented in the `idf_changes.md` document. This commit... - Added changes to kernel data structures to support multiple cores - Changes to scheduling algorithm support SMP scheduling. - Changes to each FreeRTOS function to support multiple cores and SMP scheduling algorithm.
This commit is contained in:
@@ -135,6 +135,24 @@
|
||||
* within FreeRTOSConfig.h.
|
||||
*/
|
||||
|
||||
#ifndef configNUMBER_OF_CORES
|
||||
#error Missing definition: configNUMBER_OF_CORES must be defined in FreeRTOSConfig.h
|
||||
#endif
|
||||
|
||||
#if ( configNUMBER_OF_CORES > 1 )
|
||||
#ifndef portGET_CORE_ID
|
||||
#error "Missing definition: portGET_CORE_ID() must be defined if in portmacro.h if configNUMBER_OF_CORES > 1"
|
||||
#endif
|
||||
#ifndef portYIELD_CORE
|
||||
#error "Missing definition: portYIELD_CORE() must be defined if in portmacro.h if configNUMBER_OF_CORES > 1"
|
||||
#endif
|
||||
#elif ( configNUMBER_OF_CORES == 1 )
|
||||
#undef portGET_CORE_ID
|
||||
#define portGET_CORE_ID() 0
|
||||
#else
|
||||
#error configNUMBER_OF_CORES must be defined to either 1 or > 1.
|
||||
#endif /* if ( configNUMBER_OF_CORES > 1 ) */
|
||||
|
||||
#ifndef configMINIMAL_STACK_SIZE
|
||||
#error Missing definition: configMINIMAL_STACK_SIZE must be defined in FreeRTOSConfig.h. configMINIMAL_STACK_SIZE defines the size (in words) of the stack allocated to the idle task. Refer to the demo project provided for your port for a suitable value.
|
||||
#endif
|
||||
@@ -1007,6 +1025,10 @@
|
||||
#error configUSE_MUTEXES must be set to 1 to use recursive mutexes
|
||||
#endif
|
||||
|
||||
#if ( ( configNUMBER_OF_CORES > 1 ) && ( configUSE_PORT_OPTIMISED_TASK_SELECTION != 0 ) )
|
||||
#error configUSE_PORT_OPTIMISED_TASK_SELECTION is not supported in SMP
|
||||
#endif
|
||||
|
||||
#ifndef configINITIAL_TICK_COUNT
|
||||
#define configINITIAL_TICK_COUNT 0
|
||||
#endif
|
||||
@@ -1267,6 +1289,8 @@ typedef struct xSTATIC_TCB
|
||||
UBaseType_t uxDummy5;
|
||||
void * pxDummy6;
|
||||
uint8_t ucDummy7[ configMAX_TASK_NAME_LEN ];
|
||||
/* Todo: Remove xCoreID for single core builds (IDF-7894) */
|
||||
BaseType_t xDummyCoreID;
|
||||
#if ( ( portSTACK_GROWTH > 0 ) || ( configRECORD_STACK_HIGH_ADDRESS == 1 ) )
|
||||
void * pxDummy8;
|
||||
#endif
|
||||
@@ -1441,4 +1465,29 @@ typedef StaticStreamBuffer_t StaticMessageBuffer_t;
|
||||
#endif
|
||||
/* *INDENT-ON* */
|
||||
|
||||
/*-----------------------------------------------------------
|
||||
* IDF Compatibility
|
||||
*----------------------------------------------------------*/
|
||||
|
||||
#ifdef ESP_PLATFORM
|
||||
|
||||
/*
|
||||
* Include ESP-IDF API additions implicitly for compatibility reasons.
|
||||
*
|
||||
* ESP-IDF API additions were previously added directly to FreeRTOS headers
|
||||
* (e.g., task.h, queue.h). These APIs have now been moved to
|
||||
* idf_additions.h.
|
||||
*
|
||||
* To ensure there are no breaking changes, we include idf_additions.h
|
||||
* implicitly here so that those API additions are still accessible. Given
|
||||
* that FreeRTOS.h must be included first before calling any FreeRTOS API,
|
||||
* any existing source code can continue using these relocated APIs without
|
||||
* any additional header inclusions via this implicit inclusion.
|
||||
*
|
||||
* Todo: Deprecate this implicit inclusion by ESP-IDF v6.0 (IDF-8126)
|
||||
*/
|
||||
#include "freertos/idf_additions.h"
|
||||
|
||||
#endif /* ESP_PLATFORM */
|
||||
|
||||
#endif /* INC_FREERTOS_H */
|
||||
|
@@ -60,13 +60,13 @@
|
||||
#if ( ( configCHECK_FOR_STACK_OVERFLOW == 1 ) && ( portSTACK_GROWTH < 0 ) )
|
||||
|
||||
/* Only the current stack state is to be checked. */
|
||||
#define taskCHECK_FOR_STACK_OVERFLOW() \
|
||||
{ \
|
||||
/* Is the currently saved stack pointer within the stack limit? */ \
|
||||
if( pxCurrentTCB->pxTopOfStack <= pxCurrentTCB->pxStack + portSTACK_LIMIT_PADDING ) \
|
||||
{ \
|
||||
vApplicationStackOverflowHook( ( TaskHandle_t ) pxCurrentTCB, pxCurrentTCB->pcTaskName ); \
|
||||
} \
|
||||
#define taskCHECK_FOR_STACK_OVERFLOW( xCurCoreID ) \
|
||||
{ \
|
||||
/* Is the currently saved stack pointer within the stack limit? */ \
|
||||
if( pxCurrentTCBs[ xCurCoreID ]->pxTopOfStack <= pxCurrentTCBs[ xCurCoreID ]->pxStack + portSTACK_LIMIT_PADDING ) \
|
||||
{ \
|
||||
vApplicationStackOverflowHook( ( TaskHandle_t ) pxCurrentTCBs[ xCurCoreID ], pxCurrentTCBs[ xCurCoreID ]->pcTaskName ); \
|
||||
} \
|
||||
}
|
||||
|
||||
#endif /* configCHECK_FOR_STACK_OVERFLOW == 1 */
|
||||
@@ -75,14 +75,14 @@
|
||||
#if ( ( configCHECK_FOR_STACK_OVERFLOW == 1 ) && ( portSTACK_GROWTH > 0 ) )
|
||||
|
||||
/* Only the current stack state is to be checked. */
|
||||
#define taskCHECK_FOR_STACK_OVERFLOW() \
|
||||
{ \
|
||||
\
|
||||
/* Is the currently saved stack pointer within the stack limit? */ \
|
||||
if( pxCurrentTCB->pxTopOfStack >= pxCurrentTCB->pxEndOfStack - portSTACK_LIMIT_PADDING ) \
|
||||
{ \
|
||||
vApplicationStackOverflowHook( ( TaskHandle_t ) pxCurrentTCB, pxCurrentTCB->pcTaskName ); \
|
||||
} \
|
||||
#define taskCHECK_FOR_STACK_OVERFLOW( xCurCoreID ) \
|
||||
{ \
|
||||
\
|
||||
/* Is the currently saved stack pointer within the stack limit? */ \
|
||||
if( pxCurrentTCBs[ xCurCoreID ]->pxTopOfStack >= pxCurrentTCBs[ xCurCoreID ]->pxEndOfStack - portSTACK_LIMIT_PADDING ) \
|
||||
{ \
|
||||
vApplicationStackOverflowHook( ( TaskHandle_t ) pxCurrentTCBs[ xCurCoreID ], pxCurrentTCBs[ xCurCoreID ]->pcTaskName ); \
|
||||
} \
|
||||
}
|
||||
|
||||
#endif /* configCHECK_FOR_STACK_OVERFLOW == 1 */
|
||||
@@ -90,18 +90,18 @@
|
||||
|
||||
#if ( ( configCHECK_FOR_STACK_OVERFLOW > 1 ) && ( portSTACK_GROWTH < 0 ) )
|
||||
|
||||
#define taskCHECK_FOR_STACK_OVERFLOW() \
|
||||
{ \
|
||||
const uint32_t * const pulStack = ( uint32_t * ) pxCurrentTCB->pxStack; \
|
||||
const uint32_t ulCheckValue = ( uint32_t ) 0xa5a5a5a5; \
|
||||
\
|
||||
if( ( pulStack[ 0 ] != ulCheckValue ) || \
|
||||
( pulStack[ 1 ] != ulCheckValue ) || \
|
||||
( pulStack[ 2 ] != ulCheckValue ) || \
|
||||
( pulStack[ 3 ] != ulCheckValue ) ) \
|
||||
{ \
|
||||
vApplicationStackOverflowHook( ( TaskHandle_t ) pxCurrentTCB, pxCurrentTCB->pcTaskName ); \
|
||||
} \
|
||||
#define taskCHECK_FOR_STACK_OVERFLOW( xCurCoreID ) \
|
||||
{ \
|
||||
const uint32_t * const pulStack = ( uint32_t * ) pxCurrentTCBs[ xCurCoreID ]->pxStack; \
|
||||
const uint32_t ulCheckValue = ( uint32_t ) 0xa5a5a5a5; \
|
||||
\
|
||||
if( ( pulStack[ 0 ] != ulCheckValue ) || \
|
||||
( pulStack[ 1 ] != ulCheckValue ) || \
|
||||
( pulStack[ 2 ] != ulCheckValue ) || \
|
||||
( pulStack[ 3 ] != ulCheckValue ) ) \
|
||||
{ \
|
||||
vApplicationStackOverflowHook( ( TaskHandle_t ) pxCurrentTCBs[ xCurCoreID ], pxCurrentTCBs[ xCurCoreID ]->pcTaskName ); \
|
||||
} \
|
||||
}
|
||||
|
||||
#endif /* #if( configCHECK_FOR_STACK_OVERFLOW > 1 ) */
|
||||
@@ -109,9 +109,9 @@
|
||||
|
||||
#if ( ( configCHECK_FOR_STACK_OVERFLOW > 1 ) && ( portSTACK_GROWTH > 0 ) )
|
||||
|
||||
#define taskCHECK_FOR_STACK_OVERFLOW() \
|
||||
#define taskCHECK_FOR_STACK_OVERFLOW( xCurCoreID ) \
|
||||
{ \
|
||||
int8_t * pcEndOfStack = ( int8_t * ) pxCurrentTCB->pxEndOfStack; \
|
||||
int8_t * pcEndOfStack = ( int8_t * ) pxCurrentTCBs[ xCurCoreID ]->pxEndOfStack; \
|
||||
static const uint8_t ucExpectedStackBytes[] = { tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, \
|
||||
tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, \
|
||||
tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, tskSTACK_FILL_BYTE, \
|
||||
@@ -124,7 +124,7 @@
|
||||
/* Has the extremity of the task stack ever been written over? */ \
|
||||
if( memcmp( ( void * ) pcEndOfStack, ( void * ) ucExpectedStackBytes, sizeof( ucExpectedStackBytes ) ) != 0 ) \
|
||||
{ \
|
||||
vApplicationStackOverflowHook( ( TaskHandle_t ) pxCurrentTCB, pxCurrentTCB->pcTaskName ); \
|
||||
vApplicationStackOverflowHook( ( TaskHandle_t ) pxCurrentTCBs[ xCurCoreID ], pxCurrentTCBs[ xCurCoreID ]->pcTaskName ); \
|
||||
} \
|
||||
}
|
||||
|
||||
@@ -133,7 +133,7 @@
|
||||
|
||||
/* Remove stack overflow macro if not being used. */
|
||||
#ifndef taskCHECK_FOR_STACK_OVERFLOW
|
||||
#define taskCHECK_FOR_STACK_OVERFLOW()
|
||||
#define taskCHECK_FOR_STACK_OVERFLOW( xCurCoreID )
|
||||
#endif
|
||||
|
||||
|
||||
|
@@ -170,6 +170,7 @@ typedef struct xTASK_STATUS
|
||||
StackType_t * pxEndOfStack; /* Points to the end address of the task's stack area. */
|
||||
#endif
|
||||
configSTACK_DEPTH_TYPE usStackHighWaterMark; /* The minimum amount of stack space that has remained for the task since the task was created. The closer this value is to zero the closer the task has come to overflowing its stack. */
|
||||
BaseType_t xCoreID; /*!< Core this task is pinned to (0, 1, or tskNO_AFFINITY). If configNUMBER_OF_CORES == 1, this will always be 0. */
|
||||
} TaskStatus_t;
|
||||
|
||||
/* Possible return values for eTaskConfirmSleepModeStatus(). */
|
||||
@@ -189,6 +190,14 @@ typedef enum
|
||||
*/
|
||||
#define tskIDLE_PRIORITY ( ( UBaseType_t ) 0U )
|
||||
|
||||
/**
|
||||
* Macro representing and unpinned (i.e., "no affinity") task in xCoreID parameters
|
||||
*
|
||||
* \ingroup Tasks
|
||||
*/
|
||||
#define tskNO_AFFINITY ( ( BaseType_t ) 0x7FFFFFFF )
|
||||
/* Todo: Update tskNO_AFFINITY value to -1 (IDF-7908) */
|
||||
|
||||
/**
|
||||
* task. h
|
||||
*
|
||||
@@ -294,6 +303,9 @@ typedef enum
|
||||
* support can alternatively create an MPU constrained task using
|
||||
* xTaskCreateRestricted().
|
||||
*
|
||||
* @note If configNUMBER_OF_CORES > 1, this function will create an unpinned
|
||||
* task (see tskNO_AFFINITY for more details).
|
||||
*
|
||||
* @param pxTaskCode Pointer to the task entry function. Tasks
|
||||
* must be implemented to never return (i.e. continuous loop).
|
||||
*
|
||||
@@ -301,10 +313,8 @@ typedef enum
|
||||
* facilitate debugging. Max length defined by configMAX_TASK_NAME_LEN - default
|
||||
* is 16.
|
||||
*
|
||||
* @param usStackDepth The size of the task stack specified as the number of
|
||||
* variables the stack can hold - not the number of bytes. For example, if
|
||||
* the stack is 16 bits wide and usStackDepth is defined as 100, 200 bytes
|
||||
* will be allocated for stack storage.
|
||||
* @param usStackDepth The size of the task stack specified as the NUMBER OF
|
||||
* BYTES. Note that this differs from vanilla FreeRTOS.
|
||||
*
|
||||
* @param pvParameters Pointer that will be used as the parameter for the task
|
||||
* being created.
|
||||
@@ -321,6 +331,9 @@ typedef enum
|
||||
* @return pdPASS if the task was successfully created and added to a ready
|
||||
* list, otherwise an error code defined in the file projdefs.h
|
||||
*
|
||||
* @note If program uses thread local variables (ones specified with "__thread"
|
||||
* keyword) then storage for them will be allocated on the task's stack.
|
||||
*
|
||||
* Example usage:
|
||||
* @code{c}
|
||||
* // Task to be created.
|
||||
@@ -356,13 +369,39 @@ typedef enum
|
||||
* \ingroup Tasks
|
||||
*/
|
||||
#if ( configSUPPORT_DYNAMIC_ALLOCATION == 1 )
|
||||
static inline __attribute__( ( always_inline ) )
|
||||
BaseType_t xTaskCreate( TaskFunction_t pxTaskCode,
|
||||
const char * const pcName, /*lint !e971 Unqualified char types are allowed for strings and single characters only. */
|
||||
const configSTACK_DEPTH_TYPE usStackDepth,
|
||||
void * const pvParameters,
|
||||
UBaseType_t uxPriority,
|
||||
TaskHandle_t * const pxCreatedTask ) PRIVILEGED_FUNCTION;
|
||||
#endif
|
||||
TaskHandle_t * const pxCreatedTask ) PRIVILEGED_FUNCTION
|
||||
{
|
||||
/*
|
||||
* The idf_additions.h has not been included here yet due to inclusion
|
||||
* order. Thus we manually declare the function here.
|
||||
*/
|
||||
extern BaseType_t xTaskCreatePinnedToCore( TaskFunction_t pxTaskCode,
|
||||
const char * const pcName,
|
||||
const configSTACK_DEPTH_TYPE usStackDepth,
|
||||
void * const pvParameters,
|
||||
UBaseType_t uxPriority,
|
||||
TaskHandle_t * const pvCreatedTask,
|
||||
const BaseType_t xCoreID );
|
||||
|
||||
/*
|
||||
* Call the "PinnedToCore" version with tskNO_AFFINITY to create
|
||||
* an unpinned task.
|
||||
*/
|
||||
return xTaskCreatePinnedToCore( pxTaskCode,
|
||||
pcName,
|
||||
usStackDepth,
|
||||
pvParameters,
|
||||
uxPriority,
|
||||
pxCreatedTask,
|
||||
tskNO_AFFINITY );
|
||||
}
|
||||
#endif /* configSUPPORT_DYNAMIC_ALLOCATION == 1 */
|
||||
|
||||
/**
|
||||
* task. h
|
||||
@@ -388,6 +427,9 @@ typedef enum
|
||||
* memory. xTaskCreateStatic() therefore allows a task to be created without
|
||||
* using any dynamic memory allocation.
|
||||
*
|
||||
* @note If configNUMBER_OF_CORES > 1, this function will create an unpinned
|
||||
* task (see tskNO_AFFINITY for more details).
|
||||
*
|
||||
* @param pxTaskCode Pointer to the task entry function. Tasks
|
||||
* must be implemented to never return (i.e. continuous loop).
|
||||
*
|
||||
@@ -395,10 +437,8 @@ typedef enum
|
||||
* facilitate debugging. The maximum length of the string is defined by
|
||||
* configMAX_TASK_NAME_LEN in FreeRTOSConfig.h.
|
||||
*
|
||||
* @param ulStackDepth The size of the task stack specified as the number of
|
||||
* variables the stack can hold - not the number of bytes. For example, if
|
||||
* the stack is 32-bits wide and ulStackDepth is defined as 100 then 400 bytes
|
||||
* will be allocated for stack storage.
|
||||
* @param ulStackDepth The size of the task stack specified as the NUMBER OF
|
||||
* BYTES. Note that this differs from vanilla FreeRTOS.
|
||||
*
|
||||
* @param pvParameters Pointer that will be used as the parameter for the task
|
||||
* being created.
|
||||
@@ -418,6 +458,9 @@ typedef enum
|
||||
* puxStackBuffer or pxTaskBuffer are NULL then the task will not be created and
|
||||
* NULL is returned.
|
||||
*
|
||||
* @note If program uses thread local variables (ones specified with "__thread"
|
||||
* keyword) then storage for them will be allocated on the task's stack.
|
||||
*
|
||||
* Example usage:
|
||||
* @code{c}
|
||||
*
|
||||
@@ -473,13 +516,41 @@ typedef enum
|
||||
* \ingroup Tasks
|
||||
*/
|
||||
#if ( configSUPPORT_STATIC_ALLOCATION == 1 )
|
||||
static inline __attribute__( ( always_inline ) )
|
||||
TaskHandle_t xTaskCreateStatic( 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,
|
||||
StackType_t * const puxStackBuffer,
|
||||
StaticTask_t * const pxTaskBuffer ) PRIVILEGED_FUNCTION;
|
||||
StaticTask_t * const pxTaskBuffer ) PRIVILEGED_FUNCTION
|
||||
{
|
||||
/*
|
||||
* The idf_additions.h has not been included here yet due to inclusion
|
||||
* order. Thus we manually declare the function here.
|
||||
*/
|
||||
extern TaskHandle_t xTaskCreateStaticPinnedToCore( TaskFunction_t pxTaskCode,
|
||||
const char * const pcName,
|
||||
const uint32_t ulStackDepth,
|
||||
void * const pvParameters,
|
||||
UBaseType_t uxPriority,
|
||||
StackType_t * const pxStackBuffer,
|
||||
StaticTask_t * const pxTaskBuffer,
|
||||
const BaseType_t xCoreID );
|
||||
|
||||
/*
|
||||
* Call the "PinnedToCore" version with tskNO_AFFINITY to create
|
||||
* an unpinned task.
|
||||
*/
|
||||
return xTaskCreateStaticPinnedToCore( pxTaskCode,
|
||||
pcName,
|
||||
ulStackDepth,
|
||||
pvParameters,
|
||||
uxPriority,
|
||||
puxStackBuffer,
|
||||
pxTaskBuffer,
|
||||
tskNO_AFFINITY );
|
||||
}
|
||||
#endif /* configSUPPORT_STATIC_ALLOCATION */
|
||||
|
||||
/**
|
||||
@@ -1737,8 +1808,8 @@ BaseType_t xTaskCallApplicationTaskHook( TaskHandle_t xTask,
|
||||
* xTaskGetIdleTaskHandle() is only available if
|
||||
* INCLUDE_xTaskGetIdleTaskHandle is set to 1 in FreeRTOSConfig.h.
|
||||
*
|
||||
* Simply returns the handle of the idle task. It is not valid to call
|
||||
* xTaskGetIdleTaskHandle() before the scheduler has been started.
|
||||
* Simply returns the handle of the idle task of the current core. It is not
|
||||
* valid to call xTaskGetIdleTaskHandle() before the scheduler has been started.
|
||||
*/
|
||||
TaskHandle_t xTaskGetIdleTaskHandle( void ) PRIVILEGED_FUNCTION;
|
||||
|
||||
@@ -1979,6 +2050,9 @@ void vTaskGetRunTimeStats( char * pcWriteBuffer ) PRIVILEGED_FUNCTION; /*lint !e
|
||||
* system if there are no other tasks executing at the idle priority, tickless
|
||||
* idle is not used, and configIDLE_SHOULD_YIELD is set to 0.
|
||||
*
|
||||
* @note If configNUMBER_OF_CORES > 1, calling this function will query the idle
|
||||
* task of the current core.
|
||||
*
|
||||
* @return The total run time of the idle task or the percentage of the total
|
||||
* run time consumed by the idle task. This is the amount of time the
|
||||
* idle task has actually been executing. The unit of time is dependent on the
|
||||
@@ -2954,6 +3028,9 @@ BaseType_t xTaskCatchUpTicks( TickType_t xTicksToCatchUp ) PRIVILEGED_FUNCTION;
|
||||
* or
|
||||
* + Time slicing is in use and there is a task of equal priority to the
|
||||
* currently running task.
|
||||
*
|
||||
* Note: If configNUMBER_OF_CORES > 1, this function must only be called by
|
||||
* core 0. Other cores should call xTaskIncrementTickOtherCores() instead.
|
||||
*/
|
||||
BaseType_t xTaskIncrementTick( void ) PRIVILEGED_FUNCTION;
|
||||
|
||||
|
Reference in New Issue
Block a user