// gcc Peterson_con_barrera.c -o Peterson_con_barrera -lpthread

#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>


#define NUM_THREADS 2
#define MAX_COUNT 10000000

// Just used to send the index of the id
struct tdata {
    int tid;
};

// Variables for Peterson algorithm
int states[NUM_THREADS];
int turn = 0;

int counter = 0;

void lock(int i) {
    int j =  (i + 1) % 2; // The "other"

    states[i] = 1;
    turn = j;
    __atomic_thread_fence(__ATOMIC_SEQ_CST); // Full memory barrier
    while (states[j] && turn == j);
}

void unlock(int i) {
    states[i] = 0;
}
    
void *count(void *ptr) {
    long i, max = MAX_COUNT/NUM_THREADS;
    int tid = ((struct tdata *) ptr)->tid;

    for (i=0; i < max; i++) {
        lock(tid);
        counter += 1; // The global variable, i.e. the critical section
        unlock(tid);
    }

    printf("End %d counter: %d\n", tid, counter);
}

int main (int argc, char *argv[]) {
    pthread_t threads[NUM_THREADS];
    int rc, i;
    struct tdata id[NUM_THREADS];

    for(i=0; i<NUM_THREADS; i++){
        id[i].tid = i;
        rc = pthread_create(&threads[i], NULL, count, (void *) &id[i]);
    }

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

    printf("Counter value: %d Expected: %d\n", counter, MAX_COUNT);
    return 0;
}
