#define _REENTRANT

#include <sys/types.h>
#include <stdlib.h>
#include <stdio.h>
#include <pthread.h>
#include <time.h>

pthread_key_t   myKey       ;
pthread_mutex_t mutexStdout ;

typedef struct {
  pthread_t myID  ;
  int       myInt ;
} TSD ;

#define ErrAbort(s,m)\
  if (s!=0){\
    fprintf(stderr,"%s: %s\n",strerror(s));\
    exit(1);\
  }

void myDestructor(void *p)
{
  free(p); // must free() data that malloc() created
}

void KeyInit()
{
  int status = pthread_key_create(&myKey, myDestructor);
  ErrAbort(status, "Error: pthread_create_key()");
}

void otherFcn()
{
  TSD *theData ;
  int  status  ;

  theData = (TSD *)pthread_getspecific(myKey);

  status = pthread_mutex_lock(&mutexStdout);
  ErrAbort(status, "otherFcn: mutex lock:");

  fprintf(stdout, "My ID = %d, my integer = %d\n",
          theData->myID, theData->myInt);

  status = pthread_mutex_unlock(&mutexStdout);
  ErrAbort(status, "otherFcn: mutex unlock:");
}

void *myThreadFcn(void *p)
{
  static pthread_once_t myOnce = PTHREAD_ONCE_INIT ;
  int  status ;
  TSD *myTSD  ;

  int mySeed = time(NULL);

  pthread_detach(pthread_self()); // no one will ever join

  status = pthread_once(&myOnce, KeyInit);
  ErrAbort(status,"Error calling pthread_once()");

  myTSD = (TSD *)malloc(sizeof(TSD));
  if (myTSD == (TSD *)NULL)
  {
    fprintf(stderr,"Error allocating TSD!\n");
    exit(1);
  }

  myTSD->myID  = pthread_self();
  myTSD->myInt = rand_r(&mySeed);

  status = pthread_setspecific(myKey, myTSD);
  ErrAbort(status, "Error calling pthread_setspecific()");

  otherFcn();

  return NULL ;
}

int main()
{
  int       i, status ;
  pthread_t threadID  ;

  for (i=0; i < 20; i++)
  {
    sleep(1);
    status = pthread_create(&threadID, NULL, myThreadFcn, NULL);
    if (status != 0)
      fprintf(stderr,"Error creating thread %d\n", i);
  }
  
  pthread_exit(NULL);
}


