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


// Programa para ilustrar el uso de memoria compartida en Unix/System V


int main(int argc, char *argv[])
{
	key_t Clave;
	int Id_Memoria;
	int *Memoria = NULL;
	int i;
	pid_t pid;
	int iteraciones;

	if(argc != 2){
	  fprintf(stderr, "Uso: %s <iteraciones>\n", argv[0]);
	  return 0;
	}

	iteraciones = atoi(argv[1]);

	//
	//	Conseguimos una clave para la memoria compartida. Todos los
	//	procesos que quieran compartir la memoria, deben obtener la misma
	//	clave. Esta se puede conseguir por medio de la función ftok.
	//	A esta función se le pasa un fichero cualquiera que exista y esté
	//	accesible (todos los procesos deben pasar el mismo fichero) y un
	//	entero cualquiera (todos los procesos el mismo entero).
	//
	Clave = ftok ("/bin/ls", 33);
	if (Clave == -1)
	{
	  printf("No consigo clave para memoria compartida\n");
	  exit(0);
	}

	//
	//	Creamos la memoria con la clave recién conseguida. Para ello llamamos
	//	a la función shmget pasándole la clave, el tamaño de memoria que
	//	queremos reservar (1 entero en nuestro caso) y unos flags.
	//	Los flags son  los permisos de lectura/escritura/ejecucion
	//	para propietario, grupo y otros (es el 777 en octal) y el
	//	flag IPC_CREAT para indicar que cree la memoria.
	//	La función nos devuelve un identificador para la memoria recién
	//	creada.
	//
	Id_Memoria = shmget (Clave, sizeof(int), 0777 | IPC_CREAT);
	if (Id_Memoria == -1)
	{
	  printf("No consigo Id para memoria compartida\n");
	  exit (0);
	}

	//
	//	Una vez creada la memoria, hacemos que uno de nuestros punteros
	//	apunte a la zona de memoria recién creada. Para ello llamamos a
	//	shmat, pasándole el identificador obtenido anteriormente y un
	//	par de parámetros extraños, que con ceros vale.
	//
	Memoria = (int *)shmat (Id_Memoria, (char *)0, 0);
	if (Memoria == NULL)
	{
	  printf("No consigo memoria compartida\n");
	  exit (0);
	}

	//
	//	Ya podemos utilizar la memoria.
	//


	*Memoria=0;
	pid = fork();

	if( pid == 0){
	  for(i=0; i<iteraciones; i++){
	    //sleep(rand()%3);
	    (*Memoria)++;
	  }
	  return 0;
	}

//	waitpid(pid,NULL,0);  	// Si esperamos aqui a que acabe
                                //el hijo el resultado sera siempre 10

	for(i=0; i<iteraciones; i++){
	  //sleep(rand()%3);
	  (*Memoria)++;
	}

	waitpid(pid,NULL,0);  // Esperamos a que acabe el hijo

	printf("El valor final de la memoria compartida es %d "
	       "y tenia que ser %d\n",*Memoria, 2*iteraciones);

	//
	//	Terminada de usar la memoria compartida, la liberamos.
	//
	shmdt ((char *)Memoria);
	shmctl (Id_Memoria, IPC_RMID, (struct shmid_ds *)NULL);
	return 0;
}
