Real-Time Applications with RTLinux

RTLinux gives you a hard real-time, low-level environment when you need it--and all the power and flexibility of Linux when you don't.
Task One--The Suspension Controller

Task 1 can be easily implemented using the POSIX interface. Listing 1 shows the structure as it would be implemented in RTLinux.

Listing 1. Suspension Controller
#include <rtl.h>
#include <time.h>
#include <pthread.h>
#define TASK_PERIOD 100000
         /* 100 microseconds period */
         /* priority assigned to task */
pthread_t thread;
void * task_one(void *arg) {
        struct sched_param p;
        p . sched_priority = TASK_PRIORITY;
        pthread_setschedparam (pthread_self(),
        pthread_make_periodic_np (pthread_self(),
        /* startup controller
           initialization routine
            goes here */
        while (1) {
             /* periodic controller
                routines go here */
        return 0;
int init_module(void) {
        pthread_create (&thread, NULL, task_one, 0);
        return 0;
void cleanup_module(void) {
        pthread_cancel (thread);
        pthread_join (thread, NULL);

Here, the init_module() and cleanup_module() functions can be seen as the RTLinux equivalent of the main() function in user-level C programs. Upon startup, the init_module() function is called. This function then immediately tells the scheduler to create a new thread--where the function task_one() comprises the body of the thread--and sets up permissions to enable floating point calculations. Likewise, when the program is stopped, the cleanup_module() function is executed, which in turn stops the thread from further execution, removes permissions to use the floating point unit and quits.

The thread itself can be separated into three segments--initialization, periodic and shutdown--which are represented in the code, respectively, by the segments prior to, inside and after the ``while'' loop.

First, during initialization, we establish the attributes for this particular thread. We specify the scheduler type to use (SCHED_FIFO), the priority and the frequency at which the thread will be called by the scheduler, and we perform all tasks necessary to initialize our controller.

Next, during the periodic segment, we first encounter the call to pthread_wait_np(), which causes the thread to block until the scheduler calls it again. Thus, the thread will execute the entire contents of the while loop once per execution cycle. Note that in this particular example the shutdown part of our code will never execute, since there is no provision in our example code to exit the while loop. Instead, it will be terminated immediately upon execution of the cleanup_module().

Task Two--Spin Rate Measurement

There are several ways of implementing this second task. In what follows, we shall focus on two: an Interrupt Service Routine running within RTLinux, and a signal handler running within a user-level Linux task.

To run Task 2 as an Interrupt Service Routine (ISR), we need to add the following to the code for Task 1 above (assuming that we are using IRQ 7):

#define IRQ 7<\n>
unsigned int example_isr(unsigned int, struct pt_regs *);
unsigned int example_isr(unsigned int irq_number, struct pt_regs *p)
  /* insert non FP dependent
     calculations here */

However, in order to tell RTLinux to associate example_isr() to IRQ 7, we must use the rtl_request_irq() and rtl_hard_enable() functions in init_module():

rtl_request_irq(IRQ, example_isr);<\n>
   /* <-- I/O IRQ initialization
      routines go here  --> */
And we must of course clean up after ourselves, so we add the following to cleanup_module():
The problem becomes more interesting for the implementation of the third task. The thread for Task 3 is created in much the same way as was done for Task 1, however we now use our aforementioned ISR to trigger the first execution of Task 3. The subsequent 15 executions of Task 3 have a period, P, that is dependent on the interarrival times, T, of IRQ 7 as P=T/(16+1). But that's getting beyond the scope of the present discussion.

An even more interesting example of the rich RTLinux programming API can be seen with an alternative approach to the development of Task 2. Suppose that instead of executing Task 2 within RTLinux, we instead would like to execute it in Linux itself. For example, let's say that we now want to combine the functionality of Tasks 2 and 4: We want to plot a point to the screen each time that the rotor rotates once about its axis. We can write an application in Linux that first intercepts IRQ 7 and then plot the spin speed to the screen.

Our user-level Linux program would use the rtlinux_sigaction() function--first introduced in RTLinux V3.0--to first identify a handler within our program that would be executed each time that IRQ 7 is triggered.