A, RTOS system configuration
Overall, the general release version of linux are not real-time systems, the general release version of linux precisely time-sharing system, more emphasis on multi-user time-sharing calls.
Dimensional design process, considered more of a concurrent nature of the system, to ensure a timely response task application processing needs of each user. In real-time systems, it is necessary
Ensure real-time tasks to complete the task within the stipulated time, and therefore how to ensure real-time tasks can perform real-time operating system is the core issue of scheduling mechanism. N can thus be preemptive
Scheduling strategy is the operating system kernel scheduling policy options necessary to ensure the real-time task of the highest priority, once ready is completed, regardless of the load on the system, are able to obtain
The right to use the CPU, to ensure real-time task execution.
Sentence summary is this: Change the kernel configuration, the default sub-time slice scheduling becomes available preemption.
Getting the sources
First, the kernel version should be chosen. After this, take a look if the PREEMPT_RT patch is available for this particular version.
The source of the desired version has to be downloaded (for the Linux kernel as well as for the PREEMPT_RT patch). This example is based on the Linux kernel version 4.4.12.
$ wget https://www.kernel.org/pub/linux/kernel/v4.x/linux-4.4.12.tar.xz $ wget https://www.kernel.org/pub/linux/kernel/projects/rt/4.4/patch-4.4.12-rt19.patch.xz
After downloading, unpack the archives and patch the Linux kernel:
$ xz -cd linux-4.4.12.tar.xz | tar xvf - $ cd linux-4.4.12 $ xzcat ../patch-4.4.12-rt19.patch.xz | patch -p1
Configuring the kernel
The only necessary configuration for real-time Linux kernel is the choice of the “Fully Preemptible Kernel” preemption model (CONFIG_PREEMPT_RT_FULL). All other kernel configuration parameters depend on system requirements. For detailed information about how to configure a kernel have a look at Linux kernel documentation.
When measuring system latency all kernel debug options should be turned off. They require much overhead and distort the measurement result. Examples for those debug mechanism are:
-
DEBUG_PREEMPT
-
Lock Debugging (spinlocks, mutexes, etc. . . )
-
DEBUG_OBJECTS
-
…
Some of those debugging mechanisms (like lock debugging) produce a randomized overhead in a range of some micro seconds to several milliseconds depending on the kernel configuration as well as on the compile options (DEBUG_PREEMPT has a low overhead compared to Lock Debugging or DEBUG_OBJECTS).
However, in the first run of a real-time capable Linux kernel it might be advisable to use those debugging mechanisms. This helps to locate fundamental problems.
Building the kernel
Building the kernel and starting the kernel works similarly to a kernel without PREEMPT_RT patch.
Second, the real-time application development tasks
HOWTO build a simple RT application
The POSIX API forms the basis of real-time applications running under PREEMPT_RT. For the real-time thread a POSIX thread is used (pthread). Every real-time application needs proper handling in several basic areas like scheduling, priority, memory locking and stack prefaulting.
Basic prerequisites
Three basic prerequisites are introduced in the next subsections, followed by a short example illustrating those aspects.
Scheduling and priority
The scheduling policy as well as the priority must be set by the application explicitly. There are two possibilities for this:
-
Using
sched_setscheduler()
This funcion needs to be called in the start routine of the pthread before calculating RT specific stuff. -
Using pthread attributes
The functionspthread_attr_setschedpolicy()
andpthread_attr_setschedparam()
offer the interfaces to set policy and priority. Furthermore scheduler inheritance needs to be set properly to PTHREAD_EXPLICIT_SCHED by usingpthread_attr_setinheritsched()
. This forces the new thread to use the policy and priority specified by the pthread attributes and not to use the inherit scheduling of the thread which created the real-time thread.
Memory locking
See here
Stack for RT thread
See here
Example
/*
* POSIX Real Time Example
* using a single pthread as RT thread
*/
#include <limits.h>
#include <pthread.h>
#include <sched.h>
#include <stdio.h>
#include <stdlib.h> #include <sys/mman.h> void *thread_func(void *data) { /* Do RT specific stuff here */ return NULL; } int main(int argc, char* argv[]) { struct sched_param param; pthread_attr_t attr; pthread_t thread; int ret; /* Lock memory */ if(mlockall(MCL_CURRENT|MCL_FUTURE) == -1) { printf("mlockall failed: %m\n"); exit(-2); } /* Initialize pthread attributes (default values) */ ret = pthread_attr_init(&attr); if (ret) { printf("init pthread attributes failed\n"); goto out; } /* Set a specific stack size */ ret = pthread_attr_setstacksize(&attr, PTHREAD_STACK_MIN); if (ret) { printf("pthread setstacksize failed\n"); goto out; } /* Set scheduler policy and priority of pthread */ ret = pthread_attr_setschedpolicy(&attr, SCHED_FIFO); if (ret) { printf("pthread setschedpolicy failed\n"); goto out; } param.sched_priority = 80; ret = pthread_attr_setschedparam(&attr, ¶m); if (ret) { printf("pthread setschedparam failed\n"); goto out; } /* Use scheduling parameters of attr */ ret = pthread_attr_setinheritsched(&attr, PTHREAD_EXPLICIT_SCHED); if (ret) { printf("pthread setinheritsched failed\n"); goto out; } /* Create a pthread with specified attributes */ ret = pthread_create(&thread, &attr, thread_func, NULL); if (ret) { printf("create pthread failed\n"); goto out; } /* Join the thread and wait until it is done */ ret = pthread_join(thread, NULL); if (ret) printf("join pthread failed: %m\n"); out: return ret; }