Scheduler Design
VAIOS employs a preemptive, priority-based scheduling strategy with round-robin execution among tasks of equal priority. The scheduler is designed to provide deterministic task selection with minimal overhead, making it suitable for real-time embedded systems. The flow is shown in Fig. 6.3.
Tasks are organized into multiple ready queues, one for each priority level. The system supports a fixed range of priorities, where higher numerical values correspond to higher scheduling priority. Each ready queue is implemented as a linked list, allowing tasks of the same priority to be scheduled in a round-robin manner. When a running task exhausts its time slice or yields execution, it is reinserted at the end of its corresponding ready queue, ensuring fair execution among tasks with equal priority. The structure is shown in Fig. 6.4.
To enable efficient selection of the next task, VAIOS maintains a bitmap that tracks which priority levels have ready tasks. This allows the scheduler to identify the highest-priority ready task without scanning all queues. The highest active priority is determined by inspecting this bitmap, after which the corresponding ready queue is accessed to select the next task. This approach significantly reduces scheduling overhead and ensures predictable behavior.
The scheduling process is triggered by system events such as time slice expiration, task blocking, or explicit yield requests. When a scheduling event occurs, the current task is evaluated and, if still runnable, returned to the appropriate ready queue. The scheduler then selects the next task based on priority and queue ordering, updates its state to RUNNING, and performs a context switch.
Time slicing is configurable through compile-time parameters and applies to tasks within the same priority level. This allows developers to balance fairness and responsiveness based on application requirements. Higher-priority tasks always preempt lower-priority tasks, ensuring that critical operations receive immediate processor time.
The scheduler also integrates with delayed and blocked task management. Tasks in the DELAYED state are periodically checked against the system tick and moved back to the ready queues when their delay expires. Similarly, tasks waiting on synchronization primitives are transitioned from the BLOCKED state to READY when the required condition is satisfied.