|
@@ -85,7 +85,6 @@ task.h is included from an application file. */
|
|
|
#include "StackMacros.h"
|
|
#include "StackMacros.h"
|
|
|
#include "portmacro.h"
|
|
#include "portmacro.h"
|
|
|
#include "semphr.h"
|
|
#include "semphr.h"
|
|
|
-#include "sys/reent.h"
|
|
|
|
|
|
|
|
|
|
/* Lint e961 and e750 are suppressed as a MISRA exception justified because the
|
|
/* Lint 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
|
|
MPU ports require MPU_WRAPPERS_INCLUDED_FROM_API_FILE to be defined for the
|
|
@@ -140,6 +139,26 @@ typedef enum
|
|
|
eNotified
|
|
eNotified
|
|
|
} eNotifyValue;
|
|
} eNotifyValue;
|
|
|
|
|
|
|
|
|
|
+/* Sometimes the FreeRTOSConfig.h settings only allow a task to be created using
|
|
|
|
|
+dynamically allocated RAM, in which case when any task is deleted it is known
|
|
|
|
|
+that both the task's stack and TCB need to be freed. Sometimes the
|
|
|
|
|
+FreeRTOSConfig.h settings only allow a task to be created using statically
|
|
|
|
|
+allocated RAM, in which case when any task is deleted it is known that neither
|
|
|
|
|
+the task's stack or TCB should be freed. Sometimes the FreeRTOSConfig.h
|
|
|
|
|
+settings allow a task to be created using either statically or dynamically
|
|
|
|
|
+allocated RAM, in which case a member of the TCB is used to record whether the
|
|
|
|
|
+stack and/or TCB were allocated statically or dynamically, so when a task is
|
|
|
|
|
+deleted the RAM that was allocated dynamically is freed again and no attempt is
|
|
|
|
|
+made to free the RAM that was allocated statically.
|
|
|
|
|
+tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE is only true if it is possible for a
|
|
|
|
|
+task to be created using either statically or dynamically allocated RAM. Note
|
|
|
|
|
+that if portUSING_MPU_WRAPPERS is 1 then a protected task can be created with
|
|
|
|
|
+a statically allocated stack and a dynamically allocated TCB. */
|
|
|
|
|
+#define tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE ( ( ( configSUPPORT_STATIC_ALLOCATION == 1 ) && ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) ) || ( portUSING_MPU_WRAPPERS == 1 ) )
|
|
|
|
|
+#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 )
|
|
|
|
|
+
|
|
|
/*
|
|
/*
|
|
|
* Task control block. A task control block (TCB) is allocated for each task,
|
|
* 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
|
|
* and stores task state information, including a pointer to the task's context
|
|
@@ -151,7 +170,6 @@ typedef struct tskTaskControlBlock
|
|
|
|
|
|
|
|
#if ( portUSING_MPU_WRAPPERS == 1 )
|
|
#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. */
|
|
xMPU_SETTINGS xMPUSettings; /*< The MPU settings are defined as part of the port layer. THIS MUST BE THE SECOND MEMBER OF THE TCB STRUCT. */
|
|
|
- BaseType_t xUsingStaticallyAllocatedStack; /* Set to pdTRUE if the stack is a statically allocated array, and pdFALSE if the stack is dynamically allocated. */
|
|
|
|
|
#endif
|
|
#endif
|
|
|
|
|
|
|
|
ListItem_t xGenericListItem; /*< The list that the state list item of a task is reference from denotes the state of that task (Ready, Blocked, Suspended ). */
|
|
ListItem_t xGenericListItem; /*< The list that the state list item of a task is reference from denotes the state of that task (Ready, Blocked, Suspended ). */
|
|
@@ -211,6 +229,12 @@ typedef struct tskTaskControlBlock
|
|
|
volatile eNotifyValue eNotifyState;
|
|
volatile eNotifyValue eNotifyState;
|
|
|
#endif
|
|
#endif
|
|
|
|
|
|
|
|
|
|
+ /* See the comments above the definition of
|
|
|
|
|
+ tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE. */
|
|
|
|
|
+ #if( tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE != 0 )
|
|
|
|
|
+ uint8_t ucStaticallyAllocated; /*< Set to pdTRUE if the task is a statically allocated to ensure no attempt is made to free the memory. */
|
|
|
|
|
+ #endif
|
|
|
|
|
+
|
|
|
} tskTCB;
|
|
} tskTCB;
|
|
|
|
|
|
|
|
/* The old tskTCB name is maintained above then typedefed to the new TCB_t name
|
|
/* The old tskTCB name is maintained above then typedefed to the new TCB_t name
|
|
@@ -459,12 +483,6 @@ to its original value when it is released. */
|
|
|
|
|
|
|
|
/* File private functions. --------------------------------*/
|
|
/* File private functions. --------------------------------*/
|
|
|
|
|
|
|
|
-/*
|
|
|
|
|
- * Utility to ready a TCB for a given task. Mainly just copies the parameters
|
|
|
|
|
- * into the TCB structure.
|
|
|
|
|
- */
|
|
|
|
|
-static void prvInitialiseTCBVariables( TCB_t * const pxTCB, const char * const pcName, UBaseType_t uxPriority, const MemoryRegion_t * const xRegions, const uint16_t usStackDepth, const BaseType_t xCoreID ) PRIVILEGED_FUNCTION; /*lint !e971 Unqualified char types are allowed for strings and single characters only. */
|
|
|
|
|
-
|
|
|
|
|
/**
|
|
/**
|
|
|
* Utility task that simply returns pdTRUE if the task referenced by xTask is
|
|
* 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
|
|
* currently in the Suspended state, or pdFALSE if the task referenced by xTask
|
|
@@ -519,12 +537,6 @@ static void prvCheckTasksWaitingTermination( void ) PRIVILEGED_FUNCTION;
|
|
|
*/
|
|
*/
|
|
|
static void prvAddCurrentTaskToDelayedList( const portBASE_TYPE xCoreID, const TickType_t xTimeToWake ) PRIVILEGED_FUNCTION;
|
|
static void prvAddCurrentTaskToDelayedList( const portBASE_TYPE xCoreID, const TickType_t xTimeToWake ) PRIVILEGED_FUNCTION;
|
|
|
|
|
|
|
|
-/*
|
|
|
|
|
- * Allocates memory from the heap for a TCB and associated stack. Checks the
|
|
|
|
|
- * allocation was successful.
|
|
|
|
|
- */
|
|
|
|
|
-static TCB_t *prvAllocateTCBAndStack( const uint16_t usStackDepth, StackType_t * const puxStackBuffer ) PRIVILEGED_FUNCTION;
|
|
|
|
|
-
|
|
|
|
|
/*
|
|
/*
|
|
|
* Fills an TaskStatus_t structure with information on each task that is
|
|
* 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,
|
|
* referenced from the pxList list (which may be a ready list, a delayed list,
|
|
@@ -581,6 +593,26 @@ static void prvResetNextTaskUnblockTime( void );
|
|
|
|
|
|
|
|
#endif
|
|
#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,
|
|
|
|
|
+ const uint32_t ulStackDepth,
|
|
|
|
|
+ void * const pvParameters,
|
|
|
|
|
+ UBaseType_t uxPriority,
|
|
|
|
|
+ TaskHandle_t * const pxCreatedTask,
|
|
|
|
|
+ TCB_t *pxNewTCB,
|
|
|
|
|
+ const MemoryRegion_t * const xRegions, const BaseType_t xCoreID) PRIVILEGED_FUNCTION; /*lint !e971 Unqualified char types are allowed for strings and single characters only. */
|
|
|
|
|
+
|
|
|
|
|
+/*
|
|
|
|
|
+ * 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, TaskFunction_t pxTaskCode, const BaseType_t xCoreID ) PRIVILEGED_FUNCTION;
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
|
|
|
/*-----------------------------------------------------------*/
|
|
/*-----------------------------------------------------------*/
|
|
|
|
|
|
|
@@ -612,111 +644,408 @@ void taskYIELD_OTHER_CORE( BaseType_t xCoreID, UBaseType_t uxPriority )
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+#if( configSUPPORT_STATIC_ALLOCATION == 1 )
|
|
|
|
|
|
|
|
-BaseType_t xTaskGenericCreate( TaskFunction_t pxTaskCode, const char * const pcName, const uint16_t usStackDepth, void * const pvParameters, UBaseType_t uxPriority, TaskHandle_t * const pxCreatedTask, StackType_t * const puxStackBuffer, const MemoryRegion_t * const xRegions, const BaseType_t xCoreID) /*lint !e971 Unqualified char types are allowed for strings and single characters only. */
|
|
|
|
|
-{
|
|
|
|
|
-BaseType_t xReturn;
|
|
|
|
|
-TCB_t * pxNewTCB;
|
|
|
|
|
-StackType_t *pxTopOfStack;
|
|
|
|
|
-BaseType_t i;
|
|
|
|
|
- configASSERT( pxTaskCode );
|
|
|
|
|
- configASSERT( ( ( uxPriority & ( ~portPRIVILEGE_BIT ) ) < configMAX_PRIORITIES ) );
|
|
|
|
|
- configASSERT( (xCoreID>=0 && xCoreID<portNUM_PROCESSORS) || (xCoreID==tskNO_AFFINITY) );
|
|
|
|
|
|
|
+ TaskHandle_t xTaskCreateStaticPinnedToCore( TaskFunction_t pxTaskCode,
|
|
|
|
|
+ const char * const pcName,
|
|
|
|
|
+ const uint32_t ulStackDepth,
|
|
|
|
|
+ void * const pvParameters,
|
|
|
|
|
+ UBaseType_t uxPriority,
|
|
|
|
|
+ StackType_t * const puxStackBuffer,
|
|
|
|
|
+ StaticTask_t * const pxTaskBuffer,
|
|
|
|
|
+ const BaseType_t xCoreID )
|
|
|
|
|
+ {
|
|
|
|
|
+ TCB_t *pxNewTCB;
|
|
|
|
|
+ TaskHandle_t xReturn;
|
|
|
|
|
|
|
|
- /* Allocate the memory required by the TCB and stack for the new task,
|
|
|
|
|
- checking that the allocation was successful. */
|
|
|
|
|
- pxNewTCB = prvAllocateTCBAndStack( usStackDepth, puxStackBuffer );
|
|
|
|
|
|
|
+ configASSERT( puxStackBuffer != NULL );
|
|
|
|
|
+ configASSERT( pxTaskBuffer != NULL );
|
|
|
|
|
+ configASSERT( (xCoreID>=0 && xCoreID<portNUM_PROCESSORS) || (xCoreID==tskNO_AFFINITY) );
|
|
|
|
|
|
|
|
- if( pxNewTCB != NULL )
|
|
|
|
|
|
|
+ if( ( pxTaskBuffer != NULL ) && ( puxStackBuffer != NULL ) )
|
|
|
|
|
+ {
|
|
|
|
|
+ /* The memory used for the task's TCB and stack are passed into this
|
|
|
|
|
+ function - use them. */
|
|
|
|
|
+ pxNewTCB = ( TCB_t * ) pxTaskBuffer; /*lint !e740 Unusual cast is ok as the structures are designed to have the same alignment, and the size is checked by an assert. */
|
|
|
|
|
+ pxNewTCB->pxStack = ( StackType_t * ) 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 /* configSUPPORT_DYNAMIC_ALLOCATION */
|
|
|
|
|
+
|
|
|
|
|
+ prvInitialiseNewTask( pxTaskCode, pcName, ulStackDepth, pvParameters, uxPriority, &xReturn, pxNewTCB, NULL, xCoreID );
|
|
|
|
|
+ prvAddNewTaskToReadyList( pxNewTCB, pxTaskCode, xCoreID );
|
|
|
|
|
+ }
|
|
|
|
|
+ else
|
|
|
|
|
+ {
|
|
|
|
|
+ xReturn = NULL;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ return xReturn;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+#endif /* SUPPORT_STATIC_ALLOCATION */
|
|
|
|
|
+/*-----------------------------------------------------------*/
|
|
|
|
|
+
|
|
|
|
|
+#if( portUSING_MPU_WRAPPERS == 1 )
|
|
|
|
|
+
|
|
|
|
|
+ BaseType_t xTaskCreateRestricted( const TaskParameters_t * const pxTaskDefinition, TaskHandle_t *pxCreatedTask )
|
|
|
{
|
|
{
|
|
|
- #if( portUSING_MPU_WRAPPERS == 1 )
|
|
|
|
|
- /* Should the task be created in privileged mode? */
|
|
|
|
|
- BaseType_t xRunPrivileged;
|
|
|
|
|
- if( ( uxPriority & portPRIVILEGE_BIT ) != 0U )
|
|
|
|
|
|
|
+ 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 )
|
|
|
{
|
|
{
|
|
|
- xRunPrivileged = pdTRUE;
|
|
|
|
|
|
|
+ /* Store the stack location in the TCB. */
|
|
|
|
|
+ pxNewTCB->pxStack = pxTaskDefinition->puxStackBuffer;
|
|
|
|
|
+
|
|
|
|
|
+ /* 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;
|
|
|
|
|
+
|
|
|
|
|
+ prvInitialiseNewTask( pxTaskDefinition->pvTaskCode,
|
|
|
|
|
+ pxTaskDefinition->pcName,
|
|
|
|
|
+ ( uint32_t ) pxTaskDefinition->usStackDepth,
|
|
|
|
|
+ pxTaskDefinition->pvParameters,
|
|
|
|
|
+ pxTaskDefinition->uxPriority,
|
|
|
|
|
+ pxCreatedTask, pxNewTCB,
|
|
|
|
|
+ pxTaskDefinition->xRegions,
|
|
|
|
|
+ tskNO_AFFINITY );
|
|
|
|
|
+
|
|
|
|
|
+ prvAddNewTaskToReadyList( pxNewTCB, pxTaskDefinition->pvTaskCode, tskNO_AFFINITY );
|
|
|
|
|
+ xReturn = pdPASS;
|
|
|
}
|
|
}
|
|
|
- else
|
|
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ return xReturn;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+#endif /* portUSING_MPU_WRAPPERS */
|
|
|
|
|
+/*-----------------------------------------------------------*/
|
|
|
|
|
+
|
|
|
|
|
+#if( configSUPPORT_DYNAMIC_ALLOCATION == 1 )
|
|
|
|
|
+
|
|
|
|
|
+ BaseType_t xTaskCreatePinnedToCore( TaskFunction_t pxTaskCode,
|
|
|
|
|
+ const char * const pcName,
|
|
|
|
|
+ const uint16_t usStackDepth,
|
|
|
|
|
+ void * const pvParameters,
|
|
|
|
|
+ UBaseType_t uxPriority,
|
|
|
|
|
+ TaskHandle_t * const pxCreatedTask,
|
|
|
|
|
+ const BaseType_t xCoreID )
|
|
|
|
|
+ {
|
|
|
|
|
+ TCB_t *pxNewTCB;
|
|
|
|
|
+ BaseType_t xReturn;
|
|
|
|
|
+
|
|
|
|
|
+ /* If the stack grows down then allocate the stack then the TCB so the stack
|
|
|
|
|
+ does not grow into the TCB. Likewise if the stack grows up then allocate
|
|
|
|
|
+ the TCB then the stack. */
|
|
|
|
|
+ #if( portSTACK_GROWTH > 0 )
|
|
|
|
|
+ {
|
|
|
|
|
+ /* 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 )
|
|
|
{
|
|
{
|
|
|
- xRunPrivileged = pdFALSE;
|
|
|
|
|
|
|
+ /* Allocate space for the stack used by the task being created.
|
|
|
|
|
+ The base of the stack memory stored in the TCB so the task can
|
|
|
|
|
+ be deleted later if required. */
|
|
|
|
|
+ pxNewTCB->pxStack = ( StackType_t * ) pvPortMalloc( ( ( ( size_t ) usStackDepth ) * sizeof( StackType_t ) ) ); /*lint !e961 MISRA exception as the casts are only redundant for some ports. */
|
|
|
|
|
+
|
|
|
|
|
+ if( pxNewTCB->pxStack == NULL )
|
|
|
|
|
+ {
|
|
|
|
|
+ /* Could not allocate the stack. Delete the allocated TCB. */
|
|
|
|
|
+ vPortFree( pxNewTCB );
|
|
|
|
|
+ pxNewTCB = NULL;
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
- uxPriority &= ~portPRIVILEGE_BIT;
|
|
|
|
|
|
|
+ }
|
|
|
|
|
+ #else /* portSTACK_GROWTH */
|
|
|
|
|
+ {
|
|
|
|
|
+ StackType_t *pxStack;
|
|
|
|
|
+
|
|
|
|
|
+ /* Allocate space for the stack used by the task being created. */
|
|
|
|
|
+ pxStack = ( StackType_t * ) pvPortMalloc( ( ( ( size_t ) usStackDepth ) * sizeof( StackType_t ) ) ); /*lint !e961 MISRA exception as the casts are only redundant for some ports. */
|
|
|
|
|
|
|
|
- if( puxStackBuffer != NULL )
|
|
|
|
|
|
|
+ if( pxStack != NULL )
|
|
|
{
|
|
{
|
|
|
- /* The application provided its own stack. Note this so no
|
|
|
|
|
- attempt is made to delete the stack should that task be
|
|
|
|
|
- deleted. */
|
|
|
|
|
- pxNewTCB->xUsingStaticallyAllocatedStack = pdTRUE;
|
|
|
|
|
|
|
+ /* Allocate space for the TCB. */
|
|
|
|
|
+ pxNewTCB = ( TCB_t * ) pvPortMalloc( sizeof( TCB_t ) ); /*lint !e961 MISRA exception as the casts are only redundant for some paths. */
|
|
|
|
|
+
|
|
|
|
|
+ if( pxNewTCB != NULL )
|
|
|
|
|
+ {
|
|
|
|
|
+ /* Store the stack location in the TCB. */
|
|
|
|
|
+ pxNewTCB->pxStack = pxStack;
|
|
|
|
|
+ }
|
|
|
|
|
+ else
|
|
|
|
|
+ {
|
|
|
|
|
+ /* The stack cannot be used as the TCB was not created. Free
|
|
|
|
|
+ it again. */
|
|
|
|
|
+ vPortFree( pxStack );
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
else
|
|
else
|
|
|
{
|
|
{
|
|
|
- /* The stack was allocated dynamically. Note this so it can be
|
|
|
|
|
- deleted again if the task is deleted. */
|
|
|
|
|
- pxNewTCB->xUsingStaticallyAllocatedStack = pdFALSE;
|
|
|
|
|
|
|
+ pxNewTCB = NULL;
|
|
|
}
|
|
}
|
|
|
- #endif /* portUSING_MPU_WRAPPERS == 1 */
|
|
|
|
|
|
|
+ }
|
|
|
|
|
+ #endif /* portSTACK_GROWTH */
|
|
|
|
|
|
|
|
- /* Calculate the top of stack address. This depends on whether the
|
|
|
|
|
- stack grows from high memory to low (as per the 80x86) or vice versa.
|
|
|
|
|
- portSTACK_GROWTH is used to make the result positive or negative as
|
|
|
|
|
- required by the port. */
|
|
|
|
|
- #if( portSTACK_GROWTH < 0 )
|
|
|
|
|
|
|
+ if( pxNewTCB != NULL )
|
|
|
{
|
|
{
|
|
|
- pxTopOfStack = pxNewTCB->pxStack + ( usStackDepth - ( uint16_t ) 1 );
|
|
|
|
|
- pxTopOfStack = ( StackType_t * ) ( ( ( portPOINTER_SIZE_TYPE ) pxTopOfStack ) & ( ( portPOINTER_SIZE_TYPE ) ~portBYTE_ALIGNMENT_MASK ) ); /*lint !e923 MISRA exception. Avoiding casts between pointers and integers is not practical. Size differences accounted for using portPOINTER_SIZE_TYPE type. */
|
|
|
|
|
|
|
+ #if( tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE != 0 )
|
|
|
|
|
+ {
|
|
|
|
|
+ /* Tasks can be created statically or dynamically, so note this
|
|
|
|
|
+ task was created dynamically in case it is later deleted. */
|
|
|
|
|
+ pxNewTCB->ucStaticallyAllocated = tskDYNAMICALLY_ALLOCATED_STACK_AND_TCB;
|
|
|
|
|
+ }
|
|
|
|
|
+ #endif /* configSUPPORT_STATIC_ALLOCATION */
|
|
|
|
|
|
|
|
- /* Check the alignment of the calculated top of stack is correct. */
|
|
|
|
|
- configASSERT( ( ( ( portPOINTER_SIZE_TYPE ) pxTopOfStack & ( portPOINTER_SIZE_TYPE ) portBYTE_ALIGNMENT_MASK ) == 0UL ) );
|
|
|
|
|
|
|
+ prvInitialiseNewTask( pxTaskCode, pcName, ( uint32_t ) usStackDepth, pvParameters, uxPriority, pxCreatedTask, pxNewTCB, NULL, xCoreID );
|
|
|
|
|
+ prvAddNewTaskToReadyList( pxNewTCB, pxTaskCode, xCoreID );
|
|
|
|
|
+ xReturn = pdPASS;
|
|
|
}
|
|
}
|
|
|
- #else /* portSTACK_GROWTH */
|
|
|
|
|
|
|
+ else
|
|
|
{
|
|
{
|
|
|
- pxTopOfStack = pxNewTCB->pxStack;
|
|
|
|
|
|
|
+ xReturn = errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY;
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
- /* Check the alignment of the stack buffer is correct. */
|
|
|
|
|
- configASSERT( ( ( ( portPOINTER_SIZE_TYPE ) pxNewTCB->pxStack & ( portPOINTER_SIZE_TYPE ) portBYTE_ALIGNMENT_MASK ) == 0UL ) );
|
|
|
|
|
|
|
+ return xReturn;
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
- /* If we want to use stack checking on architectures that use
|
|
|
|
|
- a positive stack growth direction then we also need to store the
|
|
|
|
|
- other extreme of the stack space. */
|
|
|
|
|
- pxNewTCB->pxEndOfStack = pxNewTCB->pxStack + ( usStackDepth - 1 );
|
|
|
|
|
- }
|
|
|
|
|
- #endif /* portSTACK_GROWTH */
|
|
|
|
|
|
|
+#endif /* configSUPPORT_DYNAMIC_ALLOCATION */
|
|
|
|
|
+/*-----------------------------------------------------------*/
|
|
|
|
|
|
|
|
- /* Setup the newly allocated TCB with the initial state of the task. */
|
|
|
|
|
- prvInitialiseTCBVariables( pxNewTCB, pcName, uxPriority, xRegions, usStackDepth, xCoreID );
|
|
|
|
|
|
|
+static void prvInitialiseNewTask( TaskFunction_t pxTaskCode,
|
|
|
|
|
+ const char * const pcName,
|
|
|
|
|
+ const uint32_t ulStackDepth,
|
|
|
|
|
+ void * const pvParameters,
|
|
|
|
|
+ UBaseType_t uxPriority,
|
|
|
|
|
+ TaskHandle_t * const pxCreatedTask,
|
|
|
|
|
+ TCB_t *pxNewTCB,
|
|
|
|
|
+ const MemoryRegion_t * const xRegions, const BaseType_t xCoreID ) /*lint !e971 Unqualified char types are allowed for strings and single characters only. */
|
|
|
|
|
+{
|
|
|
|
|
+StackType_t *pxTopOfStack;
|
|
|
|
|
+UBaseType_t x;
|
|
|
|
|
|
|
|
- /* 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( portUSING_MPU_WRAPPERS == 1 )
|
|
|
|
|
+ /* Should the task be created in privileged mode? */
|
|
|
|
|
+ BaseType_t xRunPrivileged;
|
|
|
|
|
+ if( ( uxPriority & portPRIVILEGE_BIT ) != 0U )
|
|
|
{
|
|
{
|
|
|
- pxNewTCB->pxTopOfStack = pxPortInitialiseStack( pxTopOfStack, pxTaskCode, pvParameters, xRunPrivileged );
|
|
|
|
|
|
|
+ xRunPrivileged = pdTRUE;
|
|
|
}
|
|
}
|
|
|
- #else /* portUSING_MPU_WRAPPERS */
|
|
|
|
|
|
|
+ else
|
|
|
{
|
|
{
|
|
|
- pxNewTCB->pxTopOfStack = pxPortInitialiseStack( pxTopOfStack, pxTaskCode, pvParameters );
|
|
|
|
|
|
|
+ xRunPrivileged = pdFALSE;
|
|
|
}
|
|
}
|
|
|
- #endif /* portUSING_MPU_WRAPPERS */
|
|
|
|
|
|
|
+ uxPriority &= ~portPRIVILEGE_BIT;
|
|
|
|
|
+ #endif /* portUSING_MPU_WRAPPERS == 1 */
|
|
|
|
|
|
|
|
- if( ( void * ) pxCreatedTask != NULL )
|
|
|
|
|
|
|
+ /* Avoid dependency on memset() if it is not required. */
|
|
|
|
|
+ #if( ( configCHECK_FOR_STACK_OVERFLOW > 1 ) || ( configUSE_TRACE_FACILITY == 1 ) || ( INCLUDE_uxTaskGetStackHighWaterMark == 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 /* ( ( configCHECK_FOR_STACK_OVERFLOW > 1 ) || ( ( configUSE_TRACE_FACILITY == 1 ) || ( INCLUDE_uxTaskGetStackHighWaterMark == 1 ) ) ) */
|
|
|
|
|
+
|
|
|
|
|
+ /* Calculate the top of stack address. This depends on whether the stack
|
|
|
|
|
+ grows from high memory to low (as per the 80x86) 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 MISRA exception. Avoiding casts between pointers and integers is not practical. Size differences accounted for using portPOINTER_SIZE_TYPE type. */
|
|
|
|
|
+
|
|
|
|
|
+ /* Check the alignment of the calculated top of stack is correct. */
|
|
|
|
|
+ configASSERT( ( ( ( portPOINTER_SIZE_TYPE ) pxTopOfStack & ( portPOINTER_SIZE_TYPE ) portBYTE_ALIGNMENT_MASK ) == 0UL ) );
|
|
|
|
|
+ }
|
|
|
|
|
+ #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. */
|
|
|
|
|
+ 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 ] == 0x00 )
|
|
|
{
|
|
{
|
|
|
- /* Pass the TCB out - in an anonymous way. The calling function/
|
|
|
|
|
- task can use this as a handle to delete the task later if
|
|
|
|
|
- required.*/
|
|
|
|
|
- *pxCreatedTask = ( TaskHandle_t ) pxNewTCB;
|
|
|
|
|
|
|
+ break;
|
|
|
}
|
|
}
|
|
|
else
|
|
else
|
|
|
{
|
|
{
|
|
|
mtCOVERAGE_TEST_MARKER();
|
|
mtCOVERAGE_TEST_MARKER();
|
|
|
}
|
|
}
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
- /* Ensure interrupts don't access the task lists while they are being
|
|
|
|
|
- updated. */
|
|
|
|
|
- taskENTER_CRITICAL(&xTaskQueueMutex);
|
|
|
|
|
|
|
+ /* 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';
|
|
|
|
|
+
|
|
|
|
|
+ /* This is used as an array index so must ensure it's not too large. First
|
|
|
|
|
+ remove the privilege bit if one is present. */
|
|
|
|
|
+ if( uxPriority >= ( UBaseType_t ) configMAX_PRIORITIES )
|
|
|
|
|
+ {
|
|
|
|
|
+ uxPriority = ( UBaseType_t ) configMAX_PRIORITIES - ( UBaseType_t ) 1U;
|
|
|
|
|
+ }
|
|
|
|
|
+ else
|
|
|
|
|
+ {
|
|
|
|
|
+ mtCOVERAGE_TEST_MARKER();
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ pxNewTCB->uxPriority = uxPriority;
|
|
|
|
|
+ pxNewTCB->xCoreID = xCoreID;
|
|
|
|
|
+ #if ( configUSE_MUTEXES == 1 )
|
|
|
|
|
+ {
|
|
|
|
|
+ pxNewTCB->uxBasePriority = uxPriority;
|
|
|
|
|
+ pxNewTCB->uxMutexesHeld = 0;
|
|
|
|
|
+ }
|
|
|
|
|
+ #endif /* configUSE_MUTEXES */
|
|
|
|
|
+
|
|
|
|
|
+ vListInitialiseItem( &( pxNewTCB->xGenericListItem ) );
|
|
|
|
|
+ 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->xGenericListItem ), 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 ( portCRITICAL_NESTING_IN_TCB == 1 )
|
|
|
|
|
+ {
|
|
|
|
|
+ pxNewTCB->uxCriticalNesting = ( UBaseType_t ) 0U;
|
|
|
|
|
+ }
|
|
|
|
|
+ #endif /* portCRITICAL_NESTING_IN_TCB */
|
|
|
|
|
+
|
|
|
|
|
+ #if ( configUSE_APPLICATION_TASK_TAG == 1 )
|
|
|
|
|
+ {
|
|
|
|
|
+ pxNewTCB->pxTaskTag = NULL;
|
|
|
|
|
+ }
|
|
|
|
|
+ #endif /* configUSE_APPLICATION_TASK_TAG */
|
|
|
|
|
+
|
|
|
|
|
+ #if ( configGENERATE_RUN_TIME_STATS == 1 )
|
|
|
|
|
+ {
|
|
|
|
|
+ pxNewTCB->ulRunTimeCounter = 0UL;
|
|
|
|
|
+ }
|
|
|
|
|
+ #endif /* configGENERATE_RUN_TIME_STATS */
|
|
|
|
|
+
|
|
|
|
|
+ #if ( portUSING_MPU_WRAPPERS == 1 )
|
|
|
|
|
+ {
|
|
|
|
|
+ vPortStoreTaskMPUSettings( &( pxNewTCB->xMPUSettings ), xRegions, pxNewTCB->pxStack, ulStackDepth );
|
|
|
|
|
+ }
|
|
|
|
|
+ #else
|
|
|
|
|
+ {
|
|
|
|
|
+ /* Avoid compiler warning about unreferenced parameter. */
|
|
|
|
|
+ ( void ) xRegions;
|
|
|
|
|
+ }
|
|
|
|
|
+ #endif
|
|
|
|
|
+
|
|
|
|
|
+ #if( configNUM_THREAD_LOCAL_STORAGE_POINTERS != 0 )
|
|
|
|
|
+ {
|
|
|
|
|
+ for( x = 0; x < ( UBaseType_t ) configNUM_THREAD_LOCAL_STORAGE_POINTERS; x++ )
|
|
|
|
|
+ {
|
|
|
|
|
+ pxNewTCB->pvThreadLocalStoragePointers[ x ] = NULL;
|
|
|
|
|
+ #if ( configTHREAD_LOCAL_STORAGE_DELETE_CALLBACKS == 1)
|
|
|
|
|
+ pxNewTCB->pvThreadLocalStoragePointersDelCallback[ x ] = NULL;
|
|
|
|
|
+ #endif
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ #endif
|
|
|
|
|
+
|
|
|
|
|
+ #if ( configUSE_TASK_NOTIFICATIONS == 1 )
|
|
|
|
|
+ {
|
|
|
|
|
+ pxNewTCB->ulNotifiedValue = 0;
|
|
|
|
|
+ pxNewTCB->eNotifyState = eNotWaitingNotification;
|
|
|
|
|
+ }
|
|
|
|
|
+ #endif
|
|
|
|
|
+
|
|
|
|
|
+ #if ( configUSE_NEWLIB_REENTRANT == 1 )
|
|
|
|
|
+ {
|
|
|
|
|
+ /* Initialise this task's Newlib reent structure. */
|
|
|
|
|
+ _REENT_INIT_PTR( ( &( pxNewTCB->xNewLib_reent ) ) );
|
|
|
|
|
+ }
|
|
|
|
|
+ #endif
|
|
|
|
|
+
|
|
|
|
|
+ #if( INCLUDE_xTaskAbortDelay == 1 )
|
|
|
|
|
+ {
|
|
|
|
|
+ pxNewTCB->ucDelayAborted = pdFALSE;
|
|
|
|
|
+ }
|
|
|
|
|
+ #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 )
|
|
|
|
|
+ {
|
|
|
|
|
+ pxNewTCB->pxTopOfStack = pxPortInitialiseStack( pxTopOfStack, pxTaskCode, pvParameters, xRunPrivileged );
|
|
|
|
|
+ }
|
|
|
|
|
+ #else /* portUSING_MPU_WRAPPERS */
|
|
|
|
|
+ {
|
|
|
|
|
+ pxNewTCB->pxTopOfStack = pxPortInitialiseStack( pxTopOfStack, pxTaskCode, pvParameters );
|
|
|
|
|
+ }
|
|
|
|
|
+ #endif /* portUSING_MPU_WRAPPERS */
|
|
|
|
|
+
|
|
|
|
|
+ if( ( void * ) 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, TaskFunction_t pxTaskCode, const BaseType_t xCoreID )
|
|
|
|
|
+{
|
|
|
|
|
+ BaseType_t i;
|
|
|
|
|
+
|
|
|
|
|
+ /* Ensure interrupts don't access the task lists while the lists are being
|
|
|
|
|
+ updated. */
|
|
|
|
|
+ taskENTER_CRITICAL(&xTaskQueueMutex);
|
|
|
|
|
+ {
|
|
|
|
|
+ uxCurrentNumberOfTasks++;
|
|
|
|
|
+ if( pxCurrentTCB[ xPortGetCoreID() ] == NULL )
|
|
|
{
|
|
{
|
|
|
- uxCurrentNumberOfTasks++;
|
|
|
|
|
|
|
+ /* There are no other tasks, or all the other tasks are in
|
|
|
|
|
+ the suspended state - make this the current task. */
|
|
|
|
|
+ pxCurrentTCB[ xPortGetCoreID() ] = pxNewTCB;
|
|
|
|
|
+
|
|
|
if( uxCurrentNumberOfTasks == ( UBaseType_t ) 1 )
|
|
if( uxCurrentNumberOfTasks == ( UBaseType_t ) 1 )
|
|
|
{
|
|
{
|
|
|
/* This is the first task to be created so do the preliminary
|
|
/* This is the first task to be created so do the preliminary
|
|
@@ -724,6 +1053,16 @@ BaseType_t i;
|
|
|
fails, but we will report the failure. */
|
|
fails, but we will report the failure. */
|
|
|
prvInitialiseTaskLists();
|
|
prvInitialiseTaskLists();
|
|
|
}
|
|
}
|
|
|
|
|
+ else
|
|
|
|
|
+ {
|
|
|
|
|
+ mtCOVERAGE_TEST_MARKER();
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ 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 )
|
|
if( xSchedulerRunning == pdFALSE )
|
|
|
{
|
|
{
|
|
|
/* Scheduler isn't running yet. We need to determine on which CPU to run this task. */
|
|
/* Scheduler isn't running yet. We need to determine on which CPU to run this task. */
|
|
@@ -733,7 +1072,7 @@ BaseType_t i;
|
|
|
if (xCoreID == tskNO_AFFINITY || xCoreID == i)
|
|
if (xCoreID == tskNO_AFFINITY || xCoreID == i)
|
|
|
{
|
|
{
|
|
|
/* Schedule if nothing is scheduled yet, or overwrite a task of lower prio. */
|
|
/* Schedule if nothing is scheduled yet, or overwrite a task of lower prio. */
|
|
|
- if ( pxCurrentTCB[i] == NULL || pxCurrentTCB[i]->uxPriority <= uxPriority )
|
|
|
|
|
|
|
+ if ( pxCurrentTCB[i] == NULL || pxCurrentTCB[i]->uxPriority <= pxNewTCB->uxPriority )
|
|
|
{
|
|
{
|
|
|
#if portFIRST_TASK_HOOK
|
|
#if portFIRST_TASK_HOOK
|
|
|
if ( i == 0) {
|
|
if ( i == 0) {
|
|
@@ -751,44 +1090,44 @@ BaseType_t i;
|
|
|
{
|
|
{
|
|
|
mtCOVERAGE_TEST_MARKER();
|
|
mtCOVERAGE_TEST_MARKER();
|
|
|
}
|
|
}
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
- uxTaskNumber++;
|
|
|
|
|
|
|
+ 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 );
|
|
|
|
|
|
|
+ #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 );
|
|
|
|
|
|
|
+ prvAddTaskToReadyList( pxNewTCB );
|
|
|
|
|
|
|
|
- xReturn = pdPASS;
|
|
|
|
|
- portSETUP_TCB( pxNewTCB );
|
|
|
|
|
- }
|
|
|
|
|
- taskEXIT_CRITICAL(&xTaskQueueMutex);
|
|
|
|
|
- }
|
|
|
|
|
- else
|
|
|
|
|
- {
|
|
|
|
|
- xReturn = errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY;
|
|
|
|
|
- traceTASK_CREATE_FAILED();
|
|
|
|
|
|
|
+ portSETUP_TCB( pxNewTCB );
|
|
|
}
|
|
}
|
|
|
|
|
+ taskEXIT_CRITICAL(&xTaskQueueMutex);
|
|
|
|
|
|
|
|
- if( xReturn == pdPASS )
|
|
|
|
|
|
|
+ if( xSchedulerRunning != pdFALSE )
|
|
|
{
|
|
{
|
|
|
- if( xSchedulerRunning != pdFALSE )
|
|
|
|
|
|
|
+ /* Scheduler is running. If the created task is of a higher priority than an executing task
|
|
|
|
|
+ then it should run now.
|
|
|
|
|
+ ToDo: This only works for the current core. If a task is scheduled on an other processor,
|
|
|
|
|
+ the other processor will keep running the task it's working on, and only switch to the newer
|
|
|
|
|
+ task on a timer interrupt. */
|
|
|
|
|
+ //No mux here, uxPriority is mostly atomic and there's not really any harm if this check misfires.
|
|
|
|
|
+ if( pxCurrentTCB[ xPortGetCoreID() ]->uxPriority < pxNewTCB->uxPriority )
|
|
|
{
|
|
{
|
|
|
/* Scheduler is running. If the created task is of a higher priority than an executing task
|
|
/* Scheduler is running. If the created task is of a higher priority than an executing task
|
|
|
then it should run now.
|
|
then it should run now.
|
|
|
No mux here, uxPriority is mostly atomic and there's not really any harm if this check misfires.
|
|
No mux here, uxPriority is mostly atomic and there's not really any harm if this check misfires.
|
|
|
*/
|
|
*/
|
|
|
- if( tskCAN_RUN_HERE( xCoreID ) && pxCurrentTCB[ xPortGetCoreID() ]->uxPriority < uxPriority )
|
|
|
|
|
|
|
+ if( tskCAN_RUN_HERE( xCoreID ) && pxCurrentTCB[ xPortGetCoreID() ]->uxPriority < pxNewTCB->uxPriority )
|
|
|
{
|
|
{
|
|
|
taskYIELD_IF_USING_PREEMPTION();
|
|
taskYIELD_IF_USING_PREEMPTION();
|
|
|
}
|
|
}
|
|
|
else if( xCoreID != xPortGetCoreID() ) {
|
|
else if( xCoreID != xPortGetCoreID() ) {
|
|
|
- taskYIELD_OTHER_CORE(xCoreID, uxPriority);
|
|
|
|
|
|
|
+ taskYIELD_OTHER_CORE(xCoreID, pxNewTCB->uxPriority);
|
|
|
}
|
|
}
|
|
|
else
|
|
else
|
|
|
{
|
|
{
|
|
@@ -800,8 +1139,10 @@ BaseType_t i;
|
|
|
mtCOVERAGE_TEST_MARKER();
|
|
mtCOVERAGE_TEST_MARKER();
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
- return xReturn;
|
|
|
|
|
|
|
+ else
|
|
|
|
|
+ {
|
|
|
|
|
+ mtCOVERAGE_TEST_MARKER();
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
/*-----------------------------------------------------------*/
|
|
/*-----------------------------------------------------------*/
|
|
|
|
|
|
|
@@ -3010,120 +3351,6 @@ static portTASK_FUNCTION( prvIdleTask, pvParameters )
|
|
|
#endif /* configUSE_TICKLESS_IDLE */
|
|
#endif /* configUSE_TICKLESS_IDLE */
|
|
|
/*-----------------------------------------------------------*/
|
|
/*-----------------------------------------------------------*/
|
|
|
|
|
|
|
|
-static void prvInitialiseTCBVariables( TCB_t * const pxTCB, const char * const pcName, UBaseType_t uxPriority, const MemoryRegion_t * const xRegions, const uint16_t usStackDepth, const BaseType_t xCoreID ) /*lint !e971 Unqualified char types are allowed for strings and single characters only. */
|
|
|
|
|
-{
|
|
|
|
|
-UBaseType_t x;
|
|
|
|
|
-
|
|
|
|
|
- /* Store the task name in the TCB. */
|
|
|
|
|
- for( x = ( UBaseType_t ) 0; x < ( UBaseType_t ) configMAX_TASK_NAME_LEN; x++ )
|
|
|
|
|
- {
|
|
|
|
|
- pxTCB->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 ] == 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. */
|
|
|
|
|
- pxTCB->pcTaskName[ configMAX_TASK_NAME_LEN - 1 ] = '\0';
|
|
|
|
|
-
|
|
|
|
|
- /* This is used as an array index so must ensure it's not too large. First
|
|
|
|
|
- remove the privilege bit if one is present. */
|
|
|
|
|
- if( uxPriority >= ( UBaseType_t ) configMAX_PRIORITIES )
|
|
|
|
|
- {
|
|
|
|
|
- uxPriority = ( UBaseType_t ) configMAX_PRIORITIES - ( UBaseType_t ) 1U;
|
|
|
|
|
- }
|
|
|
|
|
- else
|
|
|
|
|
- {
|
|
|
|
|
- mtCOVERAGE_TEST_MARKER();
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- pxTCB->uxPriority = uxPriority;
|
|
|
|
|
- pxTCB->xCoreID = xCoreID;
|
|
|
|
|
- #if ( configUSE_MUTEXES == 1 )
|
|
|
|
|
- {
|
|
|
|
|
- pxTCB->uxBasePriority = uxPriority;
|
|
|
|
|
- pxTCB->uxMutexesHeld = 0;
|
|
|
|
|
- }
|
|
|
|
|
- #endif /* configUSE_MUTEXES */
|
|
|
|
|
-
|
|
|
|
|
- vListInitialiseItem( &( pxTCB->xGenericListItem ) );
|
|
|
|
|
- vListInitialiseItem( &( pxTCB->xEventListItem ) );
|
|
|
|
|
-
|
|
|
|
|
- /* Set the pxTCB 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( &( pxTCB->xGenericListItem ), pxTCB );
|
|
|
|
|
-
|
|
|
|
|
- /* Event lists are always in priority order. */
|
|
|
|
|
- listSET_LIST_ITEM_VALUE( &( pxTCB->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( &( pxTCB->xEventListItem ), pxTCB );
|
|
|
|
|
-
|
|
|
|
|
- #if ( portCRITICAL_NESTING_IN_TCB == 1 )
|
|
|
|
|
- {
|
|
|
|
|
- pxTCB->uxCriticalNesting = ( UBaseType_t ) 0U;
|
|
|
|
|
- }
|
|
|
|
|
- #endif /* portCRITICAL_NESTING_IN_TCB */
|
|
|
|
|
-
|
|
|
|
|
- #if ( configUSE_APPLICATION_TASK_TAG == 1 )
|
|
|
|
|
- {
|
|
|
|
|
- pxTCB->pxTaskTag = NULL;
|
|
|
|
|
- }
|
|
|
|
|
- #endif /* configUSE_APPLICATION_TASK_TAG */
|
|
|
|
|
-
|
|
|
|
|
- #if ( configGENERATE_RUN_TIME_STATS == 1 )
|
|
|
|
|
- {
|
|
|
|
|
- pxTCB->ulRunTimeCounter = 0UL;
|
|
|
|
|
- }
|
|
|
|
|
- #endif /* configGENERATE_RUN_TIME_STATS */
|
|
|
|
|
-
|
|
|
|
|
- #if ( portUSING_MPU_WRAPPERS == 1 )
|
|
|
|
|
- {
|
|
|
|
|
- vPortStoreTaskMPUSettings( &( pxTCB->xMPUSettings ), xRegions, pxTCB->pxStack, usStackDepth );
|
|
|
|
|
- }
|
|
|
|
|
- #else /* portUSING_MPU_WRAPPERS */
|
|
|
|
|
- {
|
|
|
|
|
- ( void ) xRegions;
|
|
|
|
|
- ( void ) usStackDepth;
|
|
|
|
|
- }
|
|
|
|
|
- #endif /* portUSING_MPU_WRAPPERS */
|
|
|
|
|
-
|
|
|
|
|
- #if( configNUM_THREAD_LOCAL_STORAGE_POINTERS != 0 )
|
|
|
|
|
- {
|
|
|
|
|
- for( x = 0; x < ( UBaseType_t ) configNUM_THREAD_LOCAL_STORAGE_POINTERS; x++ )
|
|
|
|
|
- {
|
|
|
|
|
- pxTCB->pvThreadLocalStoragePointers[ x ] = NULL;
|
|
|
|
|
- #if ( configTHREAD_LOCAL_STORAGE_DELETE_CALLBACKS )
|
|
|
|
|
- pxTCB->pvThreadLocalStoragePointersDelCallback[ x ] = (TlsDeleteCallbackFunction_t)NULL;
|
|
|
|
|
- #endif
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- #endif
|
|
|
|
|
-
|
|
|
|
|
-
|
|
|
|
|
- #if ( configUSE_TASK_NOTIFICATIONS == 1 )
|
|
|
|
|
- {
|
|
|
|
|
- pxTCB->ulNotifiedValue = 0;
|
|
|
|
|
- pxTCB->eNotifyState = eNotWaitingNotification;
|
|
|
|
|
- }
|
|
|
|
|
- #endif
|
|
|
|
|
-
|
|
|
|
|
- #if ( configUSE_NEWLIB_REENTRANT == 1 )
|
|
|
|
|
- {
|
|
|
|
|
- /* Initialise this task's Newlib reent structure. */
|
|
|
|
|
- _REENT_INIT_PTR( ( &( pxTCB->xNewLib_reent ) ) );
|
|
|
|
|
- }
|
|
|
|
|
- #endif /* configUSE_NEWLIB_REENTRANT */
|
|
|
|
|
-}
|
|
|
|
|
-/*-----------------------------------------------------------*/
|
|
|
|
|
#if ( configNUM_THREAD_LOCAL_STORAGE_POINTERS != 0 )
|
|
#if ( configNUM_THREAD_LOCAL_STORAGE_POINTERS != 0 )
|
|
|
|
|
|
|
|
#if ( configTHREAD_LOCAL_STORAGE_DELETE_CALLBACKS )
|
|
#if ( configTHREAD_LOCAL_STORAGE_DELETE_CALLBACKS )
|
|
@@ -3319,81 +3546,6 @@ static void prvAddCurrentTaskToDelayedList( const BaseType_t xCoreID, const Tick
|
|
|
}
|
|
}
|
|
|
/*-----------------------------------------------------------*/
|
|
/*-----------------------------------------------------------*/
|
|
|
|
|
|
|
|
-static TCB_t *prvAllocateTCBAndStack( const uint16_t usStackDepth, StackType_t * const puxStackBuffer )
|
|
|
|
|
-{
|
|
|
|
|
-TCB_t *pxNewTCB;
|
|
|
|
|
-
|
|
|
|
|
- /* If the stack grows down then allocate the stack then the TCB so the stack
|
|
|
|
|
- does not grow into the TCB. Likewise if the stack grows up then allocate
|
|
|
|
|
- the TCB then the stack. */
|
|
|
|
|
- #if( portSTACK_GROWTH > 0 )
|
|
|
|
|
- {
|
|
|
|
|
- /* Allocate space for the TCB. Where the memory comes from depends on
|
|
|
|
|
- the implementation of the port malloc function. */
|
|
|
|
|
- pxNewTCB = ( TCB_t * ) pvPortMalloc( sizeof( TCB_t ) );
|
|
|
|
|
-
|
|
|
|
|
- if( pxNewTCB != NULL )
|
|
|
|
|
- {
|
|
|
|
|
- /* Allocate space for the stack used by the task being created.
|
|
|
|
|
- The base of the stack memory stored in the TCB so the task can
|
|
|
|
|
- be deleted later if required. */
|
|
|
|
|
- pxNewTCB->pxStack = ( StackType_t * ) pvPortMallocAligned( ( ( ( size_t ) usStackDepth ) * sizeof( StackType_t ) ), puxStackBuffer ); /*lint !e961 MISRA exception as the casts are only redundant for some ports. */
|
|
|
|
|
-
|
|
|
|
|
- if( pxNewTCB->pxStack == NULL )
|
|
|
|
|
- {
|
|
|
|
|
- /* Could not allocate the stack. Delete the allocated TCB. */
|
|
|
|
|
- vPortFree( pxNewTCB );
|
|
|
|
|
- pxNewTCB = NULL;
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- #else /* portSTACK_GROWTH */
|
|
|
|
|
- {
|
|
|
|
|
- StackType_t *pxStack;
|
|
|
|
|
-
|
|
|
|
|
- /* Allocate space for the stack used by the task being created. */
|
|
|
|
|
- pxStack = ( StackType_t * ) pvPortMallocAligned( ( ( ( size_t ) usStackDepth ) * sizeof( StackType_t ) ), puxStackBuffer ); /*lint !e961 MISRA exception as the casts are only redundant for some ports. */
|
|
|
|
|
-
|
|
|
|
|
- if( pxStack != NULL )
|
|
|
|
|
- {
|
|
|
|
|
- /* Allocate space for the TCB. Where the memory comes from depends
|
|
|
|
|
- on the implementation of the port malloc function. */
|
|
|
|
|
- pxNewTCB = ( TCB_t * ) pvPortMalloc( sizeof( TCB_t ) );
|
|
|
|
|
-
|
|
|
|
|
- if( pxNewTCB != NULL )
|
|
|
|
|
- {
|
|
|
|
|
- /* Store the stack location in the TCB. */
|
|
|
|
|
- pxNewTCB->pxStack = pxStack;
|
|
|
|
|
- }
|
|
|
|
|
- else
|
|
|
|
|
- {
|
|
|
|
|
- /* The stack cannot be used as the TCB was not created. Free it
|
|
|
|
|
- again. */
|
|
|
|
|
- vPortFree( pxStack );
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- else
|
|
|
|
|
- {
|
|
|
|
|
- pxNewTCB = NULL;
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- #endif /* portSTACK_GROWTH */
|
|
|
|
|
-
|
|
|
|
|
- if( pxNewTCB != NULL )
|
|
|
|
|
- {
|
|
|
|
|
- /* Avoid dependency on memset() if it is not required. */
|
|
|
|
|
- #if( ( configCHECK_FOR_STACK_OVERFLOW > 1 ) || ( configUSE_TRACE_FACILITY == 1 ) || ( INCLUDE_uxTaskGetStackHighWaterMark == 1 ) )
|
|
|
|
|
- {
|
|
|
|
|
- /* Just to help debugging. */
|
|
|
|
|
- ( void ) memset( pxNewTCB->pxStack, ( int ) tskSTACK_FILL_BYTE, ( size_t ) usStackDepth * sizeof( StackType_t ) );
|
|
|
|
|
- }
|
|
|
|
|
- #endif /* ( ( configCHECK_FOR_STACK_OVERFLOW > 1 ) || ( ( configUSE_TRACE_FACILITY == 1 ) || ( INCLUDE_uxTaskGetStackHighWaterMark == 1 ) ) ) */
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- return pxNewTCB;
|
|
|
|
|
-}
|
|
|
|
|
-/*-----------------------------------------------------------*/
|
|
|
|
|
-
|
|
|
|
|
BaseType_t xTaskGetAffinity( TaskHandle_t xTask )
|
|
BaseType_t xTaskGetAffinity( TaskHandle_t xTask )
|
|
|
{
|
|
{
|
|
|
TCB_t *pxTCB;
|
|
TCB_t *pxTCB;
|
|
@@ -3561,22 +3713,40 @@ BaseType_t xTaskGetAffinity( TaskHandle_t xTask )
|
|
|
}
|
|
}
|
|
|
#endif /* configUSE_NEWLIB_REENTRANT */
|
|
#endif /* configUSE_NEWLIB_REENTRANT */
|
|
|
|
|
|
|
|
- #if( portUSING_MPU_WRAPPERS == 1 )
|
|
|
|
|
|
|
+ #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. */
|
|
|
|
|
+ vPortFreeAligned( pxTCB->pxStack );
|
|
|
|
|
+ vPortFree( pxTCB );
|
|
|
|
|
+ }
|
|
|
|
|
+ #elif( tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE == 1 )
|
|
|
{
|
|
{
|
|
|
- /* Only free the stack if it was allocated dynamically in the first
|
|
|
|
|
- place. */
|
|
|
|
|
- if( pxTCB->xUsingStaticallyAllocatedStack == pdFALSE )
|
|
|
|
|
|
|
+ /* 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. */
|
|
|
vPortFreeAligned( pxTCB->pxStack );
|
|
vPortFreeAligned( 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();
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
- #else
|
|
|
|
|
- {
|
|
|
|
|
- vPortFreeAligned( pxTCB->pxStack );
|
|
|
|
|
- }
|
|
|
|
|
- #endif
|
|
|
|
|
-
|
|
|
|
|
- vPortFree( pxTCB );
|
|
|
|
|
|
|
+ #endif /* configSUPPORT_DYNAMIC_ALLOCATION */
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
#endif /* INCLUDE_vTaskDelete */
|
|
#endif /* INCLUDE_vTaskDelete */
|
|
@@ -3978,7 +4148,9 @@ is not running. Re-enabling the scheduler will re-enable the interrupts instead
|
|
|
function is executing. */
|
|
function is executing. */
|
|
|
uxArraySize = uxCurrentNumberOfTasks;
|
|
uxArraySize = uxCurrentNumberOfTasks;
|
|
|
|
|
|
|
|
- /* Allocate an array index for each task. */
|
|
|
|
|
|
|
+ /* 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 ) );
|
|
pxTaskStatusArray = pvPortMalloc( uxCurrentNumberOfTasks * sizeof( TaskStatus_t ) );
|
|
|
|
|
|
|
|
if( pxTaskStatusArray != NULL )
|
|
if( pxTaskStatusArray != NULL )
|
|
@@ -4018,7 +4190,8 @@ is not running. Re-enabling the scheduler will re-enable the interrupts instead
|
|
|
pcWriteBuffer += strlen( pcWriteBuffer );
|
|
pcWriteBuffer += strlen( pcWriteBuffer );
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- /* Free the array again. */
|
|
|
|
|
|
|
+ /* Free the array again. NOTE! If configSUPPORT_DYNAMIC_ALLOCATION
|
|
|
|
|
+ is 0 then vPortFree() will be #defined to nothing. */
|
|
|
vPortFree( pxTaskStatusArray );
|
|
vPortFree( pxTaskStatusArray );
|
|
|
}
|
|
}
|
|
|
else
|
|
else
|
|
@@ -4077,7 +4250,9 @@ is not running. Re-enabling the scheduler will re-enable the interrupts instead
|
|
|
function is executing. */
|
|
function is executing. */
|
|
|
uxArraySize = uxCurrentNumberOfTasks;
|
|
uxArraySize = uxCurrentNumberOfTasks;
|
|
|
|
|
|
|
|
- /* Allocate an array index for each task. */
|
|
|
|
|
|
|
+ /* 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 ) );
|
|
pxTaskStatusArray = pvPortMalloc( uxCurrentNumberOfTasks * sizeof( TaskStatus_t ) );
|
|
|
|
|
|
|
|
if( pxTaskStatusArray != NULL )
|
|
if( pxTaskStatusArray != NULL )
|
|
@@ -4143,7 +4318,8 @@ is not running. Re-enabling the scheduler will re-enable the interrupts instead
|
|
|
mtCOVERAGE_TEST_MARKER();
|
|
mtCOVERAGE_TEST_MARKER();
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- /* Free the array again. */
|
|
|
|
|
|
|
+ /* Free the array again. NOTE! If configSUPPORT_DYNAMIC_ALLOCATION
|
|
|
|
|
+ is 0 then vPortFree() will be #defined to nothing. */
|
|
|
vPortFree( pxTaskStatusArray );
|
|
vPortFree( pxTaskStatusArray );
|
|
|
}
|
|
}
|
|
|
else
|
|
else
|