#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <assert.h>  

int a = 10;
int b = 17;
int c = 12;

#define ITERS 1000000

pthread_mutex_t lock;

void *lock_main(void *p){

  int i;
  for(i = 0; i < ITERS; i++){

    pthread_mutex_lock(&lock);
    c += (a + b); 
    pthread_mutex_unlock(&lock);

  }

}

void *relaxed_main(void *p){

  int i;
  for(i = 0; i < ITERS; i++){

    __transaction_relaxed{ c += (a + b); }

  }

}

void *atomic_main(void *p){

  int i;
  for(i = 0; i < ITERS; i++){

    __transaction_atomic{ c += (a + b); }

  }

}

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

  assert(argc == 3);
  int NUM_THREADS = atoi(argv[1]);
  char *modeStr = argv[2];
  int mode = -1;
  if( !(strncmp(modeStr,"atom",4) ) ){
    //atomic transactions
    fprintf(stderr,"Running with __transaction_atomic\n");
    mode = 1;
  }else if( !( strncmp(modeStr,"relax",5) ) ){
    //relaxed transactions
    fprintf(stderr,"Running with __transaction_relaxed\n");
    mode = 2;
  }else{
    //locks
    fprintf(stderr,"Running with pthread_mutex_lock/unlock\n");
    pthread_mutex_init(&lock,NULL);
    mode = 3;
  }

  pthread_t threads[NUM_THREADS];

  int i;
  for(i = 0; i < NUM_THREADS; i++){
    if( mode == 1 ){
      pthread_create( &(threads[i]), NULL, atomic_main, NULL );
    }else if(mode == 2){
      pthread_create( &(threads[i]), NULL, relaxed_main, NULL );
    }else{
      pthread_create( &(threads[i]), NULL, lock_main, NULL );
    }
  }

  for(i = 0; i < NUM_THREADS; i++){
    pthread_join( threads[i], NULL );
  }

  fprintf(stderr,"%d\n",c);

}
