/*
 * Algoritmo do desempate proposto por Peterson.
 */
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

volatile int s = 0; /* Variável compartilhada */
volatile int vez0 = 0;
volatile int vez1 = 0;
volatile int interesse[3] = {0, 0, 0}; /* Indica quais threads estão
					  interessadas em entrar na região crítica */

void* f_thread_0(void *v) {
  int i;

  for (i = 0; i < 10; i++) {
    interesse[0] = 1; /* Marca que esta thread está interessada */
    sleep(1);
    vez0 = 0;
    while (vez0 == 0 && interesse[1] && interesse[2]);

    vez1 = 0;
    while (vez1 == 0 && (interesse[1] || interesse[2]));
    
    s = 0;
    sleep(1);
    printf("Thread 0, s = %d.\n", s);

    interesse[0] = 0; /* Marca que saiu da região crítica */
    sleep(1);
  }

  return NULL;
}

void* f_thread_1(void *v) {
  int i;

  for (i = 0; i < 10; i++) {

    interesse[1] = 1;
    vez0 = 1;
    while (vez0 == 1 && interesse[0] && interesse[2]);

    vez1 = 1;
    while (vez1 == 1 && (interesse[0] || interesse[2]));

    s = 1;
    sleep(1);
    printf("Thread 1, s = %d.\n", s);

    interesse[1] = 0;
    sleep(1);
  }
  return NULL;
}

void* f_thread_2(void *v) {
  int i;

  for (i = 0; i < 10; i++) {
    interesse[2] = 1; /* Marca que esta thread está interessada */
    sleep(1);
    
    vez0 = 2;
    while (vez0 == 2 && interesse[1] && interesse[0]) ;

    vez1 = 2;
    while (vez1 == 2 && (interesse[1] || interesse[0])) ;
    
    s = 2;
    sleep(1);
    printf("Thread 2, s = %d.\n", s);

    interesse[2] = 0; /* Marca que saiu da região crítica */
    sleep(1);
  }

  return NULL;
}

int main() {

  pthread_t thr0, thr1, thr2;

  pthread_create(&thr0, NULL, f_thread_0, NULL);
  pthread_create(&thr1, NULL, f_thread_1, NULL);
  pthread_create(&thr2, NULL, f_thread_2, NULL);

  pthread_join(thr0, NULL);
  pthread_join(thr1, NULL);
  pthread_join(thr2, NULL);
  return 0;
}