/*
 * Thread-local storage (TLS) is not supported on all environments.
 * This header file and test-program shows how to abstract away, using either
 *   __thread,
 *   __declspec(thread) or
 *   Pthread-Keys
 * depending on the (configure-set) CPP-variables HAVE___THREA, HAVE_DECLSPEC.
 *
 * Use the macros TLS_DECLARE, and the getters and setters TLS_GET and TLS_GET
 * to work on the declared variables.
 */

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include "thread_local_storage.h"

#define NUM_THREADS 10
#define NUM_ITERATIONS 10000

TLS_DECLARE  (static int, thread_local_storage);

static int start = 0;
static pthread_mutex_t start_mutex = PTHREAD_MUTEX_INITIALIZER;
static pthread_cond_t  start_cond = PTHREAD_COND_INITIALIZER;


void * thread_func (void * arg)
{
  int i = NUM_ITERATIONS;

  pthread_mutex_lock (&start_mutex);
  while (!start)
    pthread_cond_wait (&start_cond, &start_mutex);
  pthread_mutex_unlock (&start_mutex);

  printf ("Long loop to check that thread_local_storage is TID-value.\n");
  while (i--) {
    TLS_SET (int, thread_local_storage, *((int*)arg) );

    if (TLS_GET (int, thread_local_storage) != (int)pthread_self())
      printf ("ERROR tid:%ld != thread_local_storage:%d\n",
              (long int)pthread_self(), TLS_GET (int, thread_local_storage) );
  }
  TLS_FREE (thread_local_storage);

  return 0;
}


int main (int argc, char * argv[])
{
  int i; 
  pthread_t tid[NUM_THREADS];

  for (i = 0; i < NUM_THREADS; i++) {
    pthread_create (&tid[i], NULL, thread_func, &(tid[i])); 
  }

  pthread_mutex_lock (&start_mutex);
  start = 1;
  pthread_cond_broadcast (&start_cond);
  pthread_mutex_unlock (&start_mutex);

  for (i = 0; i < NUM_THREADS; i++) {
    pthread_join (tid[i], NULL);
  }

  return 0;
}

