Linker trouble on BlueGene/P system

Today I have learned that having a global variable in some C89 code which is not declared as static might be problematic if said code is later linked together with a Fortran program which includes a function with the exact same name es the mentioned variable. Somehow the program ended up at the location of the variable which of course ended in a crash with a signal four (illegal instruction). Took me about 12h to find and fix that bug… in my defense it was on a BlueGene system and I first thought the error had something to do with some front-/backend problems (you cross compile on the frontend and then execute the resulting binary using the LoadLeveler)… Anyway, now it works and I can finally take measurements for the thesis.

SIGPROF signal handler and pthreads

During work on my thesis the question popped up how signals generated by the SIGPROF timer were handled in multithreaded code. Signal handlers are process specific to it could have been that one random thread handled the sent signal. As I could not a find a suitable explanation in the intertubes I performed a small experiment.

My sample program installs a signal handler and starts a timer with a frequency of about 100hz. At first the number of captured signals in a ten second timespan are captured using only the main thread and then using four individual threads. The output is:
Signals caught after 10 seconds: 999
Creating 4 threads
Signals caught after 4x10 seconds by thread 0: 1000
Signals caught after 4x10 seconds by thread 1: 1000
Signals caught after 4x10 seconds by thread 2: 1000
Signals caught after 4x10 seconds by thread 3: 1000

So apparently each thread handles the SIGPROF signal, which is quite nice for my purpose.

The sourcode is here (I just assume that pthread_self is async-safe even though it’s specified by the standard. It appears, however, that assuming that is done by most people working on that kind of stuff):
[sourcecode language=”cpp”]#include <signal.h>
#include <stdio.h>
#include <pthread.h>
#include <sys/time.h>

#include "../../util/util_time_measurement.h"

const int thread_count = 4;

volatile sig_atomic_t signal_count[thread_count];

pthread_t threads[thread_count];

static void sigprof_handler(int sig_nr, siginfo_t* info, void *context)
{
   int t;
   for(t = 0; t < thread_count; ++t)
   {
      if(threads[t] == pthread_self())
      {
signal_count[t]++;

return;
      }
   }

   /* Probably no thread */
   signal_count[0]++;
}

void install_signal_handler()
{
   /* Install signal handler for SIGPROF event */
   struct sigaction sa;
   memset(&sa, 0, sizeof(sa));
   sa.sa_sigaction = sigprof_handler;
   sa.sa_flags = SA_RESTART | SA_SIGINFO;
   sigemptyset(&sa.sa_mask);

   sigaction(SIGPROF, &sa, NULL);
}

void idle_time(int seconds)
{
   timestamp_t start = util_get_timestamp();
   while(1)
   {
      if(util_get_timestamp() > start + seconds)
      {
break;
      }
   }
}

void* thread_work(void* data)
{
   idle_time(10);

   return NULL;
}

int main(int argc, char** argv)
{
   install_signal_handler();
   
   static struct itimerval timer;

   timer.it_interval.tv_sec = 0;
   timer.it_interval.tv_usec = 1000000 / 100; /* 100hz */
   timer.it_value = timer.it_interval;

   /* Reset count */
   int t;
   for(t = 0; t < thread_count; ++t)
   {
      signal_count[t] = 0;
   }

   /* Install timer */
   if (setitimer(ITIMER_PROF, &timer, NULL) != 0)
   {
      printf("Timer could not be initialized \n");
   }
   
   /* Idle for 10 seconds */
   idle_time(10);

   printf("Signals caught after 10 seconds: %d \n", signal_count[0]);

   /* Reset count */
   for(t = 0; t < thread_count; ++t)
   {
      signal_count[t] = 0;
   }

   printf("Creating %d threads… \n", thread_count);

   for(t = 0; t < thread_count; ++t)
   {
      pthread_create(&threads[t], NULL, thread_work, NULL);
   }
   
   for(t = 0; t < thread_count; ++t)
   {
      pthread_join(threads[t], NULL);
   }

   for(t = 0; t < thread_count; ++t)
   {
      printf("Signals caught after %dx10 seconds by thread %d: %d \n", thread_count, t, signal_count[t]);
   }
}
[/sourcecode]