Verifying mlockall() effects on stack memory proof

From RTwiki
(Difference between revisions)
Jump to: navigation, search
(New page: ====Verifying mlockall() effects on stack memory proof==== This is a test-application that shows the effects of mlockall() on stack memory. // g++ -o checkStackPageFaults -Wall -...)
 
m
 
Line 2: Line 2:
  
 
This is a test-application that shows the effects of mlockall() on stack memory.
 
This is a test-application that shows the effects of mlockall() on stack memory.
      
+
     /*
    // g++ -o checkStackPageFaults -Wall -O3 checkStackPageFaults.cpp -lpthread
+
      gcc -o check_stack_page_faults check_stack_page_faults.c -Wall -O3 -lpthread
   
+
      This application checks whether mlockall() forces all pages of a
    // This application checks whether mlockall() forces all pages of a
+
      stack into RAM.
    // stack into RAM.
+
     */
      
+
 
     #include <stdio.h>
 
     #include <stdio.h>
 
     #include <string.h>
 
     #include <string.h>
Line 16: Line 15:
 
     #include <sys/mman.h>
 
     #include <sys/mman.h>
 
     #include <sys/resource.h>
 
     #include <sys/resource.h>
 +
    #include <limits.h>
 
      
 
      
     // Lock the application in memory to avoid page faults
+
     /* struct thread_data communicates data to our threads */
     static void lockApplication(void)
+
    struct thread_data {
 +
    char  *name;
 +
    sem_t  semId;
 +
    size_t stack_filler_size;
 +
    };
 +
   
 +
    /* Lock the application in memory to avoid page faults */
 +
     static void lock_application(void)
 
     {
 
     {
      if (mlockall(MCL_CURRENT | MCL_FUTURE) != 0 )
+
    if (mlockall(MCL_CURRENT | MCL_FUTURE) != 0) {
      {
+
    perror("mlockall() failed");
        perror( "mlockall() failed" );
+
    }
      }
+
 
     }
 
     }
 
      
 
      
     // Dump minor and major page faults that occurred since the previous call
+
     /* Dump minor and major page faults that occurred since the previous call */
     static bool dumpPageFaults(void)
+
     static int dump_page_faults(void)
 
     {
 
     {
      bool l_PageFaultsDetected = false;
+
    int page_faults_detected = 0;
      static bool ls_Init = false;
+
    static int init = 0;
      static struct rusage ls_RusagePrevious;
+
    static struct rusage rusage_prev;
      struct rusage l_Rusage;
+
    struct rusage rusage;
 +
    int new_minor_page_faults, new_major_page_faults;
 
      
 
      
      getrusage(RUSAGE_SELF, &l_Rusage);
+
    getrusage(RUSAGE_SELF, &rusage);
      int a_NewMinorPageFaults = l_Rusage.ru_minflt - ls_RusagePrevious.ru_minflt;
+
    new_minor_page_faults = rusage.ru_minflt - rusage_prev.ru_minflt;
      int a_NewMajorPageFaults = l_Rusage.ru_majflt - ls_RusagePrevious.ru_majflt;
+
    new_major_page_faults = rusage.ru_majflt - rusage_prev.ru_majflt;
      ls_RusagePrevious.ru_minflt = l_Rusage.ru_minflt;
+
    rusage_prev.ru_minflt = rusage.ru_minflt;
      ls_RusagePrevious.ru_majflt = l_Rusage.ru_majflt;
+
    rusage_prev.ru_majflt = rusage.ru_majflt;
 
      
 
      
      if (ls_Init)
+
    if (init) {
      {
+
    if ((new_minor_page_faults > 0) ||  
        if ((a_NewMinorPageFaults > 0) || (a_NewMajorPageFaults > 0))
+
        (new_major_page_faults > 0)) {
        {
+
    printf("New minor/major page faults: %d/%d\n",
          printf ("New minor/major page faults: %d/%d\n",
+
          new_minor_page_faults, new_major_page_faults);
            a_NewMinorPageFaults,
+
    page_faults_detected = 1;
            a_NewMajorPageFaults);
+
    }
          l_PageFaultsDetected = true;
+
    }
        }
+
    init = 1;
      }
+
    return page_faults_detected;
      ls_Init = true;
+
      return l_PageFaultsDetected;
+
 
     }
 
     }
 
      
 
      
     // Start a thread
+
     /* Start a thread */
     static pthread_t startThread(int prio, int stack_size, void *(*thread_run)(void*), void *args)
+
     static pthread_t startThread(int prio, int stack_size,
 +
        void *(*thread_run) (void *), void *args)
 
     {
 
     {
      const char     * failure;
+
    const char *failure;
      pthread_attr_t   attr;
+
    pthread_attr_t attr;
      pthread_t     tid;
+
    pthread_t tid;
      struct sched_param     sched;
+
    struct sched_param sched;
      int             policy;
+
    int policy;
      int             priority_min;
+
    int priority_min;
      int             priority_max;
+
    int priority_max;
      int             min_stack_size = 16384;
+
    int min_stack_size = 16384;
 
      
 
      
      for(;;)
+
    for (;;) {
      {
+
    if ((policy = sched_getscheduler(0)) == -1) {
        if( (policy = sched_getscheduler( 0 )) == -1 )
+
    failure = "sched_getscheduler";
        {
+
    break;
          failure = "sched_getscheduler";
+
    }
          break;
+
        }
+
 
      
 
      
        if( (priority_min = sched_get_priority_min( policy )) == -1 )
+
    if ((priority_min = sched_get_priority_min(policy)) == -1) {
        {
+
    failure = "sched_get_priority_min";
          failure = "sched_get_priority_min";
+
    break;
          break;
+
    }
        }
+
 
      
 
      
        if( prio < priority_min )
+
    if (prio < priority_min)
          prio = priority_min;
+
    prio = priority_min;
 
      
 
      
        if( (priority_max = sched_get_priority_max( policy )) == -1 )
+
    if ((priority_max = sched_get_priority_max(policy)) == -1) {
        {
+
    failure = "sched_get_priority_max";
          failure = "sched_get_priority_max";
+
    break;
          break;
+
    }
        }
+
 
      
 
      
        if( prio > priority_max )
+
    if (prio > priority_max)
          prio = priority_max;
+
    prio = priority_max;
 
      
 
      
        if( sched_getparam( 0, &sched ) != 0 )
+
    if (sched_getparam(0, &sched) != 0) {
        {
+
    failure = "sched_getparam";
          failure = "sched_getparam";
+
    break;
          break;
+
    }
        }
+
 
      
 
      
        if( pthread_attr_init( &attr ) != 0 )
+
    if (pthread_attr_init(&attr) != 0) {
        {
+
    failure = "pthread_attr_init";
          failure = "pthread_attr_init";
+
    break;
          break;
+
    }
        }
+
 
      
 
      
        if( pthread_attr_setdetachstate( &attr, PTHREAD_CREATE_JOINABLE ) != 0 )
+
    if (pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE)
        {
+
        != 0) {
          failure = "pthread_attr_setdetachstate";
+
    failure = "pthread_attr_setdetachstate";
          break;
+
    break;
        }
+
    }
 
      
 
      
        if( pthread_attr_setscope( &attr, PTHREAD_SCOPE_SYSTEM ) != 0 )
+
    if (pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM) != 0) {
        {
+
    failure = "pthread_attr_setscope";
          failure = "pthread_attr_setscope";
+
    break;
          break;
+
    }
        }
+
 
      
 
      
        if( stack_size < min_stack_size )
+
    if (stack_size < min_stack_size)
          stack_size = min_stack_size;
+
    stack_size = min_stack_size;
 
      
 
      
        if( pthread_attr_setstacksize( &attr, stack_size ) != 0 )
+
    if (pthread_attr_setstacksize(&attr, stack_size) != 0) {
        {
+
    failure = "pthread_attr_setstacksize";
          failure = "pthread_attr_setstacksize";
+
    break;
          break;
+
    }
        }
+
 
      
 
      
        if( pthread_attr_setinheritsched( &attr, PTHREAD_EXPLICIT_SCHED ) != 0 )
+
    if (pthread_attr_setinheritsched(&attr, PTHREAD_EXPLICIT_SCHED)
        {
+
        != 0) {
          failure = "pthread_attr_setinheritsched";
+
    failure = "pthread_attr_setinheritsched";
          break;
+
    break;
        }
+
    }
 
      
 
      
        if( pthread_attr_setschedpolicy( &attr, policy ) != 0 )
+
    if (pthread_attr_setschedpolicy(&attr, policy) != 0) {
        {
+
    failure = "pthread_attr_setschedpolicy";
          failure = "pthread_attr_setschedpolicy";
+
    break;
          break;
+
    }
        }
+
 
      
 
      
        sched.sched_priority = prio;
+
    sched.sched_priority = prio;
 
      
 
      
        if( pthread_attr_setschedparam( &attr, &sched ) != 0 )
+
    if (pthread_attr_setschedparam(&attr, &sched) != 0) {
        {
+
    failure = "pthread_attr_setschedparam";
          failure = "pthread_attr_setschedparam";
+
    break;
          break;
+
    }
        }
+
 
      
 
      
        if( pthread_create( &tid, &attr, thread_run, args ) != 0 )
+
    if (pthread_create(&tid, &attr, thread_run, args) != 0) {
        {
+
    failure = "pthread_create";
          failure = "pthread_create";
+
    break;
          break;
+
    }
        }
+
 
      
 
      
        if( pthread_attr_destroy( &attr ) != 0 )
+
    if (pthread_attr_destroy(&attr) != 0) {
        {
+
    failure = "pthread_attr_destroy";
          failure = "pthread_attr_destroy";
+
    break;
          break;
+
    }
        }
+
 
      
 
      
        return tid;
+
    return tid;
      }
+
    }
 
      
 
      
      return tid;
+
    return tid;
 
     }
 
     }
 
      
 
      
     // threadData_t communicates data to our threads
+
     /* Define a stack size for our threads */
    typedef struct
+
     static const int stack_size = 1024 * 1024 * 8;
    {
+
      char *name;
+
      sem_t semId;
+
      size_t stackFillerSize;
+
    } threadData_t;
+
   
+
    // Define a stack size for our threads
+
     static const int gs_StackSize = 1024 * 1024 * 8;
+
 
      
 
      
     // Our thread routine
+
     /* Our thread routine */
     static void *checkStackThread(void *pArg)
+
     static void *check_stack_thread(void *pArg)
 
     {
 
     {
      threadData_t *lp_ThreadData = static_cast<threadData_t*>(pArg);
+
    struct thread_data *pthread_data = (struct thread_data *)pArg;
      int i;
+
    int i;
 
      
 
      
      // Tell the world we are alive
+
    /* Tell the world we are alive */
      printf ("%s started\n", lp_ThreadData->name);
+
    printf("%s started\n", pthread_data->name);
      // Wait until we are told to fill the stack
+
    /* Wait until we are told to fill the stack */
      sem_wait(&(lp_ThreadData->semId));
+
    sem_wait(&(pthread_data->semId));
 
      
 
      
      char stackFiller[lp_ThreadData->stackFillerSize];
+
    { /* Limit the scope */
 +
    char stack_filler[pthread_data->stack_filler_size];
 +
   
 +
    printf("%s performing checks\n", pthread_data->name);
 +
    for (i = 0;
 +
        i < (int)pthread_data->stack_filler_size;
 +
        i += sysconf(_SC_PAGESIZE)) {
 +
    stack_filler[i] = 42;
 +
    }
 +
    printf("%s done\n", pthread_data->name);
 +
    }
 
      
 
      
      printf ("%s performing checks\n", lp_ThreadData->name);
+
    /* Wait until we are told to terminate */
      for (i=0; i<(int)lp_ThreadData->stackFillerSize; i+=sysconf(_SC_PAGESIZE))
+
    sem_wait(&(pthread_data->semId));
      {
+
    printf("%s terminating\n", pthread_data->name);
        stackFiller[i] = 42;
+
      }
+
      printf ("%s done\n", lp_ThreadData->name);
+
 
      
 
      
      // Wait until we are told to terminate
+
    return 0;
      sem_wait(&(lp_ThreadData->semId));
+
      printf ("%s terminating\n", lp_ThreadData->name);
+
   
+
      return 0;
+
 
     }
 
     }
 
      
 
      
 
     int main(int argc, char *argv[])
 
     int main(int argc, char *argv[])
 
     {
 
     {
      // Thread data
+
    int lock_memory = 1;
      pthread_t l_ThreadIds[2];
+
    int i;
      threadData_t l_ThreadData[2];
+
    const int page_size = sysconf(_SC_PAGESIZE);
 +
    int page_faults_detected_in_thread1;
 +
    int page_faults_detected_in_thread2;
 +
    /* Thread data */
 +
    pthread_t thread_ids[2];
 +
    struct thread_data thread_data[2];
 
      
 
      
      // Start a thread prior to locking memory.
+
    /* Start a thread prior to locking memory. */
      l_ThreadData[0].name = "Thread 1: ";
+
    thread_data[0].name = "Thread 1: ";
      (void)sem_init(&(l_ThreadData[0].semId), 0, 0);
+
    (void)sem_init(&(thread_data[0].semId), 0, 0);
      l_ThreadData[0].stackFillerSize = gs_StackSize - (1024*16);
+
    thread_data[0].stack_filler_size = stack_size - PTHREAD_STACK_MIN;
      l_ThreadIds[0] = startThread(0, gs_StackSize, checkStackThread, static_cast<void*>(&(l_ThreadData[0])));
+
    thread_ids[0] = startThread(0, stack_size, check_stack_thread,
      // Give it 1 second to start
+
    (void *)&thread_data[0]);
      sleep(1);
+
    /* Give it 1 second to start */
 +
    sleep(1);
 
      
 
      
      bool l_LockMemory = true;
+
    for (i = 1; i < argc; i++) {
      int i;
+
    if (strncmp(argv[i], "-nolockmem", 10) == 0) {
      for (i=1; i<argc; i++)
+
    lock_memory = 0;
      {
+
    }
        if (strncmp (argv[i], "-nolockmem", 10) == 0)
+
    }
        {
+
          l_LockMemory = false;
+
        }
+
      }
+
 
      
 
      
      if (l_LockMemory)
+
    if (lock_memory) {
      {
+
    lock_application();
        lockApplication();
+
    printf("Current and future memory locked in RAM\n");
        printf ("Current and future memory locked in RAM\n");
+
    }
      }
+
    /* printf something so we avoid introducing a page fault simply by
 +
      performing the potentially first printf call. */
 +
    printf("Page size = %d\n", page_size);
 
      
 
      
      // printf something so we avoid introducing a page fault simply by performing
+
    (void)dump_page_faults(); /* Set the baseline */
      // the potentially first printf call.
+
      const int l_PageSize = sysconf(_SC_PAGESIZE);
+
      printf ("Page size = %d\n", l_PageSize);
+
 
      
 
      
      (void)dumpPageFaults();        // Set the baseline
+
    /* From this point onwards we no longer expect to have any
 +
      page faults for currently allocated memory. */
 
      
 
      
      // From this point onwards we no longer expect to have any
+
    /* Make the first thread fill the stack. */
      // page faults for currently allocated memory.
+
    sem_post(&(thread_data[0].semId));
 +
    /* Give it 1 second to complete. */
 +
    sleep(1);
 
      
 
      
      // Make the first thread fill the stack.
+
    page_faults_detected_in_thread1 = dump_page_faults();
      sem_post(&(l_ThreadData[0].semId));
+
      // Give it 1 second to complete.
+
      sleep(1);
+
 
      
 
      
      bool l_PageFaultsDetectedInThread1 = dumpPageFaults();
+
    if (lock_memory) {
 +
    if (!page_faults_detected_in_thread1)
 +
    printf("After locking memory, no new page faults " \
 +
          "have been generated during stack access of " \
 +
          "thread 1. This is expected.\n");
 +
    else
 +
    printf ("After locking memory, new page faults have " \
 +
    "been generated during during stack access " \
 +
    "of thread 1. This is unexpected!\n");
 +
    }
 +
    /* Thread 1 has not yet terminated, meaning that thread 2 will not
 +
      reuse the same (locked) stack region. */
 
      
 
      
      if (l_LockMemory)
+
    /* Start the second thread and make it fill the stack. */
      {
+
    thread_data[1].name = "Thread 2: ";
        if (l_PageFaultsDetectedInThread1 == false)
+
    (void)sem_init(&(thread_data[1].semId), 0, 0);
        {
+
    thread_data[1].stack_filler_size = stack_size - PTHREAD_STACK_MIN;
          printf ("After locking memory, no new page faults have been generated during stack access of thread 1. This is expected.\n");
+
    thread_ids[1] = startThread(0, stack_size, check_stack_thread,
        }
+
    (void *)&thread_data[1]);
        else
+
    /* Give it 1 second to start */
        {
+
    sleep(1);
          printf ("After locking memory, new page faults have been generated during during stack access of thread 1. This is unexpected!\n");
+
        }
+
      }
+
      // Thread 1 has not yet terminated, meaning that thread 2 will not
+
      // reuse the same (locked) stack region.
+
 
      
 
      
      // Start the second thread and make it fill the stack.
+
    if (lock_memory) {
      l_ThreadData[1].name = "Thread 2: ";
+
    if (dump_page_faults()) /* Reset the baseline */
      (void)sem_init(&(l_ThreadData[1].semId), 0, 0);
+
    printf("New page faults have occurred as a result " \
      l_ThreadData[1].stackFillerSize = gs_StackSize - (1024*16);
+
          "of starting thread 2. This is expected.\n");
      l_ThreadIds[1] = startThread(0, gs_StackSize, checkStackThread,  static_cast<void*>(&(l_ThreadData[1])));
+
    else
      // Give it 1 second to start
+
    printf("Did not observe new page faults as a result " \
      sleep(1);
+
          "of starting thread 2. This is unexpected!\n");
 +
    } else {
 +
    (void)dump_page_faults(); /* Reset the baseline */
 +
    }
 
      
 
      
      if (l_LockMemory)
+
    sem_post(&(thread_data[1].semId));
      {
+
    /* Give it 1 second to complete. */
        if (dumpPageFaults())        // Reset the baseline
+
    sleep(1);
        {
+
          printf ("New page faults have occurred as a result of starting thread 2. This is expected.\n");
+
        }
+
        else
+
        {
+
          printf ("Did not observe new page faults as a result of starting thread 2. This is unexpected!\n");
+
        }
+
      }
+
      else
+
      {
+
        (void)dumpPageFaults();     // Reset the baseline
+
      }
+
 
      
 
      
      sem_post(&(l_ThreadData[1].semId));
+
    page_faults_detected_in_thread2 = dump_page_faults();
      // Give it 1 second to complete.
+
      sleep(1);
+
 
      
 
      
      bool l_PageFaultsDetectedInThread2 = dumpPageFaults();
+
    /* Check whether page faults have been detected. */
 +
    int exit_code = 0;
 +
    if ((page_faults_detected_in_thread1) ||
 +
        (page_faults_detected_in_thread2)) {
 +
    exit_code = 1;
 +
    }
 +
    /* Make the threads terminate */
 +
    sem_post(&(thread_data[0].semId));
 +
    sem_post(&(thread_data[1].semId));
 +
    (void)pthread_join(thread_ids[0], 0);
 +
    (void)pthread_join(thread_ids[1], 0);
 
      
 
      
      // Check whether page faults have been detected.
+
    printf("Done, result: %s\n", (exit_code != 0) ? "failed" : "success");
      int l_ExitCode = 0;
+
      if ((l_PageFaultsDetectedInThread1 == true) ||
+
        (l_PageFaultsDetectedInThread2 == true))
+
      {
+
        l_ExitCode = 1;
+
      }
+
 
      
 
      
      // Make the threads terminate
+
    return exit_code;
      sem_post(&(l_ThreadData[0].semId));
+
    }
      sem_post(&(l_ThreadData[1].semId));
+
      (void)pthread_join(l_ThreadIds[0], 0);
+
      (void)pthread_join(l_ThreadIds[1], 0);
+
 
      
 
      
      printf ("Done, result: %s\n",
 
        (l_ExitCode != 0) ? "failed":"success");
 
   
 
      return l_ExitCode;
 
    }
 
 
 
==Authors==
 
==Authors==
 
<p>
 
<p>
 
[[User:Awa  | Alex van der Wal]]<br>
 
[[User:Awa  | Alex van der Wal]]<br>
 
</p>
 
</p>

Latest revision as of 20:37, 15 January 2008

[edit] Verifying mlockall() effects on stack memory proof

This is a test-application that shows the effects of mlockall() on stack memory.

   /* 
      gcc -o check_stack_page_faults check_stack_page_faults.c -Wall -O3 -lpthread
      This application checks whether mlockall() forces all pages of a
      stack into RAM.
   */
   #include <stdio.h>
   #include <string.h>
   #include <pthread.h>
   #include <semaphore.h>
   #include <sched.h>
   #include <unistd.h>
   #include <sys/mman.h>
   #include <sys/resource.h>
   #include <limits.h>
   
   /* struct thread_data communicates data to our threads */
   struct thread_data {
   	char   *name;
   	sem_t  semId;
   	size_t stack_filler_size;
   };
   
   /* Lock the application in memory to avoid page faults */
   static void lock_application(void)
   {
   	if (mlockall(MCL_CURRENT | MCL_FUTURE) != 0) {
   		perror("mlockall() failed");
   	}
   }
   
   /* Dump minor and major page faults that occurred since the previous call */
   static int dump_page_faults(void)
   {
   	int			page_faults_detected = 0;
   	static int		init = 0;
   	static struct rusage	rusage_prev;
   	struct rusage		rusage;
   	int 			new_minor_page_faults, new_major_page_faults;
   
   	getrusage(RUSAGE_SELF, &rusage);
   	new_minor_page_faults = rusage.ru_minflt - rusage_prev.ru_minflt;
   	new_major_page_faults = rusage.ru_majflt - rusage_prev.ru_majflt;
   	rusage_prev.ru_minflt = rusage.ru_minflt;
   	rusage_prev.ru_majflt = rusage.ru_majflt;
   
   	if (init) {
   		if ((new_minor_page_faults > 0) || 
   		    (new_major_page_faults > 0)) {
   			printf("New minor/major page faults: %d/%d\n",
   			       new_minor_page_faults, new_major_page_faults);
   			page_faults_detected = 1;
   		}
   	}
   	init = 1;
   	return page_faults_detected;
   }
   
   /* Start a thread */
   static pthread_t startThread(int prio, int stack_size,
   			     void *(*thread_run) (void *), void *args)
   {
   	const char *failure;
   	pthread_attr_t attr;
   	pthread_t tid;
   	struct sched_param sched;
   	int policy;
   	int priority_min;
   	int priority_max;
   	int min_stack_size = 16384;
   
   	for (;;) {
   		if ((policy = sched_getscheduler(0)) == -1) {
   			failure = "sched_getscheduler";
   			break;
   		}
   
   		if ((priority_min = sched_get_priority_min(policy)) == -1) {
   			failure = "sched_get_priority_min";
   			break;
   		}
   
   		if (prio < priority_min)
   			prio = priority_min;
   
   		if ((priority_max = sched_get_priority_max(policy)) == -1) {
   			failure = "sched_get_priority_max";
   			break;
   		}
   
   		if (prio > priority_max)
   			prio = priority_max;
   
   		if (sched_getparam(0, &sched) != 0) {
   			failure = "sched_getparam";
   			break;
   		}
   
   		if (pthread_attr_init(&attr) != 0) {
   			failure = "pthread_attr_init";
   			break;
   		}
   
   		if (pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE)
   		    != 0) {
   			failure = "pthread_attr_setdetachstate";
   			break;
   		}
   
   		if (pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM) != 0) {
   			failure = "pthread_attr_setscope";
   			break;
   		}
   
   		if (stack_size < min_stack_size)
   			stack_size = min_stack_size;
   
   		if (pthread_attr_setstacksize(&attr, stack_size) != 0) {
   			failure = "pthread_attr_setstacksize";
   			break;
   		}
   
   		if (pthread_attr_setinheritsched(&attr, PTHREAD_EXPLICIT_SCHED)
   		    != 0) {
   			failure = "pthread_attr_setinheritsched";
   			break;
   		}
   
   		if (pthread_attr_setschedpolicy(&attr, policy) != 0) {
   			failure = "pthread_attr_setschedpolicy";
   			break;
   		}
   
   		sched.sched_priority = prio;
   
   		if (pthread_attr_setschedparam(&attr, &sched) != 0) {
   			failure = "pthread_attr_setschedparam";
   			break;
   		}
   
   		if (pthread_create(&tid, &attr, thread_run, args) != 0) {
   			failure = "pthread_create";
   			break;
   		}
   
   		if (pthread_attr_destroy(&attr) != 0) {
   			failure = "pthread_attr_destroy";
   			break;
   		}
   
   		return tid;
   	}
   
   	return tid;
   }
   
   /* Define a stack size for our threads */
   static const int stack_size = 1024 * 1024 * 8;
   
   /* Our thread routine */
   static void *check_stack_thread(void *pArg)
   {
   	struct thread_data *pthread_data = (struct thread_data *)pArg;
   	int i;
   
   	/* Tell the world we are alive */
   	printf("%s started\n", pthread_data->name);
   	/* Wait until we are told to fill the stack */
   	sem_wait(&(pthread_data->semId));
   
   	{ /* Limit the scope */
   		char stack_filler[pthread_data->stack_filler_size];
   	
   		printf("%s performing checks\n", pthread_data->name);
   		for (i = 0; 
   		     i < (int)pthread_data->stack_filler_size;
   		     i += sysconf(_SC_PAGESIZE)) {
   			stack_filler[i] = 42;
   		}
   		printf("%s done\n", pthread_data->name);
   	}
   
   	/* Wait until we are told to terminate */
   	sem_wait(&(pthread_data->semId));
   	printf("%s terminating\n", pthread_data->name);
   
   	return 0;
   }
   
   int main(int argc, char *argv[])
   {
   	int 			lock_memory = 1;
   	int 			i;
   	const int 		page_size = sysconf(_SC_PAGESIZE);
   	int			page_faults_detected_in_thread1;
   	int			page_faults_detected_in_thread2;
   	/* Thread data */
   	pthread_t		thread_ids[2];
   	struct thread_data 	thread_data[2];
   
   	/* Start a thread prior to locking memory. */
   	thread_data[0].name = "Thread 1: ";
   	(void)sem_init(&(thread_data[0].semId), 0, 0);
   	thread_data[0].stack_filler_size = stack_size - PTHREAD_STACK_MIN;
   	thread_ids[0] = startThread(0, stack_size, check_stack_thread,
   						(void *)&thread_data[0]);
   	/* Give it 1 second to start */
   	sleep(1);
   
   	for (i = 1; i < argc; i++) {
   		if (strncmp(argv[i], "-nolockmem", 10) == 0) {
   			lock_memory = 0;
   		}
   	}
   
   	if (lock_memory) {
   		lock_application();
   		printf("Current and future memory locked in RAM\n");
   	}
   	/* printf something so we avoid introducing a page fault simply by
   	   performing the potentially first printf call. */
   	printf("Page size = %d\n", page_size);
   
   	(void)dump_page_faults(); /* Set the baseline */
   
   	/* From this point onwards we no longer expect to have any
   	   page faults for currently allocated memory. */
   
   	/* Make the first thread fill the stack. */
   	sem_post(&(thread_data[0].semId));
   	/* Give it 1 second to complete. */
   	sleep(1);
   
   	page_faults_detected_in_thread1 = dump_page_faults();
   
   	if (lock_memory) {
   		if (!page_faults_detected_in_thread1)
   			printf("After locking memory, no new page faults " \
   			       "have been generated during stack access of " \
   			       "thread 1. This is expected.\n");
   		else
   			printf ("After locking memory, new page faults have " \
   				"been generated during during stack access " \
   				"of thread 1. This is unexpected!\n");
   	}
   	/* Thread 1 has not yet terminated, meaning that thread 2 will not
   	   reuse the same (locked) stack region. */
   
   	/* Start the second thread and make it fill the stack. */
   	thread_data[1].name = "Thread 2: ";
   	(void)sem_init(&(thread_data[1].semId), 0, 0);
   	thread_data[1].stack_filler_size = stack_size - PTHREAD_STACK_MIN;
   	thread_ids[1] = startThread(0, stack_size, check_stack_thread,
   						(void *)&thread_data[1]);
   	/* Give it 1 second to start */
   	sleep(1);
   
   	if (lock_memory) {
   		if (dump_page_faults())	/* Reset the baseline */
   			printf("New page faults have occurred as a result " \
   			       "of starting thread 2. This is expected.\n");
   		else
   			printf("Did not observe new page faults as a result " \
   			       "of starting thread 2. This is unexpected!\n");
   	} else {
   		(void)dump_page_faults(); /* Reset the baseline */
   	}
   
   	sem_post(&(thread_data[1].semId));
   	/* Give it 1 second to complete. */
   	sleep(1);
   
   	page_faults_detected_in_thread2 = dump_page_faults();
   
   	/* Check whether page faults have been detected. */
   	int exit_code = 0;
   	if ((page_faults_detected_in_thread1) ||
   	    (page_faults_detected_in_thread2)) {
   		exit_code = 1;
   	}
   	/* Make the threads terminate */
   	sem_post(&(thread_data[0].semId));
   	sem_post(&(thread_data[1].semId));
   	(void)pthread_join(thread_ids[0], 0);
   	(void)pthread_join(thread_ids[1], 0);
   
   	printf("Done, result: %s\n", (exit_code != 0) ? "failed" : "success");
   
   	return exit_code;
   }
   

[edit] Authors

Alex van der Wal

Personal tools