#include <sys/shm.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <stdlib.h>
#include <sys/wait.h>

#define QUIERO_ENTRAR 0
#define RESTO_PROCESO 1



// Algoritmo de Dekker con procesos Unix System V
// ĦOjo! En sistemas multiprocesador puede fallar si no se ejecuta con
// 	          taskset -c 0 Decker_con_procesos
// para asegurar un comportamiento monoprocesador

int main(int argc, char *argv[])
{
	key_t Clave;
	int Id_Memoria;
	int *Memoria = NULL;
	int i,j,k;
	pid_t pid;
	
	if(argc != 2){
	    fprintf(stderr,"Uso: %s <iteraciones>\n", argv[0]);
	    return 0;
	}
	int iteraciones = atoi(argv[1]);

	Clave = ftok ("/bin/ls", 33);
	if (Clave == -1)
	{
	  printf("No consigo clave para memoria compartida\n");
	  exit(0);
	}

	Id_Memoria = shmget (Clave, 4*sizeof(int), 0777 | IPC_CREAT);
	if (Id_Memoria == -1)
	{
	  printf("No consigo Id para memoria compartida\n");
	  exit (0);
	}

	Memoria = (int *)shmat (Id_Memoria, (char *)0, 0);
	if (Memoria == NULL)
	{
	  printf("No consigo memoria compartida\n");
	  exit (0);
	}

	//
	//	Ya podemos utilizar la memoria compartida
	//
	Memoria[0] = RESTO_PROCESO;  //C0
	Memoria[1] = RESTO_PROCESO;  //C1
	Memoria[2] = 0;     // turno
	Memoria[3] = 0;    // Aqui esta el contador
	
	pid = fork();

	if( pid == 0)
	{
		i = 1;
		j = 0;
	}
	else
	{
		i = 0;
		j = 1;
	}

	for(k = 0; k < iteraciones; k++)
	{
		// Protocolo de entrada
		Memoria[i] = QUIERO_ENTRAR;
		while( Memoria[j] == QUIERO_ENTRAR )
		{
			if (Memoria[2] == j)
			{
				Memoria[i] = RESTO_PROCESO;
				while( Memoria[2] == j );
				Memoria[i] = QUIERO_ENTRAR;
			}
		}
			
		// Seccion critica
		Memoria[3]++;
 
		// Protocolo de salida
		Memoria[2] = j;
		Memoria[i] = RESTO_PROCESO;

		// Resto proceso
		// ...
	}
		

	if(pid != 0) // Esperamos a que acabe el hijo antes de acabar el programa
	{
		waitpid(pid,NULL,0);

		printf("El resultado final es %d y debia ser %d\n",Memoria[3],2*iteraciones);

		shmdt ((char *)Memoria);
		shmctl (Id_Memoria, IPC_RMID, (struct shmid_ds *)NULL);
	}
	return 0;
}
