Merge branch 'feature/freertos_10.4.3_sync_yielding' into 'master'

freertos: Add new macro to check for yielding

Closes IDF-5735

See merge request espressif/esp-idf!19316
This commit is contained in:
Darian
2022-08-11 22:57:05 +08:00
2 changed files with 162 additions and 90 deletions

View File

@@ -249,6 +249,15 @@ extern void esp_vApplicationIdleHook(void);
tracePOST_MOVED_TASK_TO_READY_STATE( pxTCB )
/*-----------------------------------------------------------*/
#if ( configNUM_CORES > 1 )
#define prvCheckForYield( pxTCB, xCurCoreID, xYieldEqualPriority ) ( prvCheckForYieldUsingPrioritySMP( ( pxTCB )->uxPriority, ( pxTCB )->xCoreID, xCurCoreID, xYieldEqualPriority ) == pdTRUE )
#define prvCheckForYieldUsingPriority( uxTaskPriority, xTaskCoreID, xCurCoreID, xYieldEqualPriority ) ( prvCheckForYieldUsingPrioritySMP( uxTaskPriority, xTaskCoreID, xCurCoreID, xYieldEqualPriority ) == pdTRUE )
#else
#define prvCheckForYield( pxTargetTCB, xCurCoreID, xYieldEqualPriority ) ( ( ( pxTargetTCB )->uxPriority + ( ( xYieldEqualPriority == pdTRUE ) ? 1 : 0 ) ) > pxCurrentTCB[ 0 ]->uxPriority )
#define prvCheckForYieldUsingPriority( uxTaskPriority, xTaskCoreID, xCurCoreID, xYieldEqualPriority ) ( ( uxTaskPriority + ( ( xYieldEqualPriority == pdTRUE ) ? 1 : 0 ) ) >= pxCurrentTCB[ 0 ]->uxPriority )
#endif /* configNUM_CORES > 1 */
/*-----------------------------------------------------------*/
#define tskCAN_RUN_HERE( cpuid ) ( cpuid==xPortGetCoreID() || cpuid==tskNO_AFFINITY )
/*
@@ -625,6 +634,49 @@ static void prvAddNewTaskToReadyList( TCB_t * pxNewTCB,
TaskFunction_t pxTaskCode,
BaseType_t xCoreID ) PRIVILEGED_FUNCTION;
#if ( configNUM_CORES > 1 )
/*
* Check whether a yield (on either core) is required after unblocking (or
* changing the priority of) a particular task.
*
* - This function is the SMP replacement for checking if an unblocked task has
* a higher (or equal) priority than the current task.
* - It should be called before calling taskYIELD_IF_USING_PREEMPTION() or
* before setting xYieldRequired
* - If it is the other core that requires a yield, this function will
* internally trigger the other core to yield
*
* Note: In some special instances, a yield is triggered if the unblocked task
* has an equal priority (such as in xTaskResumeAll). Thus the
* xYieldEqualPriority parameter specifies whether to yield if the current
* task has equal priority.
*
* Scheduling Algorithm:
* This function will bias towards yielding the current core.
* - If the unblocked task has a higher (or equal) priority than then current
* core, the current core is yielded regardless of the current priority of the
* other core.
* - A core (current or other) will only yield if their schedulers are not
* suspended.
*
* Todo: This can be optimized (IDF-5772)
*
* Entry:
* - This function must be called in a critical section
* - A task must just have been unblocked, or its priority raised
* Exit:
* - Returns pdTRUE if the current core requires yielding
* - The other core will be triggered to yield if required
*/
static BaseType_t prvCheckForYieldUsingPrioritySMP( UBaseType_t uxTaskPriority,
BaseType_t xTaskCoreID,
BaseType_t xCurCoreID,
BaseType_t xYieldEqualPriority ) PRIVILEGED_FUNCTION;
#endif /* configNUM_CORES > 1 */
/*
* freertos_tasks_c_additions_init() should only be called if the user definable
* macro FREERTOS_TASKS_C_ADDITIONS_INIT() is defined, as that is the only macro
@@ -1192,7 +1244,7 @@ static void prvAddNewTaskToReadyList( TCB_t * pxNewTCB,
TaskFunction_t pxTaskCode,
BaseType_t xCoreID )
{
TCB_t *curTCB, *tcb0, *tcb1;
TCB_t *tcb0, *tcb1;
#if (configNUM_CORES < 2)
xCoreID = 0;
@@ -1302,21 +1354,17 @@ static void prvAddNewTaskToReadyList( TCB_t * pxNewTCB,
* then it should run now. */
taskENTER_CRITICAL();
curTCB = pxCurrentTCB[ xCoreID ];
if( curTCB == NULL || curTCB->uxPriority < pxNewTCB->uxPriority )
/* If the created task is of a higher priority than the current task
* then it should run now. */
if( pxCurrentTCB[ xPortGetCoreID() ] == NULL || prvCheckForYield( pxNewTCB, xPortGetCoreID(), pdTRUE ) )
{
if( xCoreID == xPortGetCoreID() )
{
taskYIELD_IF_USING_PREEMPTION();
}
else {
taskYIELD_OTHER_CORE(xCoreID, pxNewTCB->uxPriority);
}
taskYIELD_IF_USING_PREEMPTION();
}
else
{
mtCOVERAGE_TEST_MARKER();
}
taskEXIT_CRITICAL();
}
else
@@ -1326,6 +1374,48 @@ static void prvAddNewTaskToReadyList( TCB_t * pxNewTCB,
}
/*-----------------------------------------------------------*/
#if ( configNUM_CORES > 1 )
static BaseType_t prvCheckForYieldUsingPrioritySMP( UBaseType_t uxTaskPriority,
BaseType_t xTaskCoreID,
BaseType_t xCurCoreID,
BaseType_t xYieldEqualPriority )
{
if( xYieldEqualPriority == pdTRUE )
{
/* Increment the task priority to achieve the same affect as if( uxTaskPriority >= pxCurrentTCB->uxPriority ) */
uxTaskPriority++;
}
/* Indicate whether the current core needs to yield */
BaseType_t xYieldRequiredCurrentCore;
/* If the target task can run on the current core, and has a higher priority than the current core, then yield the current core */
if( ( ( xTaskCoreID == xCurCoreID ) || ( xTaskCoreID == tskNO_AFFINITY ) ) && ( uxTaskPriority > pxCurrentTCB[ xCurCoreID ]->uxPriority ) )
{
/* Return true for the caller to yield the current core */
xYieldRequiredCurrentCore = pdTRUE;
}
/* If the target task can run on the other core, and has a higher priority then the other core, and the other core has not suspended scheduling, the yield the other core */
else if( ( ( xTaskCoreID == !xCurCoreID ) || ( xTaskCoreID == tskNO_AFFINITY ) )
&& ( uxTaskPriority > pxCurrentTCB[ !xCurCoreID ]->uxPriority )
&& ( uxSchedulerSuspended[ !xCurCoreID ] == ( UBaseType_t ) pdFALSE ) )
{
/* Signal the other core to yield */
vPortYieldOtherCore( !xCurCoreID );
xYieldRequiredCurrentCore = pdFALSE;
}
else
{
xYieldRequiredCurrentCore = pdFALSE;
}
return xYieldRequiredCurrentCore;
}
#endif /* configNUM_CORES > 1 */
/*-----------------------------------------------------------*/
#if ( INCLUDE_vTaskDelete == 1 )
void vTaskDelete( TaskHandle_t xTaskToDelete )
@@ -1815,19 +1905,15 @@ static void prvAddNewTaskToReadyList( TCB_t * pxNewTCB,
* priority than the calling task. */
if( uxNewPriority > uxCurrentBasePriority )
{
if( pxTCB != pxCurrentTCB[xPortGetCoreID()] )
if( pxTCB != pxCurrentTCB[ xPortGetCoreID() ] )
{
/* The priority of a task other than the currently
* running task is being raised. Is the priority being
* raised above that of the running task? */
if ( tskCAN_RUN_HERE(pxTCB->xCoreID) && uxNewPriority >= pxCurrentTCB[ xPortGetCoreID() ]->uxPriority )
if ( prvCheckForYieldUsingPriority( uxNewPriority, pxTCB->xCoreID, xPortGetCoreID(), pdTRUE ) )
{
xYieldRequired = pdTRUE;
}
else if ( pxTCB->xCoreID != xPortGetCoreID() )
{
taskYIELD_OTHER_CORE( pxTCB->xCoreID, uxNewPriority );
}
else
{
mtCOVERAGE_TEST_MARKER();
@@ -1840,31 +1926,13 @@ static void prvAddNewTaskToReadyList( TCB_t * pxNewTCB,
* priority task able to run so no yield is required. */
}
}
else if( pxTCB == pxCurrentTCB[xPortGetCoreID()] )
else if( pxTCB == pxCurrentTCB[ xPortGetCoreID() ] )
{
/* Setting the priority of the running task down means
* there may now be another task of higher priority that
* is ready to execute. */
xYieldRequired = pdTRUE;
}
else if( pxTCB != pxCurrentTCB[xPortGetCoreID()] )
{
/* The priority of a task other than the currently
* running task is being raised. Is the priority being
* raised above that of the running task? */
if( uxNewPriority >= pxCurrentTCB[xPortGetCoreID()]->uxPriority )
{
xYieldRequired = pdTRUE;
}
else if ( pxTCB->xCoreID != xPortGetCoreID() ) //Need to check if not currently running on other core
{
taskYIELD_OTHER_CORE( pxTCB->xCoreID, uxNewPriority );
}
else
{
mtCOVERAGE_TEST_MARKER();
}
}
else
{
/* Setting the priority of any other task down does not
@@ -2142,12 +2210,12 @@ static void prvAddNewTaskToReadyList( TCB_t * pxNewTCB,
/* It does not make sense to resume the calling task. */
configASSERT( xTaskToResume );
taskENTER_CRITICAL();
/* The parameter cannot be NULL as it is impossible to resume the
* currently executing task. */
if( ( pxTCB != pxCurrentTCB[xPortGetCoreID()] ) && ( pxTCB != NULL ) )
taskENTER_CRITICAL();
{
/* The parameter cannot be NULL as it is impossible to resume the
* currently executing task. */
if( ( pxTCB != pxCurrentTCB[xPortGetCoreID()] ) && ( pxTCB != NULL ) )
{
if( prvTaskIsTaskSuspended( pxTCB ) != pdFALSE )
{
@@ -2158,18 +2226,14 @@ static void prvAddNewTaskToReadyList( TCB_t * pxNewTCB,
( void ) uxListRemove( &( pxTCB->xStateListItem ) );
prvAddTaskToReadyList( pxTCB );
/* We may have just resumed a higher priority task. */
if( tskCAN_RUN_HERE(pxTCB->xCoreID) && pxTCB->uxPriority >= pxCurrentTCB[ xPortGetCoreID() ]->uxPriority )
/* A higher priority task may have just been resumed. */
if( prvCheckForYield( pxTCB, xPortGetCoreID(), pdTRUE ) )
{
/* This yield may not cause the task just resumed to run,
* but will leave the lists in the correct state for the
* next yield. */
taskYIELD_IF_USING_PREEMPTION();
}
else if( pxTCB->xCoreID != xPortGetCoreID() )
{
taskYIELD_OTHER_CORE( pxTCB->xCoreID, pxTCB->uxPriority );
}
else
{
mtCOVERAGE_TEST_MARKER();
@@ -2180,10 +2244,10 @@ static void prvAddNewTaskToReadyList( TCB_t * pxNewTCB,
mtCOVERAGE_TEST_MARKER();
}
}
}
else
{
mtCOVERAGE_TEST_MARKER();
else
{
mtCOVERAGE_TEST_MARKER();
}
}
taskEXIT_CRITICAL();
}
@@ -2217,7 +2281,7 @@ static void prvAddNewTaskToReadyList( TCB_t * pxNewTCB,
* simple as possible. More information (albeit Cortex-M specific) is
* provided on the following link:
* https://www.FreeRTOS.org/RTOS-Cortex-M3-M4.html */
//portASSERT_IF_INTERRUPT_PRIORITY_INVALID();
portASSERT_IF_INTERRUPT_PRIORITY_INVALID();
taskENTER_CRITICAL_ISR();
{
@@ -2226,32 +2290,33 @@ static void prvAddNewTaskToReadyList( TCB_t * pxNewTCB,
traceTASK_RESUME_FROM_ISR( pxTCB );
/* Check the ready lists can be accessed. */
if( uxSchedulerSuspended[xPortGetCoreID()] == ( UBaseType_t ) pdFALSE )
if( uxSchedulerSuspended[ xPortGetCoreID() ] == ( UBaseType_t ) pdFALSE )
{
( void ) uxListRemove( &( pxTCB->xStateListItem ) );
prvAddTaskToReadyList( pxTCB );
if( tskCAN_RUN_HERE( pxTCB->xCoreID ) && pxTCB->uxPriority >= pxCurrentTCB[ xPortGetCoreID() ]->uxPriority )
/* Ready lists can be accessed so move the task from the
* suspended list to the ready list directly. */
if( prvCheckForYield( pxTCB, xPortGetCoreID(), pdTRUE ) )
{
xYieldRequired = pdTRUE;
}
else if ( pxTCB->xCoreID != xPortGetCoreID() )
{
taskYIELD_OTHER_CORE( pxTCB->xCoreID, pxTCB->uxPriority);
/* Mark that a yield is pending in case the user is not
* using the return value to initiate a context switch
* from the ISR using portYIELD_FROM_ISR. */
xYieldPending[ xPortGetCoreID() ] = pdTRUE;
}
else
{
mtCOVERAGE_TEST_MARKER();
}
( void ) uxListRemove( &( pxTCB->xStateListItem ) );
prvAddTaskToReadyList( pxTCB );
}
else
{
/* The delayed or ready lists cannot be accessed so the task
* is held in the pending ready list until the scheduler is
* unsuspended. */
vListInsertEnd( &( xPendingReadyList[xPortGetCoreID()] ), &( pxTCB->xEventListItem ) );
vListInsertEnd( &( xPendingReadyList[ xPortGetCoreID() ] ), &( pxTCB->xEventListItem ) );
}
}
else
@@ -2283,7 +2348,7 @@ void vTaskStartScheduler( void )
uint32_t ulIdleTaskStackSize;
/* The Idle task is created using user provided RAM - obtain the
address of the RAM then create the idle task. */
* address of the RAM then create the idle task. */
vApplicationGetIdleTaskMemory( &pxIdleTaskTCBBuffer, &pxIdleTaskStackBuffer, &ulIdleTaskStackSize );
xIdleTaskHandle[ xCoreID ] = xTaskCreateStaticPinnedToCore( prvIdleTask,
configIDLE_TASK_NAME,
@@ -2549,7 +2614,7 @@ BaseType_t xTaskResumeAll( void )
/* If the moved task has a priority higher than the current
* task then a yield must be performed. */
if( pxTCB->uxPriority >= pxCurrentTCB[ xCoreID ]->uxPriority )
if( prvCheckForYield( pxTCB, xPortGetCoreID(), pdTRUE ) )
{
xYieldPending[ xCoreID ] = pdTRUE;
}
@@ -3050,15 +3115,11 @@ BaseType_t xTaskCatchUpTicks( TickType_t xTicksToCatchUp )
/* Preemption is on, but a context switch should only be
* performed if the unblocked task has a priority that is
* equal to or higher than the currently executing task. */
if( tskCAN_RUN_HERE(pxTCB->xCoreID) && pxTCB->uxPriority >= pxCurrentTCB[ xPortGetCoreID() ]->uxPriority )
if( prvCheckForYield( pxTCB, xPortGetCoreID(), pdFALSE ) )
{
/* Pend the yield to be performed when the scheduler
* is unsuspended. */
xYieldPending[xPortGetCoreID()] = pdTRUE;
}
else if ( pxTCB->xCoreID != xPortGetCoreID() )
{
taskYIELD_OTHER_CORE( pxTCB->xCoreID, pxTCB->uxPriority );
xYieldPending[ xPortGetCoreID() ] = pdTRUE;
}
else
{
@@ -5791,15 +5852,11 @@ TickType_t uxTaskResetEventItemValue( void )
}
#endif
if( tskCAN_RUN_HERE(pxTCB->xCoreID) && pxTCB->uxPriority > pxCurrentTCB[ xPortGetCoreID() ]->uxPriority )
if( prvCheckForYield( pxTCB, xPortGetCoreID(), pdFALSE ) )
{
/* The notified task has a priority above the currently
* executing task so a yield is required. */
portYIELD_WITHIN_API();
}
else if ( pxTCB->xCoreID != xPortGetCoreID() )
{
taskYIELD_OTHER_CORE(pxTCB->xCoreID, pxTCB->uxPriority);
taskYIELD_IF_USING_PREEMPTION();
}
else
{
@@ -5929,7 +5986,7 @@ TickType_t uxTaskResetEventItemValue( void )
vListInsertEnd( &( xPendingReadyList[xPortGetCoreID()] ), &( pxTCB->xEventListItem ) );
}
if( tskCAN_RUN_HERE(pxTCB->xCoreID) && pxTCB->uxPriority > pxCurrentTCB[ xPortGetCoreID() ]->uxPriority )
if( prvCheckForYield( pxTCB, xPortGetCoreID(), pdFALSE ) )
{
/* The notified task has a priority above the currently
* executing task so a yield is required. */
@@ -5937,10 +5994,11 @@ TickType_t uxTaskResetEventItemValue( void )
{
*pxHigherPriorityTaskWoken = pdTRUE;
}
}
else if ( pxTCB->xCoreID != xPortGetCoreID() )
{
taskYIELD_OTHER_CORE( pxTCB->xCoreID, pxTCB->uxPriority );
/* Mark that a yield is pending in case the user is not
* using the "xHigherPriorityTaskWoken" parameter to an ISR
* safe FreeRTOS function. */
xYieldPending[ xPortGetCoreID() ] = pdTRUE;
}
else
{
@@ -6019,7 +6077,7 @@ TickType_t uxTaskResetEventItemValue( void )
vListInsertEnd( &( xPendingReadyList[xPortGetCoreID()] ), &( pxTCB->xEventListItem ) );
}
if( tskCAN_RUN_HERE(pxTCB->xCoreID) && pxTCB->uxPriority > pxCurrentTCB[ xPortGetCoreID() ]->uxPriority )
if( prvCheckForYield( pxTCB, xPortGetCoreID(), pdFALSE ) )
{
/* The notified task has a priority above the currently
* executing task so a yield is required. */
@@ -6027,10 +6085,11 @@ TickType_t uxTaskResetEventItemValue( void )
{
*pxHigherPriorityTaskWoken = pdTRUE;
}
}
else if ( pxTCB->xCoreID != xPortGetCoreID() )
{
taskYIELD_OTHER_CORE( pxTCB->xCoreID, pxTCB->uxPriority );
/* Mark that a yield is pending in case the user is not
* using the "xHigherPriorityTaskWoken" parameter in an ISR
* safe FreeRTOS function. */
xYieldPending[ xPortGetCoreID() ] = pdTRUE;
}
else
{

View File

@@ -23,6 +23,9 @@ esp_event_loop_handle_t loop_without_task;
static void application_task(void* args)
{
// Wait to be started by the main task
ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
while(1) {
ESP_LOGI(TAG, "application_task: running application task");
esp_event_loop_run(loop_without_task, 100);
@@ -58,6 +61,9 @@ static void task_iteration_handler(void* handler_args, esp_event_base_t base, in
static void task_event_source(void* args)
{
// Wait to be started by the main task
ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
for(int iteration = 1; iteration <= TASK_ITERATIONS_COUNT; iteration++) {
esp_event_loop_handle_t loop_to_post_to;
@@ -112,12 +118,19 @@ void app_main(void)
ESP_ERROR_CHECK(esp_event_handler_instance_register_with(loop_with_task, TASK_EVENTS, TASK_ITERATION_EVENT, task_iteration_handler, loop_with_task, NULL));
ESP_ERROR_CHECK(esp_event_handler_instance_register_with(loop_without_task, TASK_EVENTS, TASK_ITERATION_EVENT, task_iteration_handler, loop_without_task, NULL));
// Create the event source task
TaskHandle_t task_event_source_hdl;
ESP_LOGI(TAG, "starting event source");
xTaskCreate(task_event_source, "task_event_source", 3072, NULL, uxTaskPriorityGet(NULL) + 1, &task_event_source_hdl);
// Create the event source task with the same priority as the current task
xTaskCreate(task_event_source, "task_event_source", 3072, NULL, uxTaskPriorityGet(NULL), NULL);
// Create the application task
TaskHandle_t application_task_hdl;
ESP_LOGI(TAG, "starting application task");
// Create the application task with the same priority as the current task
xTaskCreate(application_task, "application_task", 3072, NULL, uxTaskPriorityGet(NULL), NULL);
xTaskCreate(application_task, "application_task", 3072, NULL, uxTaskPriorityGet(NULL) + 1, &application_task_hdl);
// Start the event source task first to post an event
xTaskNotifyGive(task_event_source_hdl);
// Start the application task to run the event handlers
xTaskNotifyGive(application_task_hdl);
}