#include <string.h>
#include <pthread.h>
#include <stdlib.h>
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/syscall.h>
#include "../memcheck/memcheck.h"
int using_threads = 0; /* test collision with a global in gdbserver */
/* we will undefine one char on two */
static char undefined[10] = "undefined";

#define LOOPS 10000000
static int loopmain, loopt1, loopt2;

static double pi = 3.14159265358979323846264338327950288;

static pid_t gettid_sys()
{
#ifdef __NT_gettid
   return syscall(__NR_gettid);
#else
   return getpid();
#endif
}
static void whoami(char *msg)
{
   printf("pid %ld Thread %ld %s\n", (long) getpid(), (long) gettid_sys(), msg);
   fflush(stdout);
}

static int int_und;
static int sleeps = 15;
static void make_error (char *s)
{
  char *make_error_name __attribute__((unused)) = "make_error name";
  char c __attribute__((unused));
  double pi2 __attribute__((unused)) = 2.0 * pi;
  whoami(s);
  if (int_und == 0)
     printf ("%s int_und is zero %d\n", s, int_und);
  else
     printf ("%s int_und is not zero\n", s);
  fflush(stdout);
}

static void level ()
{
  char *level_name __attribute__((unused)) = "level name";
  make_error ("called from level");
}

static void loops (int *loopnr)
{
  int i, j;
  for (i = 0; i < LOOPS; i++)
    for (j = 0; j < LOOPS; j++)
      (*loopnr)++;
}
 
static void *brussels_fn(void *v)
{
  char *brussels_name __attribute__((unused)) = "Brussels";
  make_error ("called from Brussels");
  loopt1 = 1;
  while (! (loopt1 && loopt2 && loopmain))
    loopt1++;
  loops (&loopt1);
  return NULL;
}
static void *london_fn(void *v)
{
  char *london_name __attribute__((unused)) = "London";
  make_error ("called from London");
  loopt2 = 1;
  while (! (loopt1 && loopt2 && loopmain))
    loopt2++;
  loops (&loopt2);
  sleep(10);
  return NULL;
}
static void *petaouchnok_fn(void *v)
{
  char *petaouchnok_name __attribute__((unused)) = "Petaouchnok";
  struct timeval t;
  int i;
  for (i = 1; i <= sleeps; i++) {
      t.tv_sec = 5;
      t.tv_usec = 0;
      fprintf (stderr, "Petaouchnok sleep nr %d out of %d sleeping 5 seconds\n",
               i, sleeps);
      fflush(stderr);
      select (0, NULL, NULL, NULL, &t);
  }
  return NULL;
}
static void leaf(void) {}
static void breakme(int line)
{
   if (line > 1000)
      leaf(); // ensures not leaf, as ppc unwind implies VEX iropt precise exns
}
int main (int argc, char *argv[])
{
  char *main_name __attribute__((unused)) = "main name";
  pthread_t ebbr, egll, zzzz;
  int i = 1234;
  char undef = '?';
  char *some_mem __attribute__((unused)) = malloc(100);
  VALGRIND_MAKE_MEM_UNDEFINED(&undef, 1);
  int len = strlen(undefined);
  breakme(__LINE__); //break1
  for (i = len-1; i >= 0; i=i-2)
     undefined[i] = undef;
  *(char*)&int_und = undef;

  breakme(__LINE__); //break2

  if (argc > 1)
    sleeps = atoi(argv[1]);

  level();
  make_error ("called from main");

  pthread_create(&ebbr, NULL, brussels_fn, NULL);	
  pthread_create(&egll, NULL, london_fn, NULL);	
  pthread_create(&zzzz, NULL, petaouchnok_fn, NULL);	

  loopmain = 1;
  while (! (loopt1 && loopt2 && loopmain))
    loopmain++;
  for (i = 0; i < LOOPS; i++) {
     loopmain++;

     if (loopmain == 10000)
        make_error ("in main loop");
  }
  
  pthread_join(ebbr, NULL);

  make_error ("called from main (the end, before joining t3)");

  pthread_join(zzzz, NULL);

  if (argc > 2) {
     for (i = 0; i < 100; i++)
        if ((*(&undef + i*4000) == 0) || (*(&undef - i*4000) == 0)) {
           printf ("there are some null bytes here and there %d\n", i);
           fflush(stdout);
        }
  }
  exit(0);
}
