but it show arrows without much explanation. To make sense of it, I drew my own state diagram where each state has a stay condition (shown as a self-loop) and entry/exit conditions (shown on arrows). My idea is that every state represents exactly one condition of the system, and the system can only stay in that state while the stay condition is true. When the condition changes, the system should exit and go to another state
What I am not fully sure about is the exact conditions for each state. For example, in the Ready state I am thinking the task only stays there while the scheduler has not picked it, and in the Running state it stays there until it gets preempted, blocked, or suspended. In the Blocked state I assume the stay condition is always waiting for an event or a timeout, and in the Suspended state I think it stays there until it is explicitly resumed. Can someone please help with the correct conditions to stay and to exit from each state in the RTOS task model?
I think it might be helpful to read the books referenced on the page with the image.
A quick summary of the transitions.
From Running:
Moves to Ready if a higher priority task becomes ready, of on a tick interrupt if another ready task exists at the same priority level
Moves to Blocked or Suspended if it calls a function that makes it go into one of those states
For SMP systems, if another task calls vTaskSuspend targeting this task, move to the suspend state.
From Ready:
Moves to Running if it becomes the highest priority ready task
For SMP systems, if another task calls vTaskSuspend targeting this task, move to the suspend state.
From Blocked:
Moves to Ready if the blocking condition is satisfied, be it by time or the object it was blocked on becoming ready or another task calls xTaskAbortDelay targeting this task.
For SMP systems, if another task calls vTaskSuspend targetting this task, move to the suspend state.
From Suspended:
Moves to Ready if the object that the task is waiting on becomes ready, or if some task calls vTaskResume targeting this task.
Thank you for the explanation . I’m starting to understand things better now.
In FreeRTOS, each task can be in one of several states, but only one at a time.
In the Ready state, tasks are waiting for CPU time. The scheduler chooses the highest-priority task from this state and gives it control of the CPU. That task then moves from Ready to Running state.
In the Running state, the task keeps running until:
A higher-priority task becomes Ready to run (pre-emption),
It voluntarily gives up the CPU (for example, by calling a delay )
Another task suspends it.
In the Blocked state, the task is waiting for a delay to expire. When the wait ends, the task moves from Blocked state to Ready state.
In the Suspended state, the task has been stopped by another task. It will only return to Ready when another task tells it to continue.
If an interrupt occurs, the task that is currently running should be paused and the CPU starts executing the Interrupt Service Routine (ISR). Tasks that are in Ready, Blocked, or Suspended states are not paused because they were not running. After the ISR finishes, task that was running before will continue.
Also, running task becomes ready if the scheduler is called (usually by system tick timer) and there is another same priority task in ready state. This way CPU time is shared between several same priority tasks.
Not only the delay expiration may set the task Ready. Before delay expiration, an event may trigger Ready state.
Not exactly. The task may get suspended, for example, if it waits an item from a queue and infinite timeout for queue reception is set (portMAX_DELAY value). In this case, the task calls xQueueReceive() and if there is none items in the queue, the queue API sets the task suspended until an item queued.
The task can suspend itself directly by calling vTaskSuspend() with NULL or own task hangle as an argument. Or can suspend itself indirectly by waiting an event with infinite timeout.
Strictly speaking, while an ISR is executing, the task which was in Running state remains Running. Usually, any task and the scheduler are not aware if an interrupt is occurring. ISR processing evolves hardware context switching and whole OS is freezing for ISR time. So from RTOS point of view, while ISR is executing, the task remains Running. But whole task processing is paused by CPU hardware.
This wording is incorrect. Task processing is not “paused” during ISR execution, it is just very simply (st least on a single processor core) that ISRs have higher priorities than tasks and thus do not leave CPU cycles for tasks until done. Also, “whole OS is freezing” is wrong. ISRs may (and frequently will) employ OS services during execution and/or may get be preempted by nested higher OS relevant priority interrupts. For example, although that is it discouraged, the sys timer tick may run at a priority where it can interrupt other ISRs and invoke the scheduler. In that case, a task switch may be triggered at ISR time (which of course will only take effect once both ISRs have terminated).
Hi, @RAc! Thank you for correction and clarification. Can’t argue here. But this:
seems to me almost impossible to do. Recently I had to go deep into scheduler context switch mechanism and sure the context can not be switched being inside of other ISR. For this purpose, pre-empted ISR should have some kind of TCB to let the scheduler a clue where is ISR stack and which is ISR priority and how to resume an ISR after processing higher priority tasks. Also there may be difficulties with privileged mode entering/exiting. If the task have higher priority than an ISR, it should be executed like a nested interrupt in machine mode. But by design (at least on all modern CPU with different privileged modes), OS tasks should be executed at user level, not at machine one. And this may increase the complexity of context switch inside of an ISR.
Had You practiacl example of context switch while pre-empting other ISR?
No. I’m reflexively typing a replay for the sentence just saw going no further.
Newer the less, as I saw in port sources, the context switching is assuming the context switch ISR is on top. And the scheduler changes stack pointer and program counter by task list data and is not aware about an interrupt it pre-empting. And I sure, the system got corrupted if context switch will occur inside of an interrupt.
Nikolay, you a) need to be more careful of your wording and b) still appear to have only a shady idea of what happens. An OS can not “freeze” or “pause,” it is not an active entity similar to a task.
Assuming a CPU like an ARM cortex, the sequence is this:
Some event asks the OS to prepare a task switch. That means that the task currently employing the CPU should be suspended in favor of another task. That happens via code residing in API services explicitly (such as in xSemaphoreGiveFromISR() or xSemaphoreGive()) or implicitly (such as implemented in the SysTick ISR) being invoked by either ISRs or task code. That code manipulates the data structures used by the OS to manage task lists and states.
A PendSVC interrupt is then scheduled as a side effect.
The PendSVC ISR Handler, running at lowest priority (this is mandatory, see below), once having a chance to execute, will replace the context it was interrupted in by the context of the next task that was chosen to replace the current one in step 1. The reason that the PendSVC IST must run at lowest priority is that it must assume that it interrupted (“was supposed to return to”) a task context, not an ISR context.
At no time is this sequence of events “paused” or “frozen.” It simply assures that context switching appears orderly and predictably.