vTaskSuspend/vTaskResume oddity

dcrocker wrote on Monday, September 10, 2018:

I had some strange behaviourwhen trying to use these functions. My main task (task1) was doing this:

vTaskSuspend(task2handle);
... // store some variables that task2 will read
vTaskResume(task2handle);

task2 has a higher priority than task1, and task2 spends most of its time waiting for an interrupt, by calling ulTaskNotifyTake. The ISR does this:

BaseType_t higherPriorityTaskWoken = pdFALSE;
vTaskNotifyGiveFromISR(task2handle, &higherPriorityTaskWoken);
portYIELD_FROM_ISR(higherPriorityTaskWoken);

What I find it that if task1 runs in a loop making the suspend/resume call and doing other stuff as well, but never blocking, task2 doesn’t run. If I put a delay call in the task1 loop, then task2 runs sporadically. If I replace the vTaskSuspend call by taskENTER_CRITICAL() and vTaskResume by taskEXIT_CRITICAL() then the program runs correctly, even without the delay call in the task1 loop.

There is one more task in the system: task3, which has the same priority as task2 and also spends most of its time either waiting for an interrupt or delaying.

What am I doing wrong? I was expecting vTaskSuspend and vTaskResume to behave similarly to taskENTER_CRITICAL() and taskEXIT_CRITICAL() with respect to when task2 does and doesn’t run. In particular, if the interrupt occurs when task2 has been suspended by the call to vTaskSuspend(task2handle), I was expecting task2 to be scheduled when task1 makes the vTaskResume(task2handle) call. Or do I need to take some special action to tell the scheduler to schedule task2 if this happens, the same way I have to in the ISR?

I’m using FreeRTOS 10.0.0 built for ARM_CM4F.

rtel wrote on Monday, September 10, 2018:

vTaskSuspend(task2handle);
… // store some variables that task2 will read
vTaskResume(task2handle);

task2 has a higher priority than task1

So task 1 will only run when task 2 is blocked, presumably waiting on
the notification - does the task block anywhere else?

, and task2 spends most of its
time waiting for an interrupt, by calling ulTaskNotifyTake. The ISR does
this:

BaseType_t higherPriorityTaskWoken = pdFALSE;
vTaskNotifyGiveFromISR(task2handle, &higherPriorityTaskWoken);
portYIELD_FROM_ISR(higherPriorityTaskWoken);

If task 2 is blocked waiting for a notification when it is suspended and
then resumed, it will not return to wait for the notification again but
simply exit the notify wait API function - you would then have to check
the function’s return value to know if a notification was actually
received. In this case I think you would be better protecting the area
using a vTaskSuspendAll()/xTaskResumeAll() pair.