/*TESTO

Si realizzi in ambienteUnix/C la seguente interazione tra processi:

-il processo genera due processi figli;
-ogni processo figliovisualizza il proprio pid e un numero casuale tra 0 e N compresi; N e' un numero intero che l'utente 
 specifica come unico argomento di invocazione del programma;
-il processo che ha generato il numero casuale minore invia un SIGUSR1 all'altro processo figlio, visualizza un messaggio
 con il proprio pid e si pone in attesa di un segnale;
-il processo che riceve il segnale SIGUSR1 visualizza un messaggio con il proprio pid e si termina;
-il padre, dopo che un figlio e' terminato, invia un segnale all'altro figlio, e termina con un messaggio.
*/

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <errno.h>




//Funzione di gestione segnali
void handler()
{
  printf("Processo figlio %d ha ricevuto un SIGUSR1 ed esce\n",getpid());

  exit(3);
}




int main(int argc, char *argv[])
{
  struct sigaction sig;
  sigset_t newmask;
  int exit_pid,pid[2],status,pp[2][2],numero,mynumero,N,i;


  if(argc<2 || atoi(argv[1])<=0 || atoi(argv[1])>=RAND_MAX)
    {
      printf("ERRORE negli argomenti\n");
      printf("Uso: programma <N>\n");
      printf("N deve essere maggiore di 0 e minore di RAND_MAX\n");
      exit(-1);
    }

  //setto N
  N=atoi(argv[1]);

  //creo le due pipe che i figli useranno per scambiarsi i pid e il numero casuale
  //una pp[0] verra usata in scrittura dal primo figlio, pp[2] dal secondo
  //
  //pp e' un vettore di pipe
  if(pipe(pp[0])<0) 
    {
      perror("pipe 0");
      exit(-1);
    }

  if(pipe(pp[1])<0) 
    {
      perror("pipe 1");
      exit(-1);
    }

  //GENERO I FIGLI
  for(i=0;i<2;i++)
    {
      if((pid[i]=fork())<0) //genero il primo figlio
	{
	  perror("fork primo figlio");
	  exit(-1);
	}
      if(pid[i]==0)
	{
	  //CODICE FIGLI
	  printf("Sono il figlio %d\n",getpid());

	  //metto nel *mio* vettore il mio pid
	  pid[i]=getpid();

          //blocco il segnale SIGUSR1
          sigemptyset(&newmask);
          sigaddset(&newmask,SIGUSR1);
          sigprocmask(SIG_BLOCK,&newmask,NULL);

	  //installo il gestore del sengale SIGUSR1
	  sig.sa_handler = handler;
	  sigemptyset(&sig.sa_mask);
	  sig.sa_flags=0;        //non ho bisogno di flag particolari
	  sigaction(SIGUSR1,&sig,NULL);

	  //chiudo la mia pipe di scrittura dal lato di lettura
	  close(pp[i][0]);

	  //chiudo la mia pipe di lettura dal alto di scrittura
	  close(pp[(i+1)%2][1]);

	  //inizializzo il generatore di numero casuali e ne genero uno compreso tra 0 e N;
	  srand(getpid());
	  mynumero=rand()%N;
	  printf("Figlio %d ha generato il numero %d\n",getpid(),mynumero);


	  //scrivo il mio pid e il numero casuale
	  if(write(pp[i][1],&pid[i],sizeof(int))<0)
	    {
	      perror("write pid");
	      exit(-1);
	    }
	  if(write(pp[i][1],&mynumero,sizeof(int))<0)
	    {
	      perror("write numero");
	      exit(-1);
	    }
	  //leggo pid e numero casuale dall'altro figlio
	  if(read(pp[(i+1)%2][0],&pid[(i+1)%2],sizeof(int))<0)
	    {
	      perror("read pid");
	      exit(-1);
	    }
	  if(read(pp[(i+1)%2][0],&numero,sizeof(int))<0)
	    {
	      perror("read numero");
	      exit(-1);
	    }
	  //notare come la pipe sia il punto di sincronismo tra i due figli: per fare una
	  //lettura/scrittura entrambi sevono essere arrivati a questo punto, e quindi hanno
	  //anche il gestore dei segnali gia' pronto


	  //se il mio numero e' minore di quello che ho ricevuto, o se sono
	  //uguali ma il mio pid e' minore, mando un SIGUSR all'altro figlio
	  if(mynumero<numero || (mynumero==numero && getpid()<pid[(i+1)%2]))
	    {
	      printf("Figlio %d manda un SIGUSR1 a %d\n",getpid(),pid[(i+1)%2]); 
	      kill(pid[(i+1)%2],SIGUSR1);
	    }

	  //mi metto in attesa di un segnale qualunque
	  //questo va bene sia per entrambi i figli
	  //sig.sa_mask e' empty
	  printf("Figlio %d si sospende...\n",getpid());
	  sigsuspend(&(sig.sa_mask));
	}
    }

  //CODICE PADRE

  printf("Padre: ho pid %d, i figli sono %d %d\n",getpid(),pid[0],pid[1]);

  //chiudo entrambe le pipe, non mi servono
  close(pp[0][0]);
  close(pp[0][1]);
  close(pp[1][0]);
  close(pp[1][1]);

  //aspetto che il primo figlio esca (sara' quello che ha ricevuto SIGUSR1 dall'altro)
  exit_pid=wait(&status);
  if(exit_pid<0)
    {
      perror("wait");
      exit(-1);
    }
  printf("Padre: figlio %d uscito\n",exit_pid);

  //mando un sigusr1 al processo che e' ancora vivo
  kill( ((pid[0]==exit_pid) ? pid[1] : pid[0]) , SIGUSR1);
  printf("Padre: ho mandato una SIGUSR1 al figlio %d\n",((pid[0]==exit_pid) ? pid[1] : pid[0]));

  return 0;

}
 

/*
---IF aritmentico---

variabile = (condizione) ? valore1 : valore2; 

Questo e' equivalente a:

if(condizione)
  variabile=valore1:
else
  variabile=valore2;



---Resto---
L'operatore % da il resto di una divisione:

resto = dividendo%divisore;

ES.
0%2 = 0
1%2 = 1
2%2 = 0
3%2 = 1
4%2 = 0
5%2 = 1
ecc.

*/


