Hola Friends!! Welcome back to the second part of the blog series on Real-Time Operating System or RTOS. In our previous blog of Introduction to RTOS, RTOS was briefly introduced and we pondered upon questions like what it is, how it is different from other OS (Operating Systems), why they are needed and the like. In this, we will learn about the RTOS architecture, and discuss the components involved in brief.
Before we begin, it’s important to note that any OS is divided into two spaces, kernel space and user space. Space, where the kernel or the core of the OS executes and provides its services, is known as kernel space. In contrast, the User space is the space of the system memory where user processes run. We will discuss more in-depth about the kernel as we go ahead, which forms a very critical part of the RTOS.
The functionalities and therefore the architecture of your system mostly depends on the nature of the applications for which it is being deployed. If your applications are relatively simple, the RTOS consists of only a kernel, however for more complex scenarios, the kernel can be coupled with modules like debugging facilities, networking protocols, and others (given below) to increase the overall functionality of RTOS.
Since, the majority of the time our requirements are such that the kernel is sufficient and extra modules aren’t really required, we won’t be learning about them here. Instead, we will keep our focus on the kernel only and discuss that in depth.
In an OS, the kernel is the smallest and the central component. It provides services to manage memory and devices, a framework for various applications to utilize the resources among many other things. Depending upon the architecture of the OS, a kernel may also provide additional services like management of protection of programs and multitasking.
Broadly, kernels are divided into three models, monolithic kernel, microkernel and exokernel. More information on the various models can be explored further by the reader using the internet.
Usually, an RTOS avoids the monolithic kernel but instead implements a microkernel architecture with added capabilities that are configurable. As a result of this model, the flexibility in the configuration of the kernel and its functionalities according to the embedded application is dramatically increased. If programmed properly, such an approach helps in increasing the reliability and robustness of the embedded system for the particular application.
The kernel of an RTOS provides the abstraction layer between the application software and hardware, which consists of six main types of common services that the kernel provides to the application software.
RTOS allows for management of individual tasks according to a person's need. This allows the user to follow a modular approach for their software design, where different sections of code running concurrently, have a distinct target or goal with unique deadlines. These sections are small, schedulable and sequential program units which in real-time context are known as “tasks”.
These tasks are the basic units of execution that are used to achieve multitasking in real-time applications. They are governed by time-dependent properties like-
- Release Time: Point in time from which the execution of task has to start.
- Deadline: Point in time by which the task needs to be finished.
- Execution Time: Time is taken by the task to execute completely.
In RTOS, task objects are used to implement the concept of tasks into the software design, and they are defined by the following components-
- TCB or Task Control Blocks are data structures that reside in the RAM (Random Access Memory) and contain information about the status of each task. They are held in a block of memory and are accessible only by RTOS.
- Task Stack refers to the data defined in the program that resides in the RAM and is accessible by the stack pointer.
- Task Routine is the program code, located in the ROM (Read Only Memory).
Any task is capable of existing in any of the four states which are running, ready, waiting or inactive. While a program is being executed, individual tasks are continuously changing their state from one to another. However, for a single-core CPU at any given time, only a single task exists in the running state (Has CPU control).
When the control of CPU is changed between tasks, the to-be-suspended task’s context will be saved and the to-be-executed task’s context will be retrieved. This process of saving and restoring the contexts of the tasks is called context switching, and this aids RTOS in being deterministic.
In order to create and maintain task objects or in essence the tasks themselves, mechanisms such as scheduler and dispatcher are responsible.
The job of keeping record of the state of every single task, deciding which task in the ready state needs to be executed and has to be allotted CPU resources, is taken care of by the scheduler. Therefore, in a multi-tasking program, the scheduler aids in maximizing the utilization of the CPU resources among different tasks and minimizing the waiting time. In general, schedulers are classified into two types-
- Non-Preemptive: Non-preemptive or cooperative scheduling, as the name suggests works on the principle of tasks cooperating amongst themselves and the tasks explicitly giving up CPU control. When a task in the running state is completed, it releases the control of the CPU, and the task with the highest priority in line is executed next. What’s important to note is that the control transfer happens only when the running task gives up its control voluntarily after its completion.
- Preemptive: Preemptive scheduling is priority-based scheduling, where the CPU control is always with the task with the highest priority. Suppose a low-priority task is running and an event occurs that makes a high priority task ready, then the current task is immediately suspended and the control of the CPU is transferred to the higher priority task. What’s important to note here is that the control transfer is involuntary in nature.
The dispatcher can be thought of as the executor as its role is to execute the scheduling decided by the scheduler. It does this by transferring the control of the CPU from one task to another by performing context switching and modifying the execution flow. In RTOS, the flow of the execution is always through one of the three areas- task program code, ISR or the kernel at any given time.
The dispatcher marks the completion of the discussion of the service, Task Management. I hope the above discussion gave you a brief idea of the internal structure of RTOS and how it manages the tasks during its runtime. When programming, you are directly making use of the internal structure and modifying its behavior to suit your needs. However, that is something that we might discuss and implement in the upcoming parts. The remaining services will be continued in the next blog of the series. Till then, stay safe, and I hope you have a nice day!
This blog has been submitted by KRSSG, IIT-Kharagpur under the Robocraze Club Outreach Program.
Author: Ayan Kumar