Priority preemption fails in a busy loop

if a task is in a busy loop, a higher-priority task does not preempt it even if configUSE_PREEMPTION == 1, why?

I expected a real-time RTOS with priority preemption to suspend any running task if a higher priority task is on the task ready list. FreeRTOS only does it for timeslicing at the same priority level. This seems like a bug to me, but maybe I misunderstand something. Relevant code in xTaskIncrementTick():

		#if ( ( configUSE_PREEMPTION == 1 ) && ( configUSE_TIME_SLICING == 1 ) )
		{
			if( listCURRENT_LIST_LENGTH( &( pxReadyTasksLists[ pxCurrentTCB->uxPriority ] ) ) > ( UBaseType_t ) 1 )
			{
				xSwitchRequired = pdTRUE;
			}
			else
			{
				mtCOVERAGE_TEST_MARKER();
			}
		}
		#endif /* ( ( configUSE_PREEMPTION == 1 ) && ( configUSE_TIME_SLICING == 1 ) ) */

only checks the same priority, and

	#if ( configUSE_PREEMPTION == 1 )
	{
		if( xYieldPending != pdFALSE )
		{
			xSwitchRequired = pdTRUE;
		}
		else
		{
			mtCOVERAGE_TEST_MARKER();
		}
	}
	#endif /* configUSE_PREEMPTION */

only checks for yield pending.

A workaround is to do a periodic yield, but that becomes cooperative multitasking, not true priority preemption.

Let me try to understand your case. You have 2 tasks something like the following:

void LowPriorityTask( void * param )
{
    for(;;)
    {
         /* Keep Looping. */
    }
}

void HighPriorityTask( void * param )
{
    for(;;)
    {
         /* Keep Looping. */
    }
}

And you are saying that the low priority task keeps running? That would be a very fundamental bug. Which platform are you using? Can you share your code snippet?

Thanks.

I quickly verified it on a STM32 platform and it works as expected i.e. high priority task keeps running and low priority task never runs.

It’s a bit more subtle than that. Start a high-priority task, and a low priority task. The high priority task will run, as expected. Then have it yield, or wait for a short delay with vTaskDelay(), so that the low-priority task gets to busy-loop. The high priority task never gets to run again. Hope this makes sense.

It’s not visible in your example because on task creation the ready list is explicitly checked, unlike in xTaskIncrementTick().

I changed my code to the following:

static void HighPriorityTask( void *param )
{
  ( void ) param;

  for( ;; )
  {
    vTaskDelay( pdMS_TO_TICKS( 100 ) );
  }
}

static void LowPriorityTask( void *param )
{
  ( void ) param;

  for(;;)
  {

  }
}

It still works as expected - I see that high priority task is running periodically.

trying to reply, but the system tells me I’m not allowed to post links, even though there are no links in my reply

Interesting, what you are showing makes sense, but this is not at all what I see:

void high_task(void *p)
{
	int i = 1;
	while (true)
	{
		printf("high %u\n", i++);
		vTaskDelay( pdMS_TO_TICKS( 100 ) );
	}
}

void low_task(void *p)
{
	int i = 1;
	TaskHandle_t taskhandle;

	xTaskCreate(high_task, "high", 1000, NULL, 1, &taskhandle);
	vTaskDelay( pdMS_TO_TICKS( 200 ) );
	while (true)
	{
		printf("low %u\n", i++);
	}
}

void main()
{
	TaskHandle_t taskhandle;
	xTaskCreate(low_task, "low", 1000, NULL, 2, &taskhandle);

    vTaskStartScheduler();
    for (;;)
        ;
}

Output:

high 1
high 2
low 1
low 2
low 3
low 4
low 5
low 6
low 7
low 8
low 9
low 10

For reference, this is the OS version: FreeRTOS Kernel V10.0.1

and it runs on an NXP LPC MCU, bundled and built with MCUXpresso. Maybe that can clarify things.

printf might not be thread safe. Can you remove printf and check by placing breakpoint?

Did that, the breakpoint in the high-priority task is never hit after the vTaskDelay() call in the low-priority task completes.

Seems you set the wrong priorities. The low_task is created with a higher (2) prio than the high_task (1), right ?

lower numbers are higher priorities, as I understand it.

No. See the docs RTOS task priorities in FreeRTOS for pre-emptive and co-operative real time operation
Task priorities are let’s say logical priorities. Low number - low priority.
Don’t get confused with low level interrupt priorities on ARM Cortex-M MCUs where it’s reversed.
There are a number of related posts in the forum like this one:
RTOS task priorities in FreeRTOS for pre-emptive and co-operative real time operation

Confirmed, was my misreading of the direction of priorities. Thanks!