diff --git a/components/freertos/tasks.c b/components/freertos/tasks.c index 0804bb3eb5..b37e592549 100644 --- a/components/freertos/tasks.c +++ b/components/freertos/tasks.c @@ -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; iuxPriority <= 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 { diff --git a/components/freertos/test/test_freertos_eventgroups.c b/components/freertos/test/test_freertos_eventgroups.c index dce770af53..f32c20ade9 100644 --- a/components/freertos/test/test_freertos_eventgroups.c +++ b/components/freertos/test/test_freertos_eventgroups.c @@ -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 */