/* example of race condition bewtween threads updating shared variable

   For simplicity, the program terminates via exit (), timeout, or
   via a killing signal from the user.

   This program sometimes terminates with "segmentation fault".
   Can you guess how that might happen?

 */

#define _XOPEN_SOURCE 500
#define _REENTRANT
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

#define TOTAL 1000000000

volatile long A = 500000000;
volatile long B = 500000000;
volatile long count_1 = 0;
volatile long count_2 = 0;

/* why do we specify the attribute "handler (int sig) {
  fprintf (stderr, "exiting due to signal %d\n", sig);
  fprintf (stderr, "count_1 = %ld10 count_2 = %ld10\n", count_1, count_2);
  exit (-1);  
}

void check_consistency () {
  long total;
  total = A + B;
  if (total != TOTAL) {
    fprintf (stderr, "*** LOSS OF CONSISTENCY ***\n");
    fprintf (stderr, "main:  A = %ld10 B = %ld10 TOTAL-(A+B) = %ld10\n",
      A, B, TOTAL - total);
    fprintf (stderr, "count_1 = %ld10 count_2 = %ld10\n", count_1, count_2);
    exit (-1);
  }
}

void * thread_body (void *arg) {
  while (1) {
    count_2++;
    transfer (10, &B, &A);
    check_consistency ();
  }
  return (void *) NULL;
}

int
main (int argc, char **argv) {

   pthread_attr_t attrs;
   pthread_t thread;

   struct sigaction act;

   /* install handler for alarm signal */

   sigaction (SIGALRM, NULL, &act);
   act.sa_handler = handler;
   sigaction (SIGALRM, &act, NULL);

   alarm (10);  /* will kill entire process in 10 seconds */

   pthread_setconcurrency (2);

   pthread_attr_init (&attrs);
   /* use the default attributes */
   /* create thread */
   pthread_create (
     &thread,     /* place to store the id of new thread */
     &attrs,      /* thread creation attributes */
     thread_body, /* function for thread to execute */
     NULL);       /* pass no parameter */

  while (1) {
    count_1++;
    transfer (10, &A, &B);
    check_consistency ();
  }

  exit (0);
}