The whole truth about RTOS from Colin Walls. Article # 4. Tasks, context switching and interrupts

Task Identifiers


You must be able to identify each task in the system. This requirement is important for other kernel objects, but there are some nuances in the tasks that correspond to the topic of this article.



RTOS developers use different approaches to identifying tasks, but four general strategies can be distinguished:


Previous articles in the series:
Article # 3. Tasks and planning
Article # 2. RTOS: Structure and Real Time
Article # 1. RTOS: introduction.

Context switch


Context switching is a procedure for transferring control from one task to another. This topic is worth exploring more closely, since the way context switching works is a fundamental principle of how a RTOS works.

What is the challenge?


We know that a task is a quasi-independent program that shares processor time with a number of other tasks under the control of an RTOS. But you need to think about what really characterizes the task.

Register set


A task is, ultimately, a unique set of processor register values. They are either loaded into the registers of the processor (that is, the task is current), or stored somewhere until the scheduled execution time. In an ideal world, a CPU would have several sets of registers, and each could be assigned to a separate task. This was implemented for special cases. Many years ago, Texas Instruments' TI 9900 series had many sets of registers for each task, but they were implemented in main memory, which limited performance. The SPARC architecture (formerly used in Unix desktop systems) supports many sets of registers in the “ring structure”, but the number of sets is still limited.

Internal data


The task will probably have its own stack, the size of which can be set separately for each task or it can be a global parameter for all tasks in the system. This, along with registers, provides data storage for specific tasks. There may be other areas of memory for storing data intended for a specific task.

Common Resources


Virtually any resources can be shared between tasks. The code can be general: either certain functions, or the entire task code. It is necessary to make sure that the code is reentrant, in the first place, static variables (indicated as static or just outside the function) should not be used. Be careful with standard library modules that are not intended for embedded use; they usually have many non-reentrant functions.

It is also possible to share data, but you need to carefully control access to them. Ideally, only one task is the “owner” of the data at any given time.

How to keep context


When a task is rescheduled (that is, it ceases to be current), its set of registers must be saved somewhere. There are at least two possibilities:


The choice of mechanism depends on the characteristics of the particular RTOS and on the target processor. Some (usually 32-bit) devices can effectively access the stack; the rest (for example, 8-bit) can be more optimal when working with tables.

Dynamic task creation


The main aspect of the RTOS architecture is that the RTOS is either “static” or “dynamic”.

When using static RTOS, everything is determined at the time of building the application, in particular, the number of tasks in the system. This is a logical solution for embedded applications that usually have limited functionality.

Dynamic RTOS triggers one task (which can be a specialized “primary” task), and also creates and deletes other tasks as needed. This allows the system to adapt to changing requirements and is a closer analogue of the desktop system, which behaves in this way. The static / dynamic view also applies to other kernel objects.

Requirement for dynamic task creation


This feature is included in most commercial RTOS. However, only a small part of the application really needs dynamic operation. Very often, the system starts up, creates all the necessary tasks (and other objects), and then never creates anything else or destroys the application code during operation. The ability to create dynamic tasks has become a formality. One supplier introduced it; all others followed suit.

It is noteworthy that the OSEK / VDX standard requires a static architecture, even though it can be applied to fairly complex applications. The result of these requirements is the inability to implement OSEK / VDX using a wrapper, an intermediate layer on top of the usual (dynamic) RTOS.

The pitfalls of dynamic task creation


There are several problems associated with the dynamic mode of operation, which may cause concern.

First, the system becomes more complex, which means that additional information is needed for data structures describing tasks (TCBs). As a rule, they are implemented in the form of bidirectional lists, which leads to costs associated with the amount of memory.
All data describing the task should be stored in RAM. This is inefficient, since most of them may simply be permanent data elements copied from ROM. In addition, on lower-level processors (microcontrollers) may not get RAM.

Perhaps the most worrying is the possibility of an unpredictable shortage of resources, which may lead to the impossibility of creating new objects. Since the essence of the real-time system is its predictability, this is unacceptable. Therefore, care must be taken when using the creation of dynamic tasks (and other objects).

Interruptions


It is possible that an embedded real-time system can be implemented without using interrupts, but this is not typical.

Interrupts and core


When an RTOS is used, the interrupt handler (ISR) is made as easy as possible in order to “steal” the minimum amount of processor time from scheduled tasks. Often, the device can simply be serviced, and any desired task will be queued for processing. In addition, it is difficult to speak in general about interruptions and their interaction with the cores, simply because they vary greatly. On the one hand, the RTOS developer can make interrupts not relate to the kernel at all, and the programmer will have to make sure not to overload the task scheduler using a lot of CPU time in the ISR. On the other hand, the RTOS can fully control the entire interrupt subsystem. None of the approaches described is right or wrong, they are just different.

Saving context


The ISR always needs to maintain a “context” so that the code being interrupted is not affected by the ISR calculations. In a system implemented without RTOS, it is simply a matter of saving any registers used by the ISR (usually on the stack) and restoring them before returning. Some processors have a dedicated ISR stack, others simply use the same stack as the application code.

When using RTOS, the approach may be exactly the same. In the same way, the stack used by the ISR can be “borrowed” from the current task, or it can be another stack allocated for interrupts. Some cores implement this feature, even if the processor itself does not support the interrupt stack. The situation is complicated if the ISR makes an API call that affects the task scheduler. This may cause the interrupt to return to another task from the one that was started when the interrupt occurred.

Interrupts and Scheduler


There are several circumstances in which the ISR execution code can return to another task:


Clock timer (tick clock)


In embedded systems, the use of a periodic "clock timer" (time slice) is often encountered. In some RTOS, it is a required component. Typically, the presence of a clock timer is optional, and its absence simply excludes the availability of certain services. The timer interrupt handler typically provides four functionalities:


When we worked on our own real-time operating system, the MAXROS MAKS (previously published articles about it), our team “stumbled” on the blog of Colin Walls, an expert in the field of microelectronics and firmware of Mentor Graphics. The articles seemed interesting, they were translated for themselves, but in order not to “write to the table” they decided to publish. I hope they will also be useful to you. If so, then we plan to publish all the translated articles in the series.

About the author: Colin Walls has been working in the electronics industry for more than thirty years, spending a significant amount of time on embedded software. He is now an embedded software engineer in Mentor Embedded (a division of Mentor Graphics). Colin Walls often speaks at conferences and seminars, author of numerous technical articles and two books on embedded software. Lives in the UK. Colin's professional blog: blogs.mentor.com/colinwalls, e-mail: colin_walls@mentor.com

Read the first, second and third articles of the cycle, published earlier.

Source: https://habr.com/ru/post/415427/


All Articles