Threaded RT-application with memory locking and stack handling example

From RTwiki
(Difference between revisions)
Jump to: navigation, search
m (New page: ====Threaded RT-application with memory locking and stack touching example==== // Compile with 'gcc thisfile.c -lrt -Wall' #include <stdlib.h> #include <stdio.h> #in...)
 

Revision as of 20:38, 15 January 2008

Threaded RT-application with memory locking and stack touching example

   // Compile with 'gcc thisfile.c -lrt -Wall'
   #include <stdlib.h>
   #include <stdio.h>
   #include <sys/mman.h> // Needed for mlockall()
   #include <unistd.h> // needed for sysconf(int name);
   #include <malloc.h>
   #include <sys/time.h> // needed for getrusage
   #include <sys/resource.h> // needed for getrusage
   #include <pthread.h>
   #include <limits.h>
   
   // Struct containing all the info about the thread to start
   struct thread_info
   {
       void* (*thread)(void* args); // Routine name
       void* args;                  // Arguments to pass to the thread
   };
   
   #define PRE_ALLOCATION_SIZE (100*1024*1024) // 100MB pagefault free buffer
   #define MY_STACK_SIZE       (100*1024)      // 100 kB is enough for now.
   
   /*************************************************************/
   /* The thread to start */
   static int mydata = 12345;
   
   static void* my_rt_thread(void* args)
   {
       struct timespec ts;
       ts.tv_sec = 30;
       ts.tv_nsec = 0;
       
       printf("I am an RT-thread with a stack that does not generate page-faults during use, data=%i\n", *((int*)args));
       
       //<do your RT-thing>
       
       clock_nanosleep(CLOCK_REALTIME, 0, &ts, NULL); // wait 30 seconds before thread terminates
       
       return NULL;
   }
   /*************************************************************/
   
   static void* rt_thread_wrapper(void* args)
   {
       void* result;
       struct thread_info* thread_info = (struct thread_info*)args;
       
       { // limit the scope to make sure the next temporary variables are released after touching the stack.
           int cntr;
           // Calculate the size of the stack that is free after this line
           volatile int my_size = MY_STACK_SIZE - (sizeof(void*) + \
                                                   sizeof(struct thread_info*) + \
                                                   sizeof(int) + sizeof(volatile int));
           volatile char pretouch_buffer[my_size]; // Use an automatic array that claims the remaining part of the stack
   
           // Touch each page on the stack to make sure it is in RAM
           for (cntr = 0; cntr < my_size; cntr++)
           {
   	        pretouch_buffer[cntr] = cntr;
           }
       }
   
       { // limit the scope.
           struct sched_param param;
           // Set realtime priority for this thread
           param.sched_priority = sched_get_priority_max(SCHED_RR);
           if (sched_setscheduler(0, SCHED_RR, &param) < 0) 
           {
               perror("sched_setscheduler");
           }
       }
   
       // Execute the thread with the proper arguments.
       result = (*thread_info->thread)(thread_info->args);
       
       // Release the memory allocated for args
       if (args) free(args);
       return result;
   }
   
   static void error(int at)
   {
       // Just exit on error
       fprintf(stderr, "Some error occured at %d", at);
       exit(1);
   }
   
   static void start_rt_thread(void)
   {
       // thread_info is freed when the thread terminates.
       struct thread_info* thread_info = malloc(sizeof(struct thread_info));
   
       if (thread_info)
       {
           pthread_t           thread;
           pthread_attr_t      attr;
   
           thread_info->thread = my_rt_thread;
           thread_info->args   = &mydata;
   
            // init to default values
           if (pthread_attr_init(&attr)) error(1);
           // Set the requested stacksize for this thread
           if (pthread_attr_setstacksize(&attr, PTHREAD_STACK_MIN + MY_STACK_SIZE)) error(2);
           // And finally start the actual thread
           pthread_create(&thread, &attr, rt_thread_wrapper, thread_info);
       }
       else
       {
           error(3);
       }
   }
   
   int main(int argc, char* argv[])
   {
       // Allocate some memory
       int i, page_size;
       char* buffer;
       struct rusage usage;
       
       // Now lock all current and future pages from preventing of being paged
       if (mlockall(MCL_CURRENT | MCL_FUTURE ))
       {
           perror("mlockall failed:");
       }
       
       // Turn off malloc trimming.
       mallopt (M_TRIM_THRESHOLD, -1);
       
       // Turn off mmap usage.
       mallopt (M_MMAP_MAX, 0);
       
       page_size = sysconf(_SC_PAGESIZE);
       buffer = malloc(PRE_ALLOCATION_SIZE);
       
       // Touch each page in this piece of memory to get it mapped into RAM
       for (i=0; i < PRE_ALLOCATION_SIZE; i+=page_size)
       {
           // Each write to this buffer will generate a pagefault.
           // Once the pagefault is handled a page will be locked in memory and never
           // given back to the system.
           buffer[i] = 0;
           // print the number of major and minor pagefaults this application has triggered
           getrusage(RUSAGE_SELF, &usage);
           printf("Major-pagefaults:%ld, Minor Pagefaults:%ld\n", usage.ru_majflt, usage.ru_minflt);
       }
       free(buffer);
       printf("Look at the output of ps -leyf, and see that the RSS is now about %d [MB]\n", PRE_ALLOCATION_SIZE/(1024*1024));
       // buffer is now released. As Glibc is configured such that it never gives back memory to
       // the kernel, the memory allocated above is locked for this process. All malloc() and new()
       // calls come from the memory pool reserved and locked above. Issuing free() and delete()
       // does NOT make this locking undone. So, with this locking mechanism we can build C++ applications
       // that will never run into a major/minor pagefault, even with swapping enabled.
       
       start_rt_thread();
       
       //<do your RT-thing>
       
       printf("Press <ENTER> to exit\n");
       getc(stdin);
       
       return 0;
   }


The following program verifies the previous statements regarding the effects of the mlockall() function on stack memory. Verifying mlockall() effects on stack memory proof

Author/Maintainer

Remy Bohmer

Revision

Revision History
Revision 1 2008-01-15
Personal tools