vTaskDelayUntil(), vTaskSuspend(), vTaskResume()

clendinning wrote on Monday, June 06, 2016:

I’ve not been able to get vTaskDelayUntil() and vTaskSuspend() to work well together. It seems that if I call a vTaskSuspend() during the period that vTaskDelayUntil() has the task blocked, that the task is taken to the Ready Pending state, rather than suspended. At least that is what a trace of vTaskResume() appeared to indicate, when it failed to find that the task was in a suspended state.

I tried setting the wake time and then calling a vTaskResume() as was described in other posts with no success. Has anyone else noticed this behavior? I’m trying to suspend a periodic task, to be resumed at a later time. In order to do so, I tried to use a vTaskSuspend(NULL) just after the task awakened from a vTaskDelayUntil(). Of course the task was then put on the block list. The task seemed to have suspended, or at least didn’t execute again, but could not be resumed as described above.

rtel wrote on Tuesday, June 07, 2016:

What you are reporting is the expected behaviour. See the state diagram
on the following page: http://www.freertos.org/RTOS-task-states.html

clendinning wrote on Tuesday, June 07, 2016:

I would have thought, after calling a vTaskSuspend(), even during the block period of a vTaskDelayUntil(), that the task state would gone to a suspended state, either overriding the block, or moving from ready to suspended, as per the diagram. However, it appeared to be in a ready state when the vTaskResume() was called, causing the resume to be ignored. One would have expected the task to run, due to the ready state, but it did not. I don’t see that as the expected behavior.

rtel wrote on Tuesday, June 07, 2016:

In which case I don’t think I understand your post/question.

Maybe it is related to the use of vTaskDelayUntil() - the first parameter to which stores the last wake time. If you suspend a task that called vTaskDelayUntil() for a time that is greater than the next time the task would otherwise have executed then the variable that holds the last wake time will be out of date. In that case I would expect the periodic task to execute immediately a number of times after it is resumed, until the last wake time has caught up with the actual time.

…but I don’t think that is what you are describing.

clendinning wrote on Tuesday, June 07, 2016:

I have a task that is to wake periodically and start another task. I would like to suspend and resume the periodic task at will. When the periodic task is created with vTaskCreate(), it is immediately suspended, before the call to vTaskStartScheduler(). Later, calling a vTaskResume(), it begins to run. After a specified number of loops at the specified period, the task suspends itself with a vTaskSuspend() called directly after waking and calling vTaskDelayUntil() for the next period.

I would think that the periodic task would move from the blocked caused by the vTaskDelayUntil(), to the suspended state at that point. However, the next time a vTaskResume() is called, the task fails to start again.

rtel wrote on Tuesday, June 07, 2016:

When the
periodic task is created with vTaskCreate(), it is immediately
suspended, before the call to vTaskStartScheduler().

So when the scheduler starts the task is in the Suspended state.

Later, calling a
vTaskResume(), it begins to run.

After vTaskResume() has been called the task moves out of the Suspended
state into the Ready state - and depending on its priority relative to
other tasks in the Ready state - may also move into the Running state.

If the task is now periodically calling vTaskDelayUntil() it will move
from the Running state into the Blocked state each time it calls
vTaskDelayUntil(), then out of the Blocked state into the Ready state
(it must have been in the Running state to call vTaskDelayUntil(), and
to be in the Running state it must have come from the Ready state as
only Ready tasks can be selected to run) each time the block time
expires. Again, depending on the task’s priority relative to other
Ready state tasks, the task will enter the Running state.

After a specified number of loops at
the specified period, the task suspends itself with a vTaskSuspend()

At which point it will move from the Running state into the Suspended state.

called directly after waking and calling vTaskDelayUntil() for the next
period.

So it calls vTaskSuspend() after it unblocks from a vTaskDelayUntil()
call? The sequence is not clear here but I don’t think it is relevant.

If this is the sequence then I have annotated with the states:

vTaskDelayUntil(); [Running state → Blocked state]
[Back to Ready/Running state on timeout]
vTaskSuspend(); [Running state → Suspended state]

I would think that the periodic task would move from the blocked caused
by the vTaskDelayUntil(), to the suspended state at that point.

After the task unblocks it will move to the Ready/Running state
depending on priority, and only enter the Suspended state when it
suspends itself (or another task suspends it).

clendinning wrote on Tuesday, June 07, 2016:

vTaskDelayUntil(); [Running state -> Blocked state]
[Back to Ready/Running state on timeout]
(resume a class to do the real periodic work, which suspends itself after finishing its duties)
.
.
vTaskDelayUntil(); [Running state -> Blocked state]
[Back to Ready/Running state on timeout]
(resume a class to do the real periodic work, which suspends itself after finishing its duties)
.
.
n repeats
.
.
vTaskDelayUntil(); [Running state -> Blocked state]
vTaskSuspend(); [Blocked state -> Suspended state]
.
.
random amount of time
.
.
vTaskResume()
.
.
The task does not start.

Another interesting artifact using vTaskDelayUntil() is that, the periodic task called vTaskResume() for another task, which had a taskENTER_CRITICAL(), task EXIT_CRITICAL() pair. I thought the critical section was to prevent context switching, however it disabled interrupts, causing vTaskDelayUntil() to be robbed of system timer ticks so that the delay was too long by the amount of time between the ENTER_CRITCAL and EXIT_CRITICAL.