blocking higher priority task. prvProcessTimerOrBlockTask()

niksp wrote on Thursday, October 22, 2015:

Tell me please

Inside the function “prvProcessTimerOrBlockTask ()”,
after the function “vTaskSuspendAll()”,
called “prvSampleTimeNow()”.
Inside it can happen the function callback “pxTimer->pxCallbackFunction((TimerHandle_t) pxTimer)”.

It turns out that the callback function can block higher priority tasks.

I understand correctly?

rtel wrote on Thursday, October 22, 2015:

Your question is not completely clear, but I will try and answer it.

pxCallbackFunction() is the software timer callback function - but it is just a C function being called from an RTOS task (in this case the Timer task http://www.freertos.org/RTOS-software-timer.html) so it can do the same as any other C function being called from a task. Generally, it can unblock a higher priority task, but it can’t really block a higher priority task. It can suspend a higher priority task, but that is a different thing.

richard_damon wrote on Thursday, October 22, 2015:

Timer call back functions are called in the contex of the Timer task, which is high priority (I think the highest allowed), not the task that setup the time. Thus timer call backs will have higher priority than your moderate to sort of high priority tasks.

Does this answer your question?

niksp wrote on Thursday, October 22, 2015:

Function call “pxTimer->pxCallbackFunction((TimerHandle t) pxTimer)” stands between vTaskSuspendAll() and xTaskResumeAll().

If inside ISR will be called xTaskResumeFromISR () for more priority than the “Timer task”,
a context switch is blocked (vTaskSuspendAll()) while there is a execution the callback function. additional delay of switching.

it turns out you can not make the task more priority than “Timer task”?

richard_damon wrote on Thursday, October 22, 2015:

You can make a task have a higher priority by changing the definition of configTIMER_TASK_PRIORITY which lives in FreeRTOSConfig.h
What you can’t do is force a task switch during a vTaskSuspendAll() block.

TImer call backs should be fairly quick though.

richard_damon wrote on Thursday, October 22, 2015:

Looking at the code know, I see a
vTaskSuspendAll() call,
a test to see if we need to call the timer call back
vTaskResumeAll() call, then
prvPrcessExpiredTimer() call which will call pxTimer->psCallbackFunction()

so I don’t see the call back in the context of a SuspendAll() (it may be this is a recent change)

niksp wrote on Thursday, October 22, 2015:

call sequence, which I see ( freertos 8.2.3, file timers.c)

//line 437 in prvTimerTask()
prvProcessTimerOrBlockTask( xNextExpireTime, xListWasEmpty );
{
vTaskSuspendAll();
{
//line 457
xTimeNow = prvSampleTimeNow( &xTimerListsWereSwitched );
//line 540 in prvSampleTimeNow()
prvSwitchTimerLists();
//line 744 in prvSwitchTimerLists()
pxTimer->pxCallbackFunction( ( TimerHandle_t ) pxTimer );

    //and only after that the execution xTaskResumeAll in lines 463, 483, 499
}

}

rtel wrote on Thursday, October 22, 2015:

I think the path you are highlighting is a corner case that, although we
have tests to go through it, is very unlikely to be hit in a real
application. To execute that line you need to be in a situation whereby
the tick count has overflowed && for some reason there are timers in the
‘current’ timer list that have not been processed (maybe could occur if
there was a timer that expired as the tick count overflowed)

Even if that line was executed I don’t think it should cause a problem
as callback functions should not attempt to block, and if the callback
function resulted in a context switch then the context switch would just
be held pending and then performed when the scheduler was resumed.

Or am I missing something?

Regards.

niksp wrote on Friday, October 23, 2015:

Yes, this situation I had in mind.

unlikely, but possible. especially when using configUSE_16_BIT_TICKS - often overflows tickcount. it forces to take into account the execution of a callback function to meet real-time.

Why not put “xTimeNow = prvSampleTimeNow (& xTimerListsWereSwitched); (line 457)” before vTaskSuspendAll () (line 450)? It seems that it solves the problem.

rtel wrote on Friday, October 23, 2015:

It has to be called with the scheduler suspended to ensure the task
lists don’t change during the operation.

Why is it causing an issue for you?

niksp wrote on Friday, October 23, 2015:

Sorry for the many questions,

What if the disable list to switch when the scheduler is suspended,
and repeat the test and switch lists, after resuming the scheduler?

//modified function
prvProcessTimerOrBlockTask(...)
{
	...
	vTaskSuspendAll();
	{
		xTimeNow = prvSampleTimeNow( &xTimerListsWereSwitched );
		if( xTimerListsWereSwitched == pdFALSE )
		{
			...
		}
		else
		{
			//line 499
			( void ) xTaskResumeAll();
			//add new line 500: switch lists without vTaskSuspendAll
			prvSampleTimeNow( &xTimerListsWereSwitched );
		}
	}
}

//modified function
prvSampleTimeNow( BaseType_t * const pxTimerListsWereSwitched )
{
	...
	xTimeNow = xTaskGetTickCount();
	if( xTimeNow < xLastTime )
	{
		//add new line 539: not switch the lists within vTaskSuspendAll
		if (xTaskGetSchedulerState() == taskSCHEDULER_SUSPENDED)
		{
			*pxTimerListsWereSwitched = pdTRUE;
			return 0;
		}
		...
	}
	...
}

I just have a callback function is longer than the required response time to an interrupt and need 100% Satisfaction Guarantee