User Tools

Site Tools


realtime:documentation:howto:applications:application_base

This is an old revision of the document!


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:

  1. Using sched_setscheduler()
    This funcion needs to be called in the start routine of the pthread before calculating RT specific stuff.
  2. Using pthread attributes
    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.

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

/*                                                                  
 * 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, &param);
        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;
}
realtime/documentation/howto/applications/application_base.1500082613.txt.gz · Last modified: 2017/07/15 01:36 by jithu