This shows you the differences between two versions of the page.
| Both sides previous revision Previous revision Next revision | Previous revision | ||
|
realtime:documentation:howto:howto_rt_application_base [2016/09/27 16:58] anna-maria adapt link to sched_policy_prio |
— (current) | ||
|---|---|---|---|
| Line 1: | Line 1: | ||
| - | ====== 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 [[realtime:documentation:technical_basics:sched_policy_prio|scheduling policy]] as well as the priority | ||
| - | must be set by the application explicitly. There are two possibilities | ||
| - | for this: | ||
| - | |||
| - | - **Using ''sched_setscheduler()''** \\ <wrap> | ||
| - | This funcion needs to be called in the start routine of the pthread | ||
| - | before calculating RT specific stuff. | ||
| - | </wrap> | ||
| - | - **Using pthread attributes** \\ <wrap> | ||
| - | The functions ''pthread_attr_setschedpolicy()'' and | ||
| - | ''pthread_attr_setschedparam()''offer the interfaces to set policy and | ||
| - | priority. Furthermore scheduler inheritance needs to be set properly | ||
| - | to PTHREAD_EXPLICIT_SCHED by using ''pthread_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. | ||
| - | </wrap> | ||
| - | |||
| - | ==== Memory locking ==== | ||
| - | |||
| - | In real-time applications it is important to avoid non-deterministic | ||
| - | behavior. If the memory that is needed by the real-time application | ||
| - | is not locked in the RAM, this memory could be paged out. If the | ||
| - | memory is not paged in when the application tries to access the | ||
| - | memory, a page fault occurs causing non-deterministic high latency. | ||
| - | For this reason memory should be locked in real-time applications. | ||
| - | The memory lock persists until the process owning it terminates or | ||
| - | explicitly unlocks it by calling ''munlock()'' or ''munlockall()''. | ||
| - | Be aware that page faults due to paged out memory occur in systems | ||
| - | with swap as well as in systems without swap. In addition, the binary | ||
| - | of the executed application itself could be paged out. | ||
| - | |||
| - | The following call of ''mlockall()'' locks all current pages mapped | ||
| - | into the address space of the process as well as all pages that will | ||
| - | be mapped in the future. | ||
| - | |||
| - | mlockall(MCL_CURRENT|MCL_FUTURE); | ||
| - | |||
| - | ==== Stack prefaulting ==== | ||
| - | |||
| - | Since page faults cause non-deterministic behavior, the stack should | ||
| - | be prefaulted before the real-time critical section starts. | ||
| - | In case several real-time threads are used, it should be done for each | ||
| - | thread individually. In the following example, a memory block of a | ||
| - | certain size is allocated. All of its pages are touched to get them | ||
| - | mapped into RAM ensuring that no page faults occur later. | ||
| - | |||
| - | void *buffer; | ||
| - | |||
| - | buffer = mmap(NULL, MSIZE, PROT_READ | PROT_WRITE, | ||
| - | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); | ||
| - | memset(&buffer, 0, MSIZE); | ||
| - | |||
| - | The prefaulted stack can be assigned to a thread. (''&attr'' is a | ||
| - | ''pthread_attr_t'' pointer; the pthread attribute needs to have been | ||
| - | previously initialized): | ||
| - | |||
| - | pthread_attr_setstack(&attr, buffer, PTHREAD_STACK_MIN); | ||
| - | |||
| - | ===== Example ===== | ||
| - | |||
| - | <code c> | ||
| - | /* | ||
| - | * POSIX Real Time Example | ||
| - | * using a single pthread as RT thread | ||
| - | */ | ||
| - | |||
| - | #include <stdlib.h> | ||
| - | #include <stdio.h> | ||
| - | #include <time.h> | ||
| - | #include <sched.h> | ||
| - | #include <sys/mman.h> | ||
| - | #include <string.h> | ||
| - | #include <pthread.h> | ||
| - | #include <limits.h> | ||
| - | |||
| - | void *thread_func(void *data) | ||
| - | { | ||
| - | /* Do RT specific stuff here */ | ||
| - | return NULL; | ||
| - | } | ||
| - | |||
| - | int main(int argc, char* argv[]) | ||
| - | { | ||
| - | struct sched_param param; | ||
| - | void *stack_buf; | ||
| - | pthread_t thread; | ||
| - | pthread_attr_t attr; | ||
| - | int ret; | ||
| - | |||
| - | /* Lock memory */ | ||
| - | if(mlockall(MCL_CURRENT|MCL_FUTURE) == -1) { | ||
| - | printf("mlockall failed: %m\n"); | ||
| - | exit(-2); | ||
| - | } | ||
| - | |||
| - | /* Pre-fault stack for the thread */ | ||
| - | stack_buf = mmap(NULL, PTHREAD_STACK_MIN, PROT_READ | PROT_WRITE, | ||
| - | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); | ||
| - | if (stack_buf == MAP_FAILED) { | ||
| - | printf("mmap failed: %m\n"); | ||
| - | exit(-1); | ||
| - | } | ||
| - | memset(stack_buf, 0, PTHREAD_STACK_MIN); | ||
| - | |||
| - | /* Initialize pthread attributes (default values) */ | ||
| - | ret = pthread_attr_init(&attr); | ||
| - | if (ret) { | ||
| - | printf("init pthread attributes failed\n"); | ||
| - | goto out; | ||
| - | } | ||
| - | |||
| - | /* Set pthread stack to already pre-faulted stack */ | ||
| - | ret = pthread_attr_setstack(&attr, stack_buf, PTHREAD_STACK_MIN); | ||
| - | if (ret) { | ||
| - | printf("pthread setstack 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: | ||
| - | munmap(stack_buf, PTHREAD_STACK_MIN); | ||
| - | return ret; | ||
| - | } | ||
| - | |||
| - | </code> | ||