#include <errno.h>
#include <pthread.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>

/* Number of threads to create, one at a time.
   We wait for each thread to finish before creating the next one.  */

#ifndef NTHREADS
# define NTHREADS 1000000
#endif

/* The result of calling gmtime in each thread.  */
struct tm *gmtime_result[NTHREADS];

void *
thread_gmtime (void *arg)
{
  void *r = gmtime (arg);
  if (!r)
    {
      perror ("subthread gmtime");
      exit (1);
    }
  return r;
}

bool
eqtm (struct tm *a, struct tm *b)
{
  return (a->tm_year == b->tm_year
	  && a->tm_mon == b->tm_mon
	  && a->tm_mday == b->tm_mday
	  && a->tm_wday == b->tm_wday
	  && a->tm_yday == b->tm_yday
	  && a->tm_hour == b->tm_hour
	  && a->tm_min == b->tm_min
	  && a->tm_sec == b->tm_sec
	  && a->tm_isdst == b->tm_isdst
	  && a->tm_gmtoff == b->tm_gmtoff
	  && strcmp (a->tm_zone, b->tm_zone) == 0);	  
}

int
main ()
{
  for (int i = 0; i < NTHREADS; i++)
    {
      pthread_t th;
      time_t t = i;
      int err = pthread_create (&th, 0, thread_gmtime, &t);
      if (err)
	return fprintf (stderr, "pthread_create: %s\n", strerror (err)), 1;
      void *r;
      err = pthread_join (th, &r);
      if (err)
	return fprintf (stderr, "pthread_join: %s\n", strerror (err)), 1;
      gmtime_result[i] = r;
    }
  for (int i = 0; i < NTHREADS; i++)
    {
      time_t t = i;
      struct tm *tm = gmtime (&t);
      if (!tm)
	return perror ("main thread gmtime"), 1;
      if (!eqtm (gmtime_result[i], tm))
	{
	  char abuf[100], bbuf[100];
	  char const *format = "%Y-%m-%d %H:%M:%S w=%d y=%d %z";
	  strftime (abuf, sizeof abuf, format, gmtime_result[i]);
	  strftime (bbuf, sizeof bbuf, format, tm);
	  fprintf (stderr,
		   ("old gmtime (%d) results say\n"
		    "%s (%s), should say:\n"
		    "%s (%s)\n"),
		   i, abuf, gmtime_result[i]->tm_zone, bbuf, tm->tm_zone);
	  return 1;
	}
    }
}
