Linux embedded real-time operating system development and design (six)

xiaoxiao2021-03-06  121

3.3 Real-time tasks

Real-time task is a user-defined program that is executed in accordance with specific scheduling methods under kernel control.

The most beginning design is to give each real-time task with its own address space to provide memory protection. This is paised by the 80x86 processor [10]. In each context switch, the page directory is based on registers to point to page directories for new tasks.

The switch between tasks is very frequent. If it is not hit in TLB, the system is sluggish overhead, and the system performance will be reduced. The other system overhead is the call of the system, and it is also a fee in protection mode.

One way to improve performance is that all real-time tasks run in an address space. The system overhead of the protection mode transformation is removed by using the kernel address space. A very useful feature of Linux is: the kernel module can be loaded. The kernel module can be dynamically connected to the kernel address space, and the link is kernel code. Each module defines two routines: init_module () and cleanup_module (). INIT_MODULE () is called in the module to the kernel, and cleanup_module () is called when the module is deleted. This provides a simple way to operate drivers and file systems in Linux.

The linked module is used to dynamically create real-time tasks in the current RTLinux. This implementation method is also more fragile: an error in a real-time task may cause a collapse of the entire system. The use of C language has increased this problem. Applications of arrays, pointers, etc., can easily cause errors related to memory. On the other hand, since the real-time task generally controls expensive peripheral devices, it is reasonable to use the same warning level as the system kernel programming.

Real-time tasks run in the kernel address space there are several benefits. In addition to the TLB hit issues mentioned above and the problem of protection mode switching, this method allows us to reference functions and objects through the name, stroning to reference through the descriptor. For example, the real-time task is characterized by a structure of a C. Each task can give a C identifier, other tasks can also be referenced by this identifier. Dynamic link execution, the module loads solves the symbol addressing problem, so access is very efficient.

All tasks are also simpler in the system's address space and task. A context switch is to save all integer registers to the stack, and the pointer to change the stack points to the new task. It also supports tasks with floating point operations.

The interface to real-time programming for real-time tasks will be introduced in Chapter 4.

3.3.1 Real Time Thread Data Structure

Struct RTL_THREAD_STRUCT

Struct RTL_THREAD_STRUCT {

INT * stack;

INT fpu_initialized;

RTL_FPU_CONTEXT FPU_REGS;

INT USES_FP;

INT * kmalloc_stack_bottom;

Struct RTL_SCHED_PARAM SCHED_PARAM; / * Thread Scheduling Parameters * /

Struct RTL_THREAD_STRUCT * Next; / * Link list The next thread * /

INT CPU; / * CPU number * /

Hrtime_t resume_time; / * recovery time * /

HRTIME_T Period; / * Task Cycle * /

HRTIME_T TIMEVAL;

Struct Module * CREATOR; / * Thread Created Vener * /

Void (* abort) (void *);

Void * Abortdata;

Int threadflags;

RTL_SIGSET_T PENDING;

RTL_SIGSET_T Blocked;

Void * user [4];

INT errno_val;

Struct RTL_CLEANUP_STRUCT * CLEANUP;

Int magic;

Struct RTL_POSIX_THREAD_STRUCT POSIX_DATA;

Void * TSD [RTL_PTHREAD_KEYS_MAX];

}

Program 3.2 RTL_THREAD_STRUCT structure

3.3.2 Creating threads and thread scheduling

A real-time program is performed using one or several threads. The thread is a lightweight process that shares a common address space. In RTLINUX, all threads share the Linux kernel address space. Thread operations related functions will be introduced in Chapter 4.

3.4 Real-time dispatch

As long as the task of the real-time scheduler is the time requirements for meeting all real-time tasks. There are many ways to indicate time constraints and a lot of scheduling strategies [4]. There is no scheduling policy that is suitable for all tasks.

In most real-time systems, the scheduler consists of large, complex code blocks, which cannot be extended to applicable. The user is only the behavior of the scheduler by adjusting the parameters, often is not enough. General scheduler code is relatively slow.

In RTLinux, users are allowed to write their own scheduler code. It can be implemented as a loadable kernel module. This allows you to experiment with different scheduling strategies and algorithms to find a scheduling method that best suits your application.

3.4.1 Distributor implemented

Two schedulers have been achieved so far. One is a priority-based scheduler. The scheduling strategy is as follows. Each task gives a unique priority. If there are several tasks being ready, the highest priority will run. As long as a priority task is ready, it can interrupt execution of current lower priority tasks. Each task assumes that it can freely discard the CPU.

This scheduler directly supports a periodic task. The cycle and start time of each task can be given. An interrupt driven (non-period) task wakes up the corresponding task by defining an interrupt handler and then by an interrupt handler.

According to the cycle of each task and their termination time, we can determine the priority of each task based on the rate monotonic schedule algorithm (RMS) [5] based on the rate monotonic schedule algorithm. Based on this algorithm, the periodic task has a high priority. Thereof

n

Real-time scheduling of a task, meets the real-time tasks of the following formula will be able to successfully schedul, each task does not exceed their final deadline:

Here, the CI is the period of the maximum execution time of Task I at each cycle, Ti is the period of task I. Non-cycle tasks will be processed as a cycle task, which gives a priority [5].

The scheduler regards Linux as a minimum priority task. Linux is only running when there is no real-time task. To this end, when switching from Linux to real-time tasks, the soft interrupt status will be recorded and the soft interrupt is disabled. When switching back, the soft interrupt status will be restored.

Another scheduler is implemented in accordance with the earliest period priority algorithm (EARLIEST DEADLINE FIRST, EDF). There is no static priority in this algorithm. It is always the most implementation of the task that is closest to the ultimate period.

3.4.2 Designing the user's own scheduler

RTLinux As an open system, RTLINUX has the following advantages to facilitate the user to design your own scheduler to achieve its own unique scheduling mode:

l A total-priority-based kernel based on time-repeatedly

l Have precise and reliable time fragmentation;

l Precise clock control primitive;

l Fast and predictable interrupt response and process switching time;

The RTLinux scheduler is defined in the file RTL_SCHED.C and RTL_SCHEDULE.H, and the real-time thread can be set with a function pthread_attr_setschedParam when creating or in the run pthread_setchedParam changes its priority. Scheduler sets the priority of the system to -1, and all real-time threads are more than zero, thus ensuring real-time thread priority. Users need to change the RTL_SCHEDULE (scheduling process) function; two important data structures: schedule_t and rtl_thread_struct; and task queue task_queue * list, task_queue * destlist.

By modifying the above data structure and scheduling process, users can implement specific scheduling algorithms themselves. 3.5 timing

Accurate timing is the correct scheduler operation. The scheduler often requires task switching at a particular moment. The error will cause a deserted schedule to cause task release jitter [24]. Task release jitter in most applications is not good. To minimize its impact.

One reason for low time accuracy is in the operating system, the cycle clock is used. The system designer must make a fortune between the clock interrupt processing function overhead and the timing accuracy [24]. Sometimes the cycle clock does not get the required timer timing accuracy.

Also in Linux. On the IBM-compatible PC, the clock interrupt rate of the hardware timer is set to about 100 Hz. Therefore, the task can reach the accuracy of 10 milliseconds. Some commercial operating systems, such as VxWorks, REAL / IX is also a clock interrupt of the cycle, although they allow users to change the interrupt frequency.

In RTLinux, eliminating this compromise is to interrupt the CPU by using a programmable interval timer when needed. In particular, the Intel 8354 timer chip operates in Interrupt-on-Terminal-Count mode. Using this mode, the interrupt can be made to get the accuracy of about 1 microsecond. This method of timer accuracy is high and the system overhead is minimal.

The interrupt of a cycle is simulated for Linux. Using soft interrupts is very simple: in order to simulate an interrupt request, an unprocessed interrupt mask is set. When the next soft interrupt is returned, or when the soft STI is executed, the processing function will be called.

3.5.1 Time-related functions

Time-related functions will be introduced in Chapter 4.

3.6 Inter-process communication

Since the Linux kernel may be used by real-time tasks at any time, Linux threads cannot be securely called safely. In any case, there must be some mechanisms of communication (IPC) between processes. RTLinux provides three ways of communication.

3.6.1 FIFO equipment

RTLINUX uses the FIFO pipe to deliver data between Linux processes or Linux kernels with real-time processes, which is called real-time pipes to distinguish between Unix IPC mechanisms.

The RT-FIFO pipe is in the kernel address space. Create through an integer. The number of RT-FIFOS is given when compiling systems, and the system changes can be recompiled.

Operation of RT-FIFOS includes creation, deleting, reading FIFO, and writing FIFO. The read and write operation is atomic operation and cannot be interrupted. Uninterrupted is to avoid priority inverting problems.

In the Linux process, RT-FIOS is used as a normal character device, not a system call. The character device gives the user a full-featured application interface (API) that communicates with real-time tasks. This interface is a standard device interface for Linux processes, including: Open, Close, Read and Write.

Struct File_Operations RTF_FOPS

Static struct file_operations RTF_FOPS =

{

RTF_LLSeek,

RTF_READ,

RTF_WRITE,

NULL,

RTF_POLL,

NULL,

NULL,

RTF_Open,

NULL,

RTF_RELEASE,

NULL,

NULL,

NULL,

NULL,

NULL

}

Here is the original access routine:

INT RTF_CREATE (Unsigned Int Minor, int size)

INT RTF_DESTROY (Unsigned Int Minor)

INT RTF_PUT (unsigned int minor, void * buf, int count)

INT RTF_GET (unsigned int minor, void * buf, int count)

For each FIFO pipeline

INT RTF_CREATE_HANDLER (Unsigned Int Minor, INT (* Handler) (unsigned int FIFO)

Install your own handler, run when the data is read or written in the FIFO.

3.6.2 Sharing Memory

When RTLinux is started, by specifying a MEM parameter to determine the memory size of the kernel, the empty memory space is used for the shared memory for real-time tasks and Linux processes. In this memory in the RTLinux task, the Linux process is addressed in this memory, and the Linux process also provides information provided by the real-time task by reading the data of this memory, which completes communication between real-time tasks and Linux processes.

3.6.3 MBUFF driver

It is a driver that uses shared memory from Tomasz MotyleWSki to achieve sharing between core memory spaces and users. The MBUFF driver uses a linked list to manage the memory by this name by using the MBuff_alloc () function of MBuff_alloc (). This driver can also share memory between Linux kernel memory space including RTLinux and user memory space.

#include

Void * mbuff_alloc (const char * name, int size);

Void MBuff_Free (const char * name, void * mbuf);

When MBuff_alloc is called for the first time, a name is given, and a given shared memory block will be assigned. The reference number of this memory block is set to 1. The call successfully returns a pointer to the new memory block. Returns NULL when fails. If a given name already exists, the pointer to the existing memory block will be returned to operate this block shared memory block, which will add 1.

转载请注明原文地址:https://www.9cbs.com/read-125783.html

New Post(0)