Can I do a TaskNotify() before scheduler has started?

unknowcoder wrote on Tuesday, February 20, 2018:

Hello,

I would like to know what the implication are if a function call xTaskNotify() before the scheudler starts?

I understand that there are no task running so doing this makes no sense but at the moment we have code which does it and instead of pushing out a completely new release, for a bug we cannot find.
We want to know if the kernel code is safe to do this.

Thanks

rtel wrote on Wednesday, February 21, 2018:

If the task being notified has already been created, but the scheduler has not been started (so the task cannot be in the Blocked state), then it is probably ok. However I have never tried it and this is not how the feature was ever intended to work - so has not been tested.

viatorus wrote on Thursday, June 27, 2019:

Hello unknowncoder,

this seems to be currently unsafe because of the following code section in xTaskGenericNotifyFromISR: https://sourceforge.net/p/freertos/code/HEAD/tree/trunk/FreeRTOS/Source/tasks.c#l4927

if( pxTCB->uxPriority > pxCurrentTCB->uxPriority )
{
    /* The notified task has a priority above the currently
    executing task so a yield is required. */
    if( pxHigherPriorityTaskWoken != NULL )
    {
    	*pxHigherPriorityTaskWoken = pdTRUE;
    }

    /* Mark that a yield is pending in case the user is not
    using the "xHigherPriorityTaskWoken" parameter to an ISR
    safe FreeRTOS function. */
    xYieldPending = pdTRUE;
}

If the scheduler is not started yet, pxCurrentTCB is NULL and this would be an undefined behavior.

Future more in xTaskGenericNotify : https://sourceforge.net/p/freertos/code/HEAD/tree/trunk/FreeRTOS/Source/tasks.c#l4802

if( pxTCB->uxPriority > pxCurrentTCB->uxPriority )
{
    /* The notified task has a priority above the currently
    executing task so a yield is required. */
    taskYIELD_IF_USING_PREEMPTION();
}

Yield could be called which will definitely result to a hard fault.

We ran in this problem today after a long endurance test. We use task suspend and task resume before the scheduler is started (big embedded application with a C++ abstraction for multiple OS, including freeRTOS ).

Know we saw, task resume has the same UB check as task notify.

@rtel - Could it be possible to check for a valid pxCurrentTCB before accessing it in all currently unsafe places?

This would safe us much trouble. Otherwise we maybe have the change our OS abstraction API which is used alot in our products.

if( pxCurrentTCB && pxTCB->uxPriority > pxCurrentTCB->uxPriority )

Kind regards,
Toni

richarddamon wrote on Thursday, June 27, 2019:

pxCurrentTCB will become not NULL once you create your first task with xTaskCreate(). Since you would need a task to have been created to send a notify to it, it would seem that that would not be an issue. During the pre-scheduler startup time, pxCurrentTCB will be kept pointed to the highest priority ready task. The one case where you might run into an issue is if you suspend all the tasks that have been created, then pxCurrentTCB will become NULL again, as the Idle task hasn’t been created yet as the always ready task to fall back to.

viatorus wrote on Thursday, June 27, 2019:

Okay, thank you for the deeper explanation.

We have the case that every task is directly suspended on creation (in the constructor of the class task). We need to control the exact start of a task.

Since all task are suspended, we have to resume one task before we run vTaskStartScheduler(). But as you said: pxCurrentTCB is now NULL. :frowning:

richarddamon wrote on Friday, June 28, 2019:

My first guess is you are over using suspension of tasks. I find I almost never will suspend a task, because its use during execution can lead to races so easily. I would probably just have all the task start automatically and then immediate wait for a task notifaction, and send that instead of a task resume.

Adding all the checks on pxCurrentTCB would be a bit expensive (maybe not individually, but over the course of the exectuion of the system it adds up), and it is a very corner case that causes the issue. All you need to do is resume one task before you issue the notify and things will be ok.