// !> Multi-threaded sum using a single global variable and mutexes
/** 
 * Usage
 *
 * ./sum <from> <to>
 */
#include <stdio.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <unistd.h>
#include <pthread.h>
#include <assert.h>
long sum = 0;
pthread_mutex_t sum_lock = PTHREAD_MUTEX_INITIALIZER;
typedef struct {
  long from;
  long to;
} sum_args_t;
long sum_from_to(long from, long to) {
  for (long i = from; i <= to; ++i) {
    // enter if allowed, lock entry
    //while (sum_lock) { /* wait */ };
    //sum_lock = 1;
    pthread_mutex_lock(&sum_lock);
    sum += i; // not performed atomically
    pthread_mutex_unlock(&sum_lock);
    //sum_lock = 0; //unlock
    // unlock entry, and exit
    // movq sum, %rax
    // addq %rcx, %rax
    // movq %rax, sum
//
//   sum        Thread 1          Thread 2
//   100        read 100          ---
//   100        add 12 to 100
//   112        write 112 to sum
//   112        read 112 from sum 
//   112        ---               read 112 from sum
//   112                          add 52 to 112
//   164                          write 164 to sum
//   164        add 13 112        ---
//   125        write 125 to sum
  }
  fprintf(stderr, "Completed %ld to %ld\n", from, to);
}
void *sum_thread(void *args) {
  sum_args_t *sum_args = args;
  sum_from_to(sum_args->from, sum_args->to);
  return NULL;
}
int main(int argc, char **argv) {
  assert(argc >= 3);
  long from = atol(argv[1]);
  long to = atol(argv[2]);
  pthread_t th;
  sum_args_t sum_args = { .from = from, .to = to / 2 };
  // perform sum of 'from' to 'to / 2' in helper thread 
  assert(0 == pthread_create(&th, NULL, sum_thread, &sum_args));
  // perform sum of  '(to / 2) + 1' to 'to'
  sum_from_to(to / 2 + 1, to);
  assert(0 == pthread_join(th, NULL));
  printf("%ld\n", sum);
  return 0;
}