kopia lustrzana https://github.com/espressif/esp-idf
freertos: Schedule tasks immediately when they are created on opposite core
rodzic
20212ee823
commit
8de26e434c
|
@ -1046,25 +1046,59 @@ UBaseType_t x;
|
|||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void prvAddNewTaskToReadyList( TCB_t *pxNewTCB, TaskFunction_t pxTaskCode, const BaseType_t xCoreID )
|
||||
static void prvAddNewTaskToReadyList( TCB_t *pxNewTCB, TaskFunction_t pxTaskCode, BaseType_t xCoreID )
|
||||
{
|
||||
TCB_t *curTCB;
|
||||
BaseType_t i;
|
||||
TCB_t *curTCB, *tcb0, *tcb1;
|
||||
|
||||
/* Ensure interrupts don't access the task lists while the lists are being
|
||||
updated. */
|
||||
taskENTER_CRITICAL(&xTaskQueueMutex);
|
||||
{
|
||||
uxCurrentNumberOfTasks++;
|
||||
//If the task has no affinity and nothing is scheduled on this core, just throw it this core.
|
||||
//If it has affinity, throw it on the core that needs it if nothing is already scheduled there.
|
||||
BaseType_t xMyCore = xCoreID;
|
||||
if ( xMyCore == tskNO_AFFINITY) xMyCore = xPortGetCoreID();
|
||||
if( pxCurrentTCB[ xMyCore ] == NULL )
|
||||
|
||||
// Determine which core this task starts on
|
||||
if ( xCoreID == tskNO_AFFINITY )
|
||||
{
|
||||
if ( portNUM_PROCESSORS == 1 )
|
||||
{
|
||||
xCoreID = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
// if the task has no affinity, put it on either core if nothing is currently scheduled there. Failing that,
|
||||
// put it on the core where it will preempt the lowest priority running task. If neither of these are true,
|
||||
// queue it on the currently running core.
|
||||
tcb0 = pxCurrentTCB[0];
|
||||
tcb1 = pxCurrentTCB[1];
|
||||
if ( tcb0 == NULL )
|
||||
{
|
||||
xCoreID = 0;
|
||||
}
|
||||
else if ( tcb1 == NULL )
|
||||
{
|
||||
xCoreID = 1;
|
||||
}
|
||||
else if ( tcb0->uxPriority < pxNewTCB->uxPriority && tcb0->uxPriority < tcb1->uxPriority )
|
||||
{
|
||||
xCoreID = 0;
|
||||
}
|
||||
else if ( tcb1->uxPriority < pxNewTCB->uxPriority )
|
||||
{
|
||||
xCoreID = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
xCoreID = xPortGetCoreID(); // Both CPU have higher priority tasks running on them, so this won't run yet
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If nothing is running on this core, put the new task there now
|
||||
if( pxCurrentTCB[ xCoreID ] == NULL )
|
||||
{
|
||||
/* There are no other tasks, or all the other tasks are in
|
||||
the suspended state - make this the current task. */
|
||||
pxCurrentTCB[ xMyCore ] = pxNewTCB;
|
||||
pxCurrentTCB[ xCoreID ] = pxNewTCB;
|
||||
|
||||
if( uxCurrentNumberOfTasks == ( UBaseType_t ) 1 )
|
||||
{
|
||||
|
@ -1090,19 +1124,11 @@ static void prvAddNewTaskToReadyList( TCB_t *pxNewTCB, TaskFunction_t pxTaskCode
|
|||
so far. */
|
||||
if( xSchedulerRunning == pdFALSE )
|
||||
{
|
||||
/* Scheduler isn't running yet. We need to determine on which CPU to run this task. */
|
||||
for ( i=0; i<portNUM_PROCESSORS; i++ )
|
||||
/* Scheduler isn't running yet. We need to determine on which CPU to run this task.
|
||||
Schedule now if either nothing is scheduled yet or we can replace a task of lower prio. */
|
||||
if ( pxCurrentTCB[xCoreID] == NULL || pxCurrentTCB[xCoreID]->uxPriority <= pxNewTCB->uxPriority )
|
||||
{
|
||||
/* Can we schedule this task on core i? */
|
||||
if (xCoreID == tskNO_AFFINITY || xCoreID == i)
|
||||
{
|
||||
/* Schedule if nothing is scheduled yet, or overwrite a task of lower prio. */
|
||||
if ( pxCurrentTCB[i] == NULL || pxCurrentTCB[i]->uxPriority <= pxNewTCB->uxPriority )
|
||||
{
|
||||
pxCurrentTCB[i] = pxNewTCB;
|
||||
break;
|
||||
}
|
||||
}
|
||||
pxCurrentTCB[xCoreID] = pxNewTCB;
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@ -1130,37 +1156,27 @@ static void prvAddNewTaskToReadyList( TCB_t *pxNewTCB, TaskFunction_t pxTaskCode
|
|||
|
||||
if( xSchedulerRunning != pdFALSE )
|
||||
{
|
||||
taskENTER_CRITICAL(&xTaskQueueMutex);
|
||||
curTCB = pxCurrentTCB[ xPortGetCoreID() ];
|
||||
taskENTER_CRITICAL(&xTaskQueueMutex);
|
||||
|
||||
curTCB = pxCurrentTCB[ xCoreID ];
|
||||
/* 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( curTCB->uxPriority < pxNewTCB->uxPriority )
|
||||
then it should run now.
|
||||
*/
|
||||
if( curTCB == NULL || curTCB->uxPriority < pxNewTCB->uxPriority )
|
||||
{
|
||||
/* 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 ) && curTCB->uxPriority < pxNewTCB->uxPriority )
|
||||
if( xCoreID == xPortGetCoreID() )
|
||||
{
|
||||
taskYIELD_IF_USING_PREEMPTION_MUX(&xTaskQueueMutex);
|
||||
}
|
||||
else if( xCoreID != xPortGetCoreID() ) {
|
||||
else {
|
||||
taskYIELD_OTHER_CORE(xCoreID, pxNewTCB->uxPriority);
|
||||
}
|
||||
else
|
||||
{
|
||||
mtCOVERAGE_TEST_MARKER();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
mtCOVERAGE_TEST_MARKER();
|
||||
}
|
||||
taskEXIT_CRITICAL(&xTaskQueueMutex);
|
||||
taskEXIT_CRITICAL(&xTaskQueueMutex);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
@ -25,8 +25,7 @@ static void task_event_group_call_response(void *param)
|
|||
for (int i = 0; i < COUNT; i++) {
|
||||
/* Wait until the common "call" bit is set, starts off all tasks
|
||||
(clear on return) */
|
||||
while (!xEventGroupWaitBits(eg, BIT_CALL, true, false, portMAX_DELAY)) {
|
||||
}
|
||||
TEST_ASSERT( xEventGroupWaitBits(eg, BIT_CALL, true, false, portMAX_DELAY) );
|
||||
|
||||
/* Set our individual "response" bit */
|
||||
xEventGroupSetBits(eg, BIT_RESPONSE(task_num));
|
||||
|
@ -42,25 +41,25 @@ TEST_CASE("FreeRTOS Event Groups", "[freertos]")
|
|||
eg = xEventGroupCreate();
|
||||
done_sem = xSemaphoreCreateCounting(NUM_TASKS, 0);
|
||||
|
||||
/* Note: task_event_group_call_response all have higher priority than us, so will block together.
|
||||
/* Note: task_event_group_call_response all have higher priority than this task, so on this core
|
||||
they will always preempt this task.
|
||||
|
||||
This is important because we need to know they'll all have blocked on BIT_CALL each time we
|
||||
signal it, or they get out of sync.
|
||||
This is important because we need to know all tasks have blocked on BIT_CALL each time we signal it,
|
||||
or they get out of sync.
|
||||
*/
|
||||
for (int c = 0; c < NUM_TASKS; c++) {
|
||||
xTaskCreatePinnedToCore(task_event_group_call_response, "tsk_call_resp", 4096, (void *)c, configMAX_PRIORITIES - 1, NULL, c % portNUM_PROCESSORS);
|
||||
}
|
||||
/* Scheduler weirdness (bug?), if we don't sleep a few ticks here then the tasks on the other CPU aren't running yet... */
|
||||
vTaskDelay(10);
|
||||
|
||||
/* Tasks all start instantly, but this task will resume running at the same time as the higher priority tasks on the
|
||||
other processor may still be setting up, so give a tick for them to also block on BIT_CALL... */
|
||||
vTaskDelay(1);
|
||||
|
||||
for (int i = 0; i < COUNT; i++) {
|
||||
if (i % 100 == 0) {
|
||||
//printf("Call %d\n", i);
|
||||
}
|
||||
/* signal all tasks with "CALL" bit... */
|
||||
xEventGroupSetBits(eg, BIT_CALL);
|
||||
|
||||
TEST_ASSERT_EQUAL(ALL_RESPONSE_BITS, xEventGroupWaitBits(eg, ALL_RESPONSE_BITS, true, true, 100 / portMAX_DELAY));
|
||||
TEST_ASSERT_EQUAL_HEX16(ALL_RESPONSE_BITS, xEventGroupWaitBits(eg, ALL_RESPONSE_BITS, true, true, 100 / portMAX_DELAY));
|
||||
}
|
||||
|
||||
/* Ensure all tasks cleaned up correctly */
|
||||
|
|
Ładowanie…
Reference in New Issue