/* threadz.c -- compile with "gcc -Wall threadz.c -o threadz -lpthread"*/

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

enum {TMIN=1, THREADSCOUNT=3, TMAX=4, TOTALRUN=20, TIMLEN=60};

volatile int shrd;
struct state {
  pthread_t t;          /* A thread */
  int who;              /* It identifies a thread */
  unsigned int seed;    /* The seed used for random number generator*/
  char buffer[TIMLEN];  /* String represnting current time */
} states[THREADSCOUNT];

void moo(struct state *s);


int main(void)
{
  int    i;
  struct timespec maintime = {TOTALRUN, 0};
  pid_t  pid;
  
  /* Initialize states */
  pid = getpid();
  for (i=0; i<THREADSCOUNT; i++) {
    states[i].seed = i + (int)pid;
    states[i].who = i;
    if (pthread_create(&(states[i].t), NULL, 
		       (void *)moo, &(states[i])) != 0){
      perror("pthread_create");
      exit(1);}}
  /* Wait a while then exit: all existing threads will die */
  nanosleep(&maintime, NULL);
  return 0; /* when the main thread returns, the program terminates.
	       if instead we had used pthread_exit in place of return
	       the program would terminate only when all other threads
	       also had terminated.
	     */
}


void getTime(struct timeval *ts, char buffer[])
     /* It places the current time in ts and puts in buffer (assumed of 
      * sufficient length)  as a string the current time */
{
  gettimeofday(ts, NULL);
  ctime_r(&(ts->tv_sec), buffer);
  sprintf(&buffer[24], " and %ld microseconds", (ts->tv_usec));
}


void moo(struct state *s) {
  /* We assume that a thread sleeps in each loop, from a minimum of */
  /* TMIN to a maximum of TMAX, at random.                          */
  
  struct timeval tspec;
  struct timespec interval;
  int v;            /* Value returned by random number generator */
  
  printf("s->seed = %d\n", s->seed);
  while (1){
    getTime(&tspec, s->buffer);
    v = rand_r(&(s->seed));
    printf("v = %d\n", v);
    shrd = s->who;
    printf("Thread %d with shrd = %d sleeps %2d secs at time %s\n", 
	   s->who, shrd, TMIN + (v % (TMAX-TMIN)), s->buffer);
    /* sleep for an a time between TMIN and TMAX */
    interval.tv_sec = (TMIN + (v % (TMAX-TMIN)));
    interval.tv_nsec = 0;
    nanosleep(&interval, NULL);
    getTime(&tspec, s->buffer);
    printf("Thread %d with shrd = %d after sleep at time %s\n", 
	   s->who, shrd, s->buffer);}
}


