Possible bug with xTaskAbortDelay() and task waiting for notification.

maboytim wrote on Friday, April 27, 2018:

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?

Thanks,

Matt

rtel wrote on Friday, April 27, 2018:

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?

maboytim wrote on Saturday, April 28, 2018:

Hi Richard,

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.

Thanks,

Matt

rtel wrote on Sunday, April 29, 2018:

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;
    }
}

rtel wrote on Sunday, April 29, 2018:

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;
     }
}

maboytim wrote on Monday, April 30, 2018:

Hi Richard,

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.

Thanks,

Matt