Skip to content

Commit ec943bc

Browse files
authored
Static allocation and lightweight idle tasks (#323)
* added multiple idle tasks * Added multiple IDLE tasks to non-static allocation * Adjustments to tasks from PR review
1 parent 83595e8 commit ec943bc

File tree

1 file changed

+135
-35
lines changed

1 file changed

+135
-35
lines changed

tasks.c

Lines changed: 135 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -410,6 +410,11 @@ PRIVILEGED_DATA static volatile UBaseType_t uxSchedulerSuspended = ( UBaseType_t
410410

411411
/* File private functions. --------------------------------*/
412412

413+
/*
414+
* Creates the idle tasks during scheduler start
415+
*/
416+
static BaseType_t prvCreateIdleTasks( void );
417+
413418
/*
414419
* Returns the yield pending count for the calling core.
415420
*/
@@ -460,13 +465,11 @@ static void prvInitialiseTaskLists( void ) PRIVILEGED_FUNCTION;
460465
* The idle task is automatically created and added to the ready lists upon
461466
* creation of the first user task.
462467
*
463-
* The portTASK_FUNCTION_PROTO() macro is used to allow port/compiler specific
464-
* language extensions. The equivalent prototype for this function is:
465-
*
466-
* void prvIdleTask( void *pvParameters );
467-
*
468468
*/
469469
static portTASK_FUNCTION_PROTO( prvIdleTask, pvParameters ) PRIVILEGED_FUNCTION;
470+
#if ( configNUM_CORES > 1 )
471+
static portTASK_FUNCTION_PROTO( prvMinimalIdleTask, pvParameters ) PRIVILEGED_FUNCTION;
472+
#endif
470473

471474
/*
472475
* Utility to free all memory allocated by the scheduler to hold a TCB,
@@ -1545,7 +1548,20 @@ static void prvInitialiseNewTask( TaskFunction_t pxTaskCode,
15451548
pxNewTCB->xTaskRunState = taskTASK_NOT_RUNNING;
15461549

15471550
/* Is this an idle task? */
1548-
pxNewTCB->xIsIdle = ( pxTaskCode == prvIdleTask );
1551+
if(pxTaskCode == prvIdleTask)
1552+
{
1553+
pxNewTCB->xIsIdle = pdTRUE;
1554+
}
1555+
#if(configNUM_CORES > 1)
1556+
else if(pxTaskCode == prvMinimalIdleTask)
1557+
{
1558+
pxNewTCB->xIsIdle = pdTRUE;
1559+
}
1560+
#endif
1561+
else
1562+
{
1563+
pxNewTCB->xIsIdle = pdFALSE;
1564+
}
15491565

15501566
if( pxCreatedTask != NULL )
15511567
{
@@ -2598,19 +2614,13 @@ static void prvAddNewTaskToReadyList( TCB_t * pxNewTCB )
25982614
#endif /* ( ( INCLUDE_xTaskResumeFromISR == 1 ) && ( INCLUDE_vTaskSuspend == 1 ) ) */
25992615
/*-----------------------------------------------------------*/
26002616

2601-
void vTaskStartScheduler( void )
2617+
static BaseType_t prvCreateIdleTasks( void )
26022618
{
2603-
BaseType_t xReturn;
2619+
BaseType_t xReturn = pdPASS;
26042620
BaseType_t xCoreID;
26052621
char cIdleName[ configMAX_TASK_NAME_LEN ];
26062622

2607-
#if ( configUSE_TIMERS == 1 )
2608-
{
2609-
xReturn = xTimerCreateTimerTask();
2610-
}
2611-
#endif /* configUSE_TIMERS */
2612-
2613-
/* Add each idle task at the lowest priority. */
2623+
/* Add each idle task at the lowest priority. */
26142624
for( xCoreID = ( BaseType_t ) 0; xCoreID < ( BaseType_t ) configNUM_CORES; xCoreID++ )
26152625
{
26162626
BaseType_t x;
@@ -2663,22 +2673,38 @@ void vTaskStartScheduler( void )
26632673

26642674
#if ( configSUPPORT_STATIC_ALLOCATION == 1 )
26652675
{
2666-
#error User must specify an array of buffers for idle task TCBs and stacks
2667-
StaticTask_t * pxIdleTaskTCBBuffer = NULL;
2668-
StackType_t * pxIdleTaskStackBuffer = NULL;
2669-
uint32_t ulIdleTaskStackSize;
2670-
2671-
/* The Idle task is created using user provided RAM - obtain the
2672-
* address of the RAM then create the idle task. */
2673-
vApplicationGetIdleTaskMemory( &pxIdleTaskTCBBuffer, &pxIdleTaskStackBuffer, &ulIdleTaskStackSize );
2674-
xIdleTaskHandle[ xCoreID ] = xTaskCreateStatic( prvIdleTask,
2675-
cIdleName,
2676-
ulIdleTaskStackSize,
2677-
( void * ) NULL, /*lint !e961. The cast is not redundant for all compilers. */
2678-
portPRIVILEGE_BIT, /* In effect ( tskIDLE_PRIORITY | portPRIVILEGE_BIT ), but tskIDLE_PRIORITY is zero. */
2679-
pxIdleTaskStackBuffer,
2680-
pxIdleTaskTCBBuffer ); /*lint !e961 MISRA exception, justified as it is not a redundant explicit cast to all supported compilers. */
2681-
2676+
if(xCoreID == 0)
2677+
{
2678+
StaticTask_t * pxIdleTaskTCBBuffer = NULL;
2679+
StackType_t * pxIdleTaskStackBuffer = NULL;
2680+
uint32_t ulIdleTaskStackSize;
2681+
2682+
/* The Idle task is created using user provided RAM - obtain the
2683+
* address of the RAM then create the idle task. */
2684+
vApplicationGetIdleTaskMemory( &pxIdleTaskTCBBuffer, &pxIdleTaskStackBuffer, &ulIdleTaskStackSize );
2685+
xIdleTaskHandle[ xCoreID ] = xTaskCreateStatic( prvIdleTask,
2686+
cIdleName,
2687+
ulIdleTaskStackSize,
2688+
( void * ) NULL, /*lint !e961. The cast is not redundant for all compilers. */
2689+
portPRIVILEGE_BIT, /* In effect ( tskIDLE_PRIORITY | portPRIVILEGE_BIT ), but tskIDLE_PRIORITY is zero. */
2690+
pxIdleTaskStackBuffer,
2691+
pxIdleTaskTCBBuffer ); /*lint !e961 MISRA exception, justified as it is not a redundant explicit cast to all supported compilers. */
2692+
}
2693+
#if( configNUM_CORES > 1)
2694+
else
2695+
{
2696+
static StaticTask_t xIdleTCBBuffers[configNUM_CORES-1];
2697+
static StackType_t xIdleTaskStackBuffers[configMINIMAL_STACK_SIZE][configNUM_CORES-1];
2698+
2699+
xIdleTaskHandle[ xCoreID ] = xTaskCreateStatic( prvMinimalIdleTask,
2700+
cIdleName,
2701+
configMINIMAL_STACK_SIZE,
2702+
( void * ) NULL, /*lint !e961. The cast is not redundant for all compilers. */
2703+
portPRIVILEGE_BIT, /* In effect ( tskIDLE_PRIORITY | portPRIVILEGE_BIT ), but tskIDLE_PRIORITY is zero. */
2704+
xIdleTaskStackBuffers[xCoreID-1],
2705+
&xIdleTCBBuffers[xCoreID-1] ); /*lint !e961 MISRA exception, justified as it is not a redundant explicit cast to all supported compilers. */
2706+
}
2707+
#endif
26822708
if( xIdleTaskHandle[ xCoreID ] != NULL )
26832709
{
26842710
xReturn = pdPASS;
@@ -2690,16 +2716,44 @@ void vTaskStartScheduler( void )
26902716
}
26912717
#else /* if ( configSUPPORT_STATIC_ALLOCATION == 1 ) */
26922718
{
2719+
if(xCoreID == 0)
2720+
{
26932721
/* The Idle task is being created using dynamically allocated RAM. */
26942722
xReturn = xTaskCreate( prvIdleTask,
26952723
cIdleName,
26962724
configMINIMAL_STACK_SIZE,
26972725
( void * ) NULL,
26982726
portPRIVILEGE_BIT, /* In effect ( tskIDLE_PRIORITY | portPRIVILEGE_BIT ), but tskIDLE_PRIORITY is zero. */
26992727
&xIdleTaskHandle[ xCoreID ] ); /*lint !e961 MISRA exception, justified as it is not a redundant explicit cast to all supported compilers. */
2728+
}
2729+
#if( configNUM_CORES > 1 )
2730+
else
2731+
{
2732+
xReturn = xTaskCreate( prvMinimalIdleTask,
2733+
cIdleName,
2734+
configMINIMAL_STACK_SIZE,
2735+
( void * ) NULL,
2736+
portPRIVILEGE_BIT, /* In effect ( tskIDLE_PRIORITY | portPRIVILEGE_BIT ), but tskIDLE_PRIORITY is zero. */
2737+
&xIdleTaskHandle[ xCoreID ] ); /*lint !e961 MISRA exception, justified as it is not a redundant explicit cast to all supported compilers. */
2738+
}
2739+
#endif
27002740
}
27012741
#endif /* configSUPPORT_STATIC_ALLOCATION */
27022742
}
2743+
return xReturn;
2744+
}
2745+
2746+
void vTaskStartScheduler( void )
2747+
{
2748+
BaseType_t xReturn;
2749+
2750+
#if ( configUSE_TIMERS == 1 )
2751+
{
2752+
xReturn = xTimerCreateTimerTask();
2753+
}
2754+
#endif /* configUSE_TIMERS */
2755+
2756+
xReturn = prvCreateIdleTasks();
27032757

27042758
if( xReturn == pdPASS )
27052759
{
@@ -4148,13 +4202,59 @@ void vTaskMissedYield( void )
41484202

41494203
/*
41504204
* -----------------------------------------------------------
4151-
* The Idle task.
4205+
* The MinimalIdle task.
41524206
* ----------------------------------------------------------
41534207
*
4154-
* The portTASK_FUNCTION() macro is used to allow port/compiler specific
4155-
* language extensions. The equivalent prototype for this function is:
4208+
* The minimal idle task is used for all the additional Cores in a SMP system.
4209+
* There must be only 1 idle task and the rest are minimal idle tasks.
4210+
*
4211+
* @todo additional conditional compiles to remove this function.
4212+
*/
4213+
#if (configNUM_CORES > 1)
4214+
static portTASK_FUNCTION( prvMinimalIdleTask, pvParameters )
4215+
{
4216+
for(;;)
4217+
{
4218+
#if ( configUSE_PREEMPTION == 0 )
4219+
{
4220+
/* If we are not using preemption we keep forcing a task switch to
4221+
* see if any other task has become available. If we are using
4222+
* preemption we don't need to do this as any task becoming available
4223+
* will automatically get the processor anyway. */
4224+
taskYIELD();
4225+
}
4226+
#endif /* configUSE_PREEMPTION */
4227+
4228+
#if ( ( configUSE_PREEMPTION == 1 ) && ( configIDLE_SHOULD_YIELD == 1 ) )
4229+
{
4230+
/* When using preemption tasks of equal priority will be
4231+
* timesliced. If a task that is sharing the idle priority is ready
4232+
* to run then the idle task should yield before the end of the
4233+
* timeslice.
4234+
*
4235+
* A critical region is not required here as we are just reading from
4236+
* the list, and an occasional incorrect value will not matter. If
4237+
* the ready list at the idle priority contains one more task than the
4238+
* number of idle tasks, which is equal to the configured numbers of cores
4239+
* then a task other than the idle task is ready to execute. */
4240+
if( listCURRENT_LIST_LENGTH( &( pxReadyTasksLists[ tskIDLE_PRIORITY ] ) ) > ( UBaseType_t ) configNUM_CORES )
4241+
{
4242+
taskYIELD();
4243+
}
4244+
else
4245+
{
4246+
mtCOVERAGE_TEST_MARKER();
4247+
}
4248+
}
4249+
#endif /* ( ( configUSE_PREEMPTION == 1 ) && ( configIDLE_SHOULD_YIELD == 1 ) ) */
4250+
}
4251+
}
4252+
#endif
4253+
/*
4254+
* -----------------------------------------------------------
4255+
* The Idle task.
4256+
* ----------------------------------------------------------
41564257
*
4157-
* void prvIdleTask( void *pvParameters );
41584258
*
41594259
*/
41604260
static portTASK_FUNCTION( prvIdleTask, pvParameters )

0 commit comments

Comments
 (0)