Next Previous Contents

4. Writing RTLinux Programs

4.1 Introduction to writing modules

So what are modules? A Linux module is nothing but an object file, usually created with the -c flag argument to gcc. The module itself is created by compiling an ordinary C language file without the main() function. Instead there will be a pair of init_module/cleanup_module functions:

Typically, init_module() either registers a handler for something with the kernel, or it replaces one of the kernel function with its own code (usually code to do something and then call the original function). The cleanup_module() function is supposed to undo whatever init_module() did, so the module can be unloaded safely.

For example, if you have written a C file called module.c (with init_module() and cleanup_module() replacing the main() function), the code can be converted into a module by typing :

        $ gcc -c {SOME-FLAGS} my_module.c

This command creates a module file named module.o, which can now be inserted into the kernel by using the 'insmod' command :

        $ insmod module.o

Similarly, for removing the module, you can use the 'rmmod' command :

        $ rmmod module

4.2 Creating RTLinux Threads

A realtime application is usually composed of several ``threads'' of execution. Threads are light-weight processes which share a common address space. In RTLinux, all threads share the Linux kernel address space. The advantage of using threads is that switching between threads is quite inexpensive when compared with context switch. We can have complete control over the execution of a thread by using different functions as will be shown in the examples following.

4.3 An example program

The best way to understand the working of a thread is to trace a realtime program. For example, the program shown below will execute once every second, and during each iteration it will print 'Hello World'.

The Program code (file - hello.c) :

#include <rtl.h>
#include <time.h>
#include <pthread.h>

pthread_t thread;

void * thread_code(void)
{
        pthread_make_periodic_np(pthread_self(), gethrtime(), 1000000000);

        while (1)
        {
                pthread_wait_np ();
                rtl_printf("Hello World\n");
        }

        return 0;
}

int init_module(void) 
{
   return pthread_create(&thread, NULL, thread_code, NULL);
}

void cleanup_module(void) 
{
   pthread_delete_np(thread);
}

So, let us start with the init_module(). The init_module() invokes pthread_create(). This is for creating a new thread that executes concurrently with the calling thread. This function must only be called from the Linux kernel thread (i.e., using init_module()).

        int  pthread_create(pthread_t  * thread,
                            pthread_attr_t * attr,
                            void * (*thread_code)(void *),
                            void * arg);

The new thread created is of type pthread_t, defined in the header pthread.h. This thread executes the function thread_code(), passing it arg as its argument. The attr argument specifies thread attributes to be applied to the new thread. If attr is NULL, default attributes are used.

So here, thread_code() is invoked with no argument. thread_code has three components - initialization, run-time and termination.

In the initialization phase, is the call to pthread_make_periodic_np().

        int pthread_make_periodic_np(pthread_t thread, 
                                     hrtime_t start_time, 
                                     hrtime_t period);

pthread_make_periodic_np marks the thread as ready for execution. The thread will start its execution at start_time and will run at intervals specified by period given in nanoseconds.

gethrtime returns the time in nanoseconds since the system bootup.

       hrtime_t gethrtime(void);

This time is never reset or adjusted. gethrtime always gives monotonically increasing values. hrtime_t is a 64-bit signed integer.

By calling the function pthread_make_periodic_np(), the thread tells the scheduler to periodically execute this thread at a frequency of 1 Hz. This marks the end of the initialization section for the thread.

The while() loop begins with a call to the function pthread_wait_np(), which suspends execution of the currently running realtime thread until the start of the next period. The thread was previously marked for execution using pthread_make_periodic_np. Once the thread is called again, it executes the rest of the contents inside the while loop, until it encounters another call to pthread_wait_np().

Because we haven't included any way to exit the loop, this thread will continue to execute forever at a rate of 1Hz. The only way to stop the program is by removing it from the kernel with the rmmod command. This invokes the cleanup_module(), which calls pthread_delete_np() to cancel the thread and deallocate its resources.


Next Previous Contents