/*-----------------------------------------------------------*/
+/*
+ * This routine tries to send an interrupt to another core if needed to make it execute a task
+ * of higher priority. We try to figure out if needed first by inspecting the pxTCB of the
+ * other CPU first. Specifically for Xtensa, we can do this because pxTCB is an atomic pointer. It
+ * is possible that it is inaccurate because the other CPU just did a task switch, but in that case
+ * at most a superfluous interrupt is generated.
+*/
+void taskYIELD_OTHER_CORE( BaseType_t xCoreID, UBaseType_t uxPriority )
+{
+ BaseType_t i;
+ if (xCoreID != tskNO_AFFINITY) {
+ if ( pxCurrentTCB[ xCoreID ]->uxPriority < uxPriority ) {
+ vPortYieldOtherCore( xCoreID );
+ }
+ }
+ else
+ {
+ /* The task has no affinity. See if we can find a CPU to put it on.*/
+ for (i=0; i<portNUM_PROCESSORS; i++) {
+ if (i != xPortGetCoreID() && pxCurrentTCB[ i ]->uxPriority < uxPriority)
+ {
+ vPortYieldOtherCore( i );
+ break;
+ }
+ }
+ }
+}
+
+ #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
{
{
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 )
{
- taskYIELD_IF_USING_PREEMPTION();
+ /* Scheduler is running. If the created task is of a higher priority than an executing task
+ then it should run now.
+ 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();
+ }
+ else if( xCoreID != xPortGetCoreID() ) {
- taskYIELD_OTHER_CORE(xCoreID, uxPriority);
++ taskYIELD_OTHER_CORE(xCoreID, pxNewTCB->uxPriority);
+ }
+ else
+ {
+ mtCOVERAGE_TEST_MARKER();
+ }
}
else
{