Threaded RT-application with memory locking and stack handling example
From RTwiki
(Difference between revisions)
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, ¶m) < 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
Revision
Revision History | |
---|---|
Revision 1 | 2008-01-15 |