I have a task which is waiting indefinitely for lightweight task notification
ulTaskNotifyTake( pdTRUE, portMAX_DELAY );
The task is in the suspended state. When I try to abort the delay with
xTaskAbortDelay(that_task)
It does not resume running - it stays in the suspended state. Other taks which are waiting indefinitely for an OS object resume running when their delay is aborted.
I tracked this to a point in the OS (tasks.c) where it determines if the task is really suspended or waiting indefinitely
else if( pxStateList == &xSuspendedTaskList )
{
/* The task being queried is referenced from the suspended
list. Is it genuinely suspended or is it block
indefinitely? */
if( listLIST_ITEM_CONTAINER( &( pxTCB->xEventListItem ) ) == NULL )
{
eReturn = eSuspended;
}
else
{
eReturn = eBlocked;
}
}
Tasks waiting indefinitely for an OS object return eBlocked whie the task waiting indefinitely for a lightweight notification return eSuspended, and consequently fail this check
/* A task can only be prematurely removed from the Blocked state if
it is actually in the Blocked state. */
if( eTaskGetState( xTask ) == eBlocked )
{
I encountered this with FreeRTOS 9.0.0 so I tried 10.0.1 but it behaves the same.
The MCU is an NXP Kinetis K24. The compiler is IAR 8.22.1 with low optimization.
Is this how it is supposed to work or is this a bug?
I will look at this, but first some clarification.
How did the task get into the suspended state, and is it really in the
suspended state or just mistakenly reporting it is.
For example, did the task just call ulTaskNotificationTake(, pdTRUE,
portMAX_DELAY ), in which case it would actually be in the Blocked
state, not the Suspended state. Or did it enter the Blocked state in
this way, only to have another task then call vTaskSuspend() to move the
task from the Blocked state to a real Suspended state?
We have a CLI command that prints the task states. With FreeRTOS 9 I had noticed that tasks blocking indefinitely report that they are in the Suspended state - whether they are blocking for an OS object or a lightweight notification. So the task was in in the ‘Suspended’ state only because it called ulTaskNotifyTake() - as were all the other tasks waiting indefinitely for OS objects (queues, etc). The other tasks resume running when their delay is aborted, but the one waiting indefinitely for the lightweight notification stays suspended.
However, when I tried FreeRTOS 10 to see if this had been fixed I noticed that our same CLI command now reports the tasks blocking indefinitely as being in the Blocked state not the Suspended state - except for the one blocking indefinitely for the lightweight notification, it still say it’s in the Suspended state.
The behavior is essentially as I expect if I block for portMAX_DELAY-1 instead of portMAX_DELAY. In this case the task waiting for the lightweight notification says it’s blocked instead of suspended and the abort delay works.
I replied to this via email but the post didn’t show, so appologies if it now shows twice:
I just checked in the following change to the code section you posted before which changes this behaviour. Unfortunately the code view in SourceForge seems to be blank at the moment, hence I’ve just pasted it here, but when SourceForge functions correctly again you will find it here: https://sourceforge.net/p/freertos/code/
else if( pxStateList == &xSuspendedTaskList )
{
/* The task being queried is referenced from the suspended
list. Is it genuinely suspended or is it blocked
indefinitely? */
if( listLIST_ITEM_CONTAINER( &( pxTCB->xEventListItem ) ) == NULL )
{
#if( configUSE_TASK_NOTIFICATIONS == 1 )
{
/* The task does not appear on the vent list item of
and of the RTOS objects, but could still be in the
blocked state if it is waiting on its notification
rather than waiting on an object. */
if( pxTCB->ucNotifyState == taskWAITING_NOTIFICATION )
{
eReturn = eBlocked;
}
else
{
eReturn = eSuspended;
}
}
#else
{
eReturn = eSuspended;
}
#endif
}
else
{
eReturn = eBlocked;
}
}
I just checked in the following change to the code section you posted
before which changes this behaviour. Unfortunately the code view in
SourceForge seems to be blank at the moment, hence I’ve just pasted it
here, but when SourceForge functions correctly again you will find it
here: https://sourceforge.net/p/freertos/code/
else if( pxStateList == &xSuspendedTaskList )
{
/* The task being queried is referenced from the suspended
list. Is it genuinely suspended or is it blocked
indefinitely? */
if( listLIST_ITEM_CONTAINER( &( pxTCB->xEventListItem ) ) == NULL )
{
#if( configUSE_TASK_NOTIFICATIONS == 1 )
{
/* The task does not appear on the vent list item of
and of the RTOS objects, but could still be in the
blocked state if it is waiting on its notification
rather than waiting on an object. */
if( pxTCB->ucNotifyState == taskWAITING_NOTIFICATION )
{
eReturn = eBlocked;
}
else
{
eReturn = eSuspended;
}
}
#else
{
eReturn = eSuspended;
}
#endif
}
else
{
eReturn = eBlocked;
}
}
That seems to have done the trick - for version 9 anyway (in this case I just copied your change into the source. But I think this section of code is the same for 9 and 10. Let me know if you would also like me to retest with version 10.